mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-04-05 10:17:50 +00:00
Compare commits
5 Commits
36.0-dev12
...
36.0-dev17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b280ecd6d | ||
|
|
de554f5fb6 | ||
|
|
7c159fffc0 | ||
|
|
1f2f63d11b | ||
|
|
e2544aea12 |
@@ -11,7 +11,6 @@ module.exports = defineConfig({
|
|||||||
testUrl: 'http://localhost:8899/',
|
testUrl: 'http://localhost:8899/',
|
||||||
redactHeaderContent: 'User-Header[REDACTED]',
|
redactHeaderContent: 'User-Header[REDACTED]',
|
||||||
redactBodyContent: '{ "User": "[REDACTED]" }',
|
redactBodyContent: '{ "User": "[REDACTED]" }',
|
||||||
regexMaskingBodyContent: '[REDACTED]',
|
|
||||||
greenFilterColor: 'rgb(210, 250, 210)',
|
greenFilterColor: 'rgb(210, 250, 210)',
|
||||||
redFilterColor: 'rgb(250, 214, 220)',
|
redFilterColor: 'rgb(250, 214, 220)',
|
||||||
bodyJsonClass: '.hljs',
|
bodyJsonClass: '.hljs',
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import {isValueExistsInElement} from "../testHelpers/TrafficHelper";
|
|
||||||
|
|
||||||
it('Loading Mizu', function () {
|
|
||||||
cy.visit(Cypress.env('testUrl'));
|
|
||||||
});
|
|
||||||
|
|
||||||
isValueExistsInElement(true, Cypress.env('regexMaskingBodyContent'), Cypress.env('bodyJsonClass'));
|
|
||||||
@@ -2,10 +2,8 @@ package acceptanceTests
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -343,7 +341,7 @@ func TestTapRedact(t *testing.T) {
|
|||||||
|
|
||||||
tapNamespace := GetDefaultTapNamespace()
|
tapNamespace := GetDefaultTapNamespace()
|
||||||
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
||||||
tapCmdArgs = append(tapCmdArgs, "--redact")
|
tapCmdArgs = append(tapCmdArgs, "--redact", "--set", "tap.redact-patterns.request-headers=User-Header", "--set", "tap.redact-patterns.request-body=User")
|
||||||
|
|
||||||
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
||||||
t.Logf("running command: %v", tapCmd.String())
|
t.Logf("running command: %v", tapCmd.String())
|
||||||
@@ -429,60 +427,6 @@ func TestTapNoRedact(t *testing.T) {
|
|||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/NoRedact.js\"")
|
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/NoRedact.js\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTapRegexMasking(t *testing.T) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip("ignored acceptance test")
|
|
||||||
}
|
|
||||||
|
|
||||||
cliPath, cliPathErr := GetCliPath()
|
|
||||||
if cliPathErr != nil {
|
|
||||||
t.Errorf("failed to get cli path, err: %v", cliPathErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tapCmdArgs := GetDefaultTapCommandArgs()
|
|
||||||
|
|
||||||
tapNamespace := GetDefaultTapNamespace()
|
|
||||||
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
|
||||||
|
|
||||||
tapCmdArgs = append(tapCmdArgs, "--redact")
|
|
||||||
|
|
||||||
tapCmdArgs = append(tapCmdArgs, "-r", "Mizu")
|
|
||||||
|
|
||||||
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
|
||||||
t.Logf("running command: %v", tapCmd.String())
|
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
if err := CleanupCommand(tapCmd); err != nil {
|
|
||||||
t.Logf("failed to cleanup tap command, err: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := tapCmd.Start(); err != nil {
|
|
||||||
t.Errorf("failed to start tap command, err: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
apiServerUrl := GetApiServerUrl(DefaultApiServerPort)
|
|
||||||
|
|
||||||
if err := WaitTapPodsReady(apiServerUrl); err != nil {
|
|
||||||
t.Errorf("failed to start tap pods on time, err: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyUrl := GetProxyUrl(DefaultNamespaceName, DefaultServiceName)
|
|
||||||
for i := 0; i < DefaultEntriesCount; i++ {
|
|
||||||
response, requestErr := http.Post(fmt.Sprintf("%v/post", proxyUrl), "text/plain", bytes.NewBufferString("Mizu"))
|
|
||||||
if _, requestErr = ExecuteHttpRequest(response, requestErr); requestErr != nil {
|
|
||||||
t.Errorf("failed to send proxy request, err: %v", requestErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/RegexMasking.js\"")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTapIgnoredUserAgents(t *testing.T) {
|
func TestTapIgnoredUserAgents(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("ignored acceptance test")
|
t.Skip("ignored acceptance test")
|
||||||
|
|||||||
@@ -11,75 +11,30 @@ import (
|
|||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keep it because we might want cookies in the future
|
func BuildHeaders(rawHeaders map[string]interface{}) ([]Header, string, string, string, string, string) {
|
||||||
//func BuildCookies(rawCookies []interface{}) []har.Cookie {
|
|
||||||
// cookies := make([]har.Cookie, 0, len(rawCookies))
|
|
||||||
//
|
|
||||||
// for _, cookie := range rawCookies {
|
|
||||||
// c := cookie.(map[string]interface{})
|
|
||||||
// expiresStr := ""
|
|
||||||
// if c["expires"] != nil {
|
|
||||||
// expiresStr = c["expires"].(string)
|
|
||||||
// }
|
|
||||||
// expires, _ := time.Parse(time.RFC3339, expiresStr)
|
|
||||||
// httpOnly := false
|
|
||||||
// if c["httponly"] != nil {
|
|
||||||
// httpOnly, _ = strconv.ParseBool(c["httponly"].(string))
|
|
||||||
// }
|
|
||||||
// secure := false
|
|
||||||
// if c["secure"] != nil {
|
|
||||||
// secure, _ = strconv.ParseBool(c["secure"].(string))
|
|
||||||
// }
|
|
||||||
// path := ""
|
|
||||||
// if c["path"] != nil {
|
|
||||||
// path = c["path"].(string)
|
|
||||||
// }
|
|
||||||
// domain := ""
|
|
||||||
// if c["domain"] != nil {
|
|
||||||
// domain = c["domain"].(string)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// cookies = append(cookies, har.Cookie{
|
|
||||||
// Name: c["name"].(string),
|
|
||||||
// Value: c["value"].(string),
|
|
||||||
// Path: path,
|
|
||||||
// Domain: domain,
|
|
||||||
// HTTPOnly: httpOnly,
|
|
||||||
// Secure: secure,
|
|
||||||
// Expires: expires,
|
|
||||||
// Expires8601: expiresStr,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return cookies
|
|
||||||
//}
|
|
||||||
|
|
||||||
func BuildHeaders(rawHeaders []interface{}) ([]Header, string, string, string, string, string) {
|
|
||||||
var host, scheme, authority, path, status string
|
var host, scheme, authority, path, status string
|
||||||
headers := make([]Header, 0, len(rawHeaders))
|
headers := make([]Header, 0, len(rawHeaders))
|
||||||
|
|
||||||
for _, header := range rawHeaders {
|
for key, value := range rawHeaders {
|
||||||
h := header.(map[string]interface{})
|
|
||||||
|
|
||||||
headers = append(headers, Header{
|
headers = append(headers, Header{
|
||||||
Name: h["name"].(string),
|
Name: key,
|
||||||
Value: h["value"].(string),
|
Value: value.(string),
|
||||||
})
|
})
|
||||||
|
|
||||||
if h["name"] == "Host" {
|
if key == "Host" {
|
||||||
host = h["value"].(string)
|
host = value.(string)
|
||||||
}
|
}
|
||||||
if h["name"] == ":authority" {
|
if key == ":authority" {
|
||||||
authority = h["value"].(string)
|
authority = value.(string)
|
||||||
}
|
}
|
||||||
if h["name"] == ":scheme" {
|
if key == ":scheme" {
|
||||||
scheme = h["value"].(string)
|
scheme = value.(string)
|
||||||
}
|
}
|
||||||
if h["name"] == ":path" {
|
if key == ":path" {
|
||||||
path = h["value"].(string)
|
path = value.(string)
|
||||||
}
|
}
|
||||||
if h["name"] == ":status" {
|
if key == ":status" {
|
||||||
status = h["value"].(string)
|
status = value.(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,8 +74,8 @@ func BuildPostParams(rawParams []interface{}) []Param {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewRequest(request map[string]interface{}) (harRequest *Request, err error) {
|
func NewRequest(request map[string]interface{}) (harRequest *Request, err error) {
|
||||||
headers, host, scheme, authority, path, _ := BuildHeaders(request["_headers"].([]interface{}))
|
headers, host, scheme, authority, path, _ := BuildHeaders(request["headers"].(map[string]interface{}))
|
||||||
cookies := make([]Cookie, 0) // BuildCookies(request["_cookies"].([]interface{}))
|
cookies := make([]Cookie, 0)
|
||||||
|
|
||||||
postData, _ := request["postData"].(map[string]interface{})
|
postData, _ := request["postData"].(map[string]interface{})
|
||||||
mimeType := postData["mimeType"]
|
mimeType := postData["mimeType"]
|
||||||
@@ -134,12 +89,20 @@ func NewRequest(request map[string]interface{}) (harRequest *Request, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
queryString := make([]QueryString, 0)
|
queryString := make([]QueryString, 0)
|
||||||
for _, _qs := range request["_queryString"].([]interface{}) {
|
for key, value := range request["queryString"].(map[string]interface{}) {
|
||||||
qs := _qs.(map[string]interface{})
|
if valuesInterface, ok := value.([]interface{}); ok {
|
||||||
queryString = append(queryString, QueryString{
|
for _, valueInterface := range valuesInterface {
|
||||||
Name: qs["name"].(string),
|
queryString = append(queryString, QueryString{
|
||||||
Value: qs["value"].(string),
|
Name: key,
|
||||||
})
|
Value: valueInterface.(string),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
queryString = append(queryString, QueryString{
|
||||||
|
Name: key,
|
||||||
|
Value: value.(string),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s%s", host, request["url"].(string))
|
url := fmt.Sprintf("http://%s%s", host, request["url"].(string))
|
||||||
@@ -172,8 +135,8 @@ func NewRequest(request map[string]interface{}) (harRequest *Request, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewResponse(response map[string]interface{}) (harResponse *Response, err error) {
|
func NewResponse(response map[string]interface{}) (harResponse *Response, err error) {
|
||||||
headers, _, _, _, _, _status := BuildHeaders(response["_headers"].([]interface{}))
|
headers, _, _, _, _, _status := BuildHeaders(response["headers"].(map[string]interface{}))
|
||||||
cookies := make([]Cookie, 0) // BuildCookies(response["_cookies"].([]interface{}))
|
cookies := make([]Cookie, 0)
|
||||||
|
|
||||||
content, _ := response["content"].(map[string]interface{})
|
content, _ := response["content"].(map[string]interface{})
|
||||||
mimeType := content["mimeType"]
|
mimeType := content["mimeType"]
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ func init() {
|
|||||||
tapCmd.Flags().Uint16P(configStructs.GuiPortTapName, "p", defaultTapConfig.GuiPort, "Provide a custom port for the web interface webserver")
|
tapCmd.Flags().Uint16P(configStructs.GuiPortTapName, "p", defaultTapConfig.GuiPort, "Provide a custom port for the web interface webserver")
|
||||||
tapCmd.Flags().StringSliceP(configStructs.NamespacesTapName, "n", defaultTapConfig.Namespaces, "Namespaces selector")
|
tapCmd.Flags().StringSliceP(configStructs.NamespacesTapName, "n", defaultTapConfig.Namespaces, "Namespaces selector")
|
||||||
tapCmd.Flags().BoolP(configStructs.AllNamespacesTapName, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces")
|
tapCmd.Flags().BoolP(configStructs.AllNamespacesTapName, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces")
|
||||||
tapCmd.Flags().StringSliceP(configStructs.PlainTextFilterRegexesTapName, "r", defaultTapConfig.PlainTextFilterRegexes, "List of regex expressions that are used to filter matching values from text/plain http bodies")
|
|
||||||
tapCmd.Flags().Bool(configStructs.EnableRedactionTapName, defaultTapConfig.EnableRedaction, "Enables redaction of potentially sensitive request/response headers and body values")
|
tapCmd.Flags().Bool(configStructs.EnableRedactionTapName, defaultTapConfig.EnableRedaction, "Enables redaction of potentially sensitive request/response headers and body values")
|
||||||
tapCmd.Flags().String(configStructs.HumanMaxEntriesDBSizeTapName, defaultTapConfig.HumanMaxEntriesDBSize, "Override the default max entries db size")
|
tapCmd.Flags().String(configStructs.HumanMaxEntriesDBSizeTapName, defaultTapConfig.HumanMaxEntriesDBSize, "Override the default max entries db size")
|
||||||
tapCmd.Flags().String(configStructs.InsertionFilterName, defaultTapConfig.InsertionFilter, "Set the insertion filter. Accepts string or a file path.")
|
tapCmd.Flags().String(configStructs.InsertionFilterName, defaultTapConfig.InsertionFilter, "Set the insertion filter. Accepts string or a file path.")
|
||||||
|
|||||||
@@ -230,23 +230,8 @@ func getErrorDisplayTextForK8sTapManagerError(err kubernetes.K8sTapManagerError)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) {
|
func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) {
|
||||||
var compiledRegexSlice []*api.SerializableRegexp
|
|
||||||
|
|
||||||
if config.Config.Tap.PlainTextFilterRegexes != nil && len(config.Config.Tap.PlainTextFilterRegexes) > 0 {
|
|
||||||
compiledRegexSlice = make([]*api.SerializableRegexp, 0)
|
|
||||||
for _, regexStr := range config.Config.Tap.PlainTextFilterRegexes {
|
|
||||||
compiledRegex, err := api.CompileRegexToSerializableRegexp(regexStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
compiledRegexSlice = append(compiledRegexSlice, compiledRegex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &api.TrafficFilteringOptions{
|
return &api.TrafficFilteringOptions{
|
||||||
PlainTextMaskingRegexes: compiledRegexSlice,
|
IgnoredUserAgents: config.Config.Tap.IgnoredUserAgents,
|
||||||
IgnoredUserAgents: config.Config.Tap.IgnoredUserAgents,
|
|
||||||
EnableRedaction: config.Config.Tap.EnableRedaction,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
@@ -15,38 +16,43 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GuiPortTapName = "gui-port"
|
GuiPortTapName = "gui-port"
|
||||||
NamespacesTapName = "namespaces"
|
NamespacesTapName = "namespaces"
|
||||||
AllNamespacesTapName = "all-namespaces"
|
AllNamespacesTapName = "all-namespaces"
|
||||||
PlainTextFilterRegexesTapName = "regex-masking"
|
EnableRedactionTapName = "redact"
|
||||||
EnableRedactionTapName = "redact"
|
HumanMaxEntriesDBSizeTapName = "max-entries-db-size"
|
||||||
HumanMaxEntriesDBSizeTapName = "max-entries-db-size"
|
InsertionFilterName = "insertion-filter"
|
||||||
InsertionFilterName = "insertion-filter"
|
DryRunTapName = "dry-run"
|
||||||
DryRunTapName = "dry-run"
|
ServiceMeshName = "service-mesh"
|
||||||
ServiceMeshName = "service-mesh"
|
TlsName = "tls"
|
||||||
TlsName = "tls"
|
ProfilerName = "profiler"
|
||||||
ProfilerName = "profiler"
|
MaxLiveStreamsName = "max-live-streams"
|
||||||
MaxLiveStreamsName = "max-live-streams"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TapConfig struct {
|
type TapConfig struct {
|
||||||
PodRegexStr string `yaml:"regex" default:".*"`
|
PodRegexStr string `yaml:"regex" default:".*"`
|
||||||
GuiPort uint16 `yaml:"gui-port" default:"8899"`
|
GuiPort uint16 `yaml:"gui-port" default:"8899"`
|
||||||
ProxyHost string `yaml:"proxy-host" default:"127.0.0.1"`
|
ProxyHost string `yaml:"proxy-host" default:"127.0.0.1"`
|
||||||
Namespaces []string `yaml:"namespaces"`
|
Namespaces []string `yaml:"namespaces"`
|
||||||
AllNamespaces bool `yaml:"all-namespaces" default:"false"`
|
AllNamespaces bool `yaml:"all-namespaces" default:"false"`
|
||||||
PlainTextFilterRegexes []string `yaml:"regex-masking"`
|
IgnoredUserAgents []string `yaml:"ignored-user-agents"`
|
||||||
IgnoredUserAgents []string `yaml:"ignored-user-agents"`
|
EnableRedaction bool `yaml:"redact" default:"false"`
|
||||||
EnableRedaction bool `yaml:"redact" default:"false"`
|
RedactPatterns struct {
|
||||||
HumanMaxEntriesDBSize string `yaml:"max-entries-db-size" default:"200MB"`
|
RequestHeaders []string `yaml:"request-headers"`
|
||||||
InsertionFilter string `yaml:"insertion-filter" default:""`
|
ResponseHeaders []string `yaml:"response-headers"`
|
||||||
DryRun bool `yaml:"dry-run" default:"false"`
|
RequestBody []string `yaml:"request-body"`
|
||||||
ApiServerResources shared.Resources `yaml:"api-server-resources"`
|
ResponseBody []string `yaml:"response-body"`
|
||||||
TapperResources shared.Resources `yaml:"tapper-resources"`
|
RequestQueryParams []string `yaml:"request-query-params"`
|
||||||
ServiceMesh bool `yaml:"service-mesh" default:"false"`
|
} `yaml:"redact-patterns"`
|
||||||
Tls bool `yaml:"tls" default:"false"`
|
HumanMaxEntriesDBSize string `yaml:"max-entries-db-size" default:"200MB"`
|
||||||
Profiler bool `yaml:"profiler" default:"false"`
|
InsertionFilter string `yaml:"insertion-filter" default:""`
|
||||||
MaxLiveStreams int `yaml:"max-live-streams" default:"500"`
|
DryRun bool `yaml:"dry-run" default:"false"`
|
||||||
|
ApiServerResources shared.Resources `yaml:"api-server-resources"`
|
||||||
|
TapperResources shared.Resources `yaml:"tapper-resources"`
|
||||||
|
ServiceMesh bool `yaml:"service-mesh" default:"false"`
|
||||||
|
Tls bool `yaml:"tls" default:"false"`
|
||||||
|
Profiler bool `yaml:"profiler" default:"false"`
|
||||||
|
MaxLiveStreams int `yaml:"max-live-streams" default:"500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *TapConfig) PodRegex() *regexp.Regexp {
|
func (config *TapConfig) PodRegex() *regexp.Regexp {
|
||||||
@@ -71,9 +77,48 @@ func (config *TapConfig) GetInsertionFilter() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redactFilter := getRedactFilter(config)
|
||||||
|
if insertionFilter != "" && redactFilter != "" {
|
||||||
|
return fmt.Sprintf("(%s) and (%s)", insertionFilter, redactFilter)
|
||||||
|
} else if insertionFilter == "" && redactFilter != "" {
|
||||||
|
return redactFilter
|
||||||
|
}
|
||||||
|
|
||||||
return insertionFilter
|
return insertionFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRedactFilter(config *TapConfig) string {
|
||||||
|
if !config.EnableRedaction {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var redactValues []string
|
||||||
|
for _, requestHeader := range config.RedactPatterns.RequestHeaders {
|
||||||
|
redactValues = append(redactValues, fmt.Sprintf("request.headers['%s']", requestHeader))
|
||||||
|
}
|
||||||
|
for _, responseHeader := range config.RedactPatterns.ResponseHeaders {
|
||||||
|
redactValues = append(redactValues, fmt.Sprintf("response.headers['%s']", responseHeader))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, requestBody := range config.RedactPatterns.RequestBody {
|
||||||
|
redactValues = append(redactValues, fmt.Sprintf("request.postData.text.json()...%s", requestBody))
|
||||||
|
}
|
||||||
|
for _, responseBody := range config.RedactPatterns.ResponseBody {
|
||||||
|
redactValues = append(redactValues, fmt.Sprintf("response.content.text.json()...%s", responseBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, requestQueryParams := range config.RedactPatterns.RequestQueryParams {
|
||||||
|
redactValues = append(redactValues, fmt.Sprintf("request.queryString['%s']", requestQueryParams))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(redactValues) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("redact(\"%s\")", strings.Join(redactValues, "\",\""))
|
||||||
|
}
|
||||||
|
|
||||||
func (config *TapConfig) Validate() error {
|
func (config *TapConfig) Validate() error {
|
||||||
_, compileErr := regexp.Compile(config.PodRegexStr)
|
_, compileErr := regexp.Compile(config.PodRegexStr)
|
||||||
if compileErr != nil {
|
if compileErr != nil {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ log "Writing output to $MIZU_BENCHMARK_OUTPUT_DIR"
|
|||||||
cd $MIZU_HOME || exit 1
|
cd $MIZU_HOME || exit 1
|
||||||
|
|
||||||
export HOST_MODE=0
|
export HOST_MODE=0
|
||||||
export SENSITIVE_DATA_FILTERING_OPTIONS='{"EnableRedaction": false}'
|
export SENSITIVE_DATA_FILTERING_OPTIONS='{}'
|
||||||
export MIZU_DEBUG_DISABLE_PCAP=false
|
export MIZU_DEBUG_DISABLE_PCAP=false
|
||||||
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false
|
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false
|
||||||
export MIZU_DEBUG_DISABLE_TCP_STREAM=false
|
export MIZU_DEBUG_DISABLE_TCP_STREAM=false
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
type TrafficFilteringOptions struct {
|
type TrafficFilteringOptions struct {
|
||||||
IgnoredUserAgents []string
|
IgnoredUserAgents []string
|
||||||
PlainTextMaskingRegexes []*SerializableRegexp
|
|
||||||
EnableRedaction bool
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect15/amqp/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect16/amqp/\* expect
|
||||||
|
|||||||
@@ -4,16 +4,20 @@ go 1.17
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
|
github.com/up9inc/mizu/logger v0.0.0
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||||
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
|
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace github.com/up9inc/mizu/logger v0.0.0 => ../../../logger
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api
|
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl
|
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||||
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/logger"
|
||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,14 +25,14 @@ var connectionMethodMap = map[int]string{
|
|||||||
61: "connection unblocked",
|
61: "connection unblocked",
|
||||||
}
|
}
|
||||||
|
|
||||||
// var channelMethodMap = map[int]string{
|
var channelMethodMap = map[int]string{
|
||||||
// 10: "channel open",
|
10: "channel open",
|
||||||
// 11: "channel open-ok",
|
11: "channel open-ok",
|
||||||
// 20: "channel flow",
|
20: "channel flow",
|
||||||
// 21: "channel flow-ok",
|
21: "channel flow-ok",
|
||||||
// 40: "channel close",
|
40: "channel close",
|
||||||
// 41: "channel close-ok",
|
41: "channel close-ok",
|
||||||
// }
|
}
|
||||||
|
|
||||||
var exchangeMethodMap = map[int]string{
|
var exchangeMethodMap = map[int]string{
|
||||||
10: "exchange declare",
|
10: "exchange declare",
|
||||||
@@ -94,29 +94,41 @@ type AMQPWrapper struct {
|
|||||||
Details interface{} `json:"details"`
|
Details interface{} `json:"details"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitAMQP(event interface{}, _type string, method string, connectionInfo *api.ConnectionInfo, captureTime time.Time, captureSize int, emitter api.Emitter, capture api.Capture) {
|
type emptyResponse struct {
|
||||||
request := &api.GenericMessage{
|
}
|
||||||
IsRequest: true,
|
|
||||||
CaptureTime: captureTime,
|
const emptyMethod = "empty"
|
||||||
Payload: AMQPPayload{
|
|
||||||
Data: &AMQPWrapper{
|
func getIdent(reader api.TcpReader, methodFrame *MethodFrame) (ident string) {
|
||||||
Method: method,
|
tcpID := reader.GetTcpID()
|
||||||
Url: "",
|
// To match methods to their Ok(s)
|
||||||
Details: event,
|
methodId := methodFrame.MethodId - methodFrame.MethodId%10
|
||||||
},
|
|
||||||
},
|
if reader.GetIsClient() {
|
||||||
|
ident = fmt.Sprintf(
|
||||||
|
"%s_%s_%s_%s_%d_%d_%d",
|
||||||
|
tcpID.SrcIP,
|
||||||
|
tcpID.DstIP,
|
||||||
|
tcpID.SrcPort,
|
||||||
|
tcpID.DstPort,
|
||||||
|
methodFrame.ChannelId,
|
||||||
|
methodFrame.ClassId,
|
||||||
|
methodId,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ident = fmt.Sprintf(
|
||||||
|
"%s_%s_%s_%s_%d_%d_%d",
|
||||||
|
tcpID.DstIP,
|
||||||
|
tcpID.SrcIP,
|
||||||
|
tcpID.DstPort,
|
||||||
|
tcpID.SrcPort,
|
||||||
|
methodFrame.ChannelId,
|
||||||
|
methodFrame.ClassId,
|
||||||
|
methodId,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
item := &api.OutputChannelItem{
|
|
||||||
Protocol: protocol,
|
return
|
||||||
Capture: capture,
|
|
||||||
Timestamp: captureTime.UnixNano() / int64(time.Millisecond),
|
|
||||||
ConnectionInfo: connectionInfo,
|
|
||||||
Pair: &api.RequestResponsePair{
|
|
||||||
Request: *request,
|
|
||||||
Response: api.GenericMessage{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
emitter.Emit(item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func representProperties(properties map[string]interface{}, rep []interface{}) ([]interface{}, string, string) {
|
func representProperties(properties map[string]interface{}, rep []interface{}) ([]interface{}, string, string) {
|
||||||
@@ -460,6 +472,36 @@ func representQueueDeclare(event map[string]interface{}) []interface{} {
|
|||||||
return rep
|
return rep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func representQueueDeclareOk(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
details, _ := json.Marshal([]api.TableData{
|
||||||
|
{
|
||||||
|
Name: "Queue",
|
||||||
|
Value: event["queue"].(string),
|
||||||
|
Selector: `response.queue`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Message Count",
|
||||||
|
Value: fmt.Sprintf("%g", event["messageCount"].(float64)),
|
||||||
|
Selector: `response.messageCount`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Consumer Count",
|
||||||
|
Value: fmt.Sprintf("%g", event["consumerCount"].(float64)),
|
||||||
|
Selector: `response.consumerCount`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Details",
|
||||||
|
Data: string(details),
|
||||||
|
})
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|
||||||
func representExchangeDeclare(event map[string]interface{}) []interface{} {
|
func representExchangeDeclare(event map[string]interface{}) []interface{} {
|
||||||
rep := make([]interface{}, 0)
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
@@ -571,7 +613,7 @@ func representConnectionStart(event map[string]interface{}) []interface{} {
|
|||||||
x, _ := json.Marshal(value)
|
x, _ := json.Marshal(value)
|
||||||
outcome = string(x)
|
outcome = string(x)
|
||||||
default:
|
default:
|
||||||
panic("Unknown data type for the server property!")
|
logger.Log.Info("Unknown data type for the server property!")
|
||||||
}
|
}
|
||||||
headers = append(headers, api.TableData{
|
headers = append(headers, api.TableData{
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -593,6 +635,65 @@ func representConnectionStart(event map[string]interface{}) []interface{} {
|
|||||||
return rep
|
return rep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func representConnectionStartOk(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
details, _ := json.Marshal([]api.TableData{
|
||||||
|
{
|
||||||
|
Name: "Mechanism",
|
||||||
|
Value: event["mechanism"].(string),
|
||||||
|
Selector: `response.mechanism`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Mechanism",
|
||||||
|
Value: event["mechanism"].(string),
|
||||||
|
Selector: `response.response`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Locale",
|
||||||
|
Value: event["locale"].(string),
|
||||||
|
Selector: `response.locale`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Details",
|
||||||
|
Data: string(details),
|
||||||
|
})
|
||||||
|
|
||||||
|
if event["clientProperties"] != nil {
|
||||||
|
headers := make([]api.TableData, 0)
|
||||||
|
for name, value := range event["clientProperties"].(map[string]interface{}) {
|
||||||
|
var outcome string
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
outcome = v
|
||||||
|
case map[string]interface{}:
|
||||||
|
x, _ := json.Marshal(value)
|
||||||
|
outcome = string(x)
|
||||||
|
default:
|
||||||
|
logger.Log.Info("Unknown data type for the client property!")
|
||||||
|
}
|
||||||
|
headers = append(headers, api.TableData{
|
||||||
|
Name: name,
|
||||||
|
Value: outcome,
|
||||||
|
Selector: fmt.Sprintf(`response.clientProperties["%s"]`, name),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sort.Slice(headers, func(i, j int) bool {
|
||||||
|
return headers[i].Name < headers[j].Name
|
||||||
|
})
|
||||||
|
headersMarshaled, _ := json.Marshal(headers)
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Client Properties",
|
||||||
|
Data: string(headersMarshaled),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|
||||||
func representConnectionClose(event map[string]interface{}) []interface{} {
|
func representConnectionClose(event map[string]interface{}) []interface{} {
|
||||||
replyCode := ""
|
replyCode := ""
|
||||||
|
|
||||||
@@ -750,3 +851,122 @@ func representBasicConsume(event map[string]interface{}) []interface{} {
|
|||||||
|
|
||||||
return rep
|
return rep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func representBasicConsumeOk(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
details, _ := json.Marshal([]api.TableData{
|
||||||
|
{
|
||||||
|
Name: "Consumer Tag",
|
||||||
|
Value: event["consumerTag"].(string),
|
||||||
|
Selector: `response.consumerTag`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Details",
|
||||||
|
Data: string(details),
|
||||||
|
})
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|
||||||
|
func representConnectionOpen(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
details, _ := json.Marshal([]api.TableData{
|
||||||
|
{
|
||||||
|
Name: "Virtual Host",
|
||||||
|
Value: event["virtualHost"].(string),
|
||||||
|
Selector: `request.virtualHost`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Details",
|
||||||
|
Data: string(details),
|
||||||
|
})
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|
||||||
|
func representConnectionTune(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
details, _ := json.Marshal([]api.TableData{
|
||||||
|
{
|
||||||
|
Name: "Channel Max",
|
||||||
|
Value: fmt.Sprintf("%g", event["channelMax"].(float64)),
|
||||||
|
Selector: `request.channelMax`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Frame Max",
|
||||||
|
Value: fmt.Sprintf("%g", event["frameMax"].(float64)),
|
||||||
|
Selector: `request.frameMax`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Heartbeat",
|
||||||
|
Value: fmt.Sprintf("%g", event["heartbeat"].(float64)),
|
||||||
|
Selector: `request.heartbeat`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Details",
|
||||||
|
Data: string(details),
|
||||||
|
})
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|
||||||
|
func representBasicCancel(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
details, _ := json.Marshal([]api.TableData{
|
||||||
|
{
|
||||||
|
Name: "Consumer Tag",
|
||||||
|
Value: event["consumerTag"].(string),
|
||||||
|
Selector: `response.consumerTag`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NoWait",
|
||||||
|
Value: strconv.FormatBool(event["noWait"].(bool)),
|
||||||
|
Selector: `request.noWait`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Details",
|
||||||
|
Data: string(details),
|
||||||
|
})
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|
||||||
|
func representBasicCancelOk(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
details, _ := json.Marshal([]api.TableData{
|
||||||
|
{
|
||||||
|
Name: "Consumer Tag",
|
||||||
|
Value: event["consumerTag"].(string),
|
||||||
|
Selector: `response.consumerTag`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
rep = append(rep, api.SectionData{
|
||||||
|
Type: api.TABLE,
|
||||||
|
Title: "Details",
|
||||||
|
Data: string(details),
|
||||||
|
})
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|
||||||
|
func representEmpty(event map[string]interface{}) []interface{} {
|
||||||
|
rep := make([]interface{}, 0)
|
||||||
|
|
||||||
|
return rep
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,22 +46,12 @@ func (d dissecting) Ping() {
|
|||||||
log.Printf("pong %s", protocol.Name)
|
log.Printf("pong %s", protocol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
const amqpRequest string = "amqp_request"
|
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error {
|
func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error {
|
||||||
r := AmqpReader{b}
|
r := AmqpReader{b}
|
||||||
|
|
||||||
var remaining int
|
var remaining int
|
||||||
var header *HeaderFrame
|
var header *HeaderFrame
|
||||||
|
|
||||||
connectionInfo := &api.ConnectionInfo{
|
|
||||||
ClientIP: reader.GetTcpID().SrcIP,
|
|
||||||
ClientPort: reader.GetTcpID().SrcPort,
|
|
||||||
ServerIP: reader.GetTcpID().DstIP,
|
|
||||||
ServerPort: reader.GetTcpID().DstPort,
|
|
||||||
IsOutgoing: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
eventBasicPublish := &BasicPublish{
|
eventBasicPublish := &BasicPublish{
|
||||||
Exchange: "",
|
Exchange: "",
|
||||||
RoutingKey: "",
|
RoutingKey: "",
|
||||||
@@ -83,6 +73,10 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
|
|
||||||
var lastMethodFrameMessage Message
|
var lastMethodFrameMessage Message
|
||||||
|
|
||||||
|
var ident string
|
||||||
|
isClient := reader.GetIsClient()
|
||||||
|
reqResMatcher := reader.GetReqResMatcher().(*requestResponseMatcher)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
frameVal, err := r.readFrame()
|
frameVal, err := r.readFrame()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@@ -121,16 +115,22 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
switch lastMethodFrameMessage.(type) {
|
switch lastMethodFrameMessage.(type) {
|
||||||
case *BasicPublish:
|
case *BasicPublish:
|
||||||
eventBasicPublish.Body = f.Body
|
eventBasicPublish.Body = f.Body
|
||||||
emitAMQP(*eventBasicPublish, amqpRequest, basicMethodMap[40], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[40], *eventBasicPublish, reader)
|
||||||
|
reqResMatcher.emitEvent(!isClient, ident, emptyMethod, &emptyResponse{}, reader)
|
||||||
|
|
||||||
case *BasicDeliver:
|
case *BasicDeliver:
|
||||||
eventBasicDeliver.Body = f.Body
|
eventBasicDeliver.Body = f.Body
|
||||||
emitAMQP(*eventBasicDeliver, amqpRequest, basicMethodMap[60], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
reqResMatcher.emitEvent(!isClient, ident, basicMethodMap[60], *eventBasicDeliver, reader)
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, emptyMethod, &emptyResponse{}, reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *MethodFrame:
|
case *MethodFrame:
|
||||||
reader.GetParent().SetProtocol(&protocol)
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
|
|
||||||
lastMethodFrameMessage = f.Method
|
lastMethodFrameMessage = f.Method
|
||||||
|
|
||||||
|
ident = getIdent(reader, f)
|
||||||
|
|
||||||
switch m := f.Method.(type) {
|
switch m := f.Method.(type) {
|
||||||
case *BasicPublish:
|
case *BasicPublish:
|
||||||
eventBasicPublish.Exchange = m.Exchange
|
eventBasicPublish.Exchange = m.Exchange
|
||||||
@@ -146,7 +146,10 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
emitAMQP(*eventQueueBind, amqpRequest, queueMethodMap[20], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
reqResMatcher.emitEvent(isClient, ident, queueMethodMap[20], *eventQueueBind, reader)
|
||||||
|
|
||||||
|
case *QueueBindOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, queueMethodMap[21], m, reader)
|
||||||
|
|
||||||
case *BasicConsume:
|
case *BasicConsume:
|
||||||
eventBasicConsume := &BasicConsume{
|
eventBasicConsume := &BasicConsume{
|
||||||
@@ -158,7 +161,10 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
emitAMQP(*eventBasicConsume, amqpRequest, basicMethodMap[20], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[20], *eventBasicConsume, reader)
|
||||||
|
|
||||||
|
case *BasicConsumeOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[21], m, reader)
|
||||||
|
|
||||||
case *BasicDeliver:
|
case *BasicDeliver:
|
||||||
eventBasicDeliver.ConsumerTag = m.ConsumerTag
|
eventBasicDeliver.ConsumerTag = m.ConsumerTag
|
||||||
@@ -177,7 +183,10 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
emitAMQP(*eventQueueDeclare, amqpRequest, queueMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
reqResMatcher.emitEvent(isClient, ident, queueMethodMap[10], *eventQueueDeclare, reader)
|
||||||
|
|
||||||
|
case *QueueDeclareOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, queueMethodMap[11], m, reader)
|
||||||
|
|
||||||
case *ExchangeDeclare:
|
case *ExchangeDeclare:
|
||||||
eventExchangeDeclare := &ExchangeDeclare{
|
eventExchangeDeclare := &ExchangeDeclare{
|
||||||
@@ -190,17 +199,19 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
emitAMQP(*eventExchangeDeclare, amqpRequest, exchangeMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
reqResMatcher.emitEvent(isClient, ident, exchangeMethodMap[10], *eventExchangeDeclare, reader)
|
||||||
|
|
||||||
|
case *ExchangeDeclareOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, exchangeMethodMap[11], m, reader)
|
||||||
|
|
||||||
case *ConnectionStart:
|
case *ConnectionStart:
|
||||||
eventConnectionStart := &ConnectionStart{
|
// In our tests, *ConnectionStart does not result in *ConnectionStartOk
|
||||||
VersionMajor: m.VersionMajor,
|
reqResMatcher.emitEvent(!isClient, ident, connectionMethodMap[10], m, reader)
|
||||||
VersionMinor: m.VersionMinor,
|
reqResMatcher.emitEvent(isClient, ident, emptyMethod, &emptyResponse{}, reader)
|
||||||
ServerProperties: m.ServerProperties,
|
|
||||||
Mechanisms: m.Mechanisms,
|
case *ConnectionStartOk:
|
||||||
Locales: m.Locales,
|
// In our tests, *ConnectionStart does not result in *ConnectionStartOk
|
||||||
}
|
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[11], m, reader)
|
||||||
emitAMQP(*eventConnectionStart, amqpRequest, connectionMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
|
||||||
|
|
||||||
case *ConnectionClose:
|
case *ConnectionClose:
|
||||||
eventConnectionClose := &ConnectionClose{
|
eventConnectionClose := &ConnectionClose{
|
||||||
@@ -209,7 +220,40 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
ClassId: m.ClassId,
|
ClassId: m.ClassId,
|
||||||
MethodId: m.MethodId,
|
MethodId: m.MethodId,
|
||||||
}
|
}
|
||||||
emitAMQP(*eventConnectionClose, amqpRequest, connectionMethodMap[50], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[50], *eventConnectionClose, reader)
|
||||||
|
|
||||||
|
case *ConnectionCloseOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[51], m, reader)
|
||||||
|
|
||||||
|
case *connectionOpen:
|
||||||
|
eventConnectionOpen := &connectionOpen{
|
||||||
|
VirtualHost: m.VirtualHost,
|
||||||
|
}
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[40], *eventConnectionOpen, reader)
|
||||||
|
|
||||||
|
case *connectionOpenOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[41], m, reader)
|
||||||
|
|
||||||
|
case *channelOpen:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, channelMethodMap[10], m, reader)
|
||||||
|
|
||||||
|
case *channelOpenOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, channelMethodMap[11], m, reader)
|
||||||
|
|
||||||
|
case *connectionTune:
|
||||||
|
// In our tests, *connectionTune does not result in *connectionTuneOk
|
||||||
|
reqResMatcher.emitEvent(!isClient, ident, connectionMethodMap[30], m, reader)
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, emptyMethod, &emptyResponse{}, reader)
|
||||||
|
|
||||||
|
case *connectionTuneOk:
|
||||||
|
// In our tests, *connectionTune does not result in *connectionTuneOk
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[31], m, reader)
|
||||||
|
|
||||||
|
case *basicCancel:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[30], m, reader)
|
||||||
|
|
||||||
|
case *basicCancelOk:
|
||||||
|
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[31], m, reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -220,9 +264,17 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
|
|||||||
|
|
||||||
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *api.Entry {
|
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *api.Entry {
|
||||||
request := item.Pair.Request.Payload.(map[string]interface{})
|
request := item.Pair.Request.Payload.(map[string]interface{})
|
||||||
|
response := item.Pair.Response.Payload.(map[string]interface{})
|
||||||
reqDetails := request["details"].(map[string]interface{})
|
reqDetails := request["details"].(map[string]interface{})
|
||||||
|
resDetails := response["details"].(map[string]interface{})
|
||||||
|
|
||||||
|
elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds()
|
||||||
|
if elapsedTime < 0 {
|
||||||
|
elapsedTime = 0
|
||||||
|
}
|
||||||
|
|
||||||
reqDetails["method"] = request["method"]
|
reqDetails["method"] = request["method"]
|
||||||
|
resDetails["method"] = response["method"]
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
Protocol: protocol.ProtocolSummary,
|
Protocol: protocol.ProtocolSummary,
|
||||||
Capture: item.Capture,
|
Capture: item.Capture,
|
||||||
@@ -236,13 +288,15 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
IP: item.ConnectionInfo.ServerIP,
|
IP: item.ConnectionInfo.ServerIP,
|
||||||
Port: item.ConnectionInfo.ServerPort,
|
Port: item.ConnectionInfo.ServerPort,
|
||||||
},
|
},
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||||
Request: reqDetails,
|
Request: reqDetails,
|
||||||
RequestSize: item.Pair.Request.CaptureSize,
|
Response: resDetails,
|
||||||
Timestamp: item.Timestamp,
|
RequestSize: item.Pair.Request.CaptureSize,
|
||||||
StartTime: item.Pair.Request.CaptureTime,
|
ResponseSize: item.Pair.Response.CaptureSize,
|
||||||
ElapsedTime: 0,
|
Timestamp: item.Timestamp,
|
||||||
|
StartTime: item.Pair.Request.CaptureTime,
|
||||||
|
ElapsedTime: elapsedTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -283,6 +337,21 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
case basicMethodMap[20]:
|
case basicMethodMap[20]:
|
||||||
summary = entry.Request["queue"].(string)
|
summary = entry.Request["queue"].(string)
|
||||||
summaryQuery = fmt.Sprintf(`request.queue == "%s"`, summary)
|
summaryQuery = fmt.Sprintf(`request.queue == "%s"`, summary)
|
||||||
|
case connectionMethodMap[40]:
|
||||||
|
summary = entry.Request["virtualHost"].(string)
|
||||||
|
summaryQuery = fmt.Sprintf(`request.virtualHost == "%s"`, summary)
|
||||||
|
case connectionMethodMap[30]:
|
||||||
|
summary = fmt.Sprintf("%g", entry.Request["channelMax"].(float64))
|
||||||
|
summaryQuery = fmt.Sprintf(`request.channelMax == "%s"`, summary)
|
||||||
|
case connectionMethodMap[31]:
|
||||||
|
summary = fmt.Sprintf("%g", entry.Request["channelMax"].(float64))
|
||||||
|
summaryQuery = fmt.Sprintf(`request.channelMax == "%s"`, summary)
|
||||||
|
case basicMethodMap[30]:
|
||||||
|
summary = entry.Request["consumerTag"].(string)
|
||||||
|
summaryQuery = fmt.Sprintf(`request.consumerTag == "%s"`, summary)
|
||||||
|
case basicMethodMap[31]:
|
||||||
|
summary = entry.Request["consumerTag"].(string)
|
||||||
|
summaryQuery = fmt.Sprintf(`request.consumerTag == "%s"`, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
@@ -306,6 +375,8 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error) {
|
||||||
representation := make(map[string]interface{})
|
representation := make(map[string]interface{})
|
||||||
var repRequest []interface{}
|
var repRequest []interface{}
|
||||||
|
var repResponse []interface{}
|
||||||
|
|
||||||
switch request["method"].(string) {
|
switch request["method"].(string) {
|
||||||
case basicMethodMap[40]:
|
case basicMethodMap[40]:
|
||||||
repRequest = representBasicPublish(request)
|
repRequest = representBasicPublish(request)
|
||||||
@@ -323,9 +394,45 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
|
|||||||
repRequest = representQueueBind(request)
|
repRequest = representQueueBind(request)
|
||||||
case basicMethodMap[20]:
|
case basicMethodMap[20]:
|
||||||
repRequest = representBasicConsume(request)
|
repRequest = representBasicConsume(request)
|
||||||
|
case connectionMethodMap[40]:
|
||||||
|
repRequest = representConnectionOpen(request)
|
||||||
|
case channelMethodMap[10]:
|
||||||
|
repRequest = representEmpty(request)
|
||||||
|
case connectionMethodMap[30]:
|
||||||
|
repRequest = representConnectionTune(request)
|
||||||
|
case basicMethodMap[30]:
|
||||||
|
repRequest = representBasicCancel(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch response["method"].(string) {
|
||||||
|
case queueMethodMap[11]:
|
||||||
|
repResponse = representQueueDeclareOk(response)
|
||||||
|
case exchangeMethodMap[11]:
|
||||||
|
repResponse = representEmpty(response)
|
||||||
|
case connectionMethodMap[11]:
|
||||||
|
repResponse = representConnectionStartOk(response)
|
||||||
|
case connectionMethodMap[51]:
|
||||||
|
repResponse = representEmpty(response)
|
||||||
|
case basicMethodMap[21]:
|
||||||
|
repResponse = representBasicConsumeOk(response)
|
||||||
|
case queueMethodMap[21]:
|
||||||
|
repResponse = representEmpty(response)
|
||||||
|
case connectionMethodMap[41]:
|
||||||
|
repResponse = representEmpty(response)
|
||||||
|
case channelMethodMap[11]:
|
||||||
|
repResponse = representEmpty(request)
|
||||||
|
case connectionMethodMap[31]:
|
||||||
|
repResponse = representConnectionTune(request)
|
||||||
|
case basicMethodMap[31]:
|
||||||
|
repResponse = representBasicCancelOk(request)
|
||||||
|
case emptyMethod:
|
||||||
|
repResponse = representEmpty(response)
|
||||||
|
}
|
||||||
|
|
||||||
representation["request"] = repRequest
|
representation["request"] = repRequest
|
||||||
|
representation["response"] = repResponse
|
||||||
object, err = json.Marshal(representation)
|
object, err = json.Marshal(representation)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +443,7 @@ func (d dissecting) Macros() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) NewResponseRequestMatcher() api.RequestResponseMatcher {
|
func (d dissecting) NewResponseRequestMatcher() api.RequestResponseMatcher {
|
||||||
return nil
|
return createResponseRequestMatcher()
|
||||||
}
|
}
|
||||||
|
|
||||||
var Dissector dissecting
|
var Dissector dissecting
|
||||||
|
|||||||
113
tap/extensions/amqp/matcher.go
Normal file
113
tap/extensions/amqp/matcher.go
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key is {client_addr}_{client_port}_{dest_addr}_{dest_port}_{channel_id}_{class_id}_{method_id}
|
||||||
|
type requestResponseMatcher struct {
|
||||||
|
openMessagesMap *sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func createResponseRequestMatcher() api.RequestResponseMatcher {
|
||||||
|
return &requestResponseMatcher{openMessagesMap: &sync.Map{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *requestResponseMatcher) GetMap() *sync.Map {
|
||||||
|
return matcher.openMessagesMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *requestResponseMatcher) SetMaxTry(value int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *requestResponseMatcher) emitEvent(isRequest bool, ident string, method string, event interface{}, reader api.TcpReader) {
|
||||||
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
|
|
||||||
|
var item *api.OutputChannelItem
|
||||||
|
if isRequest {
|
||||||
|
item = matcher.registerRequest(ident, method, event, reader.GetCaptureTime(), reader.GetReadProgress().Current())
|
||||||
|
} else {
|
||||||
|
item = matcher.registerResponse(ident, method, event, reader.GetCaptureTime(), reader.GetReadProgress().Current())
|
||||||
|
}
|
||||||
|
|
||||||
|
if item != nil {
|
||||||
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
|
ClientIP: reader.GetTcpID().SrcIP,
|
||||||
|
ClientPort: reader.GetTcpID().SrcPort,
|
||||||
|
ServerIP: reader.GetTcpID().DstIP,
|
||||||
|
ServerPort: reader.GetTcpID().DstPort,
|
||||||
|
IsOutgoing: true,
|
||||||
|
}
|
||||||
|
item.Capture = reader.GetParent().GetOrigin()
|
||||||
|
reader.GetEmitter().Emit(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *requestResponseMatcher) registerRequest(ident string, method string, request interface{}, captureTime time.Time, captureSize int) *api.OutputChannelItem {
|
||||||
|
requestAMQPMessage := api.GenericMessage{
|
||||||
|
IsRequest: true,
|
||||||
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: captureSize,
|
||||||
|
Payload: AMQPPayload{
|
||||||
|
Data: &AMQPWrapper{
|
||||||
|
Method: method,
|
||||||
|
Url: "",
|
||||||
|
Details: request,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if response, found := matcher.openMessagesMap.LoadAndDelete(ident); found {
|
||||||
|
// Type assertion always succeeds because all of the map's values are of api.GenericMessage type
|
||||||
|
responseAMQPMessage := response.(*api.GenericMessage)
|
||||||
|
if responseAMQPMessage.IsRequest {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return matcher.preparePair(&requestAMQPMessage, responseAMQPMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher.openMessagesMap.Store(ident, &requestAMQPMessage)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *requestResponseMatcher) registerResponse(ident string, method string, response interface{}, captureTime time.Time, captureSize int) *api.OutputChannelItem {
|
||||||
|
responseAMQPMessage := api.GenericMessage{
|
||||||
|
IsRequest: false,
|
||||||
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: captureSize,
|
||||||
|
Payload: AMQPPayload{
|
||||||
|
Data: &AMQPWrapper{
|
||||||
|
Method: method,
|
||||||
|
Url: "",
|
||||||
|
Details: response,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if request, found := matcher.openMessagesMap.LoadAndDelete(ident); found {
|
||||||
|
// Type assertion always succeeds because all of the map's values are of api.GenericMessage type
|
||||||
|
requestAMQPMessage := request.(*api.GenericMessage)
|
||||||
|
if !requestAMQPMessage.IsRequest {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return matcher.preparePair(requestAMQPMessage, &responseAMQPMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher.openMessagesMap.Store(ident, &responseAMQPMessage)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *requestResponseMatcher) preparePair(requestAMQPMessage *api.GenericMessage, responseAMQPMessage *api.GenericMessage) *api.OutputChannelItem {
|
||||||
|
return &api.OutputChannelItem{
|
||||||
|
Protocol: protocol,
|
||||||
|
Timestamp: requestAMQPMessage.CaptureTime.UnixNano() / int64(time.Millisecond),
|
||||||
|
ConnectionInfo: nil,
|
||||||
|
Pair: &api.RequestResponsePair{
|
||||||
|
Request: *requestAMQPMessage,
|
||||||
|
Response: *responseAMQPMessage,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,10 +81,10 @@ func (msg *ConnectionStart) read(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConnectionStartOk struct {
|
type ConnectionStartOk struct {
|
||||||
ClientProperties Table
|
ClientProperties Table `json:"clientProperties"`
|
||||||
Mechanism string
|
Mechanism string `json:"mechanism"`
|
||||||
Response string
|
Response string `json:"response"`
|
||||||
Locale string
|
Locale string `json:"locale"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *ConnectionStartOk) read(r io.Reader) (err error) {
|
func (msg *ConnectionStartOk) read(r io.Reader) (err error) {
|
||||||
@@ -135,9 +135,9 @@ func (msg *connectionSecureOk) read(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type connectionTune struct {
|
type connectionTune struct {
|
||||||
ChannelMax uint16
|
ChannelMax uint16 `json:"channelMax"`
|
||||||
FrameMax uint32
|
FrameMax uint32 `json:"frameMax"`
|
||||||
Heartbeat uint16
|
Heartbeat uint16 `json:"heartbeat"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *connectionTune) read(r io.Reader) (err error) {
|
func (msg *connectionTune) read(r io.Reader) (err error) {
|
||||||
@@ -181,7 +181,7 @@ func (msg *connectionTuneOk) read(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type connectionOpen struct {
|
type connectionOpen struct {
|
||||||
VirtualHost string
|
VirtualHost string `json:"virtualHost"`
|
||||||
reserved1 string
|
reserved1 string
|
||||||
reserved2 bool
|
reserved2 bool
|
||||||
}
|
}
|
||||||
@@ -580,9 +580,9 @@ func (msg *QueueDeclare) read(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QueueDeclareOk struct {
|
type QueueDeclareOk struct {
|
||||||
Queue string
|
Queue string `json:"queue"`
|
||||||
MessageCount uint32
|
MessageCount uint32 `json:"messageCount"`
|
||||||
ConsumerCount uint32
|
ConsumerCount uint32 `json:"consumerCount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *QueueDeclareOk) read(r io.Reader) (err error) {
|
func (msg *QueueDeclareOk) read(r io.Reader) (err error) {
|
||||||
@@ -840,7 +840,7 @@ func (msg *BasicConsume) read(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BasicConsumeOk struct {
|
type BasicConsumeOk struct {
|
||||||
ConsumerTag string
|
ConsumerTag string `json:"consumerTag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *BasicConsumeOk) read(r io.Reader) (err error) {
|
func (msg *BasicConsumeOk) read(r io.Reader) (err error) {
|
||||||
@@ -853,8 +853,8 @@ func (msg *BasicConsumeOk) read(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type basicCancel struct {
|
type basicCancel struct {
|
||||||
ConsumerTag string
|
ConsumerTag string `json:"consumerTag"`
|
||||||
NoWait bool
|
NoWait bool `json:"noWait"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *basicCancel) read(r io.Reader) (err error) {
|
func (msg *basicCancel) read(r io.Reader) (err error) {
|
||||||
@@ -873,7 +873,7 @@ func (msg *basicCancel) read(r io.Reader) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type basicCancelOk struct {
|
type basicCancelOk struct {
|
||||||
ConsumerTag string
|
ConsumerTag string `json:"consumerTag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *basicCancelOk) read(r io.Reader) (err error) {
|
func (msg *basicCancelOk) read(r io.Reader) (err error) {
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect15/http/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect16/http/\* expect
|
||||||
|
|||||||
@@ -18,10 +18,6 @@ func filterAndEmit(item *api.OutputChannelItem, emitter api.Emitter, options *ap
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.EnableRedaction {
|
|
||||||
FilterSensitiveData(item, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceForwardedFor(item)
|
replaceForwardedFor(item)
|
||||||
|
|
||||||
emitter.Emit(item)
|
emitter.Emit(item)
|
||||||
|
|||||||
@@ -6,13 +6,16 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mapSliceRebuildAsMap(mapSlice []interface{}) (newMap map[string]interface{}) {
|
func mapSliceRebuildAsMap(mapSlice []interface{}) (newMap map[string]interface{}) {
|
||||||
newMap = make(map[string]interface{})
|
newMap = make(map[string]interface{})
|
||||||
for _, item := range mapSlice {
|
|
||||||
|
mergedMapSlice := mapSliceMergeRepeatedKeys(mapSlice)
|
||||||
|
for _, item := range mergedMapSlice {
|
||||||
h := item.(map[string]interface{})
|
h := item.(map[string]interface{})
|
||||||
newMap[h["name"].(string)] = h["value"]
|
newMap[h["name"].(string)] = h["value"]
|
||||||
}
|
}
|
||||||
@@ -20,6 +23,28 @@ func mapSliceRebuildAsMap(mapSlice []interface{}) (newMap map[string]interface{}
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapSliceRebuildAsMergedMap(mapSlice []interface{}) (newMap map[string]interface{}) {
|
||||||
|
newMap = make(map[string]interface{})
|
||||||
|
|
||||||
|
mergedMapSlice := mapSliceMergeRepeatedKeys(mapSlice)
|
||||||
|
for _, item := range mergedMapSlice {
|
||||||
|
h := item.(map[string]interface{})
|
||||||
|
|
||||||
|
if valuesInterface, ok := h["value"].([]interface{}); ok {
|
||||||
|
var values []string
|
||||||
|
for _, valueInterface := range valuesInterface {
|
||||||
|
values = append(values, valueInterface.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
newMap[h["name"].(string)] = strings.Join(values, ",")
|
||||||
|
} else {
|
||||||
|
newMap[h["name"].(string)] = h["value"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func mapSliceMergeRepeatedKeys(mapSlice []interface{}) (newMapSlice []interface{}) {
|
func mapSliceMergeRepeatedKeys(mapSlice []interface{}) (newMapSlice []interface{}) {
|
||||||
newMapSlice = make([]interface{}, 0)
|
newMapSlice = make([]interface{}, 0)
|
||||||
valuesMap := make(map[string][]interface{})
|
valuesMap := make(map[string][]interface{})
|
||||||
@@ -47,6 +72,24 @@ func mapSliceMergeRepeatedKeys(mapSlice []interface{}) (newMapSlice []interface{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func representMapAsTable(mapToTable map[string]interface{}, selectorPrefix string) (representation string) {
|
||||||
|
var table []api.TableData
|
||||||
|
|
||||||
|
keys := make([]string, 0, len(mapToTable))
|
||||||
|
for k := range mapToTable {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
table = append(table, createTableForKey(key, mapToTable[key], selectorPrefix)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, _ := json.Marshal(table)
|
||||||
|
representation = string(obj)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (representation string) {
|
func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (representation string) {
|
||||||
var table []api.TableData
|
var table []api.TableData
|
||||||
for _, item := range mapSlice {
|
for _, item := range mapSlice {
|
||||||
@@ -54,34 +97,7 @@ func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (re
|
|||||||
key := h["name"].(string)
|
key := h["name"].(string)
|
||||||
value := h["value"]
|
value := h["value"]
|
||||||
|
|
||||||
var reflectKind reflect.Kind
|
table = append(table, createTableForKey(key, value, selectorPrefix)...)
|
||||||
reflectType := reflect.TypeOf(value)
|
|
||||||
if reflectType == nil {
|
|
||||||
reflectKind = reflect.Interface
|
|
||||||
} else {
|
|
||||||
reflectKind = reflect.TypeOf(value).Kind()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch reflectKind {
|
|
||||||
case reflect.Slice:
|
|
||||||
fallthrough
|
|
||||||
case reflect.Array:
|
|
||||||
for i, el := range value.([]interface{}) {
|
|
||||||
selector := fmt.Sprintf("%s.%s[%d]", selectorPrefix, key, i)
|
|
||||||
table = append(table, api.TableData{
|
|
||||||
Name: fmt.Sprintf("%s [%d]", key, i),
|
|
||||||
Value: el,
|
|
||||||
Selector: selector,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
selector := fmt.Sprintf("%s[\"%s\"]", selectorPrefix, key)
|
|
||||||
table = append(table, api.TableData{
|
|
||||||
Name: key,
|
|
||||||
Value: value,
|
|
||||||
Selector: selector,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, _ := json.Marshal(table)
|
obj, _ := json.Marshal(table)
|
||||||
@@ -89,6 +105,41 @@ func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (re
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createTableForKey(key string, value interface{}, selectorPrefix string) []api.TableData {
|
||||||
|
var table []api.TableData
|
||||||
|
|
||||||
|
var reflectKind reflect.Kind
|
||||||
|
reflectType := reflect.TypeOf(value)
|
||||||
|
if reflectType == nil {
|
||||||
|
reflectKind = reflect.Interface
|
||||||
|
} else {
|
||||||
|
reflectKind = reflect.TypeOf(value).Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch reflectKind {
|
||||||
|
case reflect.Slice:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Array:
|
||||||
|
for i, el := range value.([]interface{}) {
|
||||||
|
selector := fmt.Sprintf("%s.%s[%d]", selectorPrefix, key, i)
|
||||||
|
table = append(table, api.TableData{
|
||||||
|
Name: fmt.Sprintf("%s [%d]", key, i),
|
||||||
|
Value: el,
|
||||||
|
Selector: selector,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
selector := fmt.Sprintf("%s[\"%s\"]", selectorPrefix, key)
|
||||||
|
table = append(table, api.TableData{
|
||||||
|
Name: key,
|
||||||
|
Value: value,
|
||||||
|
Selector: selector,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
func representSliceAsTable(slice []interface{}, selectorPrefix string) (representation string) {
|
func representSliceAsTable(slice []interface{}, selectorPrefix string) (representation string) {
|
||||||
var table []api.TableData
|
var table []api.TableData
|
||||||
for i, item := range slice {
|
for i, item := range slice {
|
||||||
|
|||||||
@@ -286,19 +286,13 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
reqDetails["pathSegments"] = strings.Split(path, "/")[1:]
|
reqDetails["pathSegments"] = strings.Split(path, "/")[1:]
|
||||||
|
|
||||||
// Rearrange the maps for the querying
|
// Rearrange the maps for the querying
|
||||||
reqDetails["_headers"] = reqDetails["headers"]
|
reqDetails["headers"] = mapSliceRebuildAsMergedMap(reqDetails["headers"].([]interface{}))
|
||||||
reqDetails["headers"] = mapSliceRebuildAsMap(reqDetails["_headers"].([]interface{}))
|
resDetails["headers"] = mapSliceRebuildAsMergedMap(resDetails["headers"].([]interface{}))
|
||||||
resDetails["_headers"] = resDetails["headers"]
|
|
||||||
resDetails["headers"] = mapSliceRebuildAsMap(resDetails["_headers"].([]interface{}))
|
|
||||||
|
|
||||||
reqDetails["_cookies"] = reqDetails["cookies"]
|
reqDetails["cookies"] = mapSliceRebuildAsMergedMap(reqDetails["cookies"].([]interface{}))
|
||||||
reqDetails["cookies"] = mapSliceRebuildAsMap(reqDetails["_cookies"].([]interface{}))
|
resDetails["cookies"] = mapSliceRebuildAsMergedMap(resDetails["cookies"].([]interface{}))
|
||||||
resDetails["_cookies"] = resDetails["cookies"]
|
|
||||||
resDetails["cookies"] = mapSliceRebuildAsMap(resDetails["_cookies"].([]interface{}))
|
|
||||||
|
|
||||||
reqDetails["_queryString"] = reqDetails["queryString"]
|
reqDetails["queryString"] = mapSliceRebuildAsMap(reqDetails["queryString"].([]interface{}))
|
||||||
reqDetails["_queryStringMerged"] = mapSliceMergeRepeatedKeys(reqDetails["_queryString"].([]interface{}))
|
|
||||||
reqDetails["queryString"] = mapSliceRebuildAsMap(reqDetails["_queryStringMerged"].([]interface{}))
|
|
||||||
|
|
||||||
elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds()
|
elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds()
|
||||||
if elapsedTime < 0 {
|
if elapsedTime < 0 {
|
||||||
@@ -397,19 +391,19 @@ func representRequest(request map[string]interface{}) (repRequest []interface{})
|
|||||||
repRequest = append(repRequest, api.SectionData{
|
repRequest = append(repRequest, api.SectionData{
|
||||||
Type: api.TABLE,
|
Type: api.TABLE,
|
||||||
Title: "Headers",
|
Title: "Headers",
|
||||||
Data: representMapSliceAsTable(request["_headers"].([]interface{}), `request.headers`),
|
Data: representMapAsTable(request["headers"].(map[string]interface{}), `request.headers`),
|
||||||
})
|
})
|
||||||
|
|
||||||
repRequest = append(repRequest, api.SectionData{
|
repRequest = append(repRequest, api.SectionData{
|
||||||
Type: api.TABLE,
|
Type: api.TABLE,
|
||||||
Title: "Cookies",
|
Title: "Cookies",
|
||||||
Data: representMapSliceAsTable(request["_cookies"].([]interface{}), `request.cookies`),
|
Data: representMapAsTable(request["cookies"].(map[string]interface{}), `request.cookies`),
|
||||||
})
|
})
|
||||||
|
|
||||||
repRequest = append(repRequest, api.SectionData{
|
repRequest = append(repRequest, api.SectionData{
|
||||||
Type: api.TABLE,
|
Type: api.TABLE,
|
||||||
Title: "Query String",
|
Title: "Query String",
|
||||||
Data: representMapSliceAsTable(request["_queryStringMerged"].([]interface{}), `request.queryString`),
|
Data: representMapAsTable(request["queryString"].(map[string]interface{}), `request.queryString`),
|
||||||
})
|
})
|
||||||
|
|
||||||
postData, _ := request["postData"].(map[string]interface{})
|
postData, _ := request["postData"].(map[string]interface{})
|
||||||
@@ -485,13 +479,13 @@ func representResponse(response map[string]interface{}) (repResponse []interface
|
|||||||
repResponse = append(repResponse, api.SectionData{
|
repResponse = append(repResponse, api.SectionData{
|
||||||
Type: api.TABLE,
|
Type: api.TABLE,
|
||||||
Title: "Headers",
|
Title: "Headers",
|
||||||
Data: representMapSliceAsTable(response["_headers"].([]interface{}), `response.headers`),
|
Data: representMapAsTable(response["headers"].(map[string]interface{}), `response.headers`),
|
||||||
})
|
})
|
||||||
|
|
||||||
repResponse = append(repResponse, api.SectionData{
|
repResponse = append(repResponse, api.SectionData{
|
||||||
Type: api.TABLE,
|
Type: api.TABLE,
|
||||||
Title: "Cookies",
|
Title: "Cookies",
|
||||||
Data: representMapSliceAsTable(response["_cookies"].([]interface{}), `response.cookies`),
|
Data: representMapAsTable(response["cookies"].(map[string]interface{}), `response.cookies`),
|
||||||
})
|
})
|
||||||
|
|
||||||
content, _ := response["content"].(map[string]interface{})
|
content, _ := response["content"].(map[string]interface{})
|
||||||
|
|||||||
@@ -1,30 +1,14 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"encoding/xml"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/beevik/etree"
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maskedFieldPlaceholderValue = "[REDACTED]"
|
|
||||||
const userAgent = "user-agent"
|
const userAgent = "user-agent"
|
||||||
|
|
||||||
//these values MUST be all lower case and contain no `-` or `_` characters
|
|
||||||
var personallyIdentifiableDataFields = []string{"token", "authorization", "authentication", "cookie", "userid", "password",
|
|
||||||
"username", "user", "key", "passcode", "pass", "auth", "authtoken", "jwt",
|
|
||||||
"bearer", "clientid", "clientsecret", "redirecturi", "phonenumber",
|
|
||||||
"zip", "zipcode", "address", "country", "firstname", "lastname",
|
|
||||||
"middlename", "fname", "lname", "birthdate"}
|
|
||||||
|
|
||||||
func IsIgnoredUserAgent(item *api.OutputChannelItem, options *api.TrafficFilteringOptions) bool {
|
func IsIgnoredUserAgent(item *api.OutputChannelItem, options *api.TrafficFilteringOptions) bool {
|
||||||
if item.Protocol.Name != "http" {
|
if item.Protocol.Name != "http" {
|
||||||
return false
|
return false
|
||||||
@@ -48,192 +32,3 @@ func IsIgnoredUserAgent(item *api.OutputChannelItem, options *api.TrafficFilteri
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func FilterSensitiveData(item *api.OutputChannelItem, options *api.TrafficFilteringOptions) {
|
|
||||||
request := item.Pair.Request.Payload.(HTTPPayload).Data.(*http.Request)
|
|
||||||
response := item.Pair.Response.Payload.(HTTPPayload).Data.(*http.Response)
|
|
||||||
|
|
||||||
filterHeaders(&request.Header)
|
|
||||||
filterHeaders(&response.Header)
|
|
||||||
filterUrl(request.URL)
|
|
||||||
filterRequestBody(request, options)
|
|
||||||
filterResponseBody(response, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterRequestBody(request *http.Request, options *api.TrafficFilteringOptions) {
|
|
||||||
contenType := getContentTypeHeaderValue(request.Header)
|
|
||||||
body, err := ioutil.ReadAll(request.Body)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filteredBody, err := filterHttpBody(body, contenType, options)
|
|
||||||
if err == nil {
|
|
||||||
request.Body = ioutil.NopCloser(bytes.NewBuffer(filteredBody))
|
|
||||||
} else {
|
|
||||||
request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterResponseBody(response *http.Response, options *api.TrafficFilteringOptions) {
|
|
||||||
contentType := getContentTypeHeaderValue(response.Header)
|
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filteredBody, err := filterHttpBody(body, contentType, options)
|
|
||||||
if err == nil {
|
|
||||||
response.Body = ioutil.NopCloser(bytes.NewBuffer(filteredBody))
|
|
||||||
} else {
|
|
||||||
response.Body = ioutil.NopCloser(bytes.NewBuffer(body))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterHeaders(headers *http.Header) {
|
|
||||||
for key := range *headers {
|
|
||||||
if strings.ToLower(key) == userAgent {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.ToLower(key) == "cookie" {
|
|
||||||
headers.Del(key)
|
|
||||||
} else if isFieldNameSensitive(key) {
|
|
||||||
headers.Set(key, maskedFieldPlaceholderValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getContentTypeHeaderValue(headers http.Header) string {
|
|
||||||
for key := range headers {
|
|
||||||
if strings.ToLower(key) == "content-type" {
|
|
||||||
return headers.Get(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func isFieldNameSensitive(fieldName string) bool {
|
|
||||||
if fieldName == ":authority" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
name := strings.ToLower(fieldName)
|
|
||||||
name = strings.ReplaceAll(name, "_", "")
|
|
||||||
name = strings.ReplaceAll(name, "-", "")
|
|
||||||
name = strings.ReplaceAll(name, " ", "")
|
|
||||||
|
|
||||||
for _, sensitiveField := range personallyIdentifiableDataFields {
|
|
||||||
if strings.Contains(name, sensitiveField) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterHttpBody(bytes []byte, contentType string, options *api.TrafficFilteringOptions) ([]byte, error) {
|
|
||||||
mimeType := strings.Split(contentType, ";")[0]
|
|
||||||
switch strings.ToLower(mimeType) {
|
|
||||||
case "application/json":
|
|
||||||
return filterJsonBody(bytes)
|
|
||||||
case "text/html":
|
|
||||||
fallthrough
|
|
||||||
case "application/xhtml+xml":
|
|
||||||
fallthrough
|
|
||||||
case "text/xml":
|
|
||||||
fallthrough
|
|
||||||
case "application/xml":
|
|
||||||
return filterXmlEtree(bytes)
|
|
||||||
case "text/plain":
|
|
||||||
if options != nil && options.PlainTextMaskingRegexes != nil {
|
|
||||||
return filterPlainText(bytes, options), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterPlainText(bytes []byte, options *api.TrafficFilteringOptions) []byte {
|
|
||||||
for _, regex := range options.PlainTextMaskingRegexes {
|
|
||||||
bytes = regex.ReplaceAll(bytes, []byte(maskedFieldPlaceholderValue))
|
|
||||||
}
|
|
||||||
return bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterXmlEtree(bytes []byte) ([]byte, error) {
|
|
||||||
if !IsValidXML(bytes) {
|
|
||||||
return nil, errors.New("Invalid XML")
|
|
||||||
}
|
|
||||||
xmlDoc := etree.NewDocument()
|
|
||||||
err := xmlDoc.ReadFromBytes(bytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
filterXmlElement(xmlDoc.Root())
|
|
||||||
}
|
|
||||||
return xmlDoc.WriteToBytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsValidXML(data []byte) bool {
|
|
||||||
return xml.Unmarshal(data, new(interface{})) == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterXmlElement(element *etree.Element) {
|
|
||||||
for i, attribute := range element.Attr {
|
|
||||||
if isFieldNameSensitive(attribute.Key) {
|
|
||||||
element.Attr[i].Value = maskedFieldPlaceholderValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if element.ChildElements() == nil || len(element.ChildElements()) == 0 {
|
|
||||||
if isFieldNameSensitive(element.Tag) {
|
|
||||||
element.SetText(maskedFieldPlaceholderValue)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, element := range element.ChildElements() {
|
|
||||||
filterXmlElement(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterJsonBody(bytes []byte) ([]byte, error) {
|
|
||||||
var bodyJsonMap map[string]interface{}
|
|
||||||
err := json.Unmarshal(bytes, &bodyJsonMap)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
filterJsonMap(bodyJsonMap)
|
|
||||||
return json.Marshal(bodyJsonMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterJsonMap(jsonMap map[string]interface{}) {
|
|
||||||
for key, value := range jsonMap {
|
|
||||||
// Do not replace nil values with maskedFieldPlaceholderValue
|
|
||||||
if value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
nestedMap, isNested := value.(map[string]interface{})
|
|
||||||
if isNested {
|
|
||||||
filterJsonMap(nestedMap)
|
|
||||||
} else {
|
|
||||||
if isFieldNameSensitive(key) {
|
|
||||||
jsonMap[key] = maskedFieldPlaceholderValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterUrl(url *url.URL) {
|
|
||||||
if len(url.RawQuery) > 0 {
|
|
||||||
newQueryArgs := make([]string, 0)
|
|
||||||
for urlQueryParamName, urlQueryParamValues := range url.Query() {
|
|
||||||
newValues := urlQueryParamValues
|
|
||||||
if isFieldNameSensitive(urlQueryParamName) {
|
|
||||||
newValues = []string{maskedFieldPlaceholderValue}
|
|
||||||
}
|
|
||||||
for _, paramValue := range newValues {
|
|
||||||
newQueryArgs = append(newQueryArgs, fmt.Sprintf("%s=%s", urlQueryParamName, paramValue))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
url.RawQuery = strings.Join(newQueryArgs, "&")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
446
ui-common/package-lock.json
generated
446
ui-common/package-lock.json
generated
@@ -18,6 +18,7 @@
|
|||||||
"@mui/styles": "^5.8.0",
|
"@mui/styles": "^5.8.0",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@uiw/react-textarea-code-editor": "^1.6.0",
|
"@uiw/react-textarea-code-editor": "^1.6.0",
|
||||||
|
"ace-builds": "^1.6.0",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"core-js": "^3.22.7",
|
"core-js": "^3.22.7",
|
||||||
"highlight.js": "^11.5.1",
|
"highlight.js": "^11.5.1",
|
||||||
@@ -30,12 +31,14 @@
|
|||||||
"node-fetch": "^3.2.4",
|
"node-fetch": "^3.2.4",
|
||||||
"numeral": "^2.0.6",
|
"numeral": "^2.0.6",
|
||||||
"protobuf-decoder": "^0.1.2",
|
"protobuf-decoder": "^0.1.2",
|
||||||
|
"react-ace": "^9.0.0",
|
||||||
"react-graph-vis": "^1.0.7",
|
"react-graph-vis": "^1.0.7",
|
||||||
"react-lowlight": "^3.0.0",
|
"react-lowlight": "^3.0.0",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scrollable-feed-virtualized": "^1.4.9",
|
"react-scrollable-feed-virtualized": "^1.4.9",
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"react-toastify": "^8.2.0",
|
"react-toastify": "^8.2.0",
|
||||||
|
"recharts": "^2.1.10",
|
||||||
"redoc": "^2.0.0-rc.71",
|
"redoc": "^2.0.0-rc.71",
|
||||||
"styled-components": "^5.3.5",
|
"styled-components": "^5.3.5",
|
||||||
"web-vitals": "^2.1.4",
|
"web-vitals": "^2.1.4",
|
||||||
@@ -44,6 +47,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||||
"@svgr/rollup": "^6.2.1",
|
"@svgr/rollup": "^6.2.1",
|
||||||
|
"@types/ace": "^0.0.48",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"gh-pages": "^4.0.0",
|
"gh-pages": "^4.0.0",
|
||||||
@@ -4538,6 +4542,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
||||||
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
|
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/ace": {
|
||||||
|
"version": "0.0.48",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ace/-/ace-0.0.48.tgz",
|
||||||
|
"integrity": "sha512-esV6hOWiDOZ6d7w5S11iLu6LQsPGe/9RPzhri7gNNLdrK1LFpO9/m7IZhQL6dat0JHICJ7l51zvHAiCgnPLLHA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.1.19",
|
"version": "7.1.19",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz",
|
||||||
@@ -5316,6 +5326,11 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ace-builds": {
|
||||||
|
"version": "1.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.7.1.tgz",
|
||||||
|
"integrity": "sha512-1mcbP5kXvr729sJ9dA/8tul0pjuvKbma0LF/ZMRwPEwjoNWNpe/x0OXpaPJo36aRpZCjRZMl5zsME3hAKTiaNw=="
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "7.4.1",
|
"version": "7.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||||
@@ -8842,6 +8857,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-unit-converter": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||||
|
},
|
||||||
"node_modules/css-vendor": {
|
"node_modules/css-vendor": {
|
||||||
"version": "2.0.8",
|
"version": "2.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
|
||||||
@@ -9178,6 +9198,73 @@
|
|||||||
"type": "^1.0.1"
|
"type": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/d3-array": {
|
||||||
|
"version": "2.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
|
||||||
|
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"internmap": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-color": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
|
||||||
|
},
|
||||||
|
"node_modules/d3-format": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
|
||||||
|
},
|
||||||
|
"node_modules/d3-interpolate": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-color": "1 - 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-path": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
|
||||||
|
},
|
||||||
|
"node_modules/d3-scale": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "^2.3.0",
|
||||||
|
"d3-format": "1 - 2",
|
||||||
|
"d3-interpolate": "1.2.0 - 2",
|
||||||
|
"d3-time": "^2.1.1",
|
||||||
|
"d3-time-format": "2 - 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-shape": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-path": "1 - 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-time": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-time-format": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-time": "1 - 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@@ -9236,6 +9323,11 @@
|
|||||||
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==",
|
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/decimal.js-light": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
|
||||||
|
},
|
||||||
"node_modules/decko": {
|
"node_modules/decko": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz",
|
||||||
@@ -9605,6 +9697,11 @@
|
|||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/diff-match-patch": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
|
||||||
|
},
|
||||||
"node_modules/diff-sequences": {
|
"node_modules/diff-sequences": {
|
||||||
"version": "26.6.2",
|
"version": "26.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
|
||||||
@@ -11566,6 +11663,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-equals": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w=="
|
||||||
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.2.11",
|
"version": "3.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||||
@@ -13871,6 +13973,11 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/internmap": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||||
|
},
|
||||||
"node_modules/ip": {
|
"node_modules/ip": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||||
@@ -17624,6 +17731,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||||
|
},
|
||||||
"node_modules/lodash.isequal": {
|
"node_modules/lodash.isequal": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
@@ -24760,6 +24872,22 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-ace": {
|
||||||
|
"version": "9.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-ace/-/react-ace-9.5.0.tgz",
|
||||||
|
"integrity": "sha512-4l5FgwGh6K7A0yWVMQlPIXDItM4Q9zzXRqOae8KkCl6MkOob7sC1CzHxZdOGvV+QioKWbX2p5HcdOVUv6cAdSg==",
|
||||||
|
"dependencies": {
|
||||||
|
"ace-builds": "^1.4.13",
|
||||||
|
"diff-match-patch": "^1.0.5",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"lodash.isequal": "^4.5.0",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0",
|
||||||
|
"react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-app-polyfill": {
|
"node_modules/react-app-polyfill": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz",
|
||||||
@@ -24987,6 +25115,11 @@
|
|||||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/react-lifecycles-compat": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||||
|
},
|
||||||
"node_modules/react-lowlight": {
|
"node_modules/react-lowlight": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-lowlight/-/react-lowlight-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-lowlight/-/react-lowlight-3.0.0.tgz",
|
||||||
@@ -25013,6 +25146,18 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-resize-detector": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.21"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
||||||
@@ -25314,6 +25459,43 @@
|
|||||||
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0"
|
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-smooth": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-Own9TA0GPPf3as4vSwFhDouVfXP15ie/wIHklhyKBH5AN6NFtdk0UpHBnonV11BtqDkAWlt40MOUc+5srmW7NA==",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-equals": "^2.0.0",
|
||||||
|
"react-transition-group": "2.9.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-smooth/node_modules/dom-helpers": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-smooth/node_modules/react-transition-group": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
|
||||||
|
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
|
||||||
|
"dependencies": {
|
||||||
|
"dom-helpers": "^3.4.0",
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"prop-types": "^15.6.2",
|
||||||
|
"react-lifecycles-compat": "^3.0.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=15.0.0",
|
||||||
|
"react-dom": ">=15.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-syntax-highlighter": {
|
"node_modules/react-syntax-highlighter": {
|
||||||
"version": "15.5.0",
|
"version": "15.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
|
||||||
@@ -25529,6 +25711,44 @@
|
|||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/recharts": {
|
||||||
|
"version": "2.1.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.12.tgz",
|
||||||
|
"integrity": "sha512-dAzEuc9AjM+IF0A33QzEdBEUnyGKJcGUPa0MYm0vd38P3WouQjrj2egBrCNInE7ZcQwN+z3MoT7Rw03u8nP9HA==",
|
||||||
|
"dependencies": {
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"d3-interpolate": "^2.0.0",
|
||||||
|
"d3-scale": "^3.0.0",
|
||||||
|
"d3-shape": "^2.0.0",
|
||||||
|
"eventemitter3": "^4.0.1",
|
||||||
|
"lodash": "^4.17.19",
|
||||||
|
"react-is": "^16.10.2",
|
||||||
|
"react-resize-detector": "^7.1.2",
|
||||||
|
"react-smooth": "^2.0.1",
|
||||||
|
"recharts-scale": "^0.4.4",
|
||||||
|
"reduce-css-calc": "^2.1.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/recharts-scale": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"decimal.js-light": "^2.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/recharts/node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
|
},
|
||||||
"node_modules/recoil": {
|
"node_modules/recoil": {
|
||||||
"version": "0.7.3",
|
"version": "0.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.3.tgz",
|
||||||
@@ -25969,6 +26189,20 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/reduce-css-calc": {
|
||||||
|
"version": "2.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
|
||||||
|
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
|
||||||
|
"dependencies": {
|
||||||
|
"css-unit-converter": "^1.1.1",
|
||||||
|
"postcss-value-parser": "^3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/reduce-css-calc/node_modules/postcss-value-parser": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||||
|
},
|
||||||
"node_modules/refractor": {
|
"node_modules/refractor": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
|
||||||
@@ -36714,6 +36948,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
||||||
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
|
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ=="
|
||||||
},
|
},
|
||||||
|
"@types/ace": {
|
||||||
|
"version": "0.0.48",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ace/-/ace-0.0.48.tgz",
|
||||||
|
"integrity": "sha512-esV6hOWiDOZ6d7w5S11iLu6LQsPGe/9RPzhri7gNNLdrK1LFpO9/m7IZhQL6dat0JHICJ7l51zvHAiCgnPLLHA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/babel__core": {
|
"@types/babel__core": {
|
||||||
"version": "7.1.19",
|
"version": "7.1.19",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz",
|
||||||
@@ -37401,6 +37641,11 @@
|
|||||||
"negotiator": "0.6.3"
|
"negotiator": "0.6.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ace-builds": {
|
||||||
|
"version": "1.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.7.1.tgz",
|
||||||
|
"integrity": "sha512-1mcbP5kXvr729sJ9dA/8tul0pjuvKbma0LF/ZMRwPEwjoNWNpe/x0OXpaPJo36aRpZCjRZMl5zsME3hAKTiaNw=="
|
||||||
|
},
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "7.4.1",
|
"version": "7.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||||
@@ -40174,6 +40419,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-unit-converter": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||||
|
},
|
||||||
"css-vendor": {
|
"css-vendor": {
|
||||||
"version": "2.0.8",
|
"version": "2.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
|
||||||
@@ -40426,6 +40676,73 @@
|
|||||||
"type": "^1.0.1"
|
"type": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"d3-array": {
|
||||||
|
"version": "2.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
|
||||||
|
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
|
||||||
|
"requires": {
|
||||||
|
"internmap": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"d3-color": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
|
||||||
|
},
|
||||||
|
"d3-format": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
|
||||||
|
},
|
||||||
|
"d3-interpolate": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
|
||||||
|
"requires": {
|
||||||
|
"d3-color": "1 - 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"d3-path": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
|
||||||
|
},
|
||||||
|
"d3-scale": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==",
|
||||||
|
"requires": {
|
||||||
|
"d3-array": "^2.3.0",
|
||||||
|
"d3-format": "1 - 2",
|
||||||
|
"d3-interpolate": "1.2.0 - 2",
|
||||||
|
"d3-time": "^2.1.1",
|
||||||
|
"d3-time-format": "2 - 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"d3-shape": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==",
|
||||||
|
"requires": {
|
||||||
|
"d3-path": "1 - 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"d3-time": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
|
||||||
|
"requires": {
|
||||||
|
"d3-array": "2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"d3-time-format": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
|
||||||
|
"requires": {
|
||||||
|
"d3-time": "1 - 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"damerau-levenshtein": {
|
"damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
@@ -40467,6 +40784,11 @@
|
|||||||
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==",
|
"integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"decimal.js-light": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
|
||||||
|
},
|
||||||
"decko": {
|
"decko": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz",
|
||||||
@@ -40750,6 +41072,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
|
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
|
||||||
},
|
},
|
||||||
|
"diff-match-patch": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
|
||||||
|
},
|
||||||
"diff-sequences": {
|
"diff-sequences": {
|
||||||
"version": "26.6.2",
|
"version": "26.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
|
||||||
@@ -42256,6 +42583,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
},
|
},
|
||||||
|
"fast-equals": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w=="
|
||||||
|
},
|
||||||
"fast-glob": {
|
"fast-glob": {
|
||||||
"version": "3.2.11",
|
"version": "3.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||||
@@ -44029,6 +44361,11 @@
|
|||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"internmap": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
|
||||||
|
},
|
||||||
"ip": {
|
"ip": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||||
@@ -46856,6 +47193,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
||||||
},
|
},
|
||||||
|
"lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||||
|
},
|
||||||
"lodash.isequal": {
|
"lodash.isequal": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
@@ -52306,6 +52648,18 @@
|
|||||||
"object-assign": "^4.1.1"
|
"object-assign": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-ace": {
|
||||||
|
"version": "9.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-ace/-/react-ace-9.5.0.tgz",
|
||||||
|
"integrity": "sha512-4l5FgwGh6K7A0yWVMQlPIXDItM4Q9zzXRqOae8KkCl6MkOob7sC1CzHxZdOGvV+QioKWbX2p5HcdOVUv6cAdSg==",
|
||||||
|
"requires": {
|
||||||
|
"ace-builds": "^1.4.13",
|
||||||
|
"diff-match-patch": "^1.0.5",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"lodash.isequal": "^4.5.0",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-app-polyfill": {
|
"react-app-polyfill": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz",
|
||||||
@@ -52490,6 +52844,11 @@
|
|||||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"react-lifecycles-compat": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||||
|
},
|
||||||
"react-lowlight": {
|
"react-lowlight": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-lowlight/-/react-lowlight-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-lowlight/-/react-lowlight-3.0.0.tgz",
|
||||||
@@ -52504,6 +52863,14 @@
|
|||||||
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==",
|
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"react-resize-detector": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==",
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.17.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-router": {
|
"react-router": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
||||||
@@ -52707,6 +53074,36 @@
|
|||||||
"integrity": "sha512-YkFkPjdIXDUsaCNYhZ+Blpp3LF+CsJWscwn/0fGSjF5QBKCtPURO9AEUA362Qnjr4S8LF2IjSAOCCFedIEnVNw==",
|
"integrity": "sha512-YkFkPjdIXDUsaCNYhZ+Blpp3LF+CsJWscwn/0fGSjF5QBKCtPURO9AEUA362Qnjr4S8LF2IjSAOCCFedIEnVNw==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"react-smooth": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-Own9TA0GPPf3as4vSwFhDouVfXP15ie/wIHklhyKBH5AN6NFtdk0UpHBnonV11BtqDkAWlt40MOUc+5srmW7NA==",
|
||||||
|
"requires": {
|
||||||
|
"fast-equals": "^2.0.0",
|
||||||
|
"react-transition-group": "2.9.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"dom-helpers": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-transition-group": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
|
||||||
|
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
|
||||||
|
"requires": {
|
||||||
|
"dom-helpers": "^3.4.0",
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"prop-types": "^15.6.2",
|
||||||
|
"react-lifecycles-compat": "^3.0.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-syntax-highlighter": {
|
"react-syntax-highlighter": {
|
||||||
"version": "15.5.0",
|
"version": "15.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
|
||||||
@@ -52880,6 +53277,39 @@
|
|||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"recharts": {
|
||||||
|
"version": "2.1.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.12.tgz",
|
||||||
|
"integrity": "sha512-dAzEuc9AjM+IF0A33QzEdBEUnyGKJcGUPa0MYm0vd38P3WouQjrj2egBrCNInE7ZcQwN+z3MoT7Rw03u8nP9HA==",
|
||||||
|
"requires": {
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"d3-interpolate": "^2.0.0",
|
||||||
|
"d3-scale": "^3.0.0",
|
||||||
|
"d3-shape": "^2.0.0",
|
||||||
|
"eventemitter3": "^4.0.1",
|
||||||
|
"lodash": "^4.17.19",
|
||||||
|
"react-is": "^16.10.2",
|
||||||
|
"react-resize-detector": "^7.1.2",
|
||||||
|
"react-smooth": "^2.0.1",
|
||||||
|
"recharts-scale": "^0.4.4",
|
||||||
|
"reduce-css-calc": "^2.1.8"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"recharts-scale": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
|
||||||
|
"requires": {
|
||||||
|
"decimal.js-light": "^2.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"recoil": {
|
"recoil": {
|
||||||
"version": "0.7.3",
|
"version": "0.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.3.tgz",
|
||||||
@@ -53215,6 +53645,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"reduce-css-calc": {
|
||||||
|
"version": "2.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
|
||||||
|
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
|
||||||
|
"requires": {
|
||||||
|
"css-unit-converter": "^1.1.1",
|
||||||
|
"postcss-value-parser": "^3.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"postcss-value-parser": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"refractor": {
|
"refractor": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
|
||||||
|
|||||||
@@ -26,11 +26,11 @@
|
|||||||
"@craco/craco": "^6.4.3",
|
"@craco/craco": "^6.4.3",
|
||||||
"@types/jest": "^26.0.24",
|
"@types/jest": "^26.0.24",
|
||||||
"@types/node": "^12.20.54",
|
"@types/node": "^12.20.54",
|
||||||
"sass": "^1.52.3",
|
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"recoil": "^0.7.2"
|
"recoil": "^0.7.2",
|
||||||
|
"sass": "^1.52.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@craco/craco": "^6.4.3",
|
"@craco/craco": "^6.4.3",
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||||
"@svgr/rollup": "^6.2.1",
|
"@svgr/rollup": "^6.2.1",
|
||||||
|
"@types/ace": "^0.0.48",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"gh-pages": "^4.0.0",
|
"gh-pages": "^4.0.0",
|
||||||
@@ -93,6 +94,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"src/*.scss",
|
||||||
"dist"
|
"dist"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const AutoRepresentation: React.FC<any> = ({ representation, color, opene
|
|||||||
badge: null
|
badge: null
|
||||||
}]
|
}]
|
||||||
|
|
||||||
if (response) {
|
if (response && response.length > 0) {
|
||||||
arr.push({
|
arr.push({
|
||||||
tab: 'Response',
|
tab: 'Response',
|
||||||
badge: null
|
badge: null
|
||||||
@@ -71,7 +71,7 @@ export const AutoRepresentation: React.FC<any> = ({ representation, color, opene
|
|||||||
{getOpenedTabIndex() === TabsEnum.Request && <React.Fragment>
|
{getOpenedTabIndex() === TabsEnum.Request && <React.Fragment>
|
||||||
<SectionsRepresentation data={request} color={color} requestRepresentation={request} />
|
<SectionsRepresentation data={request} color={color} requestRepresentation={request} />
|
||||||
</React.Fragment>}
|
</React.Fragment>}
|
||||||
{response && getOpenedTabIndex() === TabsEnum.Response && <React.Fragment>
|
{response && response.length > 0 && getOpenedTabIndex() === TabsEnum.Response && <React.Fragment>
|
||||||
<SectionsRepresentation data={response} color={color} />
|
<SectionsRepresentation data={response} color={color} />
|
||||||
</React.Fragment>}
|
</React.Fragment>}
|
||||||
</div>}
|
</div>}
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ $light-gray: #8F9BB2;
|
|||||||
failureColor: $failure-color;
|
failureColor: $failure-color;
|
||||||
blueGray: $blue-gray;
|
blueGray: $blue-gray;
|
||||||
lightGray: $light-gray;
|
lightGray: $light-gray;
|
||||||
|
contentSectionColor: $content-section-color;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user