Compare commits

...

14 Commits

Author SHA1 Message Date
lirazyehezkel
e41488ef3e TRA-4276 Folder structure refactor (#1131)
* mizu-common folder structure refactor

* no message

* change images import from absolute to relative

* relative sass imports

* no message

* remove tgz

* spinner style
2022-06-12 11:20:47 +03:00
AmitUp9
533fb71bf4 TRA-4596_Update material UI to v5 (#1132)
* install @mui v5 and change imports

* upgrade MUI v5 in mizu community

* package-lock of mizu community and ui-common

* fix ui-common path

* #run_acceptance_tests

* remove comment

* cr fixes
2022-06-08 15:32:34 +03:00
RoyUP9
6f8aad83e6 Minikube start with more memory&cpu (#1130) 2022-06-06 17:53:12 +03:00
leon-up9
6e6bcec77e Ui/TRA-4586_add-insertion-filter-to-settings-page (#1127)
* working query input

* removed prop

* splited to diffrent events

* export alias

* PR comments

Co-authored-by: Leon <>
2022-06-06 16:40:23 +03:00
leon-up9
71db792a4e list takes 100% from parent (#1129)
Co-authored-by: Leon <>
2022-06-06 16:26:07 +03:00
gadotroee
f7f61c1217 Fix cypress files to cypress version 10 (#1124) 2022-06-06 11:13:20 +03:00
AmitUp9
696501fa11 remove poweredBy by display none the css calss (#1126) 2022-06-02 14:31:34 +03:00
gadotroee
415b5e08fd Use Specific cypress version in the acceptance tests (#1125) 2022-06-02 13:21:44 +03:00
AmitUp9
7810f6defb TRA_4565 - npm packages major updates (#1123)
* Major npm packages update

* npm i command added to dockerfile

* globally install npm new version

* remove the packages lock file copy

* package-lock commit and dockerfile revert changes

* space removal

Co-authored-by: Roee Gadot <roee.gadot@up9.com>
2022-06-02 11:22:37 +03:00
gadotroee
2aeac6c9e6 Remove analyze feature (#1121) 2022-06-01 10:17:14 +03:00
AmitUp9
dc241218bf minor changes updated (#1122) 2022-05-31 15:08:15 +03:00
leon-up9
02b3672e09 added map object (#1119)
Co-authored-by: Leon <>
2022-05-30 13:13:07 +03:00
RoyUP9
45b368b33e Updated the install command UX (#1118) 2022-05-30 11:18:46 +03:00
Igor Gov
8f64fdaa61 Alert to slack if release action fails (#1117)
* Trigger mizu ent stg deployment on release
2022-05-29 15:16:45 +03:00
133 changed files with 9143 additions and 13366 deletions

View File

@@ -290,3 +290,15 @@ jobs:
tag: ${{ steps.versioning.outputs.version }}
prerelease: ${{ github.ref != 'refs/heads/main' }}
bodyFile: 'cli/bin/README.md'
- name: Slack notification on failure
uses: ravsamhq/notify-slack-action@v1
if: always()
with:
status: ${{ job.status }}
notification_title: 'Mizu enterprise {workflow} has {status_message}'
message_format: '{emoji} *{workflow}* {status_message} during <{run_url}|run>, after commit <{commit_url}|{commit_sha}> by ${{ github.event.head_commit.author.name }} <${{ github.event.head_commit.author.email }}> ```${{ github.event.head_commit.message }}```'
footer: 'Linked Repo <{repo_url}|{repo}>'
notify_when: 'failure'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

View File

@@ -1,2 +1,3 @@
test: ## Run acceptance tests.
@npm install cypress@10.0.1 -y
@go test ./... -timeout 1h -v

View File

@@ -0,0 +1,31 @@
const { defineConfig } = require('cypress')
module.exports = defineConfig({
watchForFileChanges: false,
viewportWidth: 1920,
viewportHeight: 1080,
video: false,
screenshotOnRunFailure: false,
defaultCommandTimeout: 6000,
env: {
testUrl: 'http://localhost:8899/',
redactHeaderContent: 'User-Header[REDACTED]',
redactBodyContent: '{ "User": "[REDACTED]" }',
regexMaskingBodyContent: '[REDACTED]',
greenFilterColor: 'rgb(210, 250, 210)',
redFilterColor: 'rgb(250, 214, 220)',
bodyJsonClass: '.hljs',
mizuWidth: 1920,
normalMizuHeight: 1080,
hugeMizuHeight: 3500,
},
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
// setupNodeEvents(on, config) {
// return require('./cypress/plugins/index.js')(on, config)
// },
specPattern: 'cypress/e2e/tests/*.js',
supportFile: false
},
})

View File

@@ -1,34 +0,0 @@
{
"watchForFileChanges":false,
"viewportWidth": 1920,
"viewportHeight": 1080,
"video": false,
"screenshotOnRunFailure": false,
"defaultCommandTimeout": 6000,
"testFiles": [
"tests/GuiPort.js",
"tests/MultipleNamespaces.js",
"tests/Redact.js",
"tests/NoRedact.js",
"tests/Regex.js",
"tests/RegexMasking.js",
"tests/IgnoredUserAgents.js",
"tests/UiTest.js",
"tests/Redis.js",
"tests/Rabbit.js",
"tests/serviceMapFunction.js"
],
"env": {
"testUrl": "http://localhost:8899/",
"redactHeaderContent": "User-Header[REDACTED]",
"redactBodyContent": "{ \"User\": \"[REDACTED]\" }",
"regexMaskingBodyContent": "[REDACTED]",
"greenFilterColor": "rgb(210, 250, 210)",
"redFilterColor": "rgb(250, 214, 220)",
"bodyJsonClass": ".hljs",
"mizuWidth": 1920,
"normalMizuHeight": 1080,
"hugeMizuHeight": 3500
}
}

View File

@@ -4,8 +4,6 @@ export const valueTabs = {
none: null
}
const maxEntriesInDom = 13;
export function isValueExistsInElement(shouldInclude, content, domPathToContainer){
it(`should ${shouldInclude ? '' : 'not'} include '${content}'`, function () {
cy.get(domPathToContainer).then(htmlText => {

View File

@@ -105,7 +105,7 @@ func TestRedis(t *testing.T) {
}
}
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/Redis.js\"")
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/Redis.js\"")
}
func TestAmqp(t *testing.T) {
@@ -236,5 +236,5 @@ func TestAmqp(t *testing.T) {
ch.Close()
}
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/Rabbit.js\"")
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/Rabbit.js\"")
}

View File

@@ -27,7 +27,7 @@ else
fi
echo "Starting minikube..."
minikube start
minikube start --cpus 2 --memory 6946
echo "Creating mizu tests namespaces"
kubectl create namespace mizu-tests --dry-run=client -o yaml | kubectl apply -f -

View File

@@ -78,7 +78,7 @@ func basicTapTest(t *testing.T, shouldCheckSrcAndDest bool, extraArgs... string)
expectedPodsStr += fmt.Sprintf("Name:%vNamespace:%v", expectedPods[i].Name, expectedPods[i].Namespace)
}
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/UiTest.js\" --env entriesCount=%d,arrayDict=%v,shouldCheckSrcAndDest=%v",
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/UiTest.js\" --env entriesCount=%d,arrayDict=%v,shouldCheckSrcAndDest=%v",
entriesCount, expectedPodsStr, shouldCheckSrcAndDest))
})
}
@@ -135,7 +135,7 @@ func TestTapGuiPort(t *testing.T) {
}
}
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/GuiPort.js\" --env name=%v,namespace=%v,port=%d",
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/GuiPort.js\" --env name=%v,namespace=%v,port=%d",
"httpbin", "mizu-tests", guiPort))
})
}
@@ -182,7 +182,7 @@ func TestTapAllNamespaces(t *testing.T) {
return
}
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
expectedPods[0].Name, expectedPods[1].Name, expectedPods[2].Name, expectedPods[0].Namespace, expectedPods[1].Namespace, expectedPods[2].Namespace))
}
@@ -231,7 +231,7 @@ func TestTapMultipleNamespaces(t *testing.T) {
return
}
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
expectedPods[0].Name, expectedPods[1].Name, expectedPods[2].Name, expectedPods[0].Namespace, expectedPods[1].Namespace, expectedPods[2].Namespace))
}
@@ -277,7 +277,7 @@ func TestTapRegex(t *testing.T) {
return
}
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/Regex.js\" --env name=%v,namespace=%v",
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/Regex.js\" --env name=%v,namespace=%v",
expectedPods[0].Name, expectedPods[0].Namespace))
}
@@ -376,7 +376,7 @@ func TestTapRedact(t *testing.T) {
}
}
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/Redact.js\"")
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/Redact.js\"")
}
func TestTapNoRedact(t *testing.T) {
@@ -426,7 +426,7 @@ func TestTapNoRedact(t *testing.T) {
}
}
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/NoRedact.js\"")
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/NoRedact.js\"")
}
func TestTapRegexMasking(t *testing.T) {
@@ -479,7 +479,7 @@ func TestTapRegexMasking(t *testing.T) {
}
}
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/RegexMasking.js\"")
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/RegexMasking.js\"")
}
@@ -541,7 +541,7 @@ func TestTapIgnoredUserAgents(t *testing.T) {
}
}
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/IgnoredUserAgents.js\"")
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/IgnoredUserAgents.js\"")
}
func TestTapDumpLogs(t *testing.T) {

View File

@@ -24,7 +24,6 @@ import (
"github.com/up9inc/mizu/agent/pkg/oas"
"github.com/up9inc/mizu/agent/pkg/routes"
"github.com/up9inc/mizu/agent/pkg/servicemap"
"github.com/up9inc/mizu/agent/pkg/up9"
"github.com/up9inc/mizu/agent/pkg/utils"
"github.com/up9inc/mizu/agent/pkg/api"
@@ -72,13 +71,13 @@ func main() {
} else if *tapperMode {
runInTapperMode()
} else if *apiServerMode {
app := runInApiServerMode(*namespace)
ginApp := runInApiServerMode(*namespace)
if *profiler {
pprof.Register(app)
pprof.Register(ginApp)
}
utils.StartServer(app)
utils.StartServer(ginApp)
} else if *harsReaderMode {
runInHarReaderMode()
@@ -92,9 +91,9 @@ func main() {
}
func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engine {
app := gin.Default()
ginApp := gin.Default()
app.GET("/echo", func(c *gin.Context) {
ginApp.GET("/echo", func(c *gin.Context) {
c.JSON(http.StatusOK, "Here is Mizu agent")
})
@@ -102,7 +101,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
SocketOutChannel: socketHarOutputChannel,
}
app.Use(disableRootStaticCache())
ginApp.Use(disableRootStaticCache())
staticFolder := "./site"
indexStaticFile := staticFolder + "/index.html"
@@ -110,30 +109,30 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
logger.Log.Errorf("Error setting ui flags, err: %v", err)
}
app.Use(static.ServeRoot("/", staticFolder))
app.NoRoute(func(c *gin.Context) {
ginApp.Use(static.ServeRoot("/", staticFolder))
ginApp.NoRoute(func(c *gin.Context) {
c.File(indexStaticFile)
})
app.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before
ginApp.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if it's called before
api.WebSocketRoutes(app, &eventHandlers)
api.WebSocketRoutes(ginApp, &eventHandlers)
if config.Config.OAS {
routes.OASRoutes(app)
routes.OASRoutes(ginApp)
}
if config.Config.ServiceMap {
routes.ServiceMapRoutes(app)
routes.ServiceMapRoutes(ginApp)
}
routes.QueryRoutes(app)
routes.EntriesRoutes(app)
routes.MetadataRoutes(app)
routes.StatusRoutes(app)
routes.DbRoutes(app)
routes.QueryRoutes(ginApp)
routes.EntriesRoutes(ginApp)
routes.MetadataRoutes(ginApp)
routes.StatusRoutes(ginApp)
routes.DbRoutes(ginApp)
return app
return ginApp
}
func runInApiServerMode(namespace string) *gin.Engine {
@@ -145,13 +144,6 @@ func runInApiServerMode(namespace string) *gin.Engine {
enableExpFeatureIfNeeded()
syncEntriesConfig := getSyncEntriesConfig()
if syncEntriesConfig != nil {
if err := up9.SyncEntries(syncEntriesConfig); err != nil {
logger.Log.Error("Error syncing entries, err: %v", err)
}
}
return hostApi(app.GetEntryInputChannel())
}
@@ -218,21 +210,6 @@ func enableExpFeatureIfNeeded() {
}
}
func getSyncEntriesConfig() *shared.SyncEntriesConfig {
syncEntriesConfigJson := os.Getenv(shared.SyncEntriesConfigEnvVar)
if syncEntriesConfigJson == "" {
return nil
}
var syncEntriesConfig = &shared.SyncEntriesConfig{}
err := json.Unmarshal([]byte(syncEntriesConfigJson), syncEntriesConfig)
if err != nil {
panic(fmt.Sprintf("env var %s's value of %s is invalid! json must match the shared.SyncEntriesConfig struct, err: %v", shared.SyncEntriesConfigEnvVar, syncEntriesConfigJson, err))
}
return syncEntriesConfig
}
func disableRootStaticCache() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.RequestURI == "/" {

View File

@@ -10,7 +10,6 @@ import (
"github.com/up9inc/mizu/agent/pkg/models"
"github.com/up9inc/mizu/agent/pkg/providers/tappedPods"
"github.com/up9inc/mizu/agent/pkg/providers/tappers"
"github.com/up9inc/mizu/agent/pkg/up9"
tapApi "github.com/up9inc/mizu/tap/api"
@@ -31,10 +30,6 @@ type RoutesEventHandlers struct {
SocketOutChannel chan<- *tapApi.OutputChannelItem
}
func init() {
go up9.UpdateAnalyzeStatus(BroadcastToBrowserClients)
}
func (h *RoutesEventHandlers) WebSocketConnect(_ *gin.Context, socketId int, isTapper bool) {
if isTapper {
logger.Log.Infof("Websocket event - Tapper connected, socket ID: %d", socketId)

View File

@@ -11,7 +11,6 @@ import (
"github.com/up9inc/mizu/agent/pkg/providers"
"github.com/up9inc/mizu/agent/pkg/providers/tappedPods"
"github.com/up9inc/mizu/agent/pkg/providers/tappers"
"github.com/up9inc/mizu/agent/pkg/up9"
"github.com/up9inc/mizu/agent/pkg/validation"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/shared"
@@ -71,25 +70,11 @@ func GetConnectedTappersCount(c *gin.Context) {
c.JSON(http.StatusOK, tappers.GetConnectedCount())
}
func GetAuthStatus(c *gin.Context) {
authStatus, err := providers.GetAuthStatus()
if err != nil {
c.JSON(http.StatusInternalServerError, err)
return
}
c.JSON(http.StatusOK, authStatus)
}
func GetTappingStatus(c *gin.Context) {
tappedPodsStatus := tappedPods.GetTappedPodsStatus()
c.JSON(http.StatusOK, tappedPodsStatus)
}
func AnalyzeInformation(c *gin.Context) {
c.JSON(http.StatusOK, up9.GetAnalyzeInfo())
}
func GetGeneralStats(c *gin.Context) {
c.JSON(http.StatusOK, providers.GetGeneralStats())
}

View File

@@ -43,11 +43,6 @@ type WebSocketTappedEntryMessage struct {
Data *tapApi.OutputChannelItem
}
type AuthStatus struct {
Email string `json:"email"`
Model string `json:"model"`
}
type ToastMessage struct {
Type string `json:"type"`
AutoClose uint `json:"autoClose"`

View File

@@ -1,47 +0,0 @@
package providers
import (
"encoding/json"
"fmt"
"os"
"github.com/up9inc/mizu/agent/pkg/models"
"github.com/up9inc/mizu/shared"
)
var (
authStatus *models.AuthStatus
)
func GetAuthStatus() (*models.AuthStatus, error) {
if authStatus == nil {
syncEntriesConfigJson := os.Getenv(shared.SyncEntriesConfigEnvVar)
if syncEntriesConfigJson == "" {
authStatus = &models.AuthStatus{}
return authStatus, nil
}
syncEntriesConfig := &shared.SyncEntriesConfig{}
err := json.Unmarshal([]byte(syncEntriesConfigJson), syncEntriesConfig)
if err != nil {
return nil, fmt.Errorf("failed to marshal sync entries config, err: %v", err)
}
if syncEntriesConfig.Token == "" {
authStatus = &models.AuthStatus{}
return authStatus, nil
}
tokenEmail, err := shared.GetTokenEmail(syncEntriesConfig.Token)
if err != nil {
return nil, fmt.Errorf("failed to get token email, err: %v", err)
}
authStatus = &models.AuthStatus{
Email: tokenEmail,
Model: syncEntriesConfig.Workspace,
}
}
return authStatus, nil
}

View File

@@ -15,10 +15,6 @@ func StatusRoutes(ginApp *gin.Engine) {
routeGroup.GET("/connectedTappersCount", controllers.GetConnectedTappersCount)
routeGroup.GET("/tap", controllers.GetTappingStatus)
routeGroup.GET("/auth", controllers.GetAuthStatus)
routeGroup.GET("/analyze", controllers.AnalyzeInformation)
routeGroup.GET("/general", controllers.GetGeneralStats) // get general stats about entries in DB
routeGroup.GET("/resolving", controllers.GetCurrentResolvingInformation)

View File

@@ -1,353 +0,0 @@
package up9
import (
"bytes"
"compress/zlib"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strings"
"sync"
"time"
"github.com/up9inc/mizu/agent/pkg/har"
"github.com/up9inc/mizu/agent/pkg/utils"
basenine "github.com/up9inc/basenine/client/go"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/shared"
tapApi "github.com/up9inc/mizu/tap/api"
)
const (
AnalyzeCheckSleepTime = 5 * time.Second
SentCountLogInterval = 100
)
type GuestToken struct {
Token string `json:"token"`
Model string `json:"model"`
}
type ModelStatus struct {
LastMajorGeneration float64 `json:"lastMajorGeneration"`
}
func GetRemoteUrl(analyzeDestination string, analyzeModel string, analyzeToken string, guestMode bool) string {
if guestMode {
return fmt.Sprintf("https://%s/share/%s", analyzeDestination, analyzeToken)
}
return fmt.Sprintf("https://%s/app/workspaces/%s", analyzeDestination, analyzeModel)
}
func CheckIfModelReady(analyzeDestination string, analyzeModel string, analyzeToken string, guestMode bool) bool {
statusUrl, _ := url.Parse(fmt.Sprintf("https://trcc.%s/models/%s/status", analyzeDestination, analyzeModel))
authHeader := getAuthHeader(guestMode)
req := &http.Request{
Method: http.MethodGet,
URL: statusUrl,
Header: map[string][]string{
"Content-Type": {"application/json"},
authHeader: {analyzeToken},
},
}
statusResp, err := http.DefaultClient.Do(req)
if err != nil {
return false
}
defer statusResp.Body.Close()
target := &ModelStatus{}
_ = json.NewDecoder(statusResp.Body).Decode(&target)
return target.LastMajorGeneration > 0
}
func getAuthHeader(guestMode bool) string {
if guestMode {
return "Guest-Auth"
}
return "Authorization"
}
func GetTrafficDumpUrl(analyzeDestination string, analyzeModel string) *url.URL {
strUrl := fmt.Sprintf("https://traffic.%s/dumpTrafficBulk/%s", analyzeDestination, analyzeModel)
postUrl, _ := url.Parse(strUrl)
return postUrl
}
type AnalyzeInformation struct {
IsAnalyzing bool
GuestMode bool
SentCount int
AnalyzedModel string
AnalyzeToken string
AnalyzeDestination string
}
func (info *AnalyzeInformation) Reset() {
info.IsAnalyzing = false
info.GuestMode = true
info.AnalyzedModel = ""
info.AnalyzeToken = ""
info.AnalyzeDestination = ""
info.SentCount = 0
}
var analyzeInformation = &AnalyzeInformation{}
func GetAnalyzeInfo() *shared.AnalyzeStatus {
return &shared.AnalyzeStatus{
IsAnalyzing: analyzeInformation.IsAnalyzing,
RemoteUrl: GetRemoteUrl(analyzeInformation.AnalyzeDestination, analyzeInformation.AnalyzedModel, analyzeInformation.AnalyzeToken, analyzeInformation.GuestMode),
IsRemoteReady: CheckIfModelReady(analyzeInformation.AnalyzeDestination, analyzeInformation.AnalyzedModel, analyzeInformation.AnalyzeToken, analyzeInformation.GuestMode),
SentCount: analyzeInformation.SentCount,
}
}
func SyncEntries(syncEntriesConfig *shared.SyncEntriesConfig) error {
logger.Log.Infof("Sync entries - started")
var (
token, model string
guestMode bool
)
if syncEntriesConfig.Token == "" {
logger.Log.Infof("Sync entries - creating anonymous token. env %s", syncEntriesConfig.Env)
guestToken, err := createAnonymousToken(syncEntriesConfig.Env)
if err != nil {
return fmt.Errorf("failed creating anonymous token, err: %v", err)
}
token = guestToken.Token
model = guestToken.Model
guestMode = true
} else {
token = fmt.Sprintf("bearer %s", syncEntriesConfig.Token)
model = syncEntriesConfig.Workspace
guestMode = false
logger.Log.Infof("Sync entries - upserting model. env %s, model %s", syncEntriesConfig.Env, model)
if err := upsertModel(token, model, syncEntriesConfig.Env); err != nil {
return fmt.Errorf("failed upserting model, err: %v", err)
}
}
modelRegex, _ := regexp.Compile("[A-Za-z0-9][-A-Za-z0-9_.]*[A-Za-z0-9]+$")
if len(model) > 63 || !modelRegex.MatchString(model) {
return fmt.Errorf("invalid model name, model name: %s", model)
}
logger.Log.Infof("Sync entries - syncing. token: %s, model: %s, guest mode: %v", token, model, guestMode)
go syncEntriesImpl(token, model, syncEntriesConfig.Env, syncEntriesConfig.UploadIntervalSec, guestMode)
return nil
}
func upsertModel(token string, model string, envPrefix string) error {
upsertModelUrl, _ := url.Parse(fmt.Sprintf("https://trcc.%s/models/%s", envPrefix, model))
authHeader := getAuthHeader(false)
req := &http.Request{
Method: http.MethodPost,
URL: upsertModelUrl,
Header: map[string][]string{
authHeader: {token},
},
}
response, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed request to upsert model, err: %v", err)
}
// In case the model is not created (not 201) and doesn't exists (not 409)
if response.StatusCode != 201 && response.StatusCode != 409 {
return fmt.Errorf("failed request to upsert model, status code: %v", response.StatusCode)
}
return nil
}
func createAnonymousToken(envPrefix string) (*GuestToken, error) {
tokenUrl := fmt.Sprintf("https://trcc.%s/anonymous/token", envPrefix)
if strings.HasPrefix(envPrefix, "http") {
tokenUrl = fmt.Sprintf("%s/api/token", envPrefix)
}
token := &GuestToken{}
if err := getGuestToken(tokenUrl, token); err != nil {
logger.Log.Infof("Failed to get token, %s", err)
return nil, err
}
return token, nil
}
func getGuestToken(url string, target *GuestToken) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
logger.Log.Infof("Got token from the server, starting to json decode... status code: %v", resp.StatusCode)
return json.NewDecoder(resp.Body).Decode(target)
}
func syncEntriesImpl(token string, model string, envPrefix string, uploadIntervalSec int, guestMode bool) {
analyzeInformation.IsAnalyzing = true
analyzeInformation.GuestMode = guestMode
analyzeInformation.AnalyzedModel = model
analyzeInformation.AnalyzeToken = token
analyzeInformation.AnalyzeDestination = envPrefix
analyzeInformation.SentCount = 0
// "http or grpc" filter indicates that we're only interested in HTTP and gRPC entries
query := "http or grpc"
logger.Log.Infof("Getting entries from the database")
BasenineReconnect:
var connection *basenine.Connection
var err error
connection, err = basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
if err != nil {
logger.Log.Errorf("Can't establish a new connection to Basenine server: %v", err)
connection.Close()
time.Sleep(shared.BasenineReconnectInterval * time.Second)
goto BasenineReconnect
}
data := make(chan []byte)
meta := make(chan []byte)
defer func() {
data <- []byte(basenine.CloseChannel)
meta <- []byte(basenine.CloseChannel)
connection.Close()
}()
lastTimeSynced := time.Time{}
batch := make([]har.Entry, 0)
handleDataChannel := func(wg *sync.WaitGroup, connection *basenine.Connection, data chan []byte) {
defer wg.Done()
for {
dataBytes := <-data
if string(dataBytes) == basenine.CloseChannel {
return
}
var dataMap map[string]interface{}
err = json.Unmarshal(dataBytes, &dataMap)
var entry tapApi.Entry
if err := json.Unmarshal([]byte(dataBytes), &entry); err != nil {
continue
}
harEntry, err := har.NewEntry(entry.Request, entry.Response, entry.StartTime, entry.ElapsedTime)
if err != nil {
continue
}
if entry.Source.Name != "" {
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-source", Value: entry.Source.Name})
}
if entry.Destination.Name != "" {
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-destination", Value: entry.Destination.Name})
harEntry.Request.URL = utils.SetHostname(harEntry.Request.URL, entry.Destination.Name)
}
batch = append(batch, *harEntry)
now := time.Now()
if lastTimeSynced.Add(time.Duration(uploadIntervalSec) * time.Second).After(now) {
continue
}
lastTimeSynced = now
body, jMarshalErr := json.Marshal(batch)
batchSize := len(batch)
if jMarshalErr != nil {
analyzeInformation.Reset()
logger.Log.Infof("Stopping sync entries")
logger.Log.Fatal(jMarshalErr)
}
batch = make([]har.Entry, 0)
var in bytes.Buffer
w := zlib.NewWriter(&in)
_, _ = w.Write(body)
_ = w.Close()
reqBody := ioutil.NopCloser(bytes.NewReader(in.Bytes()))
authHeader := getAuthHeader(guestMode)
req := &http.Request{
Method: http.MethodPost,
URL: GetTrafficDumpUrl(envPrefix, model),
Header: map[string][]string{
"Content-Encoding": {"deflate"},
"Content-Type": {"application/octet-stream"},
authHeader: {token},
},
Body: reqBody,
}
if _, postErr := http.DefaultClient.Do(req); postErr != nil {
analyzeInformation.Reset()
logger.Log.Info("Stopping sync entries")
logger.Log.Fatal(postErr)
}
analyzeInformation.SentCount += batchSize
if analyzeInformation.SentCount%SentCountLogInterval == 0 {
logger.Log.Infof("Uploaded %v entries until now", analyzeInformation.SentCount)
}
}
}
handleMetaChannel := func(wg *sync.WaitGroup, connection *basenine.Connection, meta chan []byte) {
defer wg.Done()
for {
metaBytes := <-meta
if string(metaBytes) == basenine.CloseChannel {
return
}
}
}
var wg sync.WaitGroup
go handleDataChannel(&wg, connection, data)
go handleMetaChannel(&wg, connection, meta)
wg.Add(2)
if err = connection.Query("latest", query, data, meta); err != nil {
logger.Log.Errorf("Query mode call failed: %v", err)
connection.Close()
time.Sleep(shared.BasenineReconnectInterval * time.Second)
goto BasenineReconnect
}
wg.Wait()
}
func UpdateAnalyzeStatus(callback func(data []byte)) {
for {
if !analyzeInformation.IsAnalyzing {
time.Sleep(AnalyzeCheckSleepTime)
continue
}
analyzeStatus := GetAnalyzeInfo()
socketMessage := shared.CreateWebSocketMessageTypeAnalyzeStatus(*analyzeStatus)
jsonMessage, _ := json.Marshal(socketMessage)
callback(jsonMessage)
time.Sleep(AnalyzeCheckSleepTime)
}
}

View File

@@ -1,147 +0,0 @@
package auth
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"time"
"github.com/google/uuid"
"github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/uiUtils"
"github.com/up9inc/mizu/logger"
"golang.org/x/oauth2"
)
const loginTimeoutInMin = 2
// Ports are configured in keycloak "cli" client as valid redirect URIs. A change here must be reflected there as well.
var listenPorts = []int{3141, 4001, 5002, 6003, 7004, 8005, 9006, 10007}
func Login() error {
token, loginErr := loginInteractively()
if loginErr != nil {
return fmt.Errorf("failed login interactively, err: %v", loginErr)
}
authConfig := configStructs.AuthConfig{
EnvName: config.Config.Auth.EnvName,
Token: token.AccessToken,
}
if err := config.UpdateConfig(func(configStruct *config.ConfigStruct) { configStruct.Auth = authConfig }); err != nil {
return fmt.Errorf("failed updating config with auth, err: %v", err)
}
config.Config.Auth = authConfig
logger.Log.Infof("Login successfully, token stored in config path: %s", fmt.Sprintf(uiUtils.Purple, config.Config.ConfigFilePath))
return nil
}
func loginInteractively() (*oauth2.Token, error) {
tokenChannel := make(chan *oauth2.Token)
errorChannel := make(chan error)
server := http.Server{}
go startLoginServer(tokenChannel, errorChannel, &server)
defer func() {
if err := server.Shutdown(context.Background()); err != nil {
logger.Log.Debugf("Error shutting down server, err: %v", err)
}
}()
select {
case <-time.After(loginTimeoutInMin * time.Minute):
return nil, errors.New("auth timed out")
case err := <-errorChannel:
return nil, err
case token := <-tokenChannel:
return token, nil
}
}
func startLoginServer(tokenChannel chan *oauth2.Token, errorChannel chan error, server *http.Server) {
for _, port := range listenPorts {
var authConfig = &oauth2.Config{
ClientID: "cli",
RedirectURL: fmt.Sprintf("http://localhost:%v/callback", port),
Endpoint: oauth2.Endpoint{
AuthURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/auth", config.Config.Auth.EnvName),
TokenURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/token", config.Config.Auth.EnvName),
},
}
state := uuid.New()
mux := http.NewServeMux()
server.Handler = mux
mux.Handle("/callback", loginCallbackHandler(tokenChannel, errorChannel, authConfig, state))
listener, listenErr := net.Listen("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", port))
if listenErr != nil {
logger.Log.Debugf("failed to start listening on port %v, err: %v", port, listenErr)
continue
}
authorizationUrl := authConfig.AuthCodeURL(state.String())
uiUtils.OpenBrowser(authorizationUrl)
serveErr := server.Serve(listener)
if serveErr == http.ErrServerClosed {
logger.Log.Debugf("received server shutdown, server on port %v is closed", port)
return
} else if serveErr != nil {
logger.Log.Debugf("failed to start serving on port %v, err: %v", port, serveErr)
continue
}
logger.Log.Debugf("didn't receive server closed on port %v", port)
return
}
errorChannel <- fmt.Errorf("failed to start serving on all listen ports, ports: %v", listenPorts)
}
func loginCallbackHandler(tokenChannel chan *oauth2.Token, errorChannel chan error, authConfig *oauth2.Config, state uuid.UUID) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
if err := request.ParseForm(); err != nil {
errorMsg := fmt.Sprintf("failed to parse form, err: %v", err)
http.Error(writer, errorMsg, http.StatusBadRequest)
errorChannel <- fmt.Errorf(errorMsg)
return
}
requestState := request.Form.Get("state")
if requestState != state.String() {
errorMsg := fmt.Sprintf("state invalid, requestState: %v, authState:%v", requestState, state.String())
http.Error(writer, errorMsg, http.StatusBadRequest)
errorChannel <- fmt.Errorf(errorMsg)
return
}
code := request.Form.Get("code")
if code == "" {
errorMsg := "code not found"
http.Error(writer, errorMsg, http.StatusBadRequest)
errorChannel <- fmt.Errorf(errorMsg)
return
}
token, err := authConfig.Exchange(context.Background(), code)
if err != nil {
errorMsg := fmt.Sprintf("failed to create token, err: %v", err)
http.Error(writer, errorMsg, http.StatusInternalServerError)
errorChannel <- fmt.Errorf(errorMsg)
return
}
tokenChannel <- token
http.Redirect(writer, request, fmt.Sprintf("https://%s/CliLogin", config.Config.Auth.EnvName), http.StatusFound)
})
}

View File

@@ -1,8 +1,11 @@
package cmd
import (
"github.com/creasty/defaults"
"github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/logger"
)
var installCmd = &cobra.Command{
@@ -17,4 +20,11 @@ var installCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(installCmd)
defaultInstallConfig := configStructs.InstallConfig{}
if err := defaults.Set(&defaultInstallConfig); err != nil {
logger.Log.Debug(err)
}
installCmd.Flags().BoolP(configStructs.OutInstallName, "o", defaultInstallConfig.Out, "print (to stdout) Kubernetes manifest used to install Mizu Pro edition")
}

View File

@@ -2,6 +2,7 @@ package cmd
import (
"fmt"
"strings"
"github.com/up9inc/mizu/cli/bucket"
"github.com/up9inc/mizu/cli/config"
@@ -9,12 +10,23 @@ import (
)
func runMizuInstall() {
bucketProvider := bucket.NewProvider(config.Config.Install.TemplateUrl, bucket.DefaultTimeout)
installTemplate, err := bucketProvider.GetInstallTemplate(config.Config.Install.TemplateName)
if err != nil {
logger.Log.Errorf("Failed getting install template, err: %v", err)
if config.Config.Install.Out {
bucketProvider := bucket.NewProvider(config.Config.Install.TemplateUrl, bucket.DefaultTimeout)
installTemplate, err := bucketProvider.GetInstallTemplate(config.Config.Install.TemplateName)
if err != nil {
logger.Log.Errorf("Failed getting install template, err: %v", err)
return
}
fmt.Print(installTemplate)
return
}
fmt.Print(installTemplate)
var sb strings.Builder
sb.WriteString("Hello! This command can be used to install Mizu Pro edition on your Kubernetes cluster.")
sb.WriteString("\nPlease run:")
sb.WriteString("\n\tmizu install -o | kubectl apply -f -")
sb.WriteString("\n\nor use helm chart as described in https://getmizu.io/docs/installing-mizu/centralized-installation\n")
fmt.Print(sb.String())
}

View File

@@ -2,24 +2,15 @@ package cmd
import (
"errors"
"fmt"
"os"
"github.com/up9inc/mizu/cli/up9"
"github.com/creasty/defaults"
"github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/auth"
"github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/errormessage"
"github.com/up9inc/mizu/cli/uiUtils"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/shared"
)
const uploadTrafficMessageToConfirm = `NOTE: running mizu with --%s flag will upload recorded traffic for further analysis and enriched presentation options.`
var tapCmd = &cobra.Command{
Use: "tap [POD REGEX]",
Short: "Record ingoing traffic of a kubernetes pod",
@@ -40,67 +31,12 @@ Supported protocols are HTTP and gRPC.`,
return errormessage.FormatError(err)
}
if config.Config.Tap.Workspace != "" {
askConfirmation(configStructs.WorkspaceTapName)
if config.Config.Auth.Token == "" {
logger.Log.Infof("This action requires authentication, please log in to continue")
if err := auth.Login(); err != nil {
logger.Log.Errorf("failed to log in, err: %v", err)
return nil
}
} else {
tokenExpired, err := shared.IsTokenExpired(config.Config.Auth.Token)
if err != nil {
logger.Log.Errorf("failed to check if token is expired, err: %v", err)
return nil
}
if tokenExpired {
logger.Log.Infof("Token expired, please log in again to continue")
if err := auth.Login(); err != nil {
logger.Log.Errorf("failed to log in, err: %v", err)
return nil
}
} else if isValidToken := up9.IsTokenValid(config.Config.Auth.Token, config.Config.Auth.EnvName); !isValidToken {
logger.Log.Errorf("Token is not valid, please log in again to continue")
if err := auth.Login(); err != nil {
logger.Log.Errorf("failed to log in, err: %v", err)
return nil
}
}
}
}
if config.Config.Tap.Analysis {
askConfirmation(configStructs.AnalysisTapName)
config.Config.Auth.Token = ""
}
logger.Log.Infof("Mizu will store up to %s of traffic, old traffic will be cleared once the limit is reached.", config.Config.Tap.HumanMaxEntriesDBSize)
return nil
},
}
func askConfirmation(flagName string) {
logger.Log.Infof(fmt.Sprintf(uploadTrafficMessageToConfirm, flagName))
if !config.Config.Tap.AskUploadConfirmation {
return
}
if !uiUtils.AskForConfirmation("Would you like to proceed [Y/n]: ") {
logger.Log.Infof("You can always run mizu without %s, aborting", flagName)
os.Exit(0)
}
if err := config.UpdateConfig(func(configStruct *config.ConfigStruct) { configStruct.Tap.AskUploadConfirmation = false }); err != nil {
logger.Log.Debugf("failed updating config with upload confirmation, err: %v", err)
}
}
func init() {
rootCmd.AddCommand(tapCmd)
@@ -111,14 +47,12 @@ func init() {
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().Bool(configStructs.AnalysisTapName, defaultTapConfig.Analysis, "Uploads traffic to UP9 for further analysis (Beta)")
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().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().Bool(configStructs.DryRunTapName, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them")
tapCmd.Flags().StringP(configStructs.WorkspaceTapName, "w", defaultTapConfig.Workspace, "Uploads traffic to your UP9 workspace for further analysis (requires auth)")
tapCmd.Flags().String(configStructs.EnforcePolicyFile, defaultTapConfig.EnforcePolicyFile, "Yaml file path with policy rules")
tapCmd.Flags().String(configStructs.ContractFile, defaultTapConfig.ContractFile, "OAS/Swagger file to validate to monitor the contracts")
tapCmd.Flags().Bool(configStructs.ServiceMeshName, defaultTapConfig.ServiceMesh, "Record decrypted traffic if the cluster is configured with a service mesh and with mtls")

View File

@@ -124,7 +124,7 @@ func RunMizuTap() {
}
logger.Log.Infof("Waiting for Mizu Agent to start...")
if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, getSyncEntriesConfig(), config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel(), config.Config.Tap.Profiler); err != nil {
if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel(), config.Config.Tap.Profiler); err != nil {
var statusError *k8serrors.StatusError
if errors.As(err, &statusError) && (statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists) {
logger.Log.Info("Mizu is already running in this namespace, change the `mizu-resources-namespace` configuration or run `mizu clean` to remove the currently running Mizu instance")
@@ -295,19 +295,6 @@ func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) {
}, nil
}
func getSyncEntriesConfig() *shared.SyncEntriesConfig {
if !config.Config.Tap.Analysis && config.Config.Tap.Workspace == "" {
return nil
}
return &shared.SyncEntriesConfig{
Token: config.Config.Auth.Token,
Env: config.Config.Auth.EnvName,
Workspace: config.Config.Tap.Workspace,
UploadIntervalSec: config.Config.Tap.UploadIntervalSec,
}
}
func watchApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", kubernetes.ApiServerPodName))
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)

View File

@@ -85,27 +85,6 @@ func WriteConfig(config *ConfigStruct) error {
return nil
}
type updateConfigStruct func(*ConfigStruct)
func UpdateConfig(updateConfigStruct updateConfigStruct) error {
configFile, err := GetConfigWithDefaults()
if err != nil {
return fmt.Errorf("failed getting config with defaults, err: %v", err)
}
if err := loadConfigFile(Config.ConfigFilePath, configFile); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("failed getting config file, err: %v", err)
}
updateConfigStruct(configFile)
if err := WriteConfig(configFile); err != nil {
return fmt.Errorf("failed writing config, err: %v", err)
}
return nil
}
func loadConfigFile(configFilePath string, config *ConfigStruct) error {
reader, openErr := os.Open(configFilePath)
if openErr != nil {

View File

@@ -27,7 +27,6 @@ type ConfigStruct struct {
Version configStructs.VersionConfig `yaml:"version"`
View configStructs.ViewConfig `yaml:"view"`
Logs configStructs.LogsConfig `yaml:"logs"`
Auth configStructs.AuthConfig `yaml:"auth"`
Config configStructs.ConfigConfig `yaml:"config,omitempty"`
AgentImage string `yaml:"agent-image,omitempty" readonly:""`
ImagePullPolicyStr string `yaml:"image-pull-policy" default:"Always"`

View File

@@ -1,6 +0,0 @@
package configStructs
type AuthConfig struct {
EnvName string `yaml:"env-name" default:"up9.app"`
Token string `yaml:"token"`
}

View File

@@ -1,6 +1,11 @@
package configStructs
const (
OutInstallName = "out"
)
type InstallConfig struct {
TemplateUrl string `yaml:"template-url" default:"https://storage.googleapis.com/static.up9.io/mizu/helm-template"`
TemplateName string `yaml:"template-name" default:"helm-template.yaml"`
Out bool `yaml:"out"`
}

View File

@@ -1,7 +1,6 @@
package configStructs
import (
"errors"
"fmt"
"io/fs"
"io/ioutil"
@@ -18,14 +17,12 @@ import (
const (
GuiPortTapName = "gui-port"
NamespacesTapName = "namespaces"
AnalysisTapName = "analysis"
AllNamespacesTapName = "all-namespaces"
PlainTextFilterRegexesTapName = "regex-masking"
EnableRedactionTapName = "redact"
HumanMaxEntriesDBSizeTapName = "max-entries-db-size"
InsertionFilterName = "insertion-filter"
DryRunTapName = "dry-run"
WorkspaceTapName = "workspace"
EnforcePolicyFile = "traffic-validation-file"
ContractFile = "contract"
ServiceMeshName = "service-mesh"
@@ -34,12 +31,10 @@ const (
)
type TapConfig struct {
UploadIntervalSec int `yaml:"upload-interval" default:"10"`
PodRegexStr string `yaml:"regex" default:".*"`
GuiPort uint16 `yaml:"gui-port" default:"8899"`
ProxyHost string `yaml:"proxy-host" default:"127.0.0.1"`
Namespaces []string `yaml:"namespaces"`
Analysis bool `yaml:"analysis" default:"false"`
AllNamespaces bool `yaml:"all-namespaces" default:"false"`
PlainTextFilterRegexes []string `yaml:"regex-masking"`
IgnoredUserAgents []string `yaml:"ignored-user-agents"`
@@ -47,10 +42,8 @@ type TapConfig struct {
HumanMaxEntriesDBSize string `yaml:"max-entries-db-size" default:"200MB"`
InsertionFilter string `yaml:"insertion-filter" default:""`
DryRun bool `yaml:"dry-run" default:"false"`
Workspace string `yaml:"workspace"`
EnforcePolicyFile string `yaml:"traffic-validation-file"`
ContractFile string `yaml:"contract"`
AskUploadConfirmation bool `yaml:"ask-upload-confirmation" default:"true"`
ApiServerResources shared.Resources `yaml:"api-server-resources"`
TapperResources shared.Resources `yaml:"tapper-resources"`
ServiceMesh bool `yaml:"service-mesh" default:"false"`
@@ -94,16 +87,5 @@ func (config *TapConfig) Validate() error {
return fmt.Errorf("Could not parse --%s value %s", HumanMaxEntriesDBSizeTapName, config.HumanMaxEntriesDBSize)
}
if config.Workspace != "" {
workspaceRegex, _ := regexp.Compile("[A-Za-z0-9][-A-Za-z0-9_.]*[A-Za-z0-9]+$")
if len(config.Workspace) > 63 || !workspaceRegex.MatchString(config.Workspace) {
return errors.New("invalid workspace name")
}
}
if config.Analysis && config.Workspace != "" {
return fmt.Errorf("Can't run with both --%s and --%s flags", AnalysisTapName, WorkspaceTapName)
}
return nil
}

View File

@@ -12,7 +12,6 @@ var (
BuildTimestamp = "" // this var is overridden using ldflags in makefile when building
RBACVersion = "v1"
Platform = ""
InstallModePersistentVolumeSizeBufferBytes = int64(500 * 1000 * 1000) //500mb
)
const DEVENVVAR = "MIZU_DISABLE_TELEMTRY"

View File

@@ -14,7 +14,7 @@ import (
core "k8s.io/api/core/v1"
)
func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, syncEntriesConfig *shared.SyncEntriesConfig, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level, profiler bool) (bool, error) {
func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level, profiler bool) (bool, error) {
if !isNsRestrictedMode {
if err := createMizuNamespace(ctx, kubernetesProvider, mizuResourcesNamespace); err != nil {
return false, err
@@ -45,7 +45,6 @@ func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.
KetoImage: "",
ServiceAccountName: serviceAccountName,
IsNamespaceRestricted: isNsRestrictedMode,
SyncEntriesConfig: syncEntriesConfig,
MaxEntriesDBSizeBytes: maxEntriesDBSizeBytes,
Resources: apiServerResources,
ImagePullPolicy: imagePullPolicy,

View File

@@ -1,26 +0,0 @@
package uiUtils
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/up9inc/mizu/logger"
)
func AskForConfirmation(s string) bool {
reader := bufio.NewReader(os.Stdin)
fmt.Printf(Magenta, s)
response, err := reader.ReadString('\n')
if err != nil {
logger.Log.Fatalf("Error while reading confirmation string, err: %v", err)
}
response = strings.ToLower(strings.TrimSpace(response))
if response == "" || response == "y" || response == "yes" {
return true
}
return false
}

View File

@@ -1,27 +0,0 @@
package up9
import (
"fmt"
"net/http"
"net/url"
)
func IsTokenValid(tokenString string, envName string) bool {
whoAmIUrl, _ := url.Parse(fmt.Sprintf("https://trcc.%s/admin/whoami", envName))
req := &http.Request{
Method: http.MethodGet,
URL: whoAmIUrl,
Header: map[string][]string{
"Authorization": {fmt.Sprintf("bearer %s", tokenString)},
},
}
response, err := http.DefaultClient.Do(req)
if err != nil {
return false
}
defer response.Body.Close()
return response.StatusCode == http.StatusOK
}

View File

@@ -2,7 +2,6 @@ package shared
const (
MizuFilteringOptionsEnvVar = "SENSITIVE_DATA_FILTERING_OPTIONS"
SyncEntriesConfigEnvVar = "SYNC_ENTRIES_CONFIG"
HostModeEnvVar = "HOST_MODE"
NodeNameEnvVar = "NODE_NAME"
ConfigDirPath = "/app/config/"

View File

@@ -32,7 +32,6 @@ import (
"k8s.io/client-go/kubernetes"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
watchtools "k8s.io/client-go/tools/watch"
@@ -41,7 +40,7 @@ import (
type Provider struct {
clientSet *kubernetes.Clientset
kubernetesConfig clientcmd.ClientConfig
clientConfig restclient.Config
clientConfig rest.Config
managedBy string
createdBy string
}
@@ -88,6 +87,7 @@ func NewProvider(kubeConfigPath string, contextName string) (*Provider, error) {
}, nil
}
//NewProviderInCluster Used in another repo that calls this function
func NewProviderInCluster() (*Provider, error) {
restClientConfig, err := rest.InClusterConfig()
if err != nil {
@@ -176,7 +176,6 @@ type ApiServerOptions struct {
KetoImage string
ServiceAccountName string
IsNamespaceRestricted bool
SyncEntriesConfig *shared.SyncEntriesConfig
MaxEntriesDBSizeBytes int64
Resources shared.Resources
ImagePullPolicy core.PullPolicy
@@ -185,14 +184,6 @@ type ApiServerOptions struct {
}
func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, mountVolumeClaim bool, volumeClaimName string, createAuthContainer bool) (*core.Pod, error) {
var marshaledSyncEntriesConfig []byte
if opts.SyncEntriesConfig != nil {
var err error
if marshaledSyncEntriesConfig, err = json.Marshal(opts.SyncEntriesConfig); err != nil {
return nil, err
}
}
configMapVolume := &core.ConfigMapVolumeSource{}
configMapVolume.Name = ConfigMapName
@@ -264,10 +255,6 @@ func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, moun
VolumeMounts: volumeMounts,
Command: command,
Env: []core.EnvVar{
{
Name: shared.SyncEntriesConfigEnvVar,
Value: string(marshaledSyncEntriesConfig),
},
{
Name: shared.LogLevelEnvVar,
Value: opts.LogLevel.String(),
@@ -1113,7 +1100,7 @@ func (provider *Provider) GetKubernetesVersion() (*semver.SemVersion, error) {
return &serverVersionSemVer, nil
}
func getClientSet(config *restclient.Config) (*kubernetes.Clientset, error) {
func getClientSet(config *rest.Config) (*kubernetes.Clientset, error) {
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err

View File

@@ -19,7 +19,6 @@ const (
WebSocketMessageTypeTappedEntry WebSocketMessageType = "tappedEntry"
WebSocketMessageTypeUpdateStatus WebSocketMessageType = "status"
WebSocketMessageTypeUpdateTappedPods WebSocketMessageType = "tappedPods"
WebSocketMessageTypeAnalyzeStatus WebSocketMessageType = "analyzeStatus"
WebSocketMessageTypeToast WebSocketMessageType = "toast"
WebSocketMessageTypeQueryMetadata WebSocketMessageType = "queryMetadata"
WebSocketMessageTypeStartTime WebSocketMessageType = "startTime"
@@ -51,17 +50,6 @@ type WebSocketMessageMetadata struct {
MessageType WebSocketMessageType `json:"messageType,omitempty"`
}
type WebSocketAnalyzeStatusMessage struct {
*WebSocketMessageMetadata
AnalyzeStatus AnalyzeStatus `json:"analyzeStatus"`
}
type AnalyzeStatus struct {
IsAnalyzing bool `json:"isAnalyzing"`
RemoteUrl string `json:"remoteUrl"`
IsRemoteReady bool `json:"isRemoteReady"`
SentCount int `json:"sentCount"`
}
type WebSocketStatusMessage struct {
*WebSocketMessageMetadata
@@ -116,13 +104,6 @@ type TLSLinkInfo struct {
ResolvedSourceName string `json:"resolvedSourceName"`
}
type SyncEntriesConfig struct {
Token string `json:"token"`
Env string `json:"env"`
Workspace string `json:"workspace"`
UploadIntervalSec int `json:"interval"`
}
func CreateWebSocketStatusMessage(tappedPodsStatus []TappedPodStatus) WebSocketStatusMessage {
return WebSocketStatusMessage{
WebSocketMessageMetadata: &WebSocketMessageMetadata{
@@ -141,15 +122,6 @@ func CreateWebSocketTappedPodsMessage(nodeToTappedPodMap NodeToPodsMap) WebSocke
}
}
func CreateWebSocketMessageTypeAnalyzeStatus(analyzeStatus AnalyzeStatus) WebSocketAnalyzeStatusMessage {
return WebSocketAnalyzeStatusMessage{
WebSocketMessageMetadata: &WebSocketMessageMetadata{
MessageType: WebSocketMessageTypeAnalyzeStatus,
},
AnalyzeStatus: analyzeStatus,
}
}
type HealthResponse struct {
TappedPods []*PodInfo `json:"tappedPods"`
ConnectedTappersCount int `json:"connectedTappersCount"`

View File

@@ -1,41 +0,0 @@
package shared
import (
"fmt"
"github.com/golang-jwt/jwt/v4"
"time"
)
func IsTokenExpired(tokenString string) (bool, error) {
claims, err := getTokenClaims(tokenString)
if err != nil {
return true, err
}
expiry := time.Unix(int64(claims["exp"].(float64)), 0)
return time.Now().After(expiry), nil
}
func GetTokenEmail(tokenString string) (string, error) {
claims, err := getTokenClaims(tokenString)
if err != nil {
return "", err
}
return claims["email"].(string), nil
}
func getTokenClaims(tokenString string) (jwt.MapClaims, error) {
token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil {
return nil, fmt.Errorf("failed to parse token, err: %v", err)
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return nil, fmt.Errorf("can't convert token's claims to standard claims")
}
return claims, nil
}

12661
ui-common/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,63 +24,63 @@
},
"peerDependencies": {
"@craco/craco": "^6.4.3",
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.60",
"@types/jest": "^26.0.22",
"@types/node": "^12.20.10",
"node-sass": "^6.0.0",
"@types/jest": "^26.0.24",
"@types/node": "^12.20.54",
"node-sass": "^6.0.1",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.0.3",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^17.0.2",
"recoil": "^0.5.2"
"recoil": "^0.7.2"
},
"dependencies": {
"@craco/craco": "^6.4.3",
"@types/lodash": "^4.14.179",
"@uiw/react-textarea-code-editor": "^1.4.12",
"axios": "^0.25.0",
"core-js": "^3.20.2",
"highlight.js": "^11.3.1",
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/icons-material": "^5.8.2",
"@mui/lab": "^5.0.0-alpha.84",
"@mui/material": "^5.8.2",
"@mui/styles": "^5.8.0",
"@types/lodash": "^4.14.182",
"@uiw/react-textarea-code-editor": "^1.6.0",
"axios": "^0.27.2",
"core-js": "^3.22.7",
"highlight.js": "^11.5.1",
"json-beautify": "^1.1.1",
"jsonpath": "^1.1.1",
"marked": "^4.0.10",
"material-ui-popup-state": "^2.0.0",
"mobx": "^6.3.10",
"moment": "^2.29.1",
"node-fetch": "^3.1.1",
"marked": "^4.0.16",
"material-ui-popup-state": "^2.0.1",
"mobx": "^6.6.0",
"moment": "^2.29.3",
"node-fetch": "^3.2.4",
"numeral": "^2.0.6",
"protobuf-decoder": "^0.1.2",
"react-graph-vis": "^1.0.7",
"react-lowlight": "^3.0.0",
"react-router-dom": "^6.2.1",
"react-router-dom": "^6.3.0",
"react-scrollable-feed-virtualized": "^1.4.9",
"react-syntax-highlighter": "^15.4.3",
"react-toastify": "^8.0.3",
"redoc": "^2.0.0-rc.59",
"styled-components": "^5.3.3",
"web-vitals": "^1.1.1",
"xml-formatter": "^2.6.0"
"react-syntax-highlighter": "^15.5.0",
"react-toastify": "^8.2.0",
"redoc": "^2.0.0-rc.71",
"styled-components": "^5.3.5",
"web-vitals": "^2.1.4",
"xml-formatter": "^2.6.1"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^13.1.3",
"@rollup/plugin-node-resolve": "^13.3.0",
"@svgr/rollup": "^6.2.1",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"cross-env": "^7.0.2",
"env-cmd": "^10.0.1",
"gh-pages": "^2.2.0",
"microbundle-crl": "^0.13.10",
"cross-env": "^7.0.3",
"env-cmd": "^10.1.0",
"gh-pages": "^4.0.0",
"microbundle-crl": "^0.13.11",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.4",
"rollup-plugin-import-css": "^3.0.2",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-sass": "^1.2.10",
"rollup-plugin-scss": "^3.0.0",
"prettier": "^2.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"typescript": "^4.2.4"
"rollup-plugin-import-css": "^3.0.3",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-sass": "^1.2.12",
"rollup-plugin-scss": "^3.0.0",
"typescript": "^4.7.2"
},
"eslintConfig": {
"extends": [

View File

@@ -1,86 +0,0 @@
import {Button} from "@material-ui/core";
import React from "react";
import logo_up9 from "logo_up9.svg";
import {makeStyles} from "@material-ui/core/styles";
import { Tooltip } from "../UI";
const useStyles = makeStyles(() => ({
tooltip: {
backgroundColor: "#3868dc",
color: "white",
fontSize: 13,
},
}));
interface AnalyseButtonProps {
analyzeStatus: any
}
export const AnalyzeButton: React.FC<AnalyseButtonProps> = ({analyzeStatus}) => {
const classes = useStyles();
const analysisMessage = analyzeStatus?.isRemoteReady ?
<span>
<table>
<tr>
<td>Status</td>
<td><b>Available</b></td>
</tr>
<tr>
<td>Messages</td>
<td><b>{analyzeStatus?.sentCount}</b></td>
</tr>
</table>
</span> :
analyzeStatus?.sentCount > 0 ?
<span>
<table>
<tr>
<td>Status</td>
<td><b>Processing</b></td>
</tr>
<tr>
<td>Messages</td>
<td><b>{analyzeStatus?.sentCount}</b></td>
</tr>
<tr>
<td colSpan={2}> Please allow a few minutes for the analysis to complete</td>
</tr>
</table>
</span> :
<span>
<table>
<tr>
<td>Status</td>
<td><b>Waiting for traffic</b></td>
</tr>
<tr>
<td>Messages</td>
<td><b>{analyzeStatus?.sentCount}</b></td>
</tr>
</table>
</span>
return ( <div>
<Tooltip title={analysisMessage} isSimple classes={classes}>
<div>
<Button
style={{fontFamily: "system-ui",
fontWeight: 600,
fontSize: 12,
padding: 8}}
size={"small"}
variant="contained"
color="primary"
startIcon={<img style={{height: 24, maxHeight: "none", maxWidth: "none"}} src={logo_up9} alt={"up9"}/>}
disabled={!analyzeStatus?.isRemoteReady}
onClick={() => {
window.open(analyzeStatus?.remoteUrl)
}}>
Analysis
</Button>
</div>
</Tooltip>
</div>);
}

View File

@@ -1,39 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" id="prefix__logo" width="148" height="88" viewBox="0 0 148 88">
<defs>
<style>
.prefix__cls-1{fill:#070047}.prefix__cls-2{fill:#fff}.prefix__cls-4{fill:#8f9bb2}
</style>
</defs>
<g id="prefix__Group_4690_2_">
<path id="prefix__Path_2985_1_" d="M0 62.1a7.832 7.832 0 0 0 3.928 6.786l31.405 18.071a7.866 7.866 0 0 0 7.84 0L74.563 68.9a7.823 7.823 0 0 0 3.928-6.784v-36.2a7.828 7.828 0 0 0-3.926-6.782L43.175 1.052a7.869 7.869 0 0 0-7.86.006L3.914 19.217A7.827 7.827 0 0 0 0 25.994z" class="prefix__cls-1" transform="translate(0 -.004)"/>
<path id="prefix__Path_2986_2_" d="M55.987 134.68a.976.976 0 0 1-.008 1.7l-4.4 2.482-.033-.02-6.832 3.948a1.966 1.966 0 0 1-1.966 0l-8.83-5.09A7.818 7.818 0 0 1 30 130.927v-29.356a7.813 7.813 0 0 1 3.979-6.8l.443-.25a.984.984 0 0 1 1.339.369.964.964 0 0 1 .127.482v36.187a.979.979 0 0 0 .488.845l4.909 2.855a.984.984 0 0 0 .981 0l.063-.035a.977.977 0 0 0 0-1.7l-3.994-2.3a.978.978 0 0 1-.49-.847V93.654a1.955 1.955 0 0 1 .995-1.7l3.429-1.936a.986.986 0 0 1 1.339.369.962.962 0 0 1 .127.48v36.187a.978.978 0 0 0 .49.847z" class="prefix__cls-2" transform="translate(-24.126 -72.289)"/>
<path id="prefix__Path_2987_2_" d="M117.554 80.338a.981.981 0 0 1-.366-1.338.969.969 0 0 1 .37-.368l9.788-5.733a.981.981 0 0 0 .484-.846V37.572a1.961 1.961 0 0 0-2.951-1.694l-8.823 5.148-4.891 2.767a1.962 1.962 0 0 0-.995 1.707v36.849a.982.982 0 0 0 .49.85l12.246 7.086a1.965 1.965 0 0 0 1.991-.016l3.46-2.076a.983.983 0 0 0-.018-1.694zM116.532 47.6l3.924-2.356a.98.98 0 0 1 1.484.842v22.619a.982.982 0 0 1-.5.854l-3.924 2.224a.984.984 0 0 1-1.339-.37.97.97 0 0 1-.127-.484V48.447a1 1 0 0 1 .482-.847z" class="prefix__cls-2" transform="translate(-88.598 -28.638)"/>
<path id="prefix__Path_2988_2_" d="M133.819 43.492V77.9a.979.979 0 0 1-.49.848l-7.858 4.545a.978.978 0 0 0 0 1.693l10.8 6.235a.977.977 0 0 1 0 1.693l-20.607 11.9a.978.978 0 0 0 0 1.7l12.279 7.01a7.87 7.87 0 0 0 7.8 0l26.5-15.161a5.871 5.871 0 0 0 2.957-5.094V62.723a7.825 7.825 0 0 0-3.92-6.778L136.762 41.8a1.959 1.959 0 0 0-2.943 1.7zm24.037 42.144L140.684 75.7a1.957 1.957 0 0 1-.977-1.693V60.981a.983.983 0 0 1 1.472-.848l14.239 8.237a7.826 7.826 0 0 1 3.91 6.772v9.647a.979.979 0 0 1-.979.98.968.968 0 0 1-.493-.133z" transform="translate(-92.625 -33.401)" style="fill:#627ef7"/>
<path id="prefix__Path_2989_2_" d="M60.346 291.555l-4.4 2.491-.033-.02-6.832 3.963a1.963 1.963 0 0 1-1.968 0l-8.835-5.111a7.826 7.826 0 0 1-2.853-2.851l4.938-2.851a1 1 0 0 0 .37.384l4.909 2.865a.981.981 0 0 0 .981 0l.063-.035a.982.982 0 0 0 0-1.7l-3.986-2.306a.981.981 0 0 1-.352-.352l5.86-3.382a.99.99 0 0 0 .378.4l11.764 6.8a.981.981 0 0 1-.006 1.7z" class="prefix__cls-4" transform="translate(-28.493 -227.445)"/>
<path id="prefix__Path_2991_2_" d="M164.463 248.2a5.858 5.858 0 0 1-2.193 2.207l-26.5 15.2a7.854 7.854 0 0 1-7.8 0l-12.279-7.026a.983.983 0 0 1 0-1.7l16.187-9.375 4.419-2.559a.98.98 0 0 0 0-1.7l-4.419-2.557-6.392-3.69a.98.98 0 0 1 0-1.7l6.385-3.7 1.472-.854a.968.968 0 0 0 .333-.321z" transform="translate(-92.637 -185.485)" style="fill:#3b4c95"/>
<path id="prefix__Path_2992_2_" d="M128.9 265.267l-.525.313-2.933 1.762a1.965 1.965 0 0 1-1.991.016l-12.244-7.082a1.021 1.021 0 0 1-.206-.161.928.928 0 0 1-.151-.2v-.006l2.692-1.555 4.445-2.567a.762.762 0 0 0-.094.084.6.6 0 0 0-.08.092.035.035 0 0 0-.012.018.479.479 0 0 0-.055.084.316.316 0 0 0-.02.035c-.01.02-.02.039-.027.059a.369.369 0 0 0-.023.059.378.378 0 0 0-.022.067.08.08 0 0 0-.01.035.729.729 0 0 0-.018.09.974.974 0 0 0 .482 1l10.274 5.872.507.288a.979.979 0 0 1 .366 1.335 1 1 0 0 1-.355.362z" class="prefix__cls-4" transform="translate(-89.145 -205.825)"/>
</g>
<g id="prefix__Group_4695" data-name="Group 4695" transform="translate(72.538 19.232)">
<g id="prefix__Group_4694" data-name="Group 4694">
<g id="prefix__Group_4691" data-name="Group 4691">
<path id="prefix__Path_2993" d="M394.794 158.1a9.4 9.4 0 0 1-6.626-2.728 9.4 9.4 0 0 1-1.987-2.937 9.248 9.248 0 0 1-.74-3.687v-31.142a3.92 3.92 0 0 1 3.916-3.916h4.455a3.92 3.92 0 0 1 3.916 3.916v28.2h.54v-28.2a3.92 3.92 0 0 1 3.916-3.916h4.507a3.92 3.92 0 0 1 3.916 3.916v36.577a3.92 3.92 0 0 1-3.916 3.916z" class="prefix__cls-2" data-name="Path 2993" transform="translate(-382.507 -110.753)"/>
<path id="prefix__Path_2994" d="M394.648 104.564a.979.979 0 0 1 .979.979v36.577a.979.979 0 0 1-.979.979h-11.9a6.454 6.454 0 0 1-4.547-1.866 6.447 6.447 0 0 1-1.367-2.025 6.291 6.291 0 0 1-.5-2.524v-31.141a.979.979 0 0 1 .979-.979h4.455a.979.979 0 0 1 .979.979v30.162a.979.979 0 0 0 .979.979h4.457a.979.979 0 0 0 .979-.979v-30.162a.979.979 0 0 1 .979-.979h4.507m0-5.874h-4.508a6.832 6.832 0 0 0-4.186 1.429 6.819 6.819 0 0 0-4.186-1.429h-4.455a6.861 6.861 0 0 0-6.853 6.853v31.141a12.147 12.147 0 0 0 .983 4.856 12.29 12.29 0 0 0 11.3 7.433h11.9a6.861 6.861 0 0 0 6.853-6.853v-36.577a6.861 6.861 0 0 0-6.853-6.853z" class="prefix__cls-1" data-name="Path 2994" transform="translate(-370.46 -98.69)"/>
</g>
<g id="prefix__Group_4692" data-name="Group 4692" transform="translate(22.447)">
<path id="prefix__Path_2995" d="M504.016 158.1a3.92 3.92 0 0 1-3.916-3.916v-36.578a3.92 3.92 0 0 1 3.916-3.916h11.848a9.332 9.332 0 0 1 3.64.73 9.635 9.635 0 0 1 2.978 1.964 9.144 9.144 0 0 1 2.054 3.015 9.312 9.312 0 0 1 .73 3.642v9.62a9.235 9.235 0 0 1-.74 3.687 9.48 9.48 0 0 1-5.024 4.985 9.3 9.3 0 0 1-3.638.73h-3.478v12.118a3.92 3.92 0 0 1-3.916 3.916zm8.911-28.374v-3.746h-.54v3.746z" class="prefix__cls-2" data-name="Path 2995" transform="translate(-497.163 -110.753)"/>
<path id="prefix__Path_2996" d="M503.8 104.564a6.351 6.351 0 0 1 2.5.5 6.709 6.709 0 0 1 2.078 1.367 6.157 6.157 0 0 1 1.392 2.05 6.358 6.358 0 0 1 .5 2.5v9.62a6.3 6.3 0 0 1-.5 2.524 6.536 6.536 0 0 1-1.392 2.05 6.453 6.453 0 0 1-2.078 1.394 6.358 6.358 0 0 1-2.5.5h-5.436a.979.979 0 0 0-.979.979v14.072a.979.979 0 0 1-.979.979h-4.455a.979.979 0 0 1-.979-.979v-36.577a.979.979 0 0 1 .979-.979H503.8m-5.434 16.036h4.457a.979.979 0 0 0 .979-.979v-7.662a.979.979 0 0 0-.979-.979h-4.457a.979.979 0 0 0-.979.979v7.662a.979.979 0 0 0 .979.979m5.434-21.91h-11.847a6.861 6.861 0 0 0-6.853 6.853v36.577a6.861 6.861 0 0 0 6.853 6.853h4.455a6.861 6.861 0 0 0 6.853-6.853v-9.181h.54a12.337 12.337 0 0 0 8.729-3.613 12.423 12.423 0 0 0 2.632-3.873 12.164 12.164 0 0 0 .981-4.854v-9.62a12.217 12.217 0 0 0-.961-4.78 12.067 12.067 0 0 0-2.714-3.981 12.589 12.589 0 0 0-3.881-2.563 12.193 12.193 0 0 0-4.786-.965z" class="prefix__cls-1" data-name="Path 2996" transform="translate(-485.1 -98.69)"/>
</g>
<g id="prefix__Group_4693" data-name="Group 4693" transform="translate(44.421)">
<path id="prefix__Path_2997" d="M621.68 158.107a9.331 9.331 0 0 1-9.35-9.35V144.9a3.92 3.92 0 0 1 3.916-3.916h1.038a9.008 9.008 0 0 1-2.26-1.7 9.676 9.676 0 0 1-1.954-2.931 9.249 9.249 0 0 1-.74-3.687v-9.62a9.328 9.328 0 0 1 9.35-9.35h6.415a9.332 9.332 0 0 1 3.64.73 9.613 9.613 0 0 1 2.978 1.964 9.127 9.127 0 0 1 2.054 3.015 9.316 9.316 0 0 1 .732 3.642v25.707a9.287 9.287 0 0 1-.73 3.638 9.113 9.113 0 0 1-2.054 3.015 9.66 9.66 0 0 1-2.98 1.966 9.308 9.308 0 0 1-3.638.73h-6.417zm3.478-12.289v-3.746h-1.747a3.905 3.905 0 0 1 1.208 2.825v.92zm0-16.085v-3.746h-.54v3.746z" class="prefix__cls-2" data-name="Path 2997" transform="translate(-609.391 -110.761)"/>
<path id="prefix__Path_2998" d="M616.024 104.564a6.351 6.351 0 0 1 2.5.5 6.708 6.708 0 0 1 2.078 1.367 6.157 6.157 0 0 1 1.392 2.05 6.358 6.358 0 0 1 .5 2.5v25.707a6.344 6.344 0 0 1-.5 2.5 6.157 6.157 0 0 1-1.392 2.05 6.709 6.709 0 0 1-2.078 1.367 6.358 6.358 0 0 1-2.5.5h-6.415a6.393 6.393 0 0 1-6.413-6.413v-3.857a.979.979 0 0 1 .979-.979h4.455a.979.979 0 0 1 .979.979v2.878a.979.979 0 0 0 .979.979h4.457a.979.979 0 0 0 .979-.979v-7.662a.979.979 0 0 0-.979-.979h-5.436a6.344 6.344 0 0 1-2.5-.5 6.133 6.133 0 0 1-2.05-1.394 6.769 6.769 0 0 1-1.367-2.05 6.291 6.291 0 0 1-.5-2.524v-9.62a6.393 6.393 0 0 1 6.413-6.413h6.415m-5.432 16.029h4.457a.979.979 0 0 0 .979-.979v-7.662a.979.979 0 0 0-.979-.979h-4.457a.979.979 0 0 0-.979.979v7.662a.979.979 0 0 0 .979.979m5.436-21.909h-6.415a12.268 12.268 0 0 0-12.289 12.287v9.62a12.147 12.147 0 0 0 .983 4.856 12.629 12.629 0 0 0 1.281 2.287 6.841 6.841 0 0 0-2.264 5.085v3.857a12.268 12.268 0 0 0 12.287 12.289h6.415a12.2 12.2 0 0 0 4.784-.963 12.579 12.579 0 0 0 3.879-2.559 12.047 12.047 0 0 0 2.714-3.981 12.233 12.233 0 0 0 .963-4.785v-25.707a12.234 12.234 0 0 0-.961-4.782 12.066 12.066 0 0 0-2.714-3.981 12.623 12.623 0 0 0-3.881-2.563 12.233 12.233 0 0 0-4.782-.961z" class="prefix__cls-1" data-name="Path 2998" transform="translate(-597.32 -98.69)"/>
</g>
</g>
</g>
<g id="prefix__Group_4697" data-name="Group 4697" transform="translate(78.412 25.106)">
<g id="prefix__Group_4696" data-name="Group 4696">
<path id="prefix__Path_2999" d="M419.753 129.669v36.577a.979.979 0 0 1-.979.979h-11.9a6.454 6.454 0 0 1-4.547-1.866 6.447 6.447 0 0 1-1.367-2.025 6.292 6.292 0 0 1-.5-2.524v-31.141a.979.979 0 0 1 .979-.979h4.455a.979.979 0 0 1 .979.979v30.162a.979.979 0 0 0 .979.979h4.457a.979.979 0 0 0 .979-.979v-30.162a.979.979 0 0 1 .979-.979h4.507a.979.979 0 0 1 .979.979z" class="prefix__cls-2" data-name="Path 2999" transform="translate(-400.46 -128.69)"/>
<path id="prefix__Path_3000" d="M534.393 135.1v9.62a6.3 6.3 0 0 1-.5 2.524 6.535 6.535 0 0 1-1.392 2.05 6.453 6.453 0 0 1-2.077 1.394 6.358 6.358 0 0 1-2.5.5h-5.436a.979.979 0 0 0-.979.979v14.076a.979.979 0 0 1-.979.979h-4.455a.979.979 0 0 1-.979-.979v-36.574a.979.979 0 0 1 .979-.979h11.848a6.351 6.351 0 0 1 2.5.5 6.708 6.708 0 0 1 2.077 1.367 6.157 6.157 0 0 1 1.392 2.05 6.358 6.358 0 0 1 .501 2.493zm-6.466 8.643v-7.662a.979.979 0 0 0-.979-.979h-4.457a.979.979 0 0 0-.979.979v7.662a.979.979 0 0 0 .979.979h4.457a.979.979 0 0 0 .979-.977z" class="prefix__cls-2" data-name="Path 3000" transform="translate(-492.653 -128.69)"/>
<path id="prefix__Path_3001" d="M646.623 135.1v25.71a6.345 6.345 0 0 1-.5 2.5 6.158 6.158 0 0 1-1.392 2.05 6.71 6.71 0 0 1-2.078 1.367 6.358 6.358 0 0 1-2.5.5h-6.415a6.393 6.393 0 0 1-6.413-6.413v-3.857a.979.979 0 0 1 .979-.979h4.455a.979.979 0 0 1 .979.979v2.878a.979.979 0 0 0 .979.979h4.457a.979.979 0 0 0 .979-.979v-7.662a.979.979 0 0 0-.979-.979h-5.436a6.344 6.344 0 0 1-2.5-.5 6.133 6.133 0 0 1-2.05-1.394 6.77 6.77 0 0 1-1.367-2.05 6.292 6.292 0 0 1-.5-2.524V135.1a6.393 6.393 0 0 1 6.413-6.413h6.415a6.351 6.351 0 0 1 2.5.5 6.709 6.709 0 0 1 2.078 1.367 6.157 6.157 0 0 1 1.392 2.05 6.359 6.359 0 0 1 .504 2.496zm-6.466 8.643v-7.662a.979.979 0 0 0-.979-.979h-4.457a.979.979 0 0 0-.979.979v7.662a.979.979 0 0 0 .979.979h4.457a.979.979 0 0 0 .979-.976z" class="prefix__cls-2" data-name="Path 3001" transform="translate(-582.908 -128.69)"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,15 +1,15 @@
import React, {useCallback, useEffect, useMemo, useState} from "react";
import styles from '../style/EntriesList.module.sass';
import styles from './EntriesList.module.sass';
import ScrollableFeedVirtualized from "react-scrollable-feed-virtualized";
import Moment from 'moment';
import {EntryItem} from "./EntryListItem/EntryListItem";
import down from "assets/downImg.svg";
import spinner from 'assets/spinner.svg';
import {EntryItem} from "../EntryListItem/EntryListItem";
import down from "../assets/downImg.svg";
import spinner from '../assets/spinner.svg';
import {RecoilState, useRecoilState, useRecoilValue, useSetRecoilState} from "recoil";
import entriesAtom from "../../recoil/entries";
import queryAtom from "../../recoil/query";
import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi";
import TrafficViewerApi from "./TrafficViewerApi";
import TrafficViewerApi from "../TrafficViewer/TrafficViewerApi";
import focusedEntryIdAtom from "../../recoil/focusedEntryId";
import {toast} from "react-toastify";
import {MAX_ENTRIES, TOAST_CONTAINER_ID} from "../../configs/Consts";

View File

@@ -1,18 +1,18 @@
import React, { useEffect, useState } from "react";
import EntryViewer from "./EntryDetailed/EntryViewer";
import { EntryItem } from "./EntryListItem/EntryListItem";
import { makeStyles } from "@material-ui/core";
import Protocol from "../UI/Protocol"
import Queryable from "../UI/Queryable";
import EntryViewer from "./EntryViewer/EntryViewer";
import { EntryItem } from "../EntryListItem/EntryListItem";
import makeStyles from '@mui/styles/makeStyles';
import Protocol from "../UI/Protocol/Protocol"
import Queryable from "../UI/Queryable/Queryable";
import { toast } from "react-toastify";
import { RecoilState, useRecoilValue } from "recoil";
import focusedEntryIdAtom from "../../recoil/focusedEntryId";
import TrafficViewerApi from "./TrafficViewerApi";
import TrafficViewerApi from "../TrafficViewer/TrafficViewerApi";
import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi/atom";
import queryAtom from "../../recoil/query/atom";
import useWindowDimensions, { useRequestTextByWidth } from "../../hooks/WindowDimensionsHook";
import { TOAST_CONTAINER_ID } from "../../configs/Consts";
import spinner from "assets/spinner.svg";
import spinner from "../assets/spinner.svg";
const useStyles = makeStyles(() => ({
entryTitle: {

View File

@@ -1,10 +1,10 @@
import styles from "./EntrySections.module.sass";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { SyntaxHighlighter } from "../../UI/SyntaxHighlighter/index";
import CollapsibleContainer from "../../UI/CollapsibleContainer";
import FancyTextDisplay from "../../UI/FancyTextDisplay";
import Queryable from "../../UI/Queryable";
import Checkbox from "../../UI/Checkbox";
import { SyntaxHighlighter } from "../../UI/SyntaxHighlighter";
import CollapsibleContainer from "../../UI/CollapsibleContainer/CollapsibleContainer";
import FancyTextDisplay from "../../UI/FancyTextDisplay/FancyTextDisplay";
import Queryable from "../../UI/Queryable/Queryable";
import Checkbox from "../../UI/Checkbox/Checkbox";
import ProtobufDecoder from "protobuf-decoder";
import { default as jsonBeautify } from "json-beautify";
import { default as xmlBeautify } from "xml-formatter";

View File

@@ -1,7 +1,7 @@
import React, {useState} from 'react';
import styles from './EntryViewer.module.sass';
import Tabs from "../../UI/Tabs";
import {EntryTableSection, EntryBodySection, EntryTablePolicySection, EntryContractSection} from "./EntrySections";
import Tabs from "../../UI/Tabs/Tabs";
import {EntryTableSection, EntryBodySection, EntryTablePolicySection, EntryContractSection} from "../EntrySections/EntrySections";
enum SectionTypes {
SectionTable = "table",

View File

@@ -1,4 +1,4 @@
@import '../../../variables.module'
@import '../../variables.module'
.row
display: flex

View File

@@ -1,21 +1,21 @@
import React from "react";
import Moment from 'moment';
import SwapHorizIcon from '@material-ui/icons/SwapHoriz';
import SwapHorizIcon from '@mui/icons-material/SwapHoriz';
import styles from './EntryListItem.module.sass';
import StatusCode, {getClassification, StatusCodeClassification} from "../../UI/StatusCode";
import Protocol, {ProtocolInterface} from "../../UI/Protocol"
import eBPFLogo from 'assets/lock.svg';
import {Summary} from "../../UI/Summary";
import Queryable from "../../UI/Queryable";
import ingoingIconSuccess from "assets/ingoing-traffic-success.svg"
import ingoingIconFailure from "assets/ingoing-traffic-failure.svg"
import ingoingIconNeutral from "assets/ingoing-traffic-neutral.svg"
import outgoingIconSuccess from "assets/outgoing-traffic-success.svg"
import outgoingIconFailure from "assets/outgoing-traffic-failure.svg"
import outgoingIconNeutral from "assets/outgoing-traffic-neutral.svg"
import StatusCode, {getClassification, StatusCodeClassification} from "../UI/StatusCode/StatusCode";
import Protocol, {ProtocolInterface} from "../UI/Protocol/Protocol"
import eBPFLogo from './assets/lock.svg';
import {Summary} from "../UI/Summary/Summary";
import Queryable from "../UI/Queryable/Queryable";
import ingoingIconSuccess from "./assets/ingoing-traffic-success.svg"
import ingoingIconFailure from "./assets/ingoing-traffic-failure.svg"
import ingoingIconNeutral from "./assets/ingoing-traffic-neutral.svg"
import outgoingIconSuccess from "./assets/outgoing-traffic-success.svg"
import outgoingIconFailure from "./assets/outgoing-traffic-failure.svg"
import outgoingIconNeutral from "./assets/outgoing-traffic-neutral.svg"
import {useRecoilState} from "recoil";
import focusedEntryIdAtom from "../../../recoil/focusedEntryId";
import queryAtom from "../../../recoil/query";
import focusedEntryIdAtom from "../../recoil/focusedEntryId";
import queryAtom from "../../recoil/query";
interface TCPInterface {
ip: string

View File

Before

Width:  |  Height:  |  Size: 959 B

After

Width:  |  Height:  |  Size: 959 B

View File

@@ -1,36 +1,43 @@
import React, {useRef, useState} from "react";
import styles from '../style/Filters.module.sass';
import {Button, Grid, Modal, Box, Typography, Backdrop, Fade, Divider} from "@material-ui/core";
import React, { FC, useEffect, useMemo, useRef, useState } from "react";
import styles from './Filters.module.sass';
import {Button, Grid, Modal, Box, Typography, Backdrop, Fade, Divider, debounce} from "@mui/material";
import CodeEditor from '@uiw/react-textarea-code-editor';
import MenuBookIcon from '@material-ui/icons/MenuBook';
import {SyntaxHighlighter} from "../UI/SyntaxHighlighter/index";
import filterUIExample1 from "assets/filter-ui-example-1.png"
import filterUIExample2 from "assets/filter-ui-example-2.png"
import MenuBookIcon from '@mui/icons-material/MenuBook';
import { SyntaxHighlighter } from "../UI/SyntaxHighlighter";
import filterUIExample1 from "../TrafficViewer/assets/filter-ui-example-1.png"
import filterUIExample2 from "../TrafficViewer/assets/filter-ui-example-2.png"
import variables from '../../variables.module.scss';
import {useRecoilState, useRecoilValue} from "recoil";
import { useRecoilState, useRecoilValue } from "recoil";
import queryAtom from "../../recoil/query";
import useKeyPress from "../../hooks/useKeyPress"
import shortcutsKeyboard from "../../configs/shortcutsKeyboard"
import trafficViewerApiAtom from "../../recoil/TrafficViewerApi"
import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi/atom";
interface FiltersProps {
backgroundColor: string
reopenConnection: any;
}
export const Filters: React.FC<FiltersProps> = ({backgroundColor, reopenConnection}) => {
export const Filters: React.FC<FiltersProps> = ({ reopenConnection }) => {
const [query, setQuery] = useRecoilState(queryAtom);
const api: any = useRecoilValue(TrafficViewerApiAtom)
return <div className={styles.container}>
<QueryForm
backgroundColor={backgroundColor}
query={query}
reopenConnection={reopenConnection}
/>
onQueryChange={(query) => { setQuery(query?.trim()); }} validateQuery={api?.validateQuery} />
</div>;
};
type OnQueryChange = { valid: boolean, message: string, query: string }
interface QueryFormProps {
backgroundColor: string
reopenConnection: any;
reopenConnection?: any;
query: string
onQueryChange?: (query: string) => void
validateQuery: (query: string) => Promise<{ valid: boolean, message: string }>;
onValidationChanged?: (event: OnQueryChange) => void
}
export const modalStyle = {
@@ -47,20 +54,57 @@ export const modalStyle = {
color: '#000',
};
export const QueryForm: React.FC<QueryFormProps> = ({backgroundColor, reopenConnection}) => {
export const CodeEditorWrap: FC<QueryFormProps> = ({ query, onQueryChange, validateQuery, onValidationChanged }) => {
const [queryBackgroundColor, setQueryBackgroundColor] = useState("#f5f5f5");
const handleQueryChange = useMemo(
() =>
debounce(async (query: string) => {
if (!query) {
setQueryBackgroundColor("#f5f5f5");
onValidationChanged && onValidationChanged({ query: query, message: "", valid: true })
} else {
const data = await validateQuery(query);
if (!data) {
return;
}
if (data.valid) {
setQueryBackgroundColor("#d2fad2");
} else {
setQueryBackgroundColor("#fad6dc");
}
onValidationChanged && onValidationChanged({ query: query, message: data.message, valid: data.valid })
}
}, 500),
[onValidationChanged, validateQuery]
) as (query: string) => void;
useEffect(() => {
handleQueryChange(query);
}, [query, handleQueryChange]);
return <CodeEditor
value={query}
language="py"
placeholder="Mizu Filter Syntax"
onChange={(event) => onQueryChange(event.target.value)}
padding={8}
style={{
fontSize: 14,
backgroundColor: `${queryBackgroundColor}`,
fontFamily: 'ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace',
}}
/>
}
export const QueryForm: React.FC<QueryFormProps> = ({ validateQuery, reopenConnection, query, onQueryChange, onValidationChanged }) => {
const formRef = useRef<HTMLFormElement>(null);
const [query, setQuery] = useRecoilState(queryAtom);
const [openModal, setOpenModal] = useState(false);
const handleOpenModal = () => setOpenModal(true);
const handleCloseModal = () => setOpenModal(false);
const handleChange = async (e) => {
setQuery(e.target.value.trim());
}
const handleSubmit = (e) => {
reopenConnection();
e.preventDefault();
@@ -86,18 +130,7 @@ export const QueryForm: React.FC<QueryFormProps> = ({backgroundColor, reopenConn
}}
>
<label>
<CodeEditor
value={query}
language="py"
placeholder="Mizu Filter Syntax"
onChange={handleChange}
padding={8}
style={{
fontSize: 14,
backgroundColor: `${backgroundColor}`,
fontFamily: 'ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace',
}}
/>
<CodeEditorWrap validateQuery={validateQuery} query={query} onQueryChange={onQueryChange} onValidationChanged={onValidationChanged} />
</label>
</Grid>
<Grid item xs={4}>

View File

@@ -1,4 +1,4 @@
@import 'src/variables.module'
@import '../../variables.module'
.TrafficPage
width: 100%

View File

@@ -1,24 +1,23 @@
import React, {useEffect, useMemo, useRef, useState} from "react";
import {Filters} from "./Filters";
import {EntriesList} from "./EntriesList";
import {makeStyles} from "@material-ui/core";
import React, { useEffect, useRef, useState } from "react";
import { Filters } from "../Filters/Filters";
import { EntriesList } from "../EntriesList/EntriesList";
import makeStyles from '@mui/styles/makeStyles';
import TrafficViewerStyles from "./TrafficViewer.module.sass";
import styles from '../style/EntriesList.module.sass';
import {EntryDetailed} from "./EntryDetailed";
import styles from '../EntriesList/EntriesList.module.sass';
import { EntryDetailed } from "../EntryDetailed/EntryDetailed";
import playIcon from 'assets/run.svg';
import pauseIcon from 'assets/pause.svg';
import variables from '../../variables.module.scss';
import {ToastContainer} from 'react-toastify';
import debounce from 'lodash/debounce';
import {RecoilRoot, RecoilState, useRecoilState, useRecoilValue, useSetRecoilState} from "recoil";
import { ToastContainer } from 'react-toastify';
import { RecoilRoot, RecoilState, useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import entriesAtom from "../../recoil/entries";
import focusedEntryIdAtom from "../../recoil/focusedEntryId";
import queryAtom from "../../recoil/query";
import trafficViewerApiAtom from "../../recoil/TrafficViewerApi"
import TrafficViewerApi from "./TrafficViewerApi";
import {StatusBar} from "../UI/StatusBar";
import { StatusBar } from "../UI/StatusBar/StatusBar";
import tappingStatusAtom from "../../recoil/tappingStatus/atom";
import {TOAST_CONTAINER_ID} from "../../configs/Consts";
import { TOAST_CONTAINER_ID } from "../../configs/Consts";
import leftOffTopAtom from "../../recoil/leftOffTop";
import { DEFAULT_LEFTOFF, DEFAULT_FETCH, DEFAULT_FETCH_TIMEOUT_MS } from '../../hooks/useWS';
@@ -43,7 +42,6 @@ const useLayoutStyles = makeStyles(() => ({
}));
interface TrafficViewerProps {
setAnalyzeStatus?: (status: any) => void;
api?: any
trafficViewerApiProp: TrafficViewerApi,
actionButtons?: JSX.Element,
@@ -55,7 +53,7 @@ interface TrafficViewerProps {
}
export const TrafficViewer: React.FC<TrafficViewerProps> = ({
setAnalyzeStatus, trafficViewerApiProp,
trafficViewerApiProp,
actionButtons, isShowStatusBar, webSocketUrl,
shouldCloseWebSocket, setShouldCloseWebSocket, isDemoBannerView
}) => {
@@ -71,34 +69,12 @@ export const TrafficViewer: React.FC<TrafficViewerProps> = ({
const [isSnappedToBottom, setIsSnappedToBottom] = useState(true);
const [wsReadyState, setWsReadyState] = useState(0);
const [queryBackgroundColor, setQueryBackgroundColor] = useState("#f5f5f5");
const setLeftOffTop = useSetRecoilState(leftOffTopAtom);
const scrollableRef = useRef(null);
const handleQueryChange = useMemo(
() =>
debounce(async (query: string) => {
if (!query) {
setQueryBackgroundColor("#f5f5f5");
} else {
const data = await trafficViewerApiProp.validateQuery(query);
if (!data) {
return;
}
if (data.valid) {
setQueryBackgroundColor("#d2fad2");
} else {
setQueryBackgroundColor("#fad6dc");
}
}
}, 500),
[]
) as (query: string) => void;
useEffect(() => {
handleQueryChange(query);
}, [query, handleQueryChange]);
useEffect(() => {
if(shouldCloseWebSocket){
@@ -176,10 +152,6 @@ export const TrafficViewer: React.FC<TrafficViewerProps> = ({
try {
const tapStatusResponse = await trafficViewerApiProp.tapStatus();
setTappingStatus(tapStatusResponse);
if (setAnalyzeStatus) {
const analyzeStatusResponse = await trafficViewerApiProp.analyzeStatus();
setAnalyzeStatus(analyzeStatusResponse);
}
} catch (error) {
console.error(error);
}
@@ -267,7 +239,6 @@ export const TrafficViewer: React.FC<TrafficViewerProps> = ({
{<div className={TrafficViewerStyles.TrafficPageContainer}>
<div className={TrafficViewerStyles.TrafficPageListContainer}>
<Filters
backgroundColor={queryBackgroundColor}
reopenConnection={reopenConnection}
/>
<div className={styles.container}>
@@ -292,16 +263,16 @@ export const TrafficViewer: React.FC<TrafficViewerProps> = ({
);
};
const MemoiedTrafficViewer = React.memo(TrafficViewer)
const MemorizedTrafficViewer = React.memo(TrafficViewer)
const TrafficViewerContainer: React.FC<TrafficViewerProps> = ({
setAnalyzeStatus, trafficViewerApiProp,
trafficViewerApiProp,
actionButtons, isShowStatusBar = true,
webSocketUrl, shouldCloseWebSocket, setShouldCloseWebSocket, isDemoBannerView
}) => {
return <RecoilRoot>
<MemoiedTrafficViewer actionButtons={actionButtons} isShowStatusBar={isShowStatusBar} webSocketUrl={webSocketUrl}
<MemorizedTrafficViewer actionButtons={actionButtons} isShowStatusBar={isShowStatusBar} webSocketUrl={webSocketUrl}
shouldCloseWebSocket={shouldCloseWebSocket} setShouldCloseWebSocket={setShouldCloseWebSocket} trafficViewerApiProp={trafficViewerApiProp}
setAnalyzeStatus={setAnalyzeStatus} isDemoBannerView={isDemoBannerView}/>
isDemoBannerView={isDemoBannerView}/>
<ToastContainer enableMultiContainer containerId={TOAST_CONTAINER_ID}
position="bottom-right"
autoClose={5000}

View File

@@ -1,7 +1,6 @@
type TrafficViewerApi = {
validateQuery: (query: any) => any
tapStatus: () => any
analyzeStatus: () => any
fetchEntries: (leftOff: any, direction: number, query: any, limit: number, timeoutMs: number) => any
getEntry: (entryId: any, query: string) => any
webSocket: {

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="50" cy="50" fill="none" stroke="#1d3f72" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138" transform="rotate(275.903 50 50)">
<animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
</circle>
<!-- [ldio] generated by https://loading.io/ --></svg>

Before

Width:  |  Height:  |  Size: 673 B

View File

@@ -1,7 +1,7 @@
import React from "react";
import collapsedImg from "assets/collapsed.svg";
import expandedImg from "assets/expanded.svg";
import styles from "./style/CollapsibleContainer.module.sass";
import collapsedImg from "../assets/collapsed.svg";
import expandedImg from "../assets/expanded.svg";
import styles from "./CollapsibleContainer.module.sass";
interface Props {
title: string | React.ReactNode,

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { makeStyles, Modal, Backdrop, Fade, Box } from '@material-ui/core';
import {useCommonStyles} from "../../helpers/commonStyle";
import { Modal, Backdrop, Fade, Box } from '@mui/material';
import makeStyles from '@mui/styles/makeStyles';
import {useCommonStyles} from "../../../helpers/commonStyle";
const useStyles = makeStyles({
modal: {
@@ -9,10 +10,10 @@ const useStyles = makeStyles({
justifyContent: "center"
},
modalContents: {
borderRadius: "5px",
borderRadius: "5px",
outline: "none",
minWidth: "300px",
backgroundColor: "rgb(255, 255, 255)",
backgroundColor: "rgb(255, 255, 255)",
},
modalBackdrop :{
background : "rgba(24, 51, 121, 0.8)"
@@ -32,16 +33,16 @@ export interface CustomModalProps {
const CustomModal: React.FunctionComponent<CustomModalProps> = ({ open = false, onClose, disableBackdropClick = false, children, className}) => {
const classes = useStyles({});
const globals = useCommonStyles().modal
const onModalClose = (reason) => {
if(reason === 'backdropClick' && disableBackdropClick)
return;
return;
onClose();
}
return <Modal disableEnforceFocus open={open} onClose={(event, reason) => onModalClose(reason)}
className={`${classes.modal}`}
className={`${classes.modal}`}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
@@ -58,4 +59,4 @@ const CustomModal: React.FunctionComponent<CustomModalProps> = ({ open = false,
</Modal>
}
export default CustomModal;
export default CustomModal;

View File

@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import duplicateImg from "assets/duplicate.svg";
import styles from './style/FancyTextDisplay.module.sass';
import duplicateImg from "../assets/duplicate.svg";
import styles from './FancyTextDisplay.module.sass';
interface Props {
text: string | number,

View File

@@ -1,5 +1,5 @@
import React from "react";
import styles from "./style/InformationIcon.module.sass"
import styles from "./InformationIcon.module.sass"
const DEFUALT_LINK = "https://getmizu.io/docs"
@@ -19,4 +19,4 @@ export const InformationIcon: React.FC<LinkProps> = ({ className }) => {
return <Link title="documentation" className={`${styles.linkStyle} ${className}`} link={DEFUALT_LINK}>
<span>Docs</span>
</Link>
}
}

View File

@@ -1,5 +1,5 @@
import React, {useEffect, useState} from "react";
import style from '../style/LoadingOverlay.module.sass';
import style from './LoadingOverlay.module.sass';
const SpinnerShowDelayMs = 350;

View File

@@ -1,6 +1,6 @@
import React from "react";
import circleImg from 'assets/dotted-circle.svg';
import styles from './style/NoDataMessage.module.sass'
import circleImg from '../assets/dotted-circle.svg';
import styles from './NoDataMessage.module.sass'
export interface Props {
messageText: string;
@@ -10,7 +10,7 @@ const NoDataMessage: React.FC<Props> = ({ messageText = "No data found" }) => {
return (
<div data-cy="noDataMessage" className={styles.messageContainer__noData}>
<div className={styles.container}>
<img src={circleImg} alt="No data Found"></img>
<img src={circleImg} alt="No data Found"/>
<div className={styles.messageContainer__noDataMessage}>{messageText}</div>
</div>
</div>

View File

@@ -1,6 +1,6 @@
import React from "react";
import styles from './style/Protocol.module.sass';
import Queryable from "./Queryable";
import styles from './Protocol.module.sass';
import Queryable from "../Queryable/Queryable";
export interface ProtocolInterface {
name: string

View File

@@ -1,9 +1,9 @@
import React, { useEffect, useState } from 'react';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import AddCircleIcon from '@material-ui/icons/AddCircle';
import QueryableStyle from './style/Queryable.module.sass';
import AddCircleIcon from '@mui/icons-material/AddCircle';
import QueryableStyle from './Queryable.module.sass';
import {useRecoilState} from "recoil";
import queryAtom from "../../recoil/query";
import queryAtom from "../../../recoil/query";
interface Props {
query: string,

View File

@@ -1,6 +1,6 @@
import React, { useRef, useState } from "react";
import styles from './style/Resizeable.module.sass'
import styles from './Resizeable.module.sass'
export interface Props {
children
@@ -56,4 +56,4 @@ const Resizeable: React.FC<Props> = ({ children, minWidth, maxWidth }) => {
);
};
export default Resizeable;
export default Resizeable;

View File

@@ -1,9 +1,9 @@
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import { Autocomplete } from "@material-ui/lab";
import { Checkbox, TextField } from "@material-ui/core";
import CheckBoxOutlineBlankIcon from "@material-ui/icons/CheckBoxOutlineBlank";
import CheckBoxIcon from "@material-ui/icons/CheckBox";
import makeStyles from '@mui/styles/makeStyles';
import { Autocomplete } from "@mui/material";
import { Checkbox, TextField } from "@mui/material";
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import CheckBoxIcon from '@mui/icons-material/CheckBox';
import DefaultIconDown from "DefaultIconDown.svg";
import styles from "./SearchableDropdown.module.sass";
@@ -56,8 +56,9 @@ const SearchableDropdown: React.FC<SearchableDropdownProps> = ({ options, select
onChange={(event, val) => onChange(val)}
size={"small"}
popupIcon={<img style={{ padding: 7 }} alt="iconDown" src={DefaultIconDown} />}
renderOption={(option, { selected }) => (
<div id={`option-${option}`} className={styles.optionItem}>
renderOption={(props, option, { selected }) => (
<li {...props}>
<div id={`option-${option}`} className={styles.optionItem} key={option}>
{multiple && <Checkbox
icon={<CheckBoxOutlineBlankIcon fontSize="small" />}
checkedIcon={<CheckBoxIcon fontSize="small" />}
@@ -66,6 +67,7 @@ const SearchableDropdown: React.FC<SearchableDropdownProps> = ({ options, select
/>}
<div title={option} className={styles.title}>{option}</div>
</div>
</li>
)}
renderTags={() => <div className={styles.optionListItem}>
<div title={selectedValues?.length > 0 ? `${selectedValues[0]} (+${selectedValues.length - 1})` : ""} className={styles.optionListItemTitle}>

View File

@@ -1,8 +1,7 @@
import {ReactComponent as DefaultIconDown} from './assets/default_icon_down.svg';
import {MenuItem, Select as MUISelect} from '@material-ui/core';
import {ReactComponent as DefaultIconDown} from '../assets/default_icon_down.svg';
import {MenuItem, Select as MUISelect, SelectProps as MUISelectProps} from '@mui/material';
import React from 'react';
import {SelectProps as MUISelectProps} from '@material-ui/core/Select/Select';
import styles from './style/Select.module.sass';
import styles from './Select.module.sass';
export const ALL_KEY= 'All';

View File

@@ -3,7 +3,7 @@
.selectListTable
user-select: none // when resizble moved we get unwanted beheviour
height: 100%
height: calc(100% - 53px)
table
width: 100%

View File

@@ -1,9 +1,9 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import Radio from "./Radio";
import styles from './style/SelectList.module.sass'
import NoDataMessage from "./NoDataMessage";
import Checkbox from "./Checkbox";
import { useCommonStyles } from "../../helpers/commonStyle";
import Radio from "../Radio/Radio";
import styles from './SelectList.module.sass'
import NoDataMessage from "../NoDataMessage/NoDataMessage";
import Checkbox from "../Checkbox/Checkbox";
import { useCommonStyles } from "../../../helpers/commonStyle";
export interface Props {
@@ -21,7 +21,7 @@ export interface Props {
const SelectList: React.FC<Props> = ({ items, tableName, checkedValues = [], multiSelect = true, setCheckedValues, tableClassName,
checkBoxWidth = 50 ,inputSearchClass,isFilterable = true}) => {
const commonClasses = useCommonStyles();
const [searchValue, setSearchValue] = useState("")
const [searchValue, setSearchValue] = useState("")
const noItemsMessage = "No items to show";
const [headerChecked, setHeaderChecked] = useState(false)

View File

@@ -1,11 +1,11 @@
import style from './style/StatusBar.module.sass';
import style from './StatusBar.module.sass';
import React, {useState} from "react";
import warningIcon from 'assets/warning_icon.svg';
import failIcon from 'assets/failed.svg';
import successIcon from 'assets/success.svg';
import warningIcon from '../assets/warning_icon.svg';
import failIcon from '../assets/failed.svg';
import successIcon from '../assets/success.svg';
import {useRecoilValue} from "recoil";
import tappingStatusAtom, {tappingStatusDetails} from "../../recoil/tappingStatus";
import Tooltip from "./Tooltip";
import tappingStatusAtom, {tappingStatusDetails} from "../../../recoil/tappingStatus";
import Tooltip from "../Tooltip/Tooltip";
const pluralize = (noun: string, amount: number) => {
return `${noun}${amount !== 1 ? 's' : ''}`

View File

@@ -1,6 +1,6 @@
import React from "react";
import styles from './style/StatusCode.module.sass';
import Queryable from "./Queryable";
import styles from './StatusCode.module.sass';
import Queryable from "../Queryable/Queryable";
export enum StatusCodeClassification {
SUCCESS = "success",

View File

@@ -1,7 +1,7 @@
import miscStyles from "./style/misc.module.sass";
import miscStyles from "./misc.module.sass";
import React from "react";
import styles from './style/Summary.module.sass';
import Queryable from "./Queryable";
import styles from './Summary.module.sass';
import Queryable from "../Queryable/Queryable";
interface SummaryProps {
method: string

Some files were not shown because too many files have changed in this diff Show More