diff --git a/.gitignore b/.gitignore
index 96896c85..57d2daa0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,9 @@ pkg/protocols/headless/engine/.cache
/tsgen
/scrapefuncs
/integration_tests/.cache/
-/integration_tests/.nuclei-config/
/*.yaml
-/pkg/protocols/headless/engine/.nuclei-config/
\ No newline at end of file
+**/*-config
+**/*-cache
+/fuzzplayground
+integration_tests/fuzzplayground
+
diff --git a/Makefile b/Makefile
index cd2c2157..f6950b31 100644
--- a/Makefile
+++ b/Makefile
@@ -42,6 +42,8 @@ jsupdate:
ts:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "tsgen" pkg/js/devtools/tsgen/cmd/tsgen/main.go
./tsgen -dir pkg/js/libs -out pkg/js/generated/ts
+fuzzplayground:
+ $(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "fuzzplayground" cmd/tools/fuzzplayground/main.go
memogen:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "memogen" cmd/memogen/memogen.go
./memogen -src pkg/js/libs -tpl cmd/memogen/function.tpl
diff --git a/README.md b/README.md
index 69ee2624..e231221c 100644
--- a/README.md
+++ b/README.md
@@ -113,12 +113,17 @@ Usage:
Flags:
TARGET:
- -u, -target string[] target URLs/hosts to scan
- -l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
- -eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
- -resume string resume scan using resume.cfg (clustering will be disabled)
- -sa, -scan-all-ips scan all the IP's associated with dns record
- -iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
+ -u, -target string[] target URLs/hosts to scan
+ -l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
+ -eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
+ -resume string resume scan using resume.cfg (clustering will be disabled)
+ -sa, -scan-all-ips scan all the IP's associated with dns record
+ -iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
+
+TARGET-FORMAT:
+ -im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger) (default "list")
+ -ro, -required-only use only required fields in input format when generating requests
+ -sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
TEMPLATES:
-nt, -new-templates run only new templates added in latest nuclei-templates release
@@ -134,6 +139,7 @@ TEMPLATES:
-tl list all available templates
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
-code enable loading code protocol-based templates
+ -dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
FILTERING:
-a, -author string[] templates to run based on authors (comma-separated, file)
@@ -142,8 +148,8 @@ FILTERING:
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
-id, -template-id string[] templates to run based on template ids (comma-separated, file, allow-wildcard)
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
- -it, -include-templates string[] templates to be executed even if they are excluded either by default or configuration
- -et, -exclude-templates string[] template or template directory to exclude (comma-separated, file)
+ -it, -include-templates string[] path to template file or directory to be executed even if they are excluded either by default or configuration
+ -et, -exclude-templates string[] path to template file or directory to exclude (comma-separated, file)
-em, -exclude-matchers string[] template matchers to exclude in result
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
@@ -215,6 +221,7 @@ INTERACTSH:
FUZZING:
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
+ -fuzz enable loading fuzzing templates
UNCOVER:
-uc, -uncover enable uncover engine
@@ -231,6 +238,8 @@ RATE-LIMIT:
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
+ -jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
+ -pc, -payload-concurrency int max payload concurrency for each template (default 25)
OPTIMIZATIONS:
-timeout int time to wait in seconds before timeout (default 10)
@@ -292,22 +301,26 @@ CLOUD:
-cup, -cloud-upload upload scan results to pdcp dashboard
-sid, -scan-id string upload scan results to given scan id
+AUTHENTICATION:
+ -sf, -secret-file string[] path to config file containing secrets for nuclei authenticated scan
+ -ps, -prefetch-secrets prefetch secrets from the secrets file
+
EXAMPLES:
Run nuclei on single host:
- $ nuclei -target example.com
+ $ nuclei -target example.com
Run nuclei with specific template directories:
- $ nuclei -target example.com -t http/cves/ -t ssl
+ $ nuclei -target example.com -t http/cves/ -t ssl
Run nuclei against a list of hosts:
- $ nuclei -list hosts.txt
+ $ nuclei -list hosts.txt
Run nuclei with a JSON output:
- $ nuclei -target example.com -json-export output.json
+ $ nuclei -target example.com -json-export output.json
Run nuclei with sorted Markdown outputs (with environment variables):
- $ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
+ $ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
Additional documentation is available at: https://docs.nuclei.sh/getting-started/running
```
diff --git a/cmd/integration-test/fuzz.go b/cmd/integration-test/fuzz.go
index 276f8550..be2ac161 100644
--- a/cmd/integration-test/fuzz.go
+++ b/cmd/integration-test/fuzz.go
@@ -12,6 +12,10 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
)
+const (
+ targetFile = "fuzz/testData/ginandjuice.proxify.yaml"
+)
+
var fuzzingTestCases = []TestCaseInfo{
{Path: "fuzz/fuzz-mode.yaml", TestCase: &fuzzModeOverride{}},
{Path: "fuzz/fuzz-type.yaml", TestCase: &fuzzTypeOverride{}},
@@ -19,6 +23,29 @@ var fuzzingTestCases = []TestCaseInfo{
{Path: "fuzz/fuzz-headless.yaml", TestCase: &HeadlessFuzzingQuery{}},
{Path: "fuzz/fuzz-header-basic.yaml", TestCase: &FuzzHeaderBasic{}},
{Path: "fuzz/fuzz-header-multiple.yaml", TestCase: &FuzzHeaderMultiple{}},
+ // for fuzzing we should prioritize adding test case related backend
+ // logic in fuzz playground server instead of adding them here
+ {Path: "fuzz/fuzz-query-num-replace.yaml", TestCase: &genericFuzzTestCase{expectedResults: 2}},
+ {Path: "fuzz/fuzz-host-header-injection.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
+ {Path: "fuzz/fuzz-path-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
+ {Path: "fuzz/fuzz-cookie-error-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
+ {Path: "fuzz/fuzz-body-json-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
+ {Path: "fuzz/fuzz-body-multipart-form-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
+ {Path: "fuzz/fuzz-body-params-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
+ {Path: "fuzz/fuzz-body-xml-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
+ {Path: "fuzz/fuzz-body-generic-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 4}},
+}
+
+type genericFuzzTestCase struct {
+ expectedResults int
+}
+
+func (g *genericFuzzTestCase) Execute(filePath string) error {
+ results, err := testutils.RunNucleiWithArgsAndGetResults(debug, "-t", filePath, "-l", targetFile, "-im", "yaml")
+ if err != nil {
+ return err
+ }
+ return expectResultsCount(results, g.expectedResults)
}
type httpFuzzQuery struct{}
@@ -34,7 +61,7 @@ func (h *httpFuzzQuery) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()
- results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example", debug)
+ results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example", debug, "-fuzz")
if err != nil {
return err
}
@@ -53,7 +80,7 @@ func (h *fuzzModeOverride) Execute(filePath string) error {
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
- results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example&name=nuclei", debug, "-fuzzing-mode", "single", "-jsonl")
+ results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example&name=nuclei", debug, "-fuzzing-mode", "single", "-jsonl", "-fuzz")
if err != nil {
return err
}
@@ -98,7 +125,7 @@ func (h *fuzzTypeOverride) Execute(filePath string) error {
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
- results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?id=example", debug, "-fuzzing-type", "replace", "-jsonl")
+ results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?id=example", debug, "-fuzzing-type", "replace", "-jsonl", "-fuzz")
if err != nil {
return err
}
@@ -143,7 +170,7 @@ func (h *HeadlessFuzzingQuery) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()
- got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?url=https://scanme.sh", debug, "-headless")
+ got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?url=https://scanme.sh", debug, "-headless", "-fuzz")
if err != nil {
return err
}
@@ -164,7 +191,7 @@ func (h *FuzzHeaderBasic) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()
- got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
+ got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-fuzz")
if err != nil {
return err
}
@@ -192,7 +219,7 @@ func (h *FuzzHeaderMultiple) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()
- got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
+ got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-fuzz")
if err != nil {
return err
}
diff --git a/cmd/integration-test/integration-test.go b/cmd/integration-test/integration-test.go
index 672224e1..76851413 100644
--- a/cmd/integration-test/integration-test.go
+++ b/cmd/integration-test/integration-test.go
@@ -9,7 +9,9 @@ import (
"github.com/logrusorgru/aurora"
+ "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
+ "github.com/projectdiscovery/nuclei/v3/pkg/testutils/fuzzplayground"
sliceutil "github.com/projectdiscovery/utils/slice"
)
@@ -53,6 +55,10 @@ var (
"flow": flowTestcases,
"javascript": jsTestcases,
}
+ // flakyTests are run with a retry count of 3
+ flakyTests = map[string]bool{
+ "protocols/http/self-contained-file-input.yaml": true,
+ }
// For debug purposes
runProtocol = ""
@@ -78,6 +84,18 @@ func main() {
os.Exit(1)
}
+ // start fuzz playground server
+ defer fuzzplayground.Cleanup()
+ server := fuzzplayground.GetPlaygroundServer()
+ defer server.Close()
+ go func() {
+ if err := server.Start("localhost:8082"); err != nil {
+ if !strings.Contains(err.Error(), "Server closed") {
+ gologger.Fatal().Msgf("Could not start server: %s\n", err)
+ }
+ }
+ }()
+
customTestsList := normalizeSplit(customTests)
failedTestTemplatePaths := runTests(customTestsList)
@@ -150,6 +168,8 @@ func runTests(customTemplatePaths []string) []string {
var err error
if proto == "interactsh" || strings.Contains(testCaseInfo.Path, "interactsh") {
failedTemplatePath, err = executeWithRetry(testCaseInfo.TestCase, testCaseInfo.Path, interactshRetryCount)
+ } else if flakyTests[testCaseInfo.Path] {
+ failedTemplatePath, err = executeWithRetry(testCaseInfo.TestCase, testCaseInfo.Path, interactshRetryCount)
} else {
failedTemplatePath, err = execute(testCaseInfo.TestCase, testCaseInfo.Path)
}
diff --git a/cmd/integration-test/library.go b/cmd/integration-test/library.go
index 5fec4226..fd02f17e 100644
--- a/cmd/integration-test/library.go
+++ b/cmd/integration-test/library.go
@@ -19,11 +19,10 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
- "github.com/projectdiscovery/nuclei/v3/pkg/core/inputs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/parsers"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
@@ -126,8 +125,7 @@ func executeNucleiAsLibrary(templatePath, templateURL string) ([]string, error)
}
store.Load()
- input := &inputs.SimpleInputProvider{Inputs: []*contextargs.MetaInput{{Input: templateURL}}}
- _ = engine.Execute(store.Templates(), input)
+ _ = engine.Execute(store.Templates(), provider.NewSimpleInputProviderWithUrls(templateURL))
engine.WorkPool().Wait() // Wait for the scan to finish
return results, nil
diff --git a/cmd/integration-test/workflow.go b/cmd/integration-test/workflow.go
index c0ccb8ee..3ffd2887 100644
--- a/cmd/integration-test/workflow.go
+++ b/cmd/integration-test/workflow.go
@@ -137,7 +137,7 @@ type workflowSharedCookies struct{}
// Execute executes a test case and returns an error if occurred
func (h *workflowSharedCookies) Execute(filePath string) error {
- handleFunc := func(name string, w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+ handleFunc := func(name string, w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
cookie := &http.Cookie{Name: name, Value: name}
http.SetCookie(w, cookie)
}
diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go
index 684ea618..731865d7 100644
--- a/cmd/nuclei/main.go
+++ b/cmd/nuclei/main.go
@@ -22,6 +22,7 @@ import (
"github.com/projectdiscovery/interactsh/pkg/client"
"github.com/projectdiscovery/nuclei/v3/internal/runner"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
@@ -46,6 +47,9 @@ var (
)
func main() {
+ // enables CLI specific configs mostly interactive behavior
+ config.CurrentAppMode = config.AppModeCLI
+
if err := runner.ConfigureOptions(); err != nil {
gologger.Fatal().Msgf("Could not initialize options: %s\n", err)
}
@@ -201,6 +205,12 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringSliceVarP(&options.IPVersion, "ip-version", "iv", nil, "IP version to scan of hostname (4,6) - (default 4)", goflags.CommaSeparatedStringSliceOptions),
)
+ flagSet.CreateGroup("target-format", "Target-Format",
+ flagSet.StringVarP(&options.InputFileMode, "input-mode", "im", "list", fmt.Sprintf("mode of input file (%v)", provider.SupportedInputFormats())),
+ flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"),
+ flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"),
+ )
+
flagSet.CreateGroup("templates", "Templates",
flagSet.BoolVarP(&options.NewTemplates, "new-templates", "nt", false, "run only new templates added in latest nuclei-templates release"),
flagSet.StringSliceVarP(&options.NewTemplatesWithVersion, "new-templates-version", "ntv", nil, "run new templates added in specific version", goflags.CommaSeparatedStringSliceOptions),
@@ -226,8 +236,8 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringSliceVarP(&options.IncludeTags, "include-tags", "itags", nil, "tags to be executed even if they are excluded either by default or configuration", goflags.FileNormalizedStringSliceOptions), // TODO show default deny list
flagSet.StringSliceVarP(&options.IncludeIds, "template-id", "id", nil, "templates to run based on template ids (comma-separated, file, allow-wildcard)", goflags.FileNormalizedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeIds, "exclude-id", "eid", nil, "templates to exclude based on template ids (comma-separated, file)", goflags.FileNormalizedStringSliceOptions),
- flagSet.StringSliceVarP(&options.IncludeTemplates, "include-templates", "it", nil, "templates to be executed even if they are excluded either by default or configuration", goflags.FileCommaSeparatedStringSliceOptions),
- flagSet.StringSliceVarP(&options.ExcludedTemplates, "exclude-templates", "et", nil, "template or template directory to exclude (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
+ flagSet.StringSliceVarP(&options.IncludeTemplates, "include-templates", "it", nil, "path to template file or directory to be executed even if they are excluded either by default or configuration", goflags.FileCommaSeparatedStringSliceOptions),
+ flagSet.StringSliceVarP(&options.ExcludedTemplates, "exclude-templates", "et", nil, "path to template file or directory to exclude (comma-separated, file)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.ExcludeMatchers, "exclude-matchers", "em", nil, "template matchers to exclude in result", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.VarP(&options.Severities, "severity", "s", fmt.Sprintf("templates to run based on severity. Possible values: %s", severity.GetSupportedSeverities().String())),
flagSet.VarP(&options.ExcludeSeverities, "exclude-severity", "es", fmt.Sprintf("templates to exclude based on severity. Possible values: %s", severity.GetSupportedSeverities().String())),
@@ -303,6 +313,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.CreateGroup("fuzzing", "Fuzzing",
flagSet.StringVarP(&options.FuzzingType, "fuzzing-type", "ft", "", "overrides fuzzing type set in template (replace, prefix, postfix, infix)"),
flagSet.StringVarP(&options.FuzzingMode, "fuzzing-mode", "fm", "", "overrides fuzzing mode set in template (multiple, single)"),
+ flagSet.BoolVar(&options.FuzzTemplates, "fuzz", false, "enable loading fuzzing templates"),
)
flagSet.CreateGroup("uncover", "Uncover",
@@ -394,6 +405,11 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.ScanID, "scan-id", "sid", "", "upload scan results to given scan id"),
)
+ flagSet.CreateGroup("Authentication", "Authentication",
+ flagSet.StringSliceVarP(&options.SecretsFile, "secret-file", "sf", nil, "path to config file containing secrets for nuclei authenticated scan", goflags.CommaSeparatedStringSliceOptions),
+ flagSet.BoolVarP(&options.PreFetchSecrets, "prefetch-secrets", "ps", false, "prefetch secrets from the secrets file"),
+ )
+
flagSet.SetCustomHelpText(`EXAMPLES:
Run nuclei on single host:
$ nuclei -target example.com
@@ -468,6 +484,14 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory)
}
+ if len(options.SecretsFile) > 0 {
+ for _, secretFile := range options.SecretsFile {
+ if !fileutil.FileExists(secretFile) {
+ gologger.Fatal().Msgf("given secrets file '%s' does not exist", options.SecretsFile)
+ }
+ }
+ }
+
cleanupOldResumeFiles()
return flagSet
}
diff --git a/cmd/tools/fuzzplayground/main.go b/cmd/tools/fuzzplayground/main.go
index 4298b12a..0ab764e8 100644
--- a/cmd/tools/fuzzplayground/main.go
+++ b/cmd/tools/fuzzplayground/main.go
@@ -1,94 +1,27 @@
package main
import (
- "fmt"
- "io"
- "os/exec"
- "strconv"
- "strings"
+ "flag"
- "github.com/labstack/echo/v4"
- "github.com/labstack/echo/v4/middleware"
- "github.com/projectdiscovery/retryablehttp-go"
+ _ "github.com/mattn/go-sqlite3"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/testutils/fuzzplayground"
+)
+
+var (
+ addr string
)
func main() {
- e := echo.New()
- e.Use(middleware.Recover())
- e.Use(middleware.Logger())
+ flag.StringVar(&addr, "addr", "localhost:8082", "playground server address")
+ flag.Parse()
- e.GET("/", indexHandler)
- e.GET("/info", infoHandler)
- e.GET("/redirect", redirectHandler)
- e.GET("/request", requestHandler)
- e.GET("/email", emailHandler)
- e.GET("/permissions", permissionsHandler)
- if err := e.Start("localhost:8082"); err != nil {
- panic(err)
+ defer fuzzplayground.Cleanup()
+ server := fuzzplayground.GetPlaygroundServer()
+ defer server.Close()
+
+ // Start the server
+ if err := server.Start(addr); err != nil {
+ gologger.Fatal().Msgf("Could not start server: %s\n", err)
}
}
-
-var bodyTemplate = `
-
-Fuzz Playground
-
-
-%s
-
-`
-
-func indexHandler(ctx echo.Context) error {
- return ctx.HTML(200, fmt.Sprintf(bodyTemplate, `Fuzzing Playground
-
-`))
-}
-
-func infoHandler(ctx echo.Context) error {
- return ctx.HTML(200, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Name of user: %s%s%s", ctx.QueryParam("name"), ctx.QueryParam("another"), ctx.QueryParam("random"))))
-}
-
-func redirectHandler(ctx echo.Context) error {
- url := ctx.QueryParam("redirect_url")
- return ctx.Redirect(302, url)
-}
-
-func requestHandler(ctx echo.Context) error {
- url := ctx.QueryParam("url")
- data, err := retryablehttp.DefaultClient().Get(url)
- if err != nil {
- return ctx.HTML(500, err.Error())
- }
- defer data.Body.Close()
-
- body, _ := io.ReadAll(data.Body)
- return ctx.HTML(200, fmt.Sprintf(bodyTemplate, string(body)))
-}
-
-func emailHandler(ctx echo.Context) error {
- text := ctx.QueryParam("text")
- if strings.Contains(text, "{{") {
- trimmed := strings.SplitN(strings.Trim(text[strings.Index(text, "{"):], "{}"), "*", 2)
- if len(trimmed) < 2 {
- return ctx.HTML(500, "invalid template")
- }
- first, _ := strconv.Atoi(trimmed[0])
- second, _ := strconv.Atoi(trimmed[1])
- text = strconv.Itoa(first * second)
- }
- return ctx.HTML(200, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Text: %s", text)))
-}
-
-func permissionsHandler(ctx echo.Context) error {
- command := ctx.QueryParam("cmd")
- fields := strings.Fields(command)
- cmd := exec.Command(fields[0], fields[1:]...)
- data, _ := cmd.CombinedOutput()
-
- return ctx.HTML(200, fmt.Sprintf(bodyTemplate, string(data)))
-}
diff --git a/go.mod b/go.mod
index 1d4d558d..e1edff2e 100644
--- a/go.mod
+++ b/go.mod
@@ -42,7 +42,6 @@ require (
golang.org/x/oauth2 v0.11.0
golang.org/x/text v0.14.0
gopkg.in/yaml.v2 v2.4.0
- moul.io/http2curl v1.0.0
)
require (
@@ -60,18 +59,22 @@ require (
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.72
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0
github.com/charmbracelet/glamour v0.6.0
+ github.com/clbanning/mxj/v2 v2.7.0
github.com/denisenkom/go-mssqldb v0.12.3
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c
github.com/docker/go-units v0.5.0
github.com/dop251/goja v0.0.0-20230828202809-3dbe69dd2b8e
github.com/fatih/structs v1.1.0
+ github.com/getkin/kin-openapi v0.123.0
github.com/go-git/go-git/v5 v5.11.0
github.com/go-ldap/ldap/v3 v3.4.5
github.com/go-pg/pg v8.0.7+incompatible
github.com/go-sql-driver/mysql v1.7.1
github.com/h2non/filetype v1.1.3
github.com/labstack/echo/v4 v4.10.2
+ github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa
github.com/lib/pq v1.10.1
+ github.com/mattn/go-sqlite3 v1.14.22
github.com/mholt/archiver v3.1.1+incompatible
github.com/ory/dockertest/v3 v3.10.0
github.com/praetorian-inc/fingerprintx v1.1.9
@@ -95,11 +98,13 @@ require (
github.com/projectdiscovery/wappalyzergo v0.0.112
github.com/redis/go-redis/v9 v9.1.0
github.com/sashabaranov/go-openai v1.15.3
+ github.com/seh-msft/burpxml v1.0.1
github.com/stretchr/testify v1.9.0
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706
golang.org/x/term v0.17.0
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.1
+ moul.io/http2curl v1.0.0
)
require (
@@ -145,6 +150,8 @@ require (
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect
+ github.com/go-openapi/jsonpointer v0.20.2 // indirect
+ github.com/go-openapi/swag v0.22.9 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
@@ -158,30 +165,35 @@ require (
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.6 // indirect
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf // indirect
+ github.com/invopop/yaml v0.2.0 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
github.com/kataras/jwt v0.1.10 // indirect
- github.com/klauspost/compress v1.17.4 // indirect
- github.com/klauspost/pgzip v1.2.5 // indirect
+ github.com/klauspost/compress v1.17.6 // indirect
+ github.com/klauspost/pgzip v1.2.6 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mackerelio/go-osstat v0.2.4 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
github.com/mholt/archiver/v3 v3.5.1 // indirect
github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/term v0.5.0 // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
- github.com/pierrec/lz4/v4 v4.1.2 // indirect
+ github.com/perimeterx/marshmallow v1.1.5 // indirect
+ github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/projectdiscovery/asnmap v1.1.0 // indirect
@@ -195,7 +207,6 @@ require (
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
- github.com/smartystreets/assertions v1.0.0 // indirect
github.com/tidwall/btree v1.7.0 // indirect
github.com/tidwall/buntdb v1.3.0 // indirect
github.com/tidwall/gjson v1.17.0 // indirect
@@ -258,8 +269,8 @@ require (
github.com/libdns/libdns v0.2.1 // indirect
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
- github.com/mattn/go-isatty v0.0.19 // indirect
- github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mholt/acmez v1.2.0 // indirect
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -268,7 +279,7 @@ require (
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/projectdiscovery/blackrock v0.0.1 // indirect
github.com/projectdiscovery/networkpolicy v0.0.8
- github.com/rivo/uniseg v0.4.4 // indirect
+ github.com/rivo/uniseg v0.4.6 // indirect
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
@@ -286,20 +297,20 @@ require (
go.uber.org/zap v1.25.0 // indirect
goftp.io/server/v2 v2.0.1 // indirect
golang.org/x/crypto v0.19.0 // indirect
- golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
+ golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.17.0
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
+ google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
)
require (
github.com/Microsoft/go-winio v0.6.1 // indirect
- github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
+ github.com/ProtonMail/go-crypto v1.1.0-alpha.0-proton // indirect
github.com/alecthomas/chroma v0.10.0
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect
diff --git a/go.sum b/go.sum
index 952f4f93..b69e157d 100644
--- a/go.sum
+++ b/go.sum
@@ -79,8 +79,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
-github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
-github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
+github.com/ProtonMail/go-crypto v1.1.0-alpha.0-proton h1:P5Wd8eQ6zAzT4HpJI67FDKnTSf3xiJGQFqY1agDJPy4=
+github.com/ProtonMail/go-crypto v1.1.0-alpha.0-proton/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/RumbleDiscovery/rumble-tools v0.0.0-20201105153123-f2adbb3244d2/go.mod h1:jD2+mU+E2SZUuAOHZvZj4xP4frlOo+N/YrXDvASFhkE=
@@ -200,7 +200,6 @@ github.com/bsm/ginkgo/v2 v2.9.5/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbA
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
-github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
@@ -230,12 +229,13 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
+github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8=
github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
-github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
@@ -330,6 +330,8 @@ github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
+github.com/getkin/kin-openapi v0.123.0 h1:zIik0mRwFNLyvtXK274Q6ut+dPh6nlxBp0x7mNrPhs8=
+github.com/getkin/kin-openapi v0.123.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
@@ -369,6 +371,10 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
+github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
+github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
+github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
github.com/go-pg/pg v8.0.7+incompatible h1:ty/sXL1OZLo+47KK9N8llRcmbA9tZasqbQ/OO4ld53g=
github.com/go-pg/pg v8.0.7+incompatible/go.mod h1:a2oXow+aFOrvwcKs3eIA0lNFmMilrxK2sOkB5NWe0vA=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@@ -389,6 +395,8 @@ github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
+github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goburrow/cache v0.1.4 h1:As4KzO3hgmzPlnaMniZU9+VmoNYseUhuELbxy9mRBfw=
github.com/goburrow/cache v0.1.4/go.mod h1:cDFesZDnIlrHoNlMYqqMpCRawuXulgx+y7mXU8HZ+/c=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
@@ -559,10 +567,13 @@ github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439Z
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
+github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
@@ -593,6 +604,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -618,15 +631,16 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
-github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
+github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
-github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
+github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -648,6 +662,8 @@ github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa h1:KQKuQDgA3DZX6C396lt3WDYB9Um1gLITLbvficVbqXk=
+github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa/go.mod h1:HbwNE4XGwjgtUELkvQaAOjWrpianHYZdQVNqSdYW3UM=
github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo=
github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
@@ -665,6 +681,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mackerelio/go-osstat v0.2.4 h1:qxGbdPkFo65PXOb/F/nhDKpF2nGmGaCFDLXoZjJTtUs=
github.com/mackerelio/go-osstat v0.2.4/go.mod h1:Zy+qzGdZs3A9cuIqmgbJvwbmLQH9dJvtio5ZjJTbdlQ=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -673,13 +691,16 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
-github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
@@ -720,6 +741,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
@@ -779,12 +802,15 @@ github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtb
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
+github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
+github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
@@ -915,13 +941,13 @@ github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
-github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
+github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
-github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -935,6 +961,8 @@ github.com/sashabaranov/go-openai v1.15.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adO
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
+github.com/seh-msft/burpxml v1.0.1 h1:5G3QPSzvfA1WcX7LkxmKBmK2RnNyGviGWnJPumE0nwg=
+github.com/seh-msft/burpxml v1.0.1/go.mod h1:lTViCHPtGGS0scK0B4krm6Ld1kVZLWzQccwUomRc58I=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@@ -955,9 +983,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
-github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -1162,7 +1189,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
@@ -1179,8 +1205,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
-golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
+golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
+golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1254,7 +1280,6 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
@@ -1371,7 +1396,6 @@ golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXR
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
@@ -1390,7 +1414,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
@@ -1550,8 +1573,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
+google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1591,6 +1614,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
diff --git a/integration_tests/fuzz/fuzz-body-generic-sqli.yaml b/integration_tests/fuzz/fuzz-body-generic-sqli.yaml
new file mode 100644
index 00000000..83ca4962
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-body-generic-sqli.yaml
@@ -0,0 +1,39 @@
+id: fuzz-body-generic
+
+info:
+ name: fuzzing error sqli payloads in http req body
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities by fuzzing http body
+ It automatically handles and parses json,xml,multipart form and x-www-form-urlencoded data
+ and performs fuzzing on the value of every key
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - method != "GET"
+ - method != "HEAD"
+ - contains(path, "/user") # for scope of integration test
+ condition: and
+
+ payloads:
+ injection:
+ - "'"
+ - "\""
+ - ";"
+
+ fuzzing:
+ - part: body
+ type: postfix
+ mode: single
+ fuzz:
+ - '{{injection}}'
+
+ stop-at-first-match: true
+ matchers:
+ - type: word
+ words:
+ - "unrecognized token:"
+ - "null"
diff --git a/integration_tests/fuzz/fuzz-body-json-sqli.yaml b/integration_tests/fuzz/fuzz-body-json-sqli.yaml
new file mode 100644
index 00000000..187ce1b4
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-body-json-sqli.yaml
@@ -0,0 +1,40 @@
+id: json-body-error-sqli
+
+info:
+ name: fuzzing error sqli payloads in json body
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities by fuzzing http body of json type.
+ This is achieved by performing [ruleType](example: postfix) on value of json key
+ Note: this is example template, and payloads/matchers need to be modified appropriately.
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - method != "GET"
+ - method != "HEAD"
+ - contains(content_type, "application/json")
+ - contains(path, "/user") # for scope of integration test
+ condition: and
+
+ payloads:
+ injection:
+ - "'"
+ - "\""
+ - ";"
+
+ fuzzing:
+ - part: body
+ type: postfix
+ mode: single
+ fuzz:
+ - '{{injection}}'
+
+ stop-at-first-match: true
+ matchers:
+ - type: word
+ words:
+ - "unrecognized token:"
+ - "null"
diff --git a/integration_tests/fuzz/fuzz-body-multipart-form-sqli.yaml b/integration_tests/fuzz/fuzz-body-multipart-form-sqli.yaml
new file mode 100644
index 00000000..dcca2e18
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-body-multipart-form-sqli.yaml
@@ -0,0 +1,41 @@
+id: body-multipart-error-sqli
+
+info:
+ name: fuzzing error sqli payloads in body of multipart form data
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities by fuzzing http body of multipart form data (file upload, etc.)
+ This is achieved by performing [ruleType](example: postfix) on value of body form key
+ Note: this is example template, and payloads/matchers need to be modified appropriately.
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - method != "GET"
+ - method != "HEAD"
+ - contains(content_type, "multipart/form-data")
+ - contains(path, "/user") # for scope of integration test
+ condition: and
+
+ payloads:
+ injection:
+ - "'"
+ - "\""
+ - ";"
+
+ fuzzing:
+ - part: body
+ type: postfix
+ mode: single
+ fuzz:
+ - '{{injection}}'
+
+ stop-at-first-match: true
+ matchers:
+ - type: word
+ words:
+ - "unrecognized token:"
+ - "null"
+ - "SELECTs to the left and right of UNION do not have the same number of result columns"
diff --git a/integration_tests/fuzz/fuzz-body-params-sqli.yaml b/integration_tests/fuzz/fuzz-body-params-sqli.yaml
new file mode 100644
index 00000000..2fdd1742
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-body-params-sqli.yaml
@@ -0,0 +1,41 @@
+id: body-params-error-sqli
+
+info:
+ name: fuzzing error sqli payloads in body with params
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities by fuzzing http body of x-www-form-urlencoded data
+ This is achieved by performing [ruleType](example: postfix) on value of body key
+ Note: this is example template, and payloads/matchers need to be modified appropriately.
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - method != "GET"
+ - method != "HEAD"
+ - contains(content_type, "application/x-www-form-urlencoded")
+ - contains(path, "/user") # for scope of integration test
+ condition: and
+
+ payloads:
+ injection:
+ - "'"
+ - "\""
+ - ";"
+
+ fuzzing:
+ - part: body
+ type: postfix
+ mode: single
+ fuzz:
+ - '{{injection}}'
+
+ stop-at-first-match: true
+ matchers:
+ - type: word
+ words:
+ - "unrecognized token:"
+ - "null"
+ - "SELECTs to the left and right of UNION do not have the same number of result columns"
diff --git a/integration_tests/fuzz/fuzz-body-xml-sqli.yaml b/integration_tests/fuzz/fuzz-body-xml-sqli.yaml
new file mode 100644
index 00000000..8ac62842
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-body-xml-sqli.yaml
@@ -0,0 +1,40 @@
+id: xml-body-error-sqli
+
+info:
+ name: fuzzing error sqli payloads in xml body
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities by fuzzing http body of xml type.
+ This is achieved by performing [ruleType](example: postfix) on value of xml key
+ Note: this is example template, and payloads/matchers need to be modified appropriately.
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - method != "GET"
+ - method != "HEAD"
+ - contains(content_type, "application/xml")
+ - contains(path, "/user") # for scope of integration test
+ condition: and
+
+ payloads:
+ injection:
+ - "'"
+ - "\""
+ - ";"
+
+ fuzzing:
+ - part: body
+ type: postfix
+ mode: single
+ fuzz:
+ - '{{injection}}'
+
+ stop-at-first-match: true
+ matchers:
+ - type: word
+ words:
+ - "unrecognized token:"
+ - "null"
diff --git a/integration_tests/fuzz/fuzz-cookie-error-sqli.yaml b/integration_tests/fuzz/fuzz-cookie-error-sqli.yaml
new file mode 100644
index 00000000..86bb2a16
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-cookie-error-sqli.yaml
@@ -0,0 +1,59 @@
+id: cookie-fuzzing-error-sqli
+
+info:
+ name: fuzzing error sqli payloads in cookie
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities by fuzzing http cookies with SQL injection payloads.
+ Note: this is example template, and payloads/matchers need to be modified appropriately.
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - 'method == "GET"'
+ - len(cookie) > 0
+ condition: and
+
+ payloads:
+ sqli:
+ - "'"
+ - ''
+ - '`'
+ - '``'
+ - ','
+ - '"'
+ - ""
+ - /
+ - //
+ - \
+ - \\
+ - ;
+ - -- or #
+ - '" OR 1 = 1 -- -'
+ - ' OR '' = '
+ - '='
+ - 'LIKE'
+ - "'=0--+"
+ - OR 1=1
+ - "' OR 'x'='x"
+ - "' AND id IS NULL; --"
+ - "'''''''''''''UNION SELECT '2"
+ - '%00'
+
+ fuzzing:
+ - part: cookie
+ type: postfix
+ mode: single
+ fuzz:
+ - '{{sqli}}'
+
+ stop-at-first-match: true
+ matchers:
+ - type: word
+ words:
+ - "unrecognized token:"
+ - "syntax error"
+ - "null"
+ - "SELECTs to the left and right of UNION do not have the same number of result columns"
diff --git a/integration_tests/fuzz/fuzz-header-basic.yaml b/integration_tests/fuzz/fuzz-header-basic.yaml
index 1441878a..10d2928c 100644
--- a/integration_tests/fuzz/fuzz-header-basic.yaml
+++ b/integration_tests/fuzz/fuzz-header-basic.yaml
@@ -28,7 +28,7 @@ http:
- "'\"><{{first}}"
fuzzing:
- - part: headers
+ - part: header
type: replace
mode: single
keys: ["Origin"]
diff --git a/integration_tests/fuzz/fuzz-header-multiple.yaml b/integration_tests/fuzz/fuzz-header-multiple.yaml
index 04b88b1f..0a535b57 100644
--- a/integration_tests/fuzz/fuzz-header-multiple.yaml
+++ b/integration_tests/fuzz/fuzz-header-multiple.yaml
@@ -25,7 +25,7 @@ http:
- "secret.local"
fuzzing:
- - part: headers
+ - part: header
type: replace
mode: multiple
keys: ["Origin", "X-Forwared-For"]
diff --git a/integration_tests/fuzz/fuzz-host-header-injection.yaml b/integration_tests/fuzz/fuzz-host-header-injection.yaml
new file mode 100644
index 00000000..cda22235
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-host-header-injection.yaml
@@ -0,0 +1,43 @@
+id: host-header-injection
+
+info:
+ name: Host Header Injection
+ author: pdteam
+ severity: info
+ description: Host header injection
+
+variables:
+ domain: "oast.fun"
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - 'method == "GET"'
+ - 'contains(path,"/host-header-lab")' # for integration testing only
+ condition: and
+
+ fuzzing:
+ - part: header
+ type: replace
+ mode: single
+ fuzz:
+ X-Forwarded-For: "{{domain}}"
+ X-Forwarded-Host: "{{domain}}"
+ Forwarded: "{{domain}}"
+ X-Real-IP: "{{domain}}"
+ X-Original-URL: "{{domain}}"
+ X-Rewrite-URL: "{{domain}}"
+ Host: "{{domain}}"
+ # " Host": "{{domain}}" # space before host (not supported yet due to lack of unsafe mode)
+
+ matchers:
+ - type: status
+ status:
+ - 200
+
+ - type: word
+ part: body
+ words:
+ - "Interactsh"
+ matchers-condition: and
\ No newline at end of file
diff --git a/integration_tests/fuzz/fuzz-mode.yaml b/integration_tests/fuzz/fuzz-mode.yaml
index d8664083..549eb54e 100644
--- a/integration_tests/fuzz/fuzz-mode.yaml
+++ b/integration_tests/fuzz/fuzz-mode.yaml
@@ -5,7 +5,7 @@ info:
author: pdteam
severity: info
-requests:
+http:
- method: GET
path:
- "{{BaseURL}}"
diff --git a/integration_tests/fuzz/fuzz-path-sqli.yaml b/integration_tests/fuzz/fuzz-path-sqli.yaml
new file mode 100644
index 00000000..e034dec3
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-path-sqli.yaml
@@ -0,0 +1,42 @@
+id: path-based-sqli
+
+info:
+ name: Path Based SQLi
+ author: pdteam
+ severity: info
+ description: |
+ This template attempts to find SQL injection vulnerabilities on path based sqli and replacing numerical values with fuzzing payloads.
+ ex: /admin/user/55/profile , /user/15/action/update, /posts/15, /blog/100/data, /page/51/ etc these types of paths are filtered and
+ replaced with sqli path payloads.
+ Note: this is example template, and payloads/matchers need to be modified appropriately.
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - 'method == "GET"'
+ - regex("/(.*?/)([0-9]+)(/.*)?",path)
+ condition: and
+
+ payloads:
+ pathsqli:
+ - "'OR1=1"
+ - '%20OR%20True'
+
+ fuzzing:
+ - part: path
+ type: replace-regex
+ mode: single
+ replace-regex: '/(.*?/)([0-9]+)(/.*)?'
+ fuzz:
+ - '/${1}${2}{{pathsqli}}${3}'
+
+ matchers:
+ - type: status
+ status:
+ - 200
+
+ - type: word
+ words:
+ - "admin"
+ matchers-condition: and
\ No newline at end of file
diff --git a/integration_tests/fuzz/fuzz-query-num-replace.yaml b/integration_tests/fuzz/fuzz-query-num-replace.yaml
new file mode 100644
index 00000000..90f3a393
--- /dev/null
+++ b/integration_tests/fuzz/fuzz-query-num-replace.yaml
@@ -0,0 +1,39 @@
+id: fuzz-query-num
+
+info:
+ name: Fuzz Query Param For IDOR
+ author: pdteam
+ severity: info
+ description: Query Value Fuzzing using Fuzzing Rules
+
+http:
+ - filters:
+ - type: dsl
+ dsl:
+ - 'len(query) > 0'
+ # below filter is related to integration testing
+ - type: word
+ part: path
+ words:
+ - /blog/post
+ filters-condition: and
+
+ payloads:
+ nums:
+ - 200
+ - 201
+
+ fuzzing:
+ - part: query
+ type: replace
+ mode: multiple
+ values:
+ - "^[0-9]+$" # only if value is number
+ fuzz:
+ - '{{nums}}'
+
+ matchers:
+ - type: status
+ status:
+ - 200
+
diff --git a/integration_tests/fuzz/fuzz-query.yaml b/integration_tests/fuzz/fuzz-query.yaml
index 3a0b672e..658ee553 100644
--- a/integration_tests/fuzz/fuzz-query.yaml
+++ b/integration_tests/fuzz/fuzz-query.yaml
@@ -5,7 +5,7 @@ info:
author: pdteam
severity: info
-requests:
+http:
- method: GET
path:
- "{{BaseURL}}"
diff --git a/integration_tests/fuzz/fuzz-type.yaml b/integration_tests/fuzz/fuzz-type.yaml
index 860432c3..e2c20556 100644
--- a/integration_tests/fuzz/fuzz-type.yaml
+++ b/integration_tests/fuzz/fuzz-type.yaml
@@ -5,7 +5,7 @@ info:
author: pdteam
severity: info
-requests:
+http:
- method: GET
path:
- "{{BaseURL}}"
diff --git a/integration_tests/fuzz/testData/ginandjuice.proxify.yaml b/integration_tests/fuzz/testData/ginandjuice.proxify.yaml
new file mode 100644
index 00000000..734ea39c
--- /dev/null
+++ b/integration_tests/fuzz/testData/ginandjuice.proxify.yaml
@@ -0,0 +1,535 @@
+timestamp: 2024-02-20T19:24:13+05:30
+url: http://127.0.0.1:8082/blog/post?postId=3&source=proxify
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: GET
+ path: /blog/post
+ scheme: https
+ raw: |+
+ GET /blog/post?postId=3&source=proxify HTTP/1.1
+ Host: 127.0.0.1:8082
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+response:
+ header:
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/, AWSALBCORS=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure, session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; Secure; HttpOnly; SameSite=None
+ X-Backend: ea6c1d8c-a8e5-4bef-b8db-879bbb13cf62
+ X-Frame-Options: SAMEORIGIN
+ raw: |+
+ HTTP/1.1 200 OK
+ Connection: close
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/
+ Set-Cookie: AWSALBCORS=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure
+ Set-Cookie: session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; Secure; HttpOnly; SameSite=None
+ X-Backend: ea6c1d8c-a8e5-4bef-b8db-879bbb13cf62
+ X-Frame-Options: SAMEORIGIN
+
+---
+timestamp: 2024-02-20T19:24:13+05:30
+url: http://127.0.0.1:8082/reset-password
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: GET
+ path: /blog/post
+ scheme: https
+ raw: |+
+ POST /reset-password HTTP/1.1
+ Host: 127.0.0.1:8082
+ X-Forwarded-For: 127.0.0.1:8082
+ Accept-Encoding: gzip
+ Connection: close
+ Content-Type: application/json
+ Content-Length: 23
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+ {"password":"12345678"}
+response:
+ header:
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/, AWSALBCORS=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure, session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; Secure; HttpOnly; SameSite=None
+ X-Backend: ea6c1d8c-a8e5-4bef-b8db-879bbb13cf62
+ X-Frame-Options: SAMEORIGIN
+ raw: |+
+ HTTP/1.1 200 OK
+ Connection: close
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/
+ Set-Cookie: AWSALBCORS=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure
+ Set-Cookie: session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; Secure; HttpOnly; SameSite=None
+ X-Backend: ea6c1d8c-a8e5-4bef-b8db-879bbb13cf62
+ X-Frame-Options: SAMEORIGIN
+
+---
+timestamp: 2024-02-20T19:24:13+06:30
+url: http://127.0.0.1:8082/user/55/profile
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: GET
+ path: /blog/post
+ scheme: https
+ raw: |+
+ GET /user/55/profile HTTP/1.1
+ Host: 127.0.0.1:8082
+ Accept-Encoding: gzip
+ Connection: close
+ Content-Type: application/json
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+response:
+ header:
+ Content-Type: application/json; charset=UTF-8
+ Date: Tue, 27 Feb 2024 18:46:44 GMT
+ raw: |+
+ HTTP/1.1 200 OK
+ Content-Type: application/json; charset=UTF-8
+ Date: Tue, 27 Feb 2024 18:46:44 GMT
+ Content-Length: 47
+
+ {"ID":75,"Name":"user","Age":30,"Role":"user"}
+
+---
+timestamp: 2024-02-20T23:25:13+06:30
+url: http://127.0.0.1:8082/user
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ Content-Type: application/json
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: POST
+ path: /user
+ scheme: http
+ raw: |+
+ POST /user HTTP/1.1
+ Host: localhost:8082
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ Accept: */*
+ Content-Length: 32
+ Connection: close
+ Content-Type: application/json
+
+ {"id": 7 , "name": "pdteam"}
+
+response:
+ header:
+ Content-Type: text/plain; charset=UTF-8
+ Date: Tue, 27 Feb 2024 18:46:44 GMT
+ raw: |+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain; charset=UTF-8
+ Date: Wed, 28 Feb 2024 13:58:52 GMT
+ Content-Length: 25
+
+ User updated successfully
+
+---
+timestamp: 2024-02-20T23:26:13+06:30
+url: http://127.0.0.1:8082/user
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ Content-Type: application/x-www-form-urlencoded
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: POST
+ path: /user
+ scheme: http
+ raw: |+
+ POST /user HTTP/1.1
+ Host: localhost:8082
+ User-Agent: curl/8.1.2
+ Accept: */*
+ Content-Length: 20
+ Connection: close
+ Content-Type: application/x-www-form-urlencoded
+
+ id=7&name=pdteam
+
+response:
+ header:
+ Content-Type: text/plain; charset=UTF-8
+ Date: Tue, 27 Feb 2024 18:46:44 GMT
+ raw: |+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain; charset=UTF-8
+ Date: Wed, 28 Feb 2024 13:58:52 GMT
+ Content-Length: 25
+
+ User updated successfully
+
+---
+timestamp: 2024-02-20T23:26:13+06:30
+url: http://127.0.0.1:8082/user
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ Content-Type: multipart/form-data
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: POST
+ path: /user
+ scheme: http
+ raw: |+
+ POST /user HTTP/1.1
+ Host: localhost:8082
+ User-Agent: curl/8.1.2
+ Accept: */*
+ Content-Length: 226
+ Connection: close
+ Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
+
+ ------WebKitFormBoundary7MA4YWxkTrZu0gW
+ Content-Disposition: form-data; name="id"
+
+ 7
+ ------WebKitFormBoundary7MA4YWxkTrZu0gW
+ Content-Disposition: form-data; name="name"
+
+ pdteam
+ ------WebKitFormBoundary7MA4YWxkTrZu0gW--
+
+response:
+ header:
+ Content-Type: text/plain; charset=UTF-8
+ Date: Tue, 27 Feb 2024 18:46:44 GMT
+ raw: |+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain; charset=UTF-8
+ Date: Wed, 28 Feb 2024 13:58:52 GMT
+ Content-Length: 25
+
+ User updated successfully
+
+---
+---
+timestamp: 2024-02-20T19:25:13+06:30
+url: http://127.0.0.1:8082/blog/posts
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ Cookie: session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; lang=en
+ method: GET
+ path: /blog/posts
+ scheme: http
+ raw: |+
+ GET /blog/posts HTTP/1.1
+ Host: 127.0.0.1:8082
+ Accept-Encoding: gzip
+ Cookie: session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; lang=en
+ Connection: close
+ Content-Type: application/json
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+response:
+ header:
+ Content-Type: application/json; charset=UTF-8
+ Date: Tue, 27 Feb 2024 18:46:44 GMT
+ raw: |+
+ HTTP/1.1 200 OK
+ Content-Type: application/json; charset=UTF-8
+ Date: Wed, 28 Feb 2024 13:58:52 GMT
+ Content-Length: 218
+
+ [{"ID":1,"Title":"The Joy of Programming","Content":"Programming is like painting a canvas with logic.","Lang":"en"},{"ID":2,"Title":"A Journey Through Code","Content":"Every line of code tells a story.","Lang":"en"}]
+
+---
+timestamp: 2024-02-20T23:26:13+06:30
+url: http://127.0.0.1:8082/user
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ Content-Type: application/xml
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: POST
+ path: /user
+ scheme: http
+ raw: |+
+ POST /user HTTP/1.1
+ Host: localhost:8082
+ User-Agent: curl/8.1.2
+ Accept: */*
+ Content-Length: 76
+ Connection: close
+ Content-Type: application/xml
+
+
+
+ 7
+ pdteam
+
+
+response:
+ header:
+ Content-Type: text/plain; charset=UTF-8
+ Date: Tue, 27 Feb 2024 18:46:44 GMT
+ raw: |+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain; charset=UTF-8
+ Date: Wed, 28 Feb 2024 13:58:52 GMT
+ Content-Length: 25
+
+ User updated successfully
+
+---
+timestamp: 2024-02-20T19:24:13+05:32
+url: http://127.0.0.1:8082/host-header-lab
+request:
+ header:
+ Accept-Encoding: gzip
+ Authorization: Bearer 3x4mpl3t0k3n
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: 127.0.0.1:8082
+ method: POST
+ path: /catalog/product
+ scheme: https
+ raw: |+
+ GET /host-header-lab HTTP/1.1
+ Host: 127.0.0.1:8082
+ Authorization: Bearer 3x4mpl3t0k3n
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+response:
+ header:
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/, AWSALBCORS=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure, session=fFcCUjmQguQy820Y8xrnRypp3KBWSPk6; Secure; HttpOnly; SameSite=None
+ X-Backend: 2235790d-f089-4324-8ac0-f64cc96f2460
+ X-Frame-Options: SAMEORIGIN
+ body: |
+
+
+
+
+
+
+
+
+
+ Fruit Overlays - Product - Gin & Juice Shop
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Fruit Overlays
+
+
+
+ $92.79
+
+
+
+
+ Description:
+ When it comes to hospitality presentation is key, and nothing looks better than a well-dressed drink. We know gin fans like plenty of fruit in their glasses, some a bit more than they really need, but hey ho, each to their own. But what about fruit not inside your glass, but classily arranged over your glass? In comes Fruitus overlayus, the best way to jazz up any party. The possible colour combinations are endless, just picture that! All you need is a nice selection of small fruits, or maybe even use our Fruit Curliwurlier to add a dash of even more drama, and we will do the rest. This one is a real winner at our Christmas and New year’s outings, give it a go and turn some heads.
+ CONTENTS: 12 cocktail sticks.
+ HOW TO USE: Let your creative juices flow (Pun intended), and spend some time working on your colour coordination, try not to think too much about it, just do it! Pick up one of the Fruitus overlayus sticks and carefully slide the fruit along until there is a small space on either end of the stick. Balance the stick across the rim of the glass. Ta-Da! Your first fruit overlay. Keep going until you have as many overlays as you need. You can always purchase more at any time with a discount on bulk buys.
+
+
+
+
+
+
+
+
+
+
+
+ View cart
+
+
+
+
+
+
+
+
+
+
+ raw: |+
+ HTTP/1.1 200 OK
+ Connection: close
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/
+ Set-Cookie: AWSALBCORS=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure
+ Set-Cookie: session=fFcCUjmQguQy820Y8xrnRypp3KBWSPk6; Secure; HttpOnly; SameSite=None
+ X-Backend: 2235790d-f089-4324-8ac0-f64cc96f2460
+ X-Frame-Options: SAMEORIGIN
\ No newline at end of file
diff --git a/integration_tests/run.sh b/integration_tests/run.sh
index 92b76ab1..f893e1b3 100755
--- a/integration_tests/run.sh
+++ b/integration_tests/run.sh
@@ -1,7 +1,7 @@
#!/bin/bash
echo "::group::Build nuclei"
-rm integration-test nuclei 2>/dev/null
+rm integration-test fuzzplayground nuclei 2>/dev/null
cd ../cmd/nuclei
go build -race .
mv nuclei ../../integration_tests/nuclei
diff --git a/internal/runner/inputs.go b/internal/runner/inputs.go
index 406986d9..8dc27a7a 100644
--- a/internal/runner/inputs.go
+++ b/internal/runner/inputs.go
@@ -8,6 +8,7 @@ import (
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/hmap/store/hybrid"
"github.com/projectdiscovery/httpx/common/httpx"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
stringsutil "github.com/projectdiscovery/utils/strings"
@@ -19,10 +20,15 @@ const probeBulkSize = 50
// initializeTemplatesHTTPInput initializes the http form of input
// for any loaded http templates if input is in non-standard format.
func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
+
hm, err := hybrid.New(hybrid.DefaultDiskOptions)
if err != nil {
return nil, errors.Wrap(err, "could not create temporary input file")
}
+ if r.inputProvider.InputType() == provider.MultiFormatInputProvider {
+ // currently http probing for input mode types is not supported
+ return hm, nil
+ }
gologger.Info().Msgf("Running httpx on input host")
var bulkSize = probeBulkSize
@@ -41,7 +47,7 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
// Probe the non-standard URLs and store them in cache
swg := sizedwaitgroup.New(bulkSize)
count := int32(0)
- r.hmapInputProvider.Scan(func(value *contextargs.MetaInput) bool {
+ r.inputProvider.Iterate(func(value *contextargs.MetaInput) bool {
if stringsutil.HasPrefixAny(value.Input, "http://", "https://") {
return true
}
diff --git a/internal/runner/lazy.go b/internal/runner/lazy.go
new file mode 100644
index 00000000..193b22ff
--- /dev/null
+++ b/internal/runner/lazy.go
@@ -0,0 +1,123 @@
+package runner
+
+import (
+ "fmt"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
+ "github.com/projectdiscovery/nuclei/v3/pkg/catalog"
+ "github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
+ "github.com/projectdiscovery/nuclei/v3/pkg/output"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/writer"
+ "github.com/projectdiscovery/nuclei/v3/pkg/scan"
+ "github.com/projectdiscovery/nuclei/v3/pkg/types"
+ errorutil "github.com/projectdiscovery/utils/errors"
+)
+
+type AuthLazyFetchOptions struct {
+ TemplateStore *loader.Store
+ ExecOpts protocols.ExecutorOptions
+ OnError func(error)
+}
+
+// GetAuthTemlStore create new loader for loading auth templates
+func GetAuthTmplStore(opts types.Options, catalog catalog.Catalog, execOpts protocols.ExecutorOptions) (*loader.Store, error) {
+ tmpls := []string{}
+ for _, file := range opts.SecretsFile {
+ data, err := authx.GetTemplatePathsFromSecretFile(file)
+ if err != nil {
+ return nil, errorutil.NewWithErr(err).Msgf("failed to get template paths from secrets file")
+ }
+ tmpls = append(tmpls, data...)
+ }
+ opts.Templates = tmpls
+ opts.Workflows = nil
+ opts.RemoteTemplateDomainList = nil
+ opts.TemplateURLs = nil
+ opts.WorkflowURLs = nil
+ opts.ExcludedTemplates = nil
+ opts.Tags = nil
+ opts.ExcludeTags = nil
+ opts.IncludeTemplates = nil
+ opts.Authors = nil
+ opts.Severities = nil
+ opts.ExcludeSeverities = nil
+ opts.IncludeTags = nil
+ opts.IncludeIds = nil
+ opts.ExcludeIds = nil
+ opts.Protocols = nil
+ opts.ExcludeProtocols = nil
+ opts.IncludeConditions = nil
+ cfg := loader.NewConfig(&opts, catalog, execOpts)
+ store, err := loader.New(cfg)
+ if err != nil {
+ return nil, errorutil.NewWithErr(err).Msgf("failed to initialize dynamic auth templates store")
+ }
+ return store, nil
+}
+
+// GetLazyAuthFetchCallback returns a lazy fetch callback for auth secrets
+func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret {
+ return func(d *authx.Dynamic) error {
+ tmpls := opts.TemplateStore.LoadTemplates([]string{d.TemplatePath})
+ if len(tmpls) == 0 {
+ return fmt.Errorf("no templates found for path: %s", d.TemplatePath)
+ }
+ if len(tmpls) > 1 {
+ return fmt.Errorf("multiple templates found for path: %s", d.TemplatePath)
+ }
+ data := map[string]interface{}{}
+ tmpl := tmpls[0]
+ // add args to tmpl here
+ vars := map[string]interface{}{}
+ ctx := scan.NewScanContext(contextargs.NewWithInput(d.Input))
+ for _, v := range d.Variables {
+ vars[v.Key] = v.Value
+ ctx.Input.Add(v.Key, v.Value)
+ }
+
+ var finalErr error
+ ctx.OnResult = func(e *output.InternalWrappedEvent) {
+ if e == nil {
+ finalErr = fmt.Errorf("no result found for template: %s", d.TemplatePath)
+ return
+ }
+ if !e.HasOperatorResult() {
+ finalErr = fmt.Errorf("no result found for template: %s", d.TemplatePath)
+ return
+ }
+ // dynamic values
+ for k, v := range e.OperatorsResult.DynamicValues {
+ if len(v) > 0 {
+ data[k] = v[0]
+ }
+ }
+ // named extractors
+ for k, v := range e.OperatorsResult.Extracts {
+ if len(v) > 0 {
+ data[k] = v[0]
+ }
+ }
+ if len(data) == 0 {
+ if e.OperatorsResult.Matched {
+ finalErr = fmt.Errorf("match found but no (dynamic/extracted) values found for template: %s", d.TemplatePath)
+ } else {
+ finalErr = fmt.Errorf("no match or (dynamic/extracted) values found for template: %s", d.TemplatePath)
+ }
+ }
+ // log result of template in result file/screen
+ _ = writer.WriteResult(e, opts.ExecOpts.Output, opts.ExecOpts.Progress, opts.ExecOpts.IssuesClient)
+ }
+ _, err := tmpl.Executer.ExecuteWithResults(ctx)
+ if err != nil {
+ finalErr = err
+ }
+ // store extracted result in auth context
+ d.Extracted = data
+ if finalErr != nil && opts.OnError != nil {
+ opts.OnError(finalErr)
+ }
+ return finalErr
+ }
+}
diff --git a/internal/runner/options.go b/internal/runner/options.go
index 21a2c213..bc89a45b 100644
--- a/internal/runner/options.go
+++ b/internal/runner/options.go
@@ -289,6 +289,12 @@ func createReportingOptions(options *types.Options) (*reporting.Options, error)
// configureOutput configures the output logging levels to be displayed on the screen
func configureOutput(options *types.Options) {
+ // disable standard logger (ref: https://github.com/golang/go/issues/19895)
+ defer logutil.DisableDefaultLogger()
+
+ if options.NoColor {
+ gologger.DefaultLogger.SetFormatter(formatter.NewCLI(true))
+ }
// If the user desires verbose output, show verbose output
if options.Debug || options.DebugRequests || options.DebugResponse {
gologger.DefaultLogger.SetMaxLevel(levels.LevelDebug)
@@ -304,9 +310,6 @@ func configureOutput(options *types.Options) {
if options.Silent {
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
}
-
- // disable standard logger (ref: https://github.com/golang/go/issues/19895)
- logutil.DisableDefaultLogger()
}
// loadResolvers loads resolvers from both user-provided flags and file
diff --git a/internal/runner/runner.go b/internal/runner/runner.go
index a8a29d81..0986760c 100644
--- a/internal/runner/runner.go
+++ b/internal/runner/runner.go
@@ -14,6 +14,8 @@ import (
"time"
"github.com/projectdiscovery/nuclei/v3/internal/pdcp"
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
uncoverlib "github.com/projectdiscovery/uncover"
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
@@ -33,7 +35,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
- "github.com/projectdiscovery/nuclei/v3/pkg/core/inputs/hybrid"
"github.com/projectdiscovery/nuclei/v3/pkg/external/customtemplates"
"github.com/projectdiscovery/nuclei/v3/pkg/input"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
@@ -69,22 +70,21 @@ var (
// Runner is a client for running the enumeration process.
type Runner struct {
- output output.Writer
- interactsh *interactsh.Client
- options *types.Options
- projectFile *projectfile.ProjectFile
- catalog catalog.Catalog
- progress progress.Progress
- colorizer aurora.Aurora
- issuesClient reporting.Client
- hmapInputProvider *hybrid.Input
- browser *engine.Browser
- rateLimiter *ratelimit.Limiter
- hostErrors hosterrorscache.CacheInterface
- resumeCfg *types.ResumeCfg
- pprofServer *http.Server
- // pdcp auto-save options
+ output output.Writer
+ interactsh *interactsh.Client
+ options *types.Options
+ projectFile *projectfile.ProjectFile
+ catalog catalog.Catalog
+ progress progress.Progress
+ colorizer aurora.Aurora
+ issuesClient reporting.Client
+ browser *engine.Browser
+ rateLimiter *ratelimit.Limiter
+ hostErrors hosterrorscache.CacheInterface
+ resumeCfg *types.ResumeCfg
+ pprofServer *http.Server
pdcpUploadErrMsg string
+ inputProvider provider.InputProvider
//general purpose temporary directory
tmpDir string
}
@@ -219,14 +219,12 @@ func New(options *types.Options) (*Runner, error) {
os.Exit(0)
}
- // Initialize the input source
- hmapInput, err := hybrid.New(&hybrid.Options{
- Options: options,
- })
+ // create the input provider and load the inputs
+ inputProvider, err := provider.NewInputProvider(provider.InputOptions{Options: options})
if err != nil {
return nil, errors.Wrap(err, "could not create input provider")
}
- runner.hmapInputProvider = hmapInput
+ runner.inputProvider = inputProvider
// Create the output file if asked
outputWriter, err := output.NewStandardWriter(options)
@@ -344,7 +342,9 @@ func (r *Runner) Close() {
if r.projectFile != nil {
r.projectFile.Close()
}
- r.hmapInputProvider.Close()
+ if r.inputProvider != nil {
+ r.inputProvider.Close()
+ }
protocolinit.Close()
if r.pprofServer != nil {
_ = r.pprofServer.Shutdown(context.Background())
@@ -433,6 +433,24 @@ func (r *Runner) RunEnumeration() error {
TemporaryDirectory: r.tmpDir,
}
+ if len(r.options.SecretsFile) > 0 && !r.options.Validate {
+ authTmplStore, err := GetAuthTmplStore(*r.options, r.catalog, executorOpts)
+ if err != nil {
+ return errors.Wrap(err, "failed to load dynamic auth templates")
+ }
+ authOpts := &authprovider.AuthProviderOptions{SecretsFiles: r.options.SecretsFile}
+ authOpts.LazyFetchSecret = GetLazyAuthFetchCallback(&AuthLazyFetchOptions{
+ TemplateStore: authTmplStore,
+ ExecOpts: executorOpts,
+ })
+ // initialize auth provider
+ provider, err := authprovider.NewAuthProvider(authOpts)
+ if err != nil {
+ return errors.Wrap(err, "could not create auth provider")
+ }
+ executorOpts.AuthProvider = provider
+ }
+
if r.options.ShouldUseHostError() {
cache := hosterrorscache.New(r.options.MaxHostError, hosterrorscache.DefaultMaxHostsCount, r.options.TrackError)
cache.SetVerbose(r.options.Verbose)
@@ -449,9 +467,16 @@ func (r *Runner) RunEnumeration() error {
}
executorOpts.WorkflowLoader = workflowLoader
- store, err := loader.New(loader.NewConfig(r.options, r.catalog, executorOpts))
+ // If using input-file flags, only load http fuzzing based templates.
+ loaderConfig := loader.NewConfig(r.options, r.catalog, executorOpts)
+ if !strings.EqualFold(r.options.InputFileMode, "list") || r.options.FuzzTemplates {
+ // if input type is not list (implicitly enable fuzzing)
+ r.options.FuzzTemplates = true
+ loaderConfig.OnlyLoadHTTPFuzzing = true
+ }
+ store, err := loader.New(loaderConfig)
if err != nil {
- return errors.Wrap(err, "could not load templates from config")
+ return errors.Wrap(err, "Could not create loader.")
}
if r.options.Validate {
@@ -484,7 +509,7 @@ func (r *Runner) RunEnumeration() error {
}
ret := uncover.GetUncoverTargetsFromMetadata(context.TODO(), store.Templates(), r.options.UncoverField, uncoverOpts)
for host := range ret {
- r.hmapInputProvider.SetWithExclusions(host)
+ _ = r.inputProvider.SetWithExclusions(host)
}
}
// list all templates
@@ -496,6 +521,14 @@ func (r *Runner) RunEnumeration() error {
// display execution info like version , templates used etc
r.displayExecutionInfo(store)
+ // prefetch secrets if enabled
+ if executorOpts.AuthProvider != nil && r.options.PreFetchSecrets {
+ gologger.Info().Msgf("Pre-fetching secrets from authprovider[s]")
+ if err := executorOpts.AuthProvider.PreFetchSecrets(); err != nil {
+ return errors.Wrap(err, "could not pre-fetch secrets")
+ }
+ }
+
// If not explicitly disabled, check if http based protocols
// are used, and if inputs are non-http to pre-perform probing
// of urls and storing them for execution.
@@ -541,7 +574,7 @@ func (r *Runner) RunEnumeration() error {
func (r *Runner) isInputNonHTTP() bool {
var nonURLInput bool
- r.hmapInputProvider.Scan(func(value *contextargs.MetaInput) bool {
+ r.inputProvider.Iterate(func(value *contextargs.MetaInput) bool {
if !strings.Contains(value.Input, "://") {
nonURLInput = true
return false
@@ -552,13 +585,13 @@ func (r *Runner) isInputNonHTTP() bool {
}
func (r *Runner) executeSmartWorkflowInput(executorOpts protocols.ExecutorOptions, store *loader.Store, engine *core.Engine) (*atomic.Bool, error) {
- r.progress.Init(r.hmapInputProvider.Count(), 0, 0)
+ r.progress.Init(r.inputProvider.Count(), 0, 0)
service, err := automaticscan.New(automaticscan.Options{
ExecuterOpts: executorOpts,
Store: store,
Engine: engine,
- Target: r.hmapInputProvider,
+ Target: r.inputProvider,
})
if err != nil {
return nil, errors.Wrap(err, "could not create automatic scan service")
@@ -589,7 +622,12 @@ func (r *Runner) executeTemplatesInput(store *loader.Store, engine *core.Engine)
return nil, errors.New("no templates provided for scan")
}
- results := engine.ExecuteScanWithOpts(finalTemplates, r.hmapInputProvider, r.options.DisableClustering)
+ // pass input provider to engine
+ // TODO: this should be not necessary after r.hmapInputProvider is removed + refactored
+ if r.inputProvider == nil {
+ return nil, errors.New("no input provider found")
+ }
+ results := engine.ExecuteScanWithOpts(finalTemplates, r.inputProvider, r.options.DisableClustering)
return results, nil
}
@@ -603,6 +641,7 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
// only print these stats in verbose mode
stats.DisplayAsWarning(parsers.HeadlessFlagWarningStats)
stats.DisplayAsWarning(parsers.CodeFlagWarningStats)
+ stats.DisplayAsWarning(parsers.FuzzFlagWarningStats)
stats.DisplayAsWarning(parsers.TemplatesExecutedStats)
}
@@ -643,8 +682,9 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
}
}
}
- if r.hmapInputProvider.Count() > 0 {
- gologger.Info().Msgf("Targets loaded for current scan: %d", r.hmapInputProvider.Count())
+
+ if r.inputProvider.Count() > 0 {
+ gologger.Info().Msgf("Targets loaded for current scan: %d", r.inputProvider.Count())
}
}
diff --git a/lib/config.go b/lib/config.go
index 65f3fc8c..58fab00a 100644
--- a/lib/config.go
+++ b/lib/config.go
@@ -4,9 +4,11 @@ import (
"context"
"time"
+ "github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/ratelimit"
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
@@ -163,7 +165,7 @@ func EnableHeadlessWithOpts(hopts *HeadlessOpts) NucleiSDKOptions {
if err != nil {
return err
}
- e.executerOpts.Browser = browser
+ e.browserInstance = browser
return nil
}
}
@@ -356,3 +358,28 @@ func EnablePassiveMode() NucleiSDKOptions {
return nil
}
}
+
+// WithAuthOptions allows setting a custom authprovider implementation
+func WithAuthProvider(provider authprovider.AuthProvider) NucleiSDKOptions {
+ return func(e *NucleiEngine) error {
+ e.authprovider = provider
+ return nil
+ }
+}
+
+// LoadSecretsFromFile allows loading secrets from file
+func LoadSecretsFromFile(files []string, prefetch bool) NucleiSDKOptions {
+ return func(e *NucleiEngine) error {
+ e.opts.SecretsFile = goflags.StringSlice(files)
+ e.opts.PreFetchSecrets = prefetch
+ return nil
+ }
+}
+
+// EnableFuzzTemplates allows enabling template fuzzing
+func EnableFuzzTemplates() NucleiSDKOptions {
+ return func(e *NucleiEngine) error {
+ e.opts.FuzzTemplates = true
+ return nil
+ }
+}
diff --git a/lib/multi.go b/lib/multi.go
index e09ea40b..7a3dd7ce 100644
--- a/lib/multi.go
+++ b/lib/multi.go
@@ -8,11 +8,10 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
- "github.com/projectdiscovery/nuclei/v3/pkg/core/inputs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/parsers"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/ratelimit"
errorutil "github.com/projectdiscovery/utils/errors"
@@ -123,14 +122,7 @@ func (e *ThreadSafeNucleiEngine) ExecuteNucleiWithOpts(targets []string, opts ..
}
store.Load()
- inputProvider := &inputs.SimpleInputProvider{
- Inputs: []*contextargs.MetaInput{},
- }
-
- // load targets
- for _, target := range targets {
- inputProvider.Set(target)
- }
+ inputProvider := provider.NewSimpleInputProviderWithUrls(targets...)
if len(store.Templates()) == 0 && len(store.Workflows()) == 0 {
return ErrNoTemplatesAvailable
diff --git a/lib/sdk.go b/lib/sdk.go
index 70a28299..69978409 100644
--- a/lib/sdk.go
+++ b/lib/sdk.go
@@ -5,11 +5,12 @@ import (
"bytes"
"io"
- "github.com/projectdiscovery/httpx/common/httpx"
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
- "github.com/projectdiscovery/nuclei/v3/pkg/core/inputs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
+ providerTypes "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/parsers"
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
@@ -65,12 +66,13 @@ type NucleiEngine struct {
catalog *disk.DiskCatalog
rateLimiter *ratelimit.Limiter
store *loader.Store
- httpxClient *httpx.HTTPX
- inputProvider *inputs.SimpleInputProvider
+ httpxClient providerTypes.InputLivenessProbe
+ inputProvider provider.InputProvider
engine *core.Engine
mode engineMode
browserInstance *engine.Browser
httpClient *retryablehttp.Client
+ authprovider authprovider.AuthProvider
// unexported meta options
opts *types.Options
@@ -110,7 +112,7 @@ func (e *NucleiEngine) GetTemplates() []*templates.Template {
func (e *NucleiEngine) LoadTargets(targets []string, probeNonHttp bool) {
for _, target := range targets {
if probeNonHttp {
- e.inputProvider.SetWithProbe(target, e.httpxClient)
+ _ = e.inputProvider.SetWithProbe(target, e.httpxClient)
} else {
e.inputProvider.Set(target)
}
@@ -122,13 +124,29 @@ func (e *NucleiEngine) LoadTargetsFromReader(reader io.Reader, probeNonHttp bool
buff := bufio.NewScanner(reader)
for buff.Scan() {
if probeNonHttp {
- e.inputProvider.SetWithProbe(buff.Text(), e.httpxClient)
+ _ = e.inputProvider.SetWithProbe(buff.Text(), e.httpxClient)
} else {
e.inputProvider.Set(buff.Text())
}
}
}
+// LoadTargetsWithHttpData loads targets that contain http data from file it currently supports
+// multiple formats like burp xml,openapi,swagger,proxify json
+// Note: this is mutually exclusive with LoadTargets and LoadTargetsFromReader
+func (e *NucleiEngine) LoadTargetsWithHttpData(filePath string, filemode string) error {
+ e.opts.TargetsFilePath = filePath
+ e.opts.InputFileMode = filemode
+ httpProvider, err := provider.NewInputProvider(provider.InputOptions{Options: e.opts})
+ if err != nil {
+ e.opts.TargetsFilePath = ""
+ e.opts.InputFileMode = ""
+ return err
+ }
+ e.inputProvider = httpProvider
+ return nil
+}
+
// GetExecuterOptions returns the nuclei executor options
func (e *NucleiEngine) GetExecuterOptions() *protocols.ExecutorOptions {
return &e.executerOpts
diff --git a/lib/sdk_private.go b/lib/sdk_private.go
index a9a2b4be..2e3f1cb1 100644
--- a/lib/sdk_private.go
+++ b/lib/sdk_private.go
@@ -8,19 +8,20 @@ import (
"time"
"github.com/logrusorgru/aurora"
+ "github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/gologger/levels"
"github.com/projectdiscovery/httpx/common/httpx"
"github.com/projectdiscovery/nuclei/v3/internal/runner"
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
- "github.com/projectdiscovery/nuclei/v3/pkg/core/inputs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
@@ -29,6 +30,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/reporting"
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
+ nucleiUtils "github.com/projectdiscovery/nuclei/v3/pkg/utils"
"github.com/projectdiscovery/ratelimit"
)
@@ -86,9 +88,7 @@ func (e *NucleiEngine) applyRequiredDefaults() {
// and idea is to disable them to avoid false positives
e.opts.ExcludeTags = append(e.opts.ExcludeTags, config.ReadIgnoreFile().Tags...)
- e.inputProvider = &inputs.SimpleInputProvider{
- Inputs: []*contextargs.MetaInput{},
- }
+ e.inputProvider = provider.NewSimpleInputProvider()
}
// init
@@ -158,6 +158,33 @@ func (e *NucleiEngine) init() error {
ResumeCfg: types.NewResumeCfg(),
Browser: e.browserInstance,
}
+ if len(e.opts.SecretsFile) > 0 {
+ authTmplStore, err := runner.GetAuthTmplStore(*e.opts, e.catalog, e.executerOpts)
+ if err != nil {
+ return errors.Wrap(err, "failed to load dynamic auth templates")
+ }
+ authOpts := &authprovider.AuthProviderOptions{SecretsFiles: e.opts.SecretsFile}
+ authOpts.LazyFetchSecret = runner.GetLazyAuthFetchCallback(&runner.AuthLazyFetchOptions{
+ TemplateStore: authTmplStore,
+ ExecOpts: e.executerOpts,
+ })
+ // initialize auth provider
+ provider, err := authprovider.NewAuthProvider(authOpts)
+ if err != nil {
+ return errors.Wrap(err, "could not create auth provider")
+ }
+ e.executerOpts.AuthProvider = provider
+ }
+ if e.authprovider != nil {
+ e.executerOpts.AuthProvider = e.authprovider
+ }
+
+ // prefetch secrets
+ if e.executerOpts.AuthProvider != nil && e.opts.PreFetchSecrets {
+ if err := e.executerOpts.AuthProvider.PreFetchSecrets(); err != nil {
+ return errors.Wrap(err, "could not prefetch secrets")
+ }
+ }
if e.opts.RateLimitMinute > 0 {
e.executerOpts.RateLimiter = ratelimit.New(context.Background(), uint(e.opts.RateLimitMinute), time.Minute)
@@ -172,8 +199,10 @@ func (e *NucleiEngine) init() error {
httpxOptions := httpx.DefaultOptions
httpxOptions.Timeout = 5 * time.Second
- if e.httpxClient, err = httpx.New(&httpxOptions); err != nil {
+ if client, err := httpx.New(&httpxOptions); err != nil {
return err
+ } else {
+ e.httpxClient = nucleiUtils.GetInputLivenessChecker(client)
}
// Only Happens once regardless how many times this function is called
diff --git a/pkg/authprovider/authx/basic_auth.go b/pkg/authprovider/authx/basic_auth.go
new file mode 100644
index 00000000..b7579066
--- /dev/null
+++ b/pkg/authprovider/authx/basic_auth.go
@@ -0,0 +1,31 @@
+package authx
+
+import (
+ "net/http"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+var (
+ _ AuthStrategy = &BasicAuthStrategy{}
+)
+
+// BasicAuthStrategy is a strategy for basic auth
+type BasicAuthStrategy struct {
+ Data *Secret
+}
+
+// NewBasicAuthStrategy creates a new basic auth strategy
+func NewBasicAuthStrategy(data *Secret) *BasicAuthStrategy {
+ return &BasicAuthStrategy{Data: data}
+}
+
+// Apply applies the basic auth strategy to the request
+func (s *BasicAuthStrategy) Apply(req *http.Request) {
+ req.SetBasicAuth(s.Data.Username, s.Data.Password)
+}
+
+// ApplyOnRR applies the basic auth strategy to the retryable request
+func (s *BasicAuthStrategy) ApplyOnRR(req *retryablehttp.Request) {
+ req.SetBasicAuth(s.Data.Username, s.Data.Password)
+}
diff --git a/pkg/authprovider/authx/bearer_auth.go b/pkg/authprovider/authx/bearer_auth.go
new file mode 100644
index 00000000..edf6f439
--- /dev/null
+++ b/pkg/authprovider/authx/bearer_auth.go
@@ -0,0 +1,31 @@
+package authx
+
+import (
+ "net/http"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+var (
+ _ AuthStrategy = &BearerTokenAuthStrategy{}
+)
+
+// BearerTokenAuthStrategy is a strategy for bearer token auth
+type BearerTokenAuthStrategy struct {
+ Data *Secret
+}
+
+// NewBearerTokenAuthStrategy creates a new bearer token auth strategy
+func NewBearerTokenAuthStrategy(data *Secret) *BearerTokenAuthStrategy {
+ return &BearerTokenAuthStrategy{Data: data}
+}
+
+// Apply applies the bearer token auth strategy to the request
+func (s *BearerTokenAuthStrategy) Apply(req *http.Request) {
+ req.Header.Set("Authorization", "Bearer "+s.Data.Token)
+}
+
+// ApplyOnRR applies the bearer token auth strategy to the retryable request
+func (s *BearerTokenAuthStrategy) ApplyOnRR(req *retryablehttp.Request) {
+ req.Header.Set("Authorization", "Bearer "+s.Data.Token)
+}
diff --git a/pkg/authprovider/authx/cookies_auth.go b/pkg/authprovider/authx/cookies_auth.go
new file mode 100644
index 00000000..7f3e756a
--- /dev/null
+++ b/pkg/authprovider/authx/cookies_auth.go
@@ -0,0 +1,43 @@
+package authx
+
+import (
+ "net/http"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+var (
+ _ AuthStrategy = &CookiesAuthStrategy{}
+)
+
+// CookiesAuthStrategy is a strategy for cookies auth
+type CookiesAuthStrategy struct {
+ Data *Secret
+}
+
+// NewCookiesAuthStrategy creates a new cookies auth strategy
+func NewCookiesAuthStrategy(data *Secret) *CookiesAuthStrategy {
+ return &CookiesAuthStrategy{Data: data}
+}
+
+// Apply applies the cookies auth strategy to the request
+func (s *CookiesAuthStrategy) Apply(req *http.Request) {
+ for _, cookie := range s.Data.Cookies {
+ c := &http.Cookie{
+ Name: cookie.Key,
+ Value: cookie.Value,
+ }
+ req.AddCookie(c)
+ }
+}
+
+// ApplyOnRR applies the cookies auth strategy to the retryable request
+func (s *CookiesAuthStrategy) ApplyOnRR(req *retryablehttp.Request) {
+ for _, cookie := range s.Data.Cookies {
+ c := &http.Cookie{
+ Name: cookie.Key,
+ Value: cookie.Value,
+ }
+ req.AddCookie(c)
+ }
+}
diff --git a/pkg/authprovider/authx/dynamic.go b/pkg/authprovider/authx/dynamic.go
new file mode 100644
index 00000000..0e210cf5
--- /dev/null
+++ b/pkg/authprovider/authx/dynamic.go
@@ -0,0 +1,167 @@
+package authx
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+ "sync"
+
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
+ errorutil "github.com/projectdiscovery/utils/errors"
+)
+
+type LazyFetchSecret func(d *Dynamic) error
+
+var (
+ _ json.Unmarshaler = &Dynamic{}
+)
+
+// Dynamic is a struct for dynamic secret or credential
+// these are high level secrets that take action to generate the actual secret
+// ex: username and password are dynamic secrets, the actual secret is the token obtained
+// after authenticating with the username and password
+type Dynamic struct {
+ Secret `yaml:",inline"` // this is a static secret that will be generated after the dynamic secret is resolved
+ TemplatePath string `json:"template" yaml:"template"`
+ Variables []KV `json:"variables" yaml:"variables"`
+ Input string `json:"input" yaml:"input"` // (optional) target for the dynamic secret
+ Extracted map[string]interface{} `json:"-" yaml:"-"` // extracted values from the dynamic secret
+ fetchCallback LazyFetchSecret `json:"-" yaml:"-"`
+ m *sync.Mutex `json:"-" yaml:"-"` // mutex for lazy fetch
+ fetched bool `json:"-" yaml:"-"` // flag to check if the secret has been fetched
+ error error `json:"-" yaml:"-"` // error if any
+}
+
+func (d *Dynamic) UnmarshalJSON(data []byte) error {
+ if err := json.Unmarshal(data, &d); err != nil {
+ return err
+ }
+ var s Secret
+ if err := json.Unmarshal(data, &s); err != nil {
+ return err
+ }
+ d.Secret = s
+ return nil
+}
+
+// Validate validates the dynamic secret
+func (d *Dynamic) Validate() error {
+ d.m = &sync.Mutex{}
+ if d.TemplatePath == "" {
+ return errorutil.New(" template-path is required for dynamic secret")
+ }
+ if len(d.Variables) == 0 {
+ return errorutil.New("variables are required for dynamic secret")
+ }
+ d.skipCookieParse = true // skip cookie parsing in dynamic secrets during validation
+ if err := d.Secret.Validate(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// SetLazyFetchCallback sets the lazy fetch callback for the dynamic secret
+func (d *Dynamic) SetLazyFetchCallback(callback LazyFetchSecret) {
+ d.fetchCallback = func(d *Dynamic) error {
+ err := callback(d)
+ d.fetched = true
+ if err != nil {
+ d.error = err
+ return err
+ }
+ if len(d.Extracted) == 0 {
+ return fmt.Errorf("no extracted values found for dynamic secret")
+ }
+
+ // evaluate headers
+ for i, header := range d.Headers {
+ if strings.Contains(header.Value, "{{") {
+ header.Value = replacer.Replace(header.Value, d.Extracted)
+ }
+ if strings.Contains(header.Key, "{{") {
+ header.Key = replacer.Replace(header.Key, d.Extracted)
+ }
+ d.Headers[i] = header
+ }
+
+ // evaluate cookies
+ for i, cookie := range d.Cookies {
+ if strings.Contains(cookie.Value, "{{") {
+ cookie.Value = replacer.Replace(cookie.Value, d.Extracted)
+ }
+ if strings.Contains(cookie.Key, "{{") {
+ cookie.Key = replacer.Replace(cookie.Key, d.Extracted)
+ }
+ if strings.Contains(cookie.Raw, "{{") {
+ cookie.Raw = replacer.Replace(cookie.Raw, d.Extracted)
+ }
+ d.Cookies[i] = cookie
+ }
+
+ // evaluate query params
+ for i, query := range d.Params {
+ if strings.Contains(query.Value, "{{") {
+ query.Value = replacer.Replace(query.Value, d.Extracted)
+ }
+ if strings.Contains(query.Key, "{{") {
+ query.Key = replacer.Replace(query.Key, d.Extracted)
+ }
+ d.Params[i] = query
+ }
+
+ // check username, password and token
+ if strings.Contains(d.Username, "{{") {
+ d.Username = replacer.Replace(d.Username, d.Extracted)
+ }
+ if strings.Contains(d.Password, "{{") {
+ d.Password = replacer.Replace(d.Password, d.Extracted)
+ }
+ if strings.Contains(d.Token, "{{") {
+ d.Token = replacer.Replace(d.Token, d.Extracted)
+ }
+
+ // now attempt to parse the cookies
+ d.skipCookieParse = false
+ for i, cookie := range d.Cookies {
+ if cookie.Raw != "" {
+ if err := cookie.Parse(); err != nil {
+ return fmt.Errorf("[%s] invalid raw cookie in cookiesAuth: %s", d.TemplatePath, err)
+ }
+ d.Cookies[i] = cookie
+ }
+ }
+ return nil
+ }
+}
+
+// GetStrategy returns the auth strategy for the dynamic secret
+func (d *Dynamic) GetStrategy() AuthStrategy {
+ if !d.fetched {
+ _ = d.Fetch(true)
+ }
+ if d.error != nil {
+ return nil
+ }
+ return d.Secret.GetStrategy()
+}
+
+// Fetch fetches the dynamic secret
+// if isFatal is true, it will stop the execution if the secret could not be fetched
+func (d *Dynamic) Fetch(isFatal bool) error {
+ d.m.Lock()
+ defer d.m.Unlock()
+ if d.fetched {
+ return nil
+ }
+ d.error = d.fetchCallback(d)
+ if d.error != nil && isFatal {
+ gologger.Fatal().Msgf("Could not fetch dynamic secret: %s\n", d.error)
+ }
+ return d.error
+}
+
+// Error returns the error if any
+func (d *Dynamic) Error() error {
+ return d.error
+}
diff --git a/pkg/authprovider/authx/file.go b/pkg/authprovider/authx/file.go
new file mode 100644
index 00000000..698aafe8
--- /dev/null
+++ b/pkg/authprovider/authx/file.go
@@ -0,0 +1,253 @@
+package authx
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ errorutil "github.com/projectdiscovery/utils/errors"
+ "github.com/projectdiscovery/utils/generic"
+ stringsutil "github.com/projectdiscovery/utils/strings"
+ "gopkg.in/yaml.v3"
+)
+
+type AuthType string
+
+const (
+ BasicAuth AuthType = "BasicAuth"
+ BearerTokenAuth AuthType = "BearerToken"
+ HeadersAuth AuthType = "Header"
+ CookiesAuth AuthType = "Cookie"
+ QueryAuth AuthType = "Query"
+)
+
+// SupportedAuthTypes returns the supported auth types
+func SupportedAuthTypes() []string {
+ return []string{
+ string(BasicAuth),
+ string(BearerTokenAuth),
+ string(HeadersAuth),
+ string(CookiesAuth),
+ string(QueryAuth),
+ }
+}
+
+// Authx is a struct for secrets or credentials file
+type Authx struct {
+ ID string `json:"id" yaml:"id"`
+ Info AuthFileInfo `json:"info" yaml:"info"`
+ Secrets []Secret `json:"static" yaml:"static"`
+ Dynamic []Dynamic `json:"dynamic" yaml:"dynamic"`
+}
+
+type AuthFileInfo struct {
+ Name string `json:"name" yaml:"name"`
+ Author string `json:"author" yaml:"author"`
+ Severity string `json:"severity" yaml:"severity"`
+ Description string `json:"description" yaml:"description"`
+}
+
+// Secret is a struct for secret or credential
+type Secret struct {
+ Type string `json:"type" yaml:"type"`
+ Domains []string `json:"domains" yaml:"domains"`
+ DomainsRegex []string `json:"domains-regex" yaml:"domains-regex"`
+ Headers []KV `json:"headers" yaml:"headers"`
+ Cookies []Cookie `json:"cookies" yaml:"cookies"`
+ Params []KV `json:"params" yaml:"params"`
+ Username string `json:"username" yaml:"username"` // can be either email or username
+ Password string `json:"password" yaml:"password"`
+ Token string `json:"token" yaml:"token"` // Bearer Auth token
+ skipCookieParse bool `json:"-" yaml:"-"` // temporary flag to skip cookie parsing (used in dynamic secrets)
+}
+
+// GetStrategy returns the auth strategy for the secret
+func (s *Secret) GetStrategy() AuthStrategy {
+ switch {
+ case strings.EqualFold(s.Type, string(BasicAuth)):
+ return NewBasicAuthStrategy(s)
+ case strings.EqualFold(s.Type, string(BearerTokenAuth)):
+ return NewBearerTokenAuthStrategy(s)
+ case strings.EqualFold(s.Type, string(HeadersAuth)):
+ return NewHeadersAuthStrategy(s)
+ case strings.EqualFold(s.Type, string(CookiesAuth)):
+ return NewCookiesAuthStrategy(s)
+ case strings.EqualFold(s.Type, string(QueryAuth)):
+ return NewQueryAuthStrategy(s)
+ }
+ return nil
+}
+
+func (s *Secret) Validate() error {
+ if !stringsutil.EqualFoldAny(s.Type, SupportedAuthTypes()...) {
+ return fmt.Errorf("invalid type: %s", s.Type)
+ }
+ if len(s.Domains) == 0 && len(s.DomainsRegex) == 0 {
+ return fmt.Errorf("domains or domains-regex cannot be empty")
+ }
+ if len(s.DomainsRegex) > 0 {
+ for _, domain := range s.DomainsRegex {
+ _, err := regexp.Compile(domain)
+ if err != nil {
+ return fmt.Errorf("invalid domain regex: %s", domain)
+ }
+ }
+ }
+
+ switch {
+ case strings.EqualFold(s.Type, string(BasicAuth)):
+ if s.Username == "" {
+ return fmt.Errorf("username cannot be empty in basic auth")
+ }
+ if s.Password == "" {
+ return fmt.Errorf("password cannot be empty in basic auth")
+ }
+ case strings.EqualFold(s.Type, string(BearerTokenAuth)):
+ if s.Token == "" {
+ return fmt.Errorf("token cannot be empty in bearer token auth")
+ }
+ case strings.EqualFold(s.Type, string(HeadersAuth)):
+ if len(s.Headers) == 0 {
+ return fmt.Errorf("headers cannot be empty in headers auth")
+ }
+ for _, header := range s.Headers {
+ if err := header.Validate(); err != nil {
+ return fmt.Errorf("invalid header in headersAuth: %s", err)
+ }
+ }
+ case strings.EqualFold(s.Type, string(CookiesAuth)):
+ if len(s.Cookies) == 0 {
+ return fmt.Errorf("cookies cannot be empty in cookies auth")
+ }
+ for _, cookie := range s.Cookies {
+ if cookie.Raw != "" && !s.skipCookieParse {
+ if err := cookie.Parse(); err != nil {
+ return fmt.Errorf("invalid raw cookie in cookiesAuth: %s", err)
+ }
+ }
+ if err := cookie.Validate(); err != nil {
+ return fmt.Errorf("invalid cookie in cookiesAuth: %s", err)
+ }
+ }
+ case strings.EqualFold(s.Type, string(QueryAuth)):
+ if len(s.Params) == 0 {
+ return fmt.Errorf("query cannot be empty in query auth")
+ }
+ for _, query := range s.Params {
+ if err := query.Validate(); err != nil {
+ return fmt.Errorf("invalid query in queryAuth: %s", err)
+ }
+ }
+ default:
+ return fmt.Errorf("invalid type: %s", s.Type)
+ }
+ return nil
+}
+
+type KV struct {
+ Key string `json:"key" yaml:"key"`
+ Value string `json:"value" yaml:"value"`
+}
+
+func (k *KV) Validate() error {
+ if k.Key == "" {
+ return fmt.Errorf("key cannot be empty")
+ }
+ if k.Value == "" {
+ return fmt.Errorf("value cannot be empty")
+ }
+ return nil
+}
+
+type Cookie struct {
+ Key string `json:"key" yaml:"key"`
+ Value string `json:"value" yaml:"value"`
+ Raw string `json:"raw" yaml:"raw"`
+}
+
+func (c *Cookie) Validate() error {
+ if c.Raw != "" {
+ return nil
+ }
+ if c.Key == "" {
+ return fmt.Errorf("key cannot be empty")
+ }
+ if c.Value == "" {
+ return fmt.Errorf("value cannot be empty")
+ }
+ return nil
+}
+
+// Parse parses the cookie
+// in raw the cookie is in format of
+// Set-Cookie: =; Expires=; Path=; Domain=; Secure; HttpOnly
+func (c *Cookie) Parse() error {
+ if c.Raw == "" {
+ return fmt.Errorf("raw cookie cannot be empty")
+ }
+ tmp := strings.TrimPrefix(c.Raw, "Set-Cookie: ")
+ slice := strings.Split(tmp, ";")
+ if len(slice) == 0 {
+ return fmt.Errorf("invalid raw cookie no ; found")
+ }
+ // first element is the cookie name and value
+ cookie := strings.Split(slice[0], "=")
+ if len(cookie) == 2 {
+ c.Key = cookie[0]
+ c.Value = cookie[1]
+ return nil
+ }
+ return fmt.Errorf("invalid raw cookie: %s", c.Raw)
+}
+
+// GetAuthDataFromFile reads the auth data from file
+func GetAuthDataFromFile(file string) (*Authx, error) {
+ ext := filepath.Ext(file)
+ if !generic.EqualsAny(ext, ".yml", ".yaml", ".json") {
+ return nil, fmt.Errorf("invalid file extension: supported extensions are .yml,.yaml and .json got %s", ext)
+ }
+ bin, err := os.ReadFile(file)
+ if err != nil {
+ return nil, err
+ }
+ if ext == ".yml" || ext == ".yaml" {
+ return GetAuthDataFromYAML(bin)
+ }
+ return GetAuthDataFromJSON(bin)
+}
+
+// GetTemplateIDsFromSecretFile reads the template IDs from the secret file
+func GetTemplatePathsFromSecretFile(file string) ([]string, error) {
+ auth, err := GetAuthDataFromFile(file)
+ if err != nil {
+ return nil, err
+ }
+ var paths []string
+ for _, dynamic := range auth.Dynamic {
+ paths = append(paths, dynamic.TemplatePath)
+ }
+ return paths, nil
+}
+
+// GetAuthDataFromYAML reads the auth data from yaml
+func GetAuthDataFromYAML(data []byte) (*Authx, error) {
+ var auth Authx
+ err := yaml.Unmarshal(data, &auth)
+ if err != nil {
+ return nil, errorutil.NewWithErr(err).Msgf("could not unmarshal yaml")
+ }
+ return &auth, nil
+}
+
+// GetAuthDataFromJSON reads the auth data from json
+func GetAuthDataFromJSON(data []byte) (*Authx, error) {
+ var auth Authx
+ err := json.Unmarshal(data, &auth)
+ if err != nil {
+ return nil, errorutil.NewWithErr(err).Msgf("could not unmarshal json")
+ }
+ return &auth, nil
+}
diff --git a/pkg/authprovider/authx/file_test.go b/pkg/authprovider/authx/file_test.go
new file mode 100644
index 00000000..0e7ada81
--- /dev/null
+++ b/pkg/authprovider/authx/file_test.go
@@ -0,0 +1,20 @@
+package authx
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestSecretsUnmarshal(t *testing.T) {
+ loc := "testData/example-auth.yaml"
+ data, err := GetAuthDataFromFile(loc)
+ require.Nil(t, err, "could not read secrets file")
+ require.NotNil(t, data, "could not read secrets file")
+ for _, s := range data.Secrets {
+ require.Nil(t, s.Validate(), "could not validate secret")
+ }
+ for _, d := range data.Dynamic {
+ require.Nil(t, d.Validate(), "could not validate dynamic")
+ }
+}
diff --git a/pkg/authprovider/authx/headers_auth.go b/pkg/authprovider/authx/headers_auth.go
new file mode 100644
index 00000000..b3ede114
--- /dev/null
+++ b/pkg/authprovider/authx/headers_auth.go
@@ -0,0 +1,35 @@
+package authx
+
+import (
+ "net/http"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+var (
+ _ AuthStrategy = &HeadersAuthStrategy{}
+)
+
+// HeadersAuthStrategy is a strategy for headers auth
+type HeadersAuthStrategy struct {
+ Data *Secret
+}
+
+// NewHeadersAuthStrategy creates a new headers auth strategy
+func NewHeadersAuthStrategy(data *Secret) *HeadersAuthStrategy {
+ return &HeadersAuthStrategy{Data: data}
+}
+
+// Apply applies the headers auth strategy to the request
+func (s *HeadersAuthStrategy) Apply(req *http.Request) {
+ for _, header := range s.Data.Headers {
+ req.Header.Set(header.Key, header.Value)
+ }
+}
+
+// ApplyOnRR applies the headers auth strategy to the retryable request
+func (s *HeadersAuthStrategy) ApplyOnRR(req *retryablehttp.Request) {
+ for _, header := range s.Data.Headers {
+ req.Header.Set(header.Key, header.Value)
+ }
+}
diff --git a/pkg/authprovider/authx/query_auth.go b/pkg/authprovider/authx/query_auth.go
new file mode 100644
index 00000000..796d8b1f
--- /dev/null
+++ b/pkg/authprovider/authx/query_auth.go
@@ -0,0 +1,42 @@
+package authx
+
+import (
+ "net/http"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+ urlutil "github.com/projectdiscovery/utils/url"
+)
+
+var (
+ _ AuthStrategy = &QueryAuthStrategy{}
+)
+
+// QueryAuthStrategy is a strategy for query auth
+type QueryAuthStrategy struct {
+ Data *Secret
+}
+
+// NewQueryAuthStrategy creates a new query auth strategy
+func NewQueryAuthStrategy(data *Secret) *QueryAuthStrategy {
+ return &QueryAuthStrategy{Data: data}
+}
+
+// Apply applies the query auth strategy to the request
+func (s *QueryAuthStrategy) Apply(req *http.Request) {
+ q := urlutil.NewOrderedParams()
+ q.Decode(req.URL.RawQuery)
+ for _, p := range s.Data.Params {
+ q.Add(p.Key, p.Value)
+ }
+ req.URL.RawQuery = q.Encode()
+}
+
+// ApplyOnRR applies the query auth strategy to the retryable request
+func (s *QueryAuthStrategy) ApplyOnRR(req *retryablehttp.Request) {
+ q := urlutil.NewOrderedParams()
+ q.Decode(req.Request.URL.RawQuery)
+ for _, p := range s.Data.Params {
+ q.Add(p.Key, p.Value)
+ }
+ req.Request.URL.RawQuery = q.Encode()
+}
diff --git a/pkg/authprovider/authx/strategy.go b/pkg/authprovider/authx/strategy.go
new file mode 100644
index 00000000..82040839
--- /dev/null
+++ b/pkg/authprovider/authx/strategy.go
@@ -0,0 +1,39 @@
+package authx
+
+import (
+ "net/http"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+// AuthStrategy is an interface for auth strategies
+// basic auth , bearer token, headers, cookies, query
+type AuthStrategy interface {
+ // Apply applies the strategy to the request
+ Apply(*http.Request)
+ // ApplyOnRR applies the strategy to the retryable request
+ ApplyOnRR(*retryablehttp.Request)
+}
+
+// DynamicAuthStrategy is an auth strategy for dynamic secrets
+// it implements the AuthStrategy interface
+type DynamicAuthStrategy struct {
+ // Dynamic is the dynamic secret to use
+ Dynamic Dynamic
+}
+
+// Apply applies the strategy to the request
+func (d *DynamicAuthStrategy) Apply(req *http.Request) {
+ strategy := d.Dynamic.GetStrategy()
+ if strategy != nil {
+ strategy.Apply(req)
+ }
+}
+
+// ApplyOnRR applies the strategy to the retryable request
+func (d *DynamicAuthStrategy) ApplyOnRR(req *retryablehttp.Request) {
+ strategy := d.Dynamic.GetStrategy()
+ if strategy != nil {
+ strategy.ApplyOnRR(req)
+ }
+}
diff --git a/pkg/authprovider/authx/testData/example-auth.yaml b/pkg/authprovider/authx/testData/example-auth.yaml
new file mode 100644
index 00000000..0c317509
--- /dev/null
+++ b/pkg/authprovider/authx/testData/example-auth.yaml
@@ -0,0 +1,70 @@
+id: pd-nuclei-auth-test
+
+info:
+ name: ProjectDiscovery Test Dev Servers
+ author: pdteam
+ description: |
+ This is a auth file for ProjectDiscovery dev servers.
+ It contains auth data of all projectdiscovery dev servers.
+
+# Note: this is a dummy example file. none of the secrets here are real.
+
+# static secrets
+static:
+ # for header based auth session
+ - type: header
+ domains:
+ - api.projectdiscovery.io
+ - cve.projectdiscovery.io
+ - chaos.projectdiscovery.io
+ headers:
+ - key: x-pdcp-key
+ value:
+
+ # for query based auth session
+ - type: Query
+ domains:
+ - scanme.sh
+ params:
+ - key: token
+ value: 1a2b3c4d5e6f7g8h9i0j
+
+ # for cookie based auth session
+ - type: Cookie
+ domains:
+ - scanme.sh
+ cookies:
+ - key: PHPSESSID
+ value: 1a2b3c4d5e6f7g8h9i0j
+
+ # for basic auth session
+ - type: BasicAuth
+ domains:
+ - scanme.sh
+ username: test
+ password: test
+
+ # for authorization bearer token
+ - type: BearerToken
+ domains-regex:
+ - .*scanme.sh
+ - .*pdtm.sh
+ token: test
+
+
+# dynamic secrets (powered by nuclei-templates)
+dynamic:
+ - template: /path/to/wordpress-login.yaml
+ variables:
+ - name: username
+ value: pdteam
+ - name: password
+ value: nuclei-v3.2.0
+ type: Cookie
+ domains:
+ - localhost:8080
+ cookies:
+ - raw: "{{wp-global-cookie}}"
+ - raw: "{{wp-admin-cookie}}"
+ - raw: "{{wp-plugin-cookie}}"
+
diff --git a/pkg/authprovider/file.go b/pkg/authprovider/file.go
new file mode 100644
index 00000000..77f45e40
--- /dev/null
+++ b/pkg/authprovider/file.go
@@ -0,0 +1,168 @@
+package authprovider
+
+import (
+ "net"
+ "net/url"
+ "regexp"
+ "strings"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
+ errorutil "github.com/projectdiscovery/utils/errors"
+ urlutil "github.com/projectdiscovery/utils/url"
+)
+
+// FileAuthProvider is an auth provider for file based auth
+// it accepts a secrets file and returns its provider
+type FileAuthProvider struct {
+ Path string
+ store *authx.Authx
+ compiled map[*regexp.Regexp]authx.AuthStrategy
+ domains map[string]authx.AuthStrategy
+}
+
+// NewFileAuthProvider creates a new file based auth provider
+func NewFileAuthProvider(path string, callback authx.LazyFetchSecret) (AuthProvider, error) {
+ store, err := authx.GetAuthDataFromFile(path)
+ if err != nil {
+ return nil, err
+ }
+ if len(store.Secrets) == 0 && len(store.Dynamic) == 0 {
+ return nil, ErrNoSecrets
+ }
+ if len(store.Dynamic) > 0 && callback == nil {
+ return nil, errorutil.New("lazy fetch callback is required for dynamic secrets")
+ }
+ for _, secret := range store.Secrets {
+ if err := secret.Validate(); err != nil {
+ return nil, errorutil.NewWithErr(err).Msgf("invalid secret in file: %s", path)
+ }
+ }
+ for i, dynamic := range store.Dynamic {
+ if err := dynamic.Validate(); err != nil {
+ return nil, errorutil.NewWithErr(err).Msgf("invalid dynamic in file: %s", path)
+ }
+ dynamic.SetLazyFetchCallback(callback)
+ store.Dynamic[i] = dynamic
+ }
+ f := &FileAuthProvider{Path: path, store: store}
+ f.init()
+ return f, nil
+}
+
+// init initializes the file auth provider
+func (f *FileAuthProvider) init() {
+ for _, secret := range f.store.Secrets {
+ if len(secret.DomainsRegex) > 0 {
+ for _, domain := range secret.DomainsRegex {
+ if f.compiled == nil {
+ f.compiled = make(map[*regexp.Regexp]authx.AuthStrategy)
+ }
+ compiled, err := regexp.Compile(domain)
+ if err != nil {
+ continue
+ }
+ f.compiled[compiled] = secret.GetStrategy()
+ }
+ }
+ for _, domain := range secret.Domains {
+ if f.domains == nil {
+ f.domains = make(map[string]authx.AuthStrategy)
+ }
+ f.domains[strings.TrimSpace(domain)] = secret.GetStrategy()
+ if strings.HasSuffix(domain, ":80") {
+ f.domains[strings.TrimSuffix(domain, ":80")] = secret.GetStrategy()
+ }
+ if strings.HasSuffix(domain, ":443") {
+ f.domains[strings.TrimSuffix(domain, ":443")] = secret.GetStrategy()
+ }
+ }
+ }
+ for _, dynamic := range f.store.Dynamic {
+ if len(dynamic.DomainsRegex) > 0 {
+ for _, domain := range dynamic.DomainsRegex {
+ if f.compiled == nil {
+ f.compiled = make(map[*regexp.Regexp]authx.AuthStrategy)
+ }
+ compiled, err := regexp.Compile(domain)
+ if err != nil {
+ continue
+ }
+ f.compiled[compiled] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
+ }
+ }
+ for _, domain := range dynamic.Domains {
+ if f.domains == nil {
+ f.domains = make(map[string]authx.AuthStrategy)
+ }
+ f.domains[strings.TrimSpace(domain)] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
+ if strings.HasSuffix(domain, ":80") {
+ f.domains[strings.TrimSuffix(domain, ":80")] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
+ }
+ if strings.HasSuffix(domain, ":443") {
+ f.domains[strings.TrimSuffix(domain, ":443")] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
+ }
+ }
+ }
+}
+
+// LookupAddr looks up a given domain/address and returns appropriate auth strategy
+func (f *FileAuthProvider) LookupAddr(addr string) authx.AuthStrategy {
+ if strings.Contains(addr, ":") {
+ // default normalization for host:port
+ host, port, err := net.SplitHostPort(addr)
+ if err == nil && (port == "80" || port == "443") {
+ addr = host
+ }
+ }
+ for domain, strategy := range f.domains {
+ if strings.EqualFold(domain, addr) {
+ return strategy
+ }
+ }
+ for compiled, strategy := range f.compiled {
+ if compiled.MatchString(addr) {
+ return strategy
+ }
+ }
+ return nil
+}
+
+// LookupURL looks up a given URL and returns appropriate auth strategy
+func (f *FileAuthProvider) LookupURL(u *url.URL) authx.AuthStrategy {
+ return f.LookupAddr(u.Host)
+}
+
+// LookupURLX looks up a given URL and returns appropriate auth strategy
+func (f *FileAuthProvider) LookupURLX(u *urlutil.URL) authx.AuthStrategy {
+ return f.LookupAddr(u.Host)
+}
+
+// GetTemplatePaths returns the template path for the auth provider
+func (f *FileAuthProvider) GetTemplatePaths() []string {
+ res := []string{}
+ for _, dynamic := range f.store.Dynamic {
+ if dynamic.TemplatePath != "" {
+ res = append(res, dynamic.TemplatePath)
+ }
+ }
+ return res
+}
+
+// PreFetchSecrets pre-fetches the secrets from the auth provider
+func (f *FileAuthProvider) PreFetchSecrets() error {
+ for _, s := range f.domains {
+ if val, ok := s.(*authx.DynamicAuthStrategy); ok {
+ if err := val.Dynamic.Fetch(false); err != nil {
+ return err
+ }
+ }
+ }
+ for _, s := range f.compiled {
+ if val, ok := s.(*authx.DynamicAuthStrategy); ok {
+ if err := val.Dynamic.Fetch(false); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/pkg/authprovider/interface.go b/pkg/authprovider/interface.go
new file mode 100644
index 00000000..b21668fc
--- /dev/null
+++ b/pkg/authprovider/interface.go
@@ -0,0 +1,59 @@
+package authprovider
+
+import (
+ "fmt"
+ "net/url"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
+ urlutil "github.com/projectdiscovery/utils/url"
+)
+
+var (
+ ErrNoSecrets = fmt.Errorf("no secrets in given provider")
+)
+
+var (
+ _ AuthProvider = &FileAuthProvider{}
+)
+
+// AuthProvider is an interface for auth providers
+// It implements a data structure suitable for quick lookup and retrieval
+// of auth strategies
+type AuthProvider interface {
+ // LookupAddr looks up a given domain/address and returns appropriate auth strategy
+ // for it (accepted inputs are scanme.sh or scanme.sh:443)
+ LookupAddr(string) authx.AuthStrategy
+ // LookupURL looks up a given URL and returns appropriate auth strategy
+ // it accepts a valid url struct and returns the auth strategy
+ LookupURL(*url.URL) authx.AuthStrategy
+ // LookupURLX looks up a given URL and returns appropriate auth strategy
+ // it accepts pd url struct (i.e urlutil.URL) and returns the auth strategy
+ LookupURLX(*urlutil.URL) authx.AuthStrategy
+ // GetTemplatePaths returns the template path for the auth provider
+ // that will be used for dynamic secret fetching
+ GetTemplatePaths() []string
+ // PreFetchSecrets pre-fetches the secrets from the auth provider
+ // instead of lazy fetching
+ PreFetchSecrets() error
+}
+
+// AuthProviderOptions contains options for the auth provider
+type AuthProviderOptions struct {
+ // File based auth provider options
+ SecretsFiles []string
+ // LazyFetchSecret is a callback for lazy fetching of dynamic secrets
+ LazyFetchSecret authx.LazyFetchSecret
+}
+
+// NewAuthProvider creates a new auth provider from the given options
+func NewAuthProvider(options *AuthProviderOptions) (AuthProvider, error) {
+ var providers []AuthProvider
+ for _, file := range options.SecretsFiles {
+ provider, err := NewFileAuthProvider(file, options.LazyFetchSecret)
+ if err != nil {
+ return nil, err
+ }
+ providers = append(providers, provider)
+ }
+ return NewMultiAuthProvider(providers...), nil
+}
diff --git a/pkg/authprovider/multi.go b/pkg/authprovider/multi.go
new file mode 100644
index 00000000..2e9b19df
--- /dev/null
+++ b/pkg/authprovider/multi.go
@@ -0,0 +1,67 @@
+package authprovider
+
+import (
+ "net/url"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
+ urlutil "github.com/projectdiscovery/utils/url"
+)
+
+// MultiAuthProvider is a convenience wrapper for multiple auth providers
+// it returns the first matching auth strategy for a given domain
+// if there are multiple auth strategies for a given domain, it returns the first one
+type MultiAuthProvider struct {
+ Providers []AuthProvider
+}
+
+// NewMultiAuthProvider creates a new multi auth provider
+func NewMultiAuthProvider(providers ...AuthProvider) AuthProvider {
+ return &MultiAuthProvider{Providers: providers}
+}
+
+func (m *MultiAuthProvider) LookupAddr(host string) authx.AuthStrategy {
+ for _, provider := range m.Providers {
+ strategy := provider.LookupAddr(host)
+ if strategy != nil {
+ return strategy
+ }
+ }
+ return nil
+}
+
+func (m *MultiAuthProvider) LookupURL(u *url.URL) authx.AuthStrategy {
+ for _, provider := range m.Providers {
+ strategy := provider.LookupURL(u)
+ if strategy != nil {
+ return strategy
+ }
+ }
+ return nil
+}
+
+func (m *MultiAuthProvider) LookupURLX(u *urlutil.URL) authx.AuthStrategy {
+ for _, provider := range m.Providers {
+ strategy := provider.LookupURLX(u)
+ if strategy != nil {
+ return strategy
+ }
+ }
+ return nil
+}
+
+func (m *MultiAuthProvider) GetTemplatePaths() []string {
+ var res []string
+ for _, provider := range m.Providers {
+ res = append(res, provider.GetTemplatePaths()...)
+ }
+ return res
+}
+
+func (m *MultiAuthProvider) PreFetchSecrets() error {
+ for _, provider := range m.Providers {
+ if err := provider.PreFetchSecrets(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/pkg/catalog/config/constants.go b/pkg/catalog/config/constants.go
index 09f6f481..06d4a1cc 100644
--- a/pkg/catalog/config/constants.go
+++ b/pkg/catalog/config/constants.go
@@ -6,6 +6,20 @@ import (
"github.com/Masterminds/semver/v3"
)
+type AppMode string
+
+const (
+ AppModeLibrary AppMode = "library"
+ AppModeCLI AppMode = "cli"
+)
+
+var (
+ // Global Var to control behaviours specific to cli or library
+ // maybe this should be moved to utils ??
+ // this is overwritten in cmd/nuclei/main.go
+ CurrentAppMode = AppModeLibrary
+)
+
const (
TemplateConfigFileName = ".templates-config.json"
NucleiTemplatesDirName = "nuclei-templates"
@@ -17,7 +31,7 @@ const (
CLIConfigFileName = "config.yaml"
ReportingConfigFilename = "reporting-config.yaml"
// Version is the current version of nuclei
- Version = `v3.2.0-dev`
+ Version = `v3.2.0`
// Directory Names of custom templates
CustomS3TemplatesDirName = "s3"
CustomGitHubTemplatesDirName = "github"
diff --git a/pkg/catalog/loader/loader.go b/pkg/catalog/loader/loader.go
index ea737003..4c35d31f 100644
--- a/pkg/catalog/loader/loader.go
+++ b/pkg/catalog/loader/loader.go
@@ -13,7 +13,6 @@ import (
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
- cfg "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader/filter"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/parsers"
@@ -62,6 +61,8 @@ type Config struct {
Catalog catalog.Catalog
ExecutorOptions protocols.ExecutorOptions
+
+ OnlyLoadHTTPFuzzing bool
}
// Store is a storage for loaded nuclei templates
@@ -111,19 +112,19 @@ func NewConfig(options *types.Options, catalog catalog.Catalog, executerOpts pro
}
// New creates a new template store based on provided configuration
-func New(config *Config) (*Store, error) {
+func New(cfg *Config) (*Store, error) {
tagFilter, err := filter.New(&filter.Config{
- Tags: config.Tags,
- ExcludeTags: config.ExcludeTags,
- Authors: config.Authors,
- Severities: config.Severities,
- ExcludeSeverities: config.ExcludeSeverities,
- IncludeTags: config.IncludeTags,
- IncludeIds: config.IncludeIds,
- ExcludeIds: config.ExcludeIds,
- Protocols: config.Protocols,
- ExcludeProtocols: config.ExcludeProtocols,
- IncludeConditions: config.IncludeConditions,
+ Tags: cfg.Tags,
+ ExcludeTags: cfg.ExcludeTags,
+ Authors: cfg.Authors,
+ Severities: cfg.Severities,
+ ExcludeSeverities: cfg.ExcludeSeverities,
+ IncludeTags: cfg.IncludeTags,
+ IncludeIds: cfg.IncludeIds,
+ ExcludeIds: cfg.ExcludeIds,
+ Protocols: cfg.Protocols,
+ ExcludeProtocols: cfg.ExcludeProtocols,
+ IncludeConditions: cfg.IncludeConditions,
})
if err != nil {
return nil, err
@@ -131,23 +132,23 @@ func New(config *Config) (*Store, error) {
// Create a tag filter based on provided configuration
store := &Store{
- config: config,
+ config: cfg,
tagFilter: tagFilter,
pathFilter: filter.NewPathFilter(&filter.PathFilterConfig{
- IncludedTemplates: config.IncludeTemplates,
- ExcludedTemplates: config.ExcludeTemplates,
- }, config.Catalog),
- finalTemplates: config.Templates,
- finalWorkflows: config.Workflows,
+ IncludedTemplates: cfg.IncludeTemplates,
+ ExcludedTemplates: cfg.ExcludeTemplates,
+ }, cfg.Catalog),
+ finalTemplates: cfg.Templates,
+ finalWorkflows: cfg.Workflows,
}
// Do a check to see if we have URLs in templates flag, if so
// we need to processs them separately and remove them from the initial list
var templatesFinal []string
- for _, template := range config.Templates {
+ for _, template := range cfg.Templates {
// TODO: Add and replace this with urlutil.IsURL() helper
if stringsutil.HasPrefixAny(template, httpPrefix, httpsPrefix) {
- config.TemplateURLs = append(config.TemplateURLs, template)
+ cfg.TemplateURLs = append(cfg.TemplateURLs, template)
} else {
templatesFinal = append(templatesFinal, template)
}
@@ -155,7 +156,7 @@ func New(config *Config) (*Store, error) {
// fix editor paths
remoteTemplates := []string{}
- for _, v := range config.TemplateURLs {
+ for _, v := range cfg.TemplateURLs {
if _, err := urlutil.Parse(v); err == nil {
remoteTemplates = append(remoteTemplates, handleTemplatesEditorURLs(v))
} else {
@@ -163,12 +164,12 @@ func New(config *Config) (*Store, error) {
templatesFinal = append(templatesFinal, v) // something went wrong, treat it as a file
}
}
- config.TemplateURLs = remoteTemplates
+ cfg.TemplateURLs = remoteTemplates
store.finalTemplates = templatesFinal
- urlBasedTemplatesProvided := len(config.TemplateURLs) > 0 || len(config.WorkflowURLs) > 0
+ urlBasedTemplatesProvided := len(cfg.TemplateURLs) > 0 || len(cfg.WorkflowURLs) > 0
if urlBasedTemplatesProvided {
- remoteTemplates, remoteWorkflows, err := getRemoteTemplatesAndWorkflows(config.TemplateURLs, config.WorkflowURLs, config.RemoteTemplateDomainList)
+ remoteTemplates, remoteWorkflows, err := getRemoteTemplatesAndWorkflows(cfg.TemplateURLs, cfg.WorkflowURLs, cfg.RemoteTemplateDomainList)
if err != nil {
return store, err
}
@@ -186,7 +187,7 @@ func New(config *Config) (*Store, error) {
}
// Handle a case with no templates or workflows, where we use base directory
if len(store.finalTemplates) == 0 && len(store.finalWorkflows) == 0 && !urlBasedTemplatesProvided {
- store.finalTemplates = []string{cfg.DefaultConfig.TemplatesDirectory}
+ store.finalTemplates = []string{config.DefaultConfig.TemplatesDirectory}
}
return store, nil
@@ -405,13 +406,13 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
if len(parsed.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
// donot include headless template in final list if headless flag is not set
stats.Increment(parsers.HeadlessFlagWarningStats)
- if cfg.DefaultConfig.LogAllEvents {
+ if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Headless flag is required for headless template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else if len(parsed.RequestsCode) > 0 && !store.config.ExecutorOptions.Options.EnableCodeTemplates {
// donot include 'Code' protocol custom template in final list if code flag is not set
stats.Increment(parsers.CodeFlagWarningStats)
- if cfg.DefaultConfig.LogAllEvents {
+ if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Code flag is required for code protocol template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else if len(parsed.RequestsCode) > 0 && !parsed.Verified && len(parsed.Workflows) == 0 {
@@ -419,9 +420,16 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
stats.Increment(parsers.UnsignedCodeWarning)
// these will be skipped so increment skip counter
stats.Increment(parsers.SkippedUnsignedStats)
- if cfg.DefaultConfig.LogAllEvents {
+ if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Tampered/Unsigned template at %v.\n", aurora.Yellow("WRN").String(), templatePath)
}
+ } else if parsed.IsFuzzing() && !store.config.ExecutorOptions.Options.FuzzTemplates {
+ stats.Increment(parsers.FuzzFlagWarningStats)
+ if config.DefaultConfig.LogAllEvents {
+ gologger.Print().Msgf("[%v] Fuzz flag is required for fuzzing template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
+ }
+ } else if store.config.OnlyLoadHTTPFuzzing && !parsed.IsFuzzing() {
+ gologger.Warning().Msgf("Non-Fuzzing template '%s' can only be run on list input mode targets\n", templatePath)
} else {
loadedTemplates = append(loadedTemplates, parsed)
}
diff --git a/pkg/core/engine.go b/pkg/core/engine.go
index b9a8036a..93915bc2 100644
--- a/pkg/core/engine.go
+++ b/pkg/core/engine.go
@@ -3,7 +3,6 @@ package core
import (
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
)
@@ -22,21 +21,6 @@ type Engine struct {
Callback func(*output.ResultEvent) // Executed on results
}
-// InputProvider is an input providing interface for the nuclei execution
-// engine.
-//
-// An example InputProvider implementation is provided in form of hybrid
-// input provider in pkg/core/inputs/hybrid/hmap.go
-type InputProvider interface {
- // Count returns the number of items for input provider
- Count() int64
- // Scan iterates the input and each found item is passed to the
- // callback consumer.
- Scan(callback func(value *contextargs.MetaInput) bool)
- // Set adds item to input provider
- Set(value string)
-}
-
// New returns a new Engine instance
func New(options *types.Options) *Engine {
engine := &Engine{
diff --git a/pkg/core/execute_options.go b/pkg/core/execute_options.go
index 50c61de3..fd1fadae 100644
--- a/pkg/core/execute_options.go
+++ b/pkg/core/execute_options.go
@@ -7,6 +7,7 @@ import (
"github.com/remeh/sizedwaitgroup"
"github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
@@ -20,18 +21,18 @@ import (
//
// All the execution logic for the templates/workflows happens in this part
// of the engine.
-func (e *Engine) Execute(templates []*templates.Template, target InputProvider) *atomic.Bool {
+func (e *Engine) Execute(templates []*templates.Template, target provider.InputProvider) *atomic.Bool {
return e.ExecuteScanWithOpts(templates, target, false)
}
// ExecuteWithResults a list of templates with results
-func (e *Engine) ExecuteWithResults(templatesList []*templates.Template, target InputProvider, callback func(*output.ResultEvent)) *atomic.Bool {
+func (e *Engine) ExecuteWithResults(templatesList []*templates.Template, target provider.InputProvider, callback func(*output.ResultEvent)) *atomic.Bool {
e.Callback = callback
return e.ExecuteScanWithOpts(templatesList, target, false)
}
// ExecuteScanWithOpts executes scan with given scanStrategy
-func (e *Engine) ExecuteScanWithOpts(templatesList []*templates.Template, target InputProvider, noCluster bool) *atomic.Bool {
+func (e *Engine) ExecuteScanWithOpts(templatesList []*templates.Template, target provider.InputProvider, noCluster bool) *atomic.Bool {
results := &atomic.Bool{}
selfcontainedWg := &sync.WaitGroup{}
@@ -100,7 +101,7 @@ func (e *Engine) ExecuteScanWithOpts(templatesList []*templates.Template, target
}
// executeTemplateSpray executes scan using template spray strategy where targets are iterated over each template
-func (e *Engine) executeTemplateSpray(templatesList []*templates.Template, target InputProvider) *atomic.Bool {
+func (e *Engine) executeTemplateSpray(templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool {
results := &atomic.Bool{}
// wp is workpool that contains different waitgroups for
@@ -131,11 +132,11 @@ func (e *Engine) executeTemplateSpray(templatesList []*templates.Template, targe
}
// executeHostSpray executes scan using host spray strategy where templates are iterated over each target
-func (e *Engine) executeHostSpray(templatesList []*templates.Template, target InputProvider) *atomic.Bool {
+func (e *Engine) executeHostSpray(templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool {
results := &atomic.Bool{}
wp := sizedwaitgroup.New(e.options.BulkSize + e.options.HeadlessBulkSize)
- target.Scan(func(value *contextargs.MetaInput) bool {
+ target.Iterate(func(value *contextargs.MetaInput) bool {
wp.Add()
go func(targetval *contextargs.MetaInput) {
defer wp.Done()
diff --git a/pkg/core/executors.go b/pkg/core/executors.go
index 81baa020..b491bd8e 100644
--- a/pkg/core/executors.go
+++ b/pkg/core/executors.go
@@ -5,6 +5,7 @@ import (
"sync/atomic"
"github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
@@ -44,7 +45,7 @@ func (e *Engine) executeAllSelfContained(alltemplates []*templates.Template, res
}
// executeTemplateWithTarget executes a given template on x targets (with a internal targetpool(i.e concurrency))
-func (e *Engine) executeTemplateWithTargets(template *templates.Template, target InputProvider, results *atomic.Bool) {
+func (e *Engine) executeTemplateWithTargets(template *templates.Template, target provider.InputProvider, results *atomic.Bool) {
// this is target pool i.e max target to execute
wg := e.workPool.InputPool(template.Type())
@@ -75,7 +76,7 @@ func (e *Engine) executeTemplateWithTargets(template *templates.Template, target
currentInfo.Unlock()
}
- target.Scan(func(scannedValue *contextargs.MetaInput) bool {
+ target.Iterate(func(scannedValue *contextargs.MetaInput) bool {
// Best effort to track the host progression
// skips indexes lower than the minimum in-flight at interruption time
var skip bool
diff --git a/pkg/core/inputs/inputs.go b/pkg/core/inputs/inputs.go
deleted file mode 100644
index 3e8e456b..00000000
--- a/pkg/core/inputs/inputs.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package inputs
-
-import (
- "github.com/projectdiscovery/httpx/common/httpx"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
- "github.com/projectdiscovery/nuclei/v3/pkg/utils"
-)
-
-type SimpleInputProvider struct {
- Inputs []*contextargs.MetaInput
-}
-
-// Count returns the number of items for input provider
-func (s *SimpleInputProvider) Count() int64 {
- return int64(len(s.Inputs))
-}
-
-// Scan calls a callback function till the input provider is exhausted
-func (s *SimpleInputProvider) Scan(callback func(value *contextargs.MetaInput) bool) {
- for _, v := range s.Inputs {
- if !callback(v) {
- return
- }
- }
-}
-
-// Set adds item to input provider
-func (s *SimpleInputProvider) Set(value string) {
- s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: value})
-}
-
-// SetWithProbe adds item to input provider with http probing
-func (s *SimpleInputProvider) SetWithProbe(value string, httpxClient *httpx.HTTPX) {
- valueToAppend := value
- if result := utils.ProbeURL(value, httpxClient); result != "" {
- valueToAppend = result
- }
- s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: valueToAppend})
-}
diff --git a/pkg/fuzz/component/body.go b/pkg/fuzz/component/body.go
new file mode 100644
index 00000000..79d8d6a8
--- /dev/null
+++ b/pkg/fuzz/component/body.go
@@ -0,0 +1,140 @@
+package component
+
+import (
+ "bytes"
+ "context"
+ "io"
+ "strconv"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
+ "github.com/projectdiscovery/retryablehttp-go"
+ readerutil "github.com/projectdiscovery/utils/reader"
+)
+
+// Body is a component for a request body
+type Body struct {
+ value *Value
+
+ req *retryablehttp.Request
+}
+
+var _ Component = &Body{}
+
+// NewBody creates a new body component
+func NewBody() *Body {
+ return &Body{}
+}
+
+// Name returns the name of the component
+func (b *Body) Name() string {
+ return RequestBodyComponent
+}
+
+// Parse parses the component and returns the
+// parsed component
+func (b *Body) Parse(req *retryablehttp.Request) (bool, error) {
+ if req.Body == nil {
+ return false, nil
+ }
+ b.req = req
+
+ contentType := req.Header.Get("Content-Type")
+
+ data, err := io.ReadAll(req.Body)
+ if err != nil {
+ return false, errors.Wrap(err, "could not read body")
+ }
+ req.Body = io.NopCloser(bytes.NewReader(data))
+ dataStr := string(data)
+
+ if dataStr == "" {
+ return false, nil
+ }
+
+ b.value = NewValue(dataStr)
+ if b.value.Parsed() != nil {
+ return true, nil
+ }
+
+ switch {
+ case strings.Contains(contentType, "application/json") && b.value.Parsed() == nil:
+ return b.parseBody(dataformat.JSONDataFormat, req)
+ case strings.Contains(contentType, "application/xml") && b.value.Parsed() == nil:
+ return b.parseBody(dataformat.XMLDataFormat, req)
+ case strings.Contains(contentType, "multipart/form-data") && b.value.Parsed() == nil:
+ return b.parseBody(dataformat.MultiPartFormDataFormat, req)
+ }
+ parsed, err := b.parseBody(dataformat.FormDataFormat, req)
+ if err != nil {
+ gologger.Warning().Msgf("Could not parse body as form data: %s\n", err)
+ return b.parseBody(dataformat.RawDataFormat, req)
+ }
+ return parsed, err
+}
+
+// parseBody parses a body with a custom decoder
+func (b *Body) parseBody(decoderName string, req *retryablehttp.Request) (bool, error) {
+ decoder := dataformat.Get(decoderName)
+ if decoderName == dataformat.MultiPartFormDataFormat {
+ // set content type to extract boundary
+ if err := decoder.(*dataformat.MultiPartForm).ParseBoundary(req.Header.Get("Content-Type")); err != nil {
+ return false, errors.Wrap(err, "could not parse boundary")
+ }
+ }
+ decoded, err := decoder.Decode(b.value.String())
+ if err != nil {
+ return false, errors.Wrap(err, "could not decode raw")
+ }
+ b.value.SetParsed(decoded, decoder.Name())
+ return true, nil
+}
+
+// Iterate iterates through the component
+func (b *Body) Iterate(callback func(key string, value interface{}) error) error {
+ for key, value := range b.value.Parsed() {
+ if strings.HasPrefix(key, "#_") {
+ continue
+ }
+ if err := callback(key, value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SetValue sets a value in the component
+func (b *Body) SetValue(key string, value string) error {
+ if !b.value.SetParsedValue(key, value) {
+ return ErrSetValue
+ }
+ return nil
+}
+
+// Delete deletes a key from the component
+func (b *Body) Delete(key string) error {
+ if !b.value.Delete(key) {
+ return ErrKeyNotFound
+ }
+ return nil
+}
+
+// Rebuild returns a new request with the
+// component rebuilt
+func (b *Body) Rebuild() (*retryablehttp.Request, error) {
+ encoded, err := b.value.Encode()
+ if err != nil {
+ return nil, errors.Wrap(err, "could not encode body")
+ }
+ cloned := b.req.Clone(context.Background())
+ reusableReader, err := readerutil.NewReusableReadCloser(encoded)
+ if err != nil {
+ return nil, errors.Wrap(err, "could not create reusable reader")
+ }
+ cloned.Body = reusableReader
+ cloned.ContentLength = int64(len(encoded))
+ cloned.Header.Set("Content-Length", strconv.Itoa(len(encoded)))
+ return cloned, nil
+}
diff --git a/pkg/fuzz/component/body_test.go b/pkg/fuzz/component/body_test.go
new file mode 100644
index 00000000..42e7e405
--- /dev/null
+++ b/pkg/fuzz/component/body_test.go
@@ -0,0 +1,175 @@
+package component
+
+import (
+ "bytes"
+ "io"
+ "mime/multipart"
+ "net/url"
+ "strings"
+ "testing"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+ "github.com/stretchr/testify/require"
+)
+
+func TestBodyComponent(t *testing.T) {
+ req, err := retryablehttp.NewRequest("POST", "https://example.com", strings.NewReader(`{"foo":"bar"}`))
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Set("Content-Type", "application/json")
+
+ body := New(RequestBodyComponent)
+ _, err = body.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var keys []string
+ var values []string
+ _ = body.Iterate(func(key string, value interface{}) error {
+ keys = append(keys, key)
+ values = append(values, value.(string))
+ return nil
+ })
+
+ require.Equal(t, []string{"foo"}, keys, "unexpected keys")
+ require.Equal(t, []string{"bar"}, values, "unexpected values")
+
+ _ = body.SetValue("foo", "baz")
+
+ rebuilt, err := body.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ newBody, err := io.ReadAll(rebuilt.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ require.Equal(t, `{"foo":"baz"}`, string(newBody), "unexpected body")
+}
+
+func TestBodyXMLComponent(t *testing.T) {
+ var body = "1 1 "
+
+ req, err := retryablehttp.NewRequest("POST", "https://example.com", strings.NewReader(body))
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Set("Content-Type", "application/xml")
+
+ bodyComponent := New(RequestBodyComponent)
+ parsed, err := bodyComponent.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ require.True(t, parsed, "could not parse body")
+
+ _ = bodyComponent.SetValue("stockCheck~productId", "2'6842")
+ rebuilt, err := bodyComponent.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ newBody, err := io.ReadAll(rebuilt.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ require.Equal(t, "2'6842 1 ", string(newBody), "unexpected body")
+}
+
+func TestBodyFormComponent(t *testing.T) {
+ formData := url.Values{}
+ formData.Set("key1", "value1")
+ formData.Set("key2", "value2")
+
+ req, err := retryablehttp.NewRequest("POST", "https://example.com", strings.NewReader(formData.Encode()))
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+ body := New(RequestBodyComponent)
+ _, err = body.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var keys []string
+ var values []string
+ _ = body.Iterate(func(key string, value interface{}) error {
+ keys = append(keys, key)
+ values = append(values, value.(string))
+ return nil
+ })
+
+ require.ElementsMatch(t, []string{"key1", "key2"}, keys, "unexpected keys")
+ require.ElementsMatch(t, []string{"value1", "value2"}, values, "unexpected values")
+
+ _ = body.SetValue("key1", "updatedValue1")
+
+ rebuilt, err := body.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ newBody, err := io.ReadAll(rebuilt.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ require.Equal(t, "key1=updatedValue1&key2=value2", string(newBody), "unexpected body")
+}
+
+func TestMultiPartFormComponent(t *testing.T) {
+ formData := &bytes.Buffer{}
+ writer := multipart.NewWriter(formData)
+
+ // Hypothetical form fields
+ _ = writer.WriteField("username", "testuser")
+ _ = writer.WriteField("password", "testpass")
+
+ contentType := writer.FormDataContentType()
+ _ = writer.Close()
+
+ req, err := retryablehttp.NewRequest("POST", "https://example.com", formData)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Set("Content-Type", contentType)
+
+ body := New(RequestBodyComponent)
+ _, err = body.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var keys []string
+ var values []string
+ _ = body.Iterate(func(key string, value interface{}) error {
+ keys = append(keys, key)
+ values = append(values, value.(string))
+ return nil
+ })
+
+ require.ElementsMatch(t, []string{"username", "password"}, keys, "unexpected keys")
+ require.ElementsMatch(t, []string{"testuser", "testpass"}, values, "unexpected values")
+
+ // Update a value in the form
+ _ = body.SetValue("password", "updatedTestPass")
+
+ rebuilt, err := body.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ newBody, err := io.ReadAll(rebuilt.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Check if the body contains the updated multipart form data
+ require.Contains(t, string(newBody), "updatedTestPass", "unexpected body content")
+ require.Contains(t, string(newBody), "username", "unexpected body content")
+ require.Contains(t, string(newBody), "testuser", "unexpected body content")
+}
diff --git a/pkg/fuzz/component/component.go b/pkg/fuzz/component/component.go
new file mode 100644
index 00000000..5a8279c4
--- /dev/null
+++ b/pkg/fuzz/component/component.go
@@ -0,0 +1,95 @@
+package component
+
+import (
+ "errors"
+ "strings"
+
+ "github.com/leslie-qiwa/flat"
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+// ErrSetValue is a error raised when a value cannot be set
+var ErrSetValue = errors.New("could not set value")
+
+func IsErrSetValue(err error) bool {
+ if err == nil {
+ return false
+ }
+ return strings.Contains(err.Error(), "could not set value")
+}
+
+// ErrKeyNotFound is a error raised when a key is not found
+var ErrKeyNotFound = errors.New("key not found")
+
+// Component is a component for a request
+type Component interface {
+ // Name returns the name of the component
+ Name() string
+ // Parse parses the component and returns the
+ // parsed component
+ Parse(req *retryablehttp.Request) (bool, error)
+ // Iterate iterates over all values of a component
+ // ex in case of query component, it will iterate over each query parameter
+ // depending on the rule if mode is single
+ // request is rebuilt for each value in this callback
+ // and in case of multiple, request will be rebuilt after iteration of all values
+ Iterate(func(key string, value interface{}) error) error
+ // SetValue sets a value in the component
+ // for a key
+ //
+ // After calling setValue for mutation, the value must be
+ // called again so as to reset the body to its original state.
+ SetValue(key string, value string) error
+ // Delete deletes a key from the component
+ // If it is applicable
+ Delete(key string) error
+ // Rebuild returns a new request with the
+ // component rebuilt
+ Rebuild() (*retryablehttp.Request, error)
+}
+
+const (
+ // RequestBodyComponent is the name of the request body component
+ RequestBodyComponent = "body"
+ // RequestQueryComponent is the name of the request query component
+ RequestQueryComponent = "query"
+ // RequestPathComponent is the name of the request url component
+ RequestPathComponent = "path"
+ // RequestHeaderComponent is the name of the request header component
+ RequestHeaderComponent = "header"
+ // RequestCookieComponent is the name of the request cookie component
+ RequestCookieComponent = "cookie"
+)
+
+// Components is a list of all available components
+var Components = []string{
+ RequestBodyComponent,
+ RequestQueryComponent,
+ RequestPathComponent,
+ RequestHeaderComponent,
+ RequestCookieComponent,
+}
+
+// New creates a new component for a componentType
+func New(componentType string) Component {
+ switch componentType {
+ case "body":
+ return NewBody()
+ case "query":
+ return NewQuery()
+ case "path":
+ return NewPath()
+ case "header":
+ return NewHeader()
+ case "cookie":
+ return NewCookie()
+ }
+ return nil
+}
+
+var (
+ flatOpts = &flat.Options{
+ Safe: true,
+ Delimiter: "~",
+ }
+)
diff --git a/pkg/fuzz/component/cookie.go b/pkg/fuzz/component/cookie.go
new file mode 100644
index 00000000..7269284c
--- /dev/null
+++ b/pkg/fuzz/component/cookie.go
@@ -0,0 +1,138 @@
+package component
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+// Cookie is a component for a request cookie
+type Cookie struct {
+ value *Value
+
+ req *retryablehttp.Request
+}
+
+var _ Component = &Cookie{}
+
+// NewCookie creates a new cookie component
+func NewCookie() *Cookie {
+ return &Cookie{}
+}
+
+// Name returns the name of the component
+func (c *Cookie) Name() string {
+ return RequestCookieComponent
+}
+
+// Parse parses the component and returns the
+// parsed component
+func (c *Cookie) Parse(req *retryablehttp.Request) (bool, error) {
+ if len(req.Cookies()) == 0 {
+ return false, nil
+ }
+ c.req = req
+ c.value = NewValue("")
+
+ parsedCookies := make(map[string]interface{})
+ for _, cookie := range req.Cookies() {
+ parsedCookies[cookie.Name] = cookie.Value
+ }
+ if len(parsedCookies) == 0 {
+ return false, nil
+ }
+ c.value.SetParsed(parsedCookies, "")
+ return true, nil
+}
+
+// Iterate iterates through the component
+func (c *Cookie) Iterate(callback func(key string, value interface{}) error) error {
+ for key, value := range c.value.Parsed() {
+ // Skip ignored cookies
+ if _, ok := defaultIgnoredCookieKeys[key]; ok {
+ continue
+ }
+ if err := callback(key, value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SetValue sets a value in the component
+// for a key
+func (c *Cookie) SetValue(key string, value string) error {
+ if !c.value.SetParsedValue(key, value) {
+ return ErrSetValue
+ }
+ return nil
+}
+
+// Delete deletes a key from the component
+func (c *Cookie) Delete(key string) error {
+ if !c.value.Delete(key) {
+ return ErrKeyNotFound
+ }
+ return nil
+}
+
+// Rebuild returns a new request with the
+// component rebuilt
+func (c *Cookie) Rebuild() (*retryablehttp.Request, error) {
+ cloned := c.req.Clone(context.Background())
+
+ cloned.Header.Del("Cookie")
+ for key, value := range c.value.Parsed() {
+ cookie := &http.Cookie{
+ Name: key,
+ Value: value.(string), // Assume the value is always a string for cookies
+ }
+ cloned.AddCookie(cookie)
+ }
+ return cloned, nil
+}
+
+// A list of cookies that are essential to the request and
+// must not be fuzzed.
+var defaultIgnoredCookieKeys = map[string]struct{}{
+ "awsELB": {},
+ "AWSALB": {},
+ "AWSALBCORS": {},
+ "__utma": {},
+ "__utmb": {},
+ "__utmc": {},
+ "__utmt": {},
+ "__utmz": {},
+ "_ga": {},
+ "_gat": {},
+ "_gid": {},
+ "_gcl_au": {},
+ "_fbp": {},
+ "fr": {},
+ "__hstc": {},
+ "hubspotutk": {},
+ "__hssc": {},
+ "__hssrc": {},
+ "mp_mixpanel__c": {},
+ "JSESSIONID": {},
+ "NREUM": {},
+ "_pk_id": {},
+ "_pk_ref": {},
+ "_pk_ses": {},
+ "_pk_cvar": {},
+ "_pk_hsr": {},
+ "_hjIncludedInSample": {},
+ "__cfduid": {},
+ "cf_use_ob": {},
+ "cf_ob_info": {},
+ "intercom-session": {},
+ "optimizelyEndUserId": {},
+ "optimizelySegments": {},
+ "optimizelyBuckets": {},
+ "optimizelyPendingLogEvents": {},
+ "YSC": {},
+ "VISITOR_INFO1_LIVE": {},
+ "PREF": {},
+ "GPS": {},
+}
diff --git a/pkg/fuzz/component/cookie_test.go b/pkg/fuzz/component/cookie_test.go
new file mode 100644
index 00000000..2e4ea947
--- /dev/null
+++ b/pkg/fuzz/component/cookie_test.go
@@ -0,0 +1,57 @@
+package component
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCookieComponent(t *testing.T) {
+ req, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cookie := &http.Cookie{
+ Name: "session",
+ Value: "test-session",
+ }
+ req.AddCookie(cookie)
+
+ cookieComponent := NewCookie() // Assuming you have a function like this for creating a new cookie component
+ _, err = cookieComponent.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var cookieNames []string
+ var cookieValues []string
+ _ = cookieComponent.Iterate(func(key string, value interface{}) error {
+ cookieNames = append(cookieNames, key)
+ switch v := value.(type) {
+ case string:
+ cookieValues = append(cookieValues, v)
+ case []string:
+ cookieValues = append(cookieValues, v...)
+ }
+ return nil
+ })
+
+ require.Equal(t, []string{"session"}, cookieNames, "unexpected cookie names")
+ require.Equal(t, []string{"test-session"}, cookieValues, "unexpected cookie values")
+
+ err = cookieComponent.SetValue("session", "new-session")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rebuilt, err := cookieComponent.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Assuming the Rebuild function will reconstruct the entire request and also set the modified cookies
+ newCookie, _ := rebuilt.Cookie("session")
+ require.Equal(t, "new-session", newCookie.Value, "unexpected cookie value")
+}
diff --git a/pkg/fuzz/component/headers.go b/pkg/fuzz/component/headers.go
new file mode 100644
index 00000000..60ac9804
--- /dev/null
+++ b/pkg/fuzz/component/headers.go
@@ -0,0 +1,186 @@
+package component
+
+import (
+ "context"
+ "strings"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+// Header is a component for a request header
+type Header struct {
+ value *Value
+
+ req *retryablehttp.Request
+}
+
+var _ Component = &Header{}
+
+// NewHeader creates a new header component
+func NewHeader() *Header {
+ return &Header{}
+}
+
+// Name returns the name of the component
+func (q *Header) Name() string {
+ return RequestHeaderComponent
+}
+
+// Parse parses the component and returns the
+// parsed component
+func (q *Header) Parse(req *retryablehttp.Request) (bool, error) {
+ q.req = req
+ q.value = NewValue("")
+
+ parsedHeaders := make(map[string]interface{})
+ for key, value := range req.Header {
+ if len(value) == 1 {
+ parsedHeaders[key] = value[0]
+ continue
+ }
+ parsedHeaders[key] = value
+ }
+ q.value.SetParsed(parsedHeaders, "")
+ return true, nil
+}
+
+// Iterate iterates through the component
+func (q *Header) Iterate(callback func(key string, value interface{}) error) error {
+ for key, value := range q.value.Parsed() {
+ // Skip ignored headers
+ if _, ok := defaultIgnoredHeaderKeys[key]; ok {
+ continue
+ }
+ if err := callback(key, value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SetValue sets a value in the component
+// for a key
+func (q *Header) SetValue(key string, value string) error {
+ if !q.value.SetParsedValue(key, value) {
+ return ErrSetValue
+ }
+ return nil
+}
+
+// Delete deletes a key from the component
+func (q *Header) Delete(key string) error {
+ if !q.value.Delete(key) {
+ return ErrKeyNotFound
+ }
+ return nil
+}
+
+// Rebuild returns a new request with the
+// component rebuilt
+func (q *Header) Rebuild() (*retryablehttp.Request, error) {
+ cloned := q.req.Clone(context.Background())
+ for key, value := range q.value.parsed {
+ if strings.EqualFold(key, "Host") {
+ cloned.Host = value.(string)
+ }
+ switch v := value.(type) {
+ case []interface{}:
+ for _, vv := range v {
+ if cloned.Header[key] == nil {
+ cloned.Header[key] = make([]string, 0)
+ }
+ cloned.Header[key] = append(cloned.Header[key], vv.(string))
+ }
+ case string:
+ cloned.Header[key] = []string{v}
+ }
+ }
+ return cloned, nil
+}
+
+// A list of headers that are essential to the request and
+// must not be fuzzed.
+var defaultIgnoredHeaderKeys = map[string]struct{}{
+ "Accept-Charset": {},
+ "Accept-Datetime": {},
+ "Accept-Encoding": {},
+ "Accept-Language": {},
+ "Accept": {},
+ "Access-Control-Request-Headers": {},
+ "Access-Control-Request-Method": {},
+ "Authorization": {},
+ "Cache-Control": {},
+ "Connection": {},
+ "Cookie": {},
+ "Content-Length": {},
+ "Content-Type": {},
+ "Date": {},
+ "Dnt": {},
+ "Expect": {},
+ "Forwarded": {},
+ "From": {},
+ "Host": {},
+ "If-Match": {},
+ "If-Modified-Since": {},
+ "If-None-Match": {},
+ "If-Range": {},
+ "If-Unmodified-Since": {},
+ "Max-Forwards": {},
+ "Pragma": {},
+ "Priority": {},
+ "Proxy-Authorization": {},
+ "Range": {},
+ "Sec-Ch-Ua": {},
+ "Sec-Ch-Ua-Mobile": {},
+ "Sec-Ch-Ua-Platform": {},
+ "Sec-Fetch-Dest": {},
+ "Sec-Fetch-Mode": {},
+ "Sec-Fetch-Site": {},
+ "Sec-Fetch-User": {},
+ "TE": {},
+ "Upgrade": {},
+ "Via": {},
+ "Warning": {},
+ "Upgrade-Insecure-Requests": {},
+ "X-CSRF-Token": {},
+ "X-Requested-With": {},
+ "Strict-Transport-Security": {},
+ "Content-Security-Policy": {},
+ "X-Content-Type-Options": {},
+ "X-Frame-Options": {},
+ "X-XSS-Protection": {},
+ "Public-Key-Pins": {},
+ "Referrer-Policy": {},
+ "Access-Control-Allow-Origin": {},
+ "Access-Control-Allow-Credentials": {},
+ "Access-Control-Expose-Headers": {},
+ "Access-Control-Max-Age": {},
+ "Access-Control-Allow-Methods": {},
+ "Access-Control-Allow-Headers": {},
+ "Server": {},
+ "X-Powered-By": {},
+ "X-AspNet-Version": {},
+ "X-AspNetMvc-Version": {},
+ "ETag": {},
+ "Vary": {},
+ "Expires": {},
+ "Last-Modified": {},
+ "X-Cache": {},
+ "X-Proxy-ID": {},
+ "CF-Ray": {}, // Cloudflare
+ "X-Served-By": {}, // Varnish, etc.
+ "X-Cache-Hits": {},
+ "Content-Encoding": {},
+ "Transfer-Encoding": {},
+ "Location": {},
+ "WWW-Authenticate": {},
+ "Proxy-Authenticate": {},
+ "X-Access-Token": {},
+ "X-Refresh-Token": {},
+ "Link": {},
+ "X-Content-Duration": {},
+ "X-UA-Compatible": {},
+ "X-RateLimit-Limit": {}, // Rate limiting header
+ "X-RateLimit-Remaining": {}, // Rate limiting header
+ "X-RateLimit-Reset": {}, // Rate limiting header
+}
diff --git a/pkg/fuzz/component/headers_test.go b/pkg/fuzz/component/headers_test.go
new file mode 100644
index 00000000..db5574a3
--- /dev/null
+++ b/pkg/fuzz/component/headers_test.go
@@ -0,0 +1,51 @@
+package component
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+ "github.com/stretchr/testify/require"
+)
+
+func TestHeaderComponent(t *testing.T) {
+ req, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Set("User-Agent", "test-agent")
+
+ header := NewHeader()
+ _, err = header.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var keys []string
+ var values []string
+ _ = header.Iterate(func(key string, value interface{}) error {
+ keys = append(keys, key)
+ switch v := value.(type) {
+ case string:
+ values = append(values, v)
+ case []string:
+ values = append(values, v...)
+ }
+ return nil
+ })
+
+ require.Equal(t, []string{"User-Agent"}, keys, "unexpected keys")
+ require.Equal(t, []string{"test-agent"}, values, "unexpected values")
+
+ err = header.SetValue("User-Agent", "new-agent")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rebuilt, err := header.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ require.Equal(t, "new-agent", rebuilt.Header.Get("User-Agent"), "unexpected header value")
+}
diff --git a/pkg/fuzz/component/path.go b/pkg/fuzz/component/path.go
new file mode 100644
index 00000000..c1d31cee
--- /dev/null
+++ b/pkg/fuzz/component/path.go
@@ -0,0 +1,83 @@
+package component
+
+import (
+ "context"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+// Path is a component for a request Path
+type Path struct {
+ value *Value
+
+ req *retryablehttp.Request
+}
+
+var _ Component = &Path{}
+
+// NewPath creates a new URL component
+func NewPath() *Path {
+ return &Path{}
+}
+
+// Name returns the name of the component
+func (q *Path) Name() string {
+ return RequestPathComponent
+}
+
+// Parse parses the component and returns the
+// parsed component
+func (q *Path) Parse(req *retryablehttp.Request) (bool, error) {
+ q.req = req
+ q.value = NewValue(req.URL.Path)
+
+ parsed, err := dataformat.Get(dataformat.RawDataFormat).Decode(q.value.String())
+ if err != nil {
+ return false, err
+ }
+ q.value.SetParsed(parsed, dataformat.RawDataFormat)
+ return true, nil
+}
+
+// Iterate iterates through the component
+func (q *Path) Iterate(callback func(key string, value interface{}) error) error {
+ for key, value := range q.value.Parsed() {
+ if err := callback(key, value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SetValue sets a value in the component
+// for a key
+func (q *Path) SetValue(key string, value string) error {
+ if !q.value.SetParsedValue(key, value) {
+ return ErrSetValue
+ }
+ return nil
+}
+
+// Delete deletes a key from the component
+func (q *Path) Delete(key string) error {
+ if !q.value.Delete(key) {
+ return ErrKeyNotFound
+ }
+ return nil
+}
+
+// Rebuild returns a new request with the
+// component rebuilt
+func (q *Path) Rebuild() (*retryablehttp.Request, error) {
+ encoded, err := q.value.Encode()
+ if err != nil {
+ return nil, errors.Wrap(err, "could not encode query")
+ }
+ cloned := q.req.Clone(context.Background())
+ if err := cloned.UpdateRelPath(encoded, true); err != nil {
+ cloned.URL.RawPath = encoded
+ }
+ return cloned, nil
+}
diff --git a/pkg/fuzz/component/path_test.go b/pkg/fuzz/component/path_test.go
new file mode 100644
index 00000000..859ffcde
--- /dev/null
+++ b/pkg/fuzz/component/path_test.go
@@ -0,0 +1,46 @@
+package component
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+ "github.com/stretchr/testify/require"
+)
+
+func TestURLComponent(t *testing.T) {
+ req, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com/testpath", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ urlComponent := NewPath()
+ _, err = urlComponent.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var keys []string
+ var values []string
+ _ = urlComponent.Iterate(func(key string, value interface{}) error {
+ keys = append(keys, key)
+ values = append(values, value.(string))
+ return nil
+ })
+
+ require.Equal(t, []string{"value"}, keys, "unexpected keys")
+ require.Equal(t, []string{"/testpath"}, values, "unexpected values")
+
+ err = urlComponent.SetValue("value", "/newpath")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rebuilt, err := urlComponent.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ require.Equal(t, "/newpath", rebuilt.URL.Path, "unexpected URL path")
+ require.Equal(t, "https://example.com/newpath", rebuilt.URL.String(), "unexpected full URL")
+}
diff --git a/pkg/fuzz/component/query.go b/pkg/fuzz/component/query.go
new file mode 100644
index 00000000..0952c979
--- /dev/null
+++ b/pkg/fuzz/component/query.go
@@ -0,0 +1,92 @@
+package component
+
+import (
+ "context"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
+ "github.com/projectdiscovery/retryablehttp-go"
+ urlutil "github.com/projectdiscovery/utils/url"
+)
+
+// Query is a component for a request query
+type Query struct {
+ value *Value
+
+ req *retryablehttp.Request
+}
+
+var _ Component = &Query{}
+
+// NewQuery creates a new query component
+func NewQuery() *Query {
+ return &Query{}
+}
+
+// Name returns the name of the component
+func (q *Query) Name() string {
+ return RequestQueryComponent
+}
+
+// Parse parses the component and returns the
+// parsed component
+func (q *Query) Parse(req *retryablehttp.Request) (bool, error) {
+ if req.URL.Query().IsEmpty() {
+ return false, nil
+ }
+ q.req = req
+
+ q.value = NewValue(req.URL.Query().Encode())
+
+ parsed, err := dataformat.Get(dataformat.FormDataFormat).Decode(q.value.String())
+ if err != nil {
+ return false, err
+ }
+ q.value.SetParsed(parsed, dataformat.FormDataFormat)
+ return true, nil
+}
+
+// Iterate iterates through the component
+func (q *Query) Iterate(callback func(key string, value interface{}) error) error {
+ for key, value := range q.value.Parsed() {
+ if err := callback(key, value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SetValue sets a value in the component
+// for a key
+func (q *Query) SetValue(key string, value string) error {
+ if !q.value.SetParsedValue(key, value) {
+ return ErrSetValue
+ }
+ return nil
+}
+
+// Delete deletes a key from the component
+func (q *Query) Delete(key string) error {
+ if !q.value.Delete(key) {
+ return ErrKeyNotFound
+ }
+ return nil
+}
+
+// Rebuild returns a new request with the
+// component rebuilt
+func (q *Query) Rebuild() (*retryablehttp.Request, error) {
+ encoded, err := q.value.Encode()
+ if err != nil {
+ return nil, errors.Wrap(err, "could not encode query")
+ }
+ cloned := q.req.Clone(context.Background())
+ cloned.URL.RawQuery = encoded
+
+ // Clear the query parameters and re-add them
+ cloned.Params = nil
+ cloned.Params = urlutil.NewOrderedParams()
+ cloned.Params.Decode(encoded)
+ cloned.Update()
+ return cloned, nil
+}
diff --git a/pkg/fuzz/component/query_test.go b/pkg/fuzz/component/query_test.go
new file mode 100644
index 00000000..48fe5aa2
--- /dev/null
+++ b/pkg/fuzz/component/query_test.go
@@ -0,0 +1,46 @@
+package component
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+ "github.com/stretchr/testify/require"
+)
+
+func TestQueryComponent(t *testing.T) {
+ req, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com?foo=bar", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ query := NewQuery()
+ _, err = query.Parse(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var keys []string
+ var values []string
+ _ = query.Iterate(func(key string, value interface{}) error {
+ keys = append(keys, key)
+ values = append(values, value.(string))
+ return nil
+ })
+
+ require.Equal(t, []string{"foo"}, keys, "unexpected keys")
+ require.Equal(t, []string{"bar"}, values, "unexpected values")
+
+ err = query.SetValue("foo", "baz")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rebuilt, err := query.Rebuild()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ require.Equal(t, "foo=baz", rebuilt.URL.RawQuery, "unexpected query string")
+ require.Equal(t, "https://example.com?foo=baz", rebuilt.URL.String(), "unexpected url")
+}
diff --git a/pkg/fuzz/component/value.go b/pkg/fuzz/component/value.go
new file mode 100644
index 00000000..c6d7a960
--- /dev/null
+++ b/pkg/fuzz/component/value.go
@@ -0,0 +1,120 @@
+package component
+
+import (
+ "strconv"
+
+ "github.com/leslie-qiwa/flat"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
+)
+
+// Value is a value component containing a single
+// parameter for the component
+//
+// It is a type of container that is used to represent
+// all the data values that are used in a request.
+type Value struct {
+ data string
+ parsed map[string]interface{}
+ dataFormat string
+}
+
+// NewValue returns a new value component
+func NewValue(data string) *Value {
+ if data == "" {
+ return &Value{}
+ }
+ v := &Value{data: data}
+
+ // Do any dataformat decoding on the data if needed
+ decodedDataformat, err := dataformat.Decode(data)
+ if err == nil && decodedDataformat != nil {
+ v.SetParsed(decodedDataformat.Data, decodedDataformat.DataFormat)
+ }
+ return v
+}
+
+// String returns the string representation of the value
+func (v *Value) String() string {
+ return v.data
+}
+
+// Parsed returns the parsed value
+func (v *Value) Parsed() map[string]interface{} {
+ return v.parsed
+}
+
+// SetParsed sets the parsed value map
+func (v *Value) SetParsed(parsed map[string]interface{}, dataFormat string) {
+ flattened, err := flat.Flatten(parsed, flatOpts)
+ if err == nil {
+ v.parsed = flattened
+ } else {
+ v.parsed = parsed
+ }
+ v.dataFormat = dataFormat
+}
+
+// SetParsedValue sets the parsed value for a key
+// in the parsed map
+func (v *Value) SetParsedValue(key string, value string) bool {
+ origValue, ok := v.parsed[key]
+ if !ok {
+ v.parsed[key] = value
+ return true
+ }
+ // If the value is a list, append to it
+ // otherwise replace it
+ switch v := origValue.(type) {
+ case []interface{}:
+ origValue = append(v, value)
+ case string:
+ origValue = value
+ case int, int32, int64, float32, float64:
+ parsed, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return false
+ }
+ origValue = parsed
+ case bool:
+ parsed, err := strconv.ParseBool(value)
+ if err != nil {
+ return false
+ }
+ origValue = parsed
+ case nil:
+ origValue = value
+ default:
+ gologger.Error().Msgf("unknown type %T for value %s", v, v)
+ }
+ v.parsed[key] = origValue
+ return true
+}
+
+// Delete removes a key from the parsed value
+func (v *Value) Delete(key string) bool {
+ if _, ok := v.parsed[key]; !ok {
+ return false
+ }
+ delete(v.parsed, key)
+ return true
+}
+
+// Encode encodes the value into a string
+// using the dataformat and encoding
+func (v *Value) Encode() (string, error) {
+ toEncodeStr := v.data
+
+ nested, err := flat.Unflatten(v.parsed, flatOpts)
+ if err != nil {
+ return "", err
+ }
+ if v.dataFormat != "" {
+ dataformatStr, err := dataformat.Encode(nested, v.dataFormat)
+ if err != nil {
+ return "", err
+ }
+ toEncodeStr = dataformatStr
+ }
+ return toEncodeStr, nil
+}
diff --git a/pkg/fuzz/component/value_test.go b/pkg/fuzz/component/value_test.go
new file mode 100644
index 00000000..bafd0277
--- /dev/null
+++ b/pkg/fuzz/component/value_test.go
@@ -0,0 +1,39 @@
+package component
+
+import (
+ "testing"
+
+ "github.com/leslie-qiwa/flat"
+ "github.com/stretchr/testify/require"
+)
+
+func TestFlatMap_FlattenUnflatten(t *testing.T) {
+ data := map[string]interface{}{
+ "foo": "bar",
+ "bar": map[string]interface{}{
+ "baz": "foo",
+ },
+ "slice": []interface{}{
+ "foo",
+ "bar",
+ },
+ "with.dot": map[string]interface{}{
+ "foo": "bar",
+ },
+ }
+
+ opts := &flat.Options{
+ Safe: true,
+ Delimiter: "~",
+ }
+ flattened, err := flat.Flatten(data, opts)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ nested, err := flat.Unflatten(flattened, opts)
+ if err != nil {
+ t.Fatal(err)
+ }
+ require.Equal(t, data, nested, "unexpected data")
+}
diff --git a/pkg/fuzz/dataformat/dataformat.go b/pkg/fuzz/dataformat/dataformat.go
new file mode 100644
index 00000000..a07abc28
--- /dev/null
+++ b/pkg/fuzz/dataformat/dataformat.go
@@ -0,0 +1,92 @@
+package dataformat
+
+import (
+ "errors"
+ "fmt"
+)
+
+// dataformats is a list of dataformats
+var dataformats map[string]DataFormat
+
+func init() {
+ dataformats = make(map[string]DataFormat)
+
+ // register the default data formats
+ RegisterDataFormat(NewJSON())
+ RegisterDataFormat(NewXML())
+ RegisterDataFormat(NewRaw())
+ RegisterDataFormat(NewForm())
+ RegisterDataFormat(NewMultiPartForm())
+}
+
+const (
+ // JSONDataFormat is the name of the JSON data format
+ JSONDataFormat = "json"
+ // XMLDataFormat is the name of the XML data format
+ XMLDataFormat = "xml"
+ // RawDataFormat is the name of the Raw data format
+ RawDataFormat = "raw"
+ // FormDataFormat is the name of the Form data format
+ FormDataFormat = "form"
+ // MultiPartFormDataFormat is the name of the MultiPartForm data format
+ MultiPartFormDataFormat = "multipart/form-data"
+)
+
+// Get returns the dataformat by name
+func Get(name string) DataFormat {
+ return dataformats[name]
+}
+
+// RegisterEncoder registers an encoder
+func RegisterDataFormat(dataformat DataFormat) {
+ dataformats[dataformat.Name()] = dataformat
+}
+
+// DataFormat is an interface for encoding and decoding
+type DataFormat interface {
+ // IsType returns true if the data is of the type
+ IsType(data string) bool
+ // Name returns the name of the encoder
+ Name() string
+ // Encode encodes the data into a format
+ Encode(data map[string]interface{}) (string, error)
+ // Decode decodes the data from a format
+ Decode(input string) (map[string]interface{}, error)
+}
+
+// Decoded is a decoded data format
+type Decoded struct {
+ // DataFormat is the data format
+ DataFormat string
+ // Data is the decoded data
+ Data map[string]interface{}
+}
+
+// Decode decodes the data from a format
+func Decode(data string) (*Decoded, error) {
+ for _, dataformat := range dataformats {
+ if dataformat.IsType(data) {
+ decoded, err := dataformat.Decode(data)
+ if err != nil {
+ return nil, err
+ }
+ value := &Decoded{
+ DataFormat: dataformat.Name(),
+ Data: decoded,
+ }
+ return value, nil
+ }
+ }
+ return nil, nil
+}
+
+// Encode encodes the data into a format
+func Encode(data map[string]interface{}, dataformat string) (string, error) {
+ if dataformat == "" {
+ return "", errors.New("dataformat is required")
+ }
+ if encoder, ok := dataformats[dataformat]; ok {
+ return encoder.Encode(data)
+ }
+ return "", fmt.Errorf("dataformat %s is not supported", dataformat)
+}
diff --git a/pkg/fuzz/dataformat/dataformat_test.go b/pkg/fuzz/dataformat/dataformat_test.go
new file mode 100644
index 00000000..7595f9b9
--- /dev/null
+++ b/pkg/fuzz/dataformat/dataformat_test.go
@@ -0,0 +1,54 @@
+package dataformat
+
+import (
+ "testing"
+)
+
+func TestDataformatDecodeEncode_JSON(t *testing.T) {
+ obj := `{"foo":"bar"}`
+
+ decoded, err := Decode(obj)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if decoded.DataFormat != "json" {
+ t.Fatal("unexpected data format")
+ }
+ if decoded.Data["foo"] != "bar" {
+ t.Fatal("unexpected data")
+ }
+
+ encoded, err := Encode(decoded.Data, decoded.DataFormat)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if encoded != obj {
+ t.Fatal("unexpected data")
+ }
+}
+
+func TestDataformatDecodeEncode_XML(t *testing.T) {
+ obj := `bar `
+
+ decoded, err := Decode(obj)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if decoded.DataFormat != "xml" {
+ t.Fatal("unexpected data format")
+ }
+ if decoded.Data["foo"].(map[string]interface{})["#text"] != "bar" {
+ t.Fatal("unexpected data")
+ }
+ if decoded.Data["foo"].(map[string]interface{})["-attr"] != "baz" {
+ t.Fatal("unexpected data")
+ }
+
+ encoded, err := Encode(decoded.Data, decoded.DataFormat)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if encoded != obj {
+ t.Fatal("unexpected data")
+ }
+}
diff --git a/pkg/fuzz/dataformat/form.go b/pkg/fuzz/dataformat/form.go
new file mode 100644
index 00000000..088a62fe
--- /dev/null
+++ b/pkg/fuzz/dataformat/form.go
@@ -0,0 +1,61 @@
+package dataformat
+
+import (
+ "net/url"
+)
+
+type Form struct{}
+
+var (
+ _ DataFormat = &Form{}
+)
+
+// NewForm returns a new Form encoder
+func NewForm() *Form {
+ return &Form{}
+}
+
+// IsType returns true if the data is Form encoded
+func (f *Form) IsType(data string) bool {
+ return false
+}
+
+// Encode encodes the data into Form format
+func (f *Form) Encode(data map[string]interface{}) (string, error) {
+ query := url.Values{}
+ for key, value := range data {
+ switch v := value.(type) {
+ case []interface{}:
+ for _, val := range v {
+ query.Add(key, val.(string))
+ }
+ case string:
+ query.Set(key, v)
+ }
+ }
+ encoded := query.Encode()
+ return encoded, nil
+}
+
+// Decode decodes the data from Form format
+func (f *Form) Decode(data string) (map[string]interface{}, error) {
+ parsed, err := url.ParseQuery(data)
+ if err != nil {
+ return nil, err
+ }
+
+ values := make(map[string]interface{})
+ for key, value := range parsed {
+ if len(value) == 1 {
+ values[key] = value[0]
+ } else {
+ values[key] = value
+ }
+ }
+ return values, nil
+}
+
+// Name returns the name of the encoder
+func (f *Form) Name() string {
+ return FormDataFormat
+}
diff --git a/pkg/fuzz/dataformat/json.go b/pkg/fuzz/dataformat/json.go
new file mode 100644
index 00000000..3979ed5e
--- /dev/null
+++ b/pkg/fuzz/dataformat/json.go
@@ -0,0 +1,48 @@
+package dataformat
+
+import (
+ "strings"
+
+ jsoniter "github.com/json-iterator/go"
+)
+
+// JSON is a JSON encoder
+//
+// For now JSON only supports objects as the root data type
+// and not arrays
+//
+// TODO: Support arrays + other JSON oddities by
+// adding more attirbutes to the map[string]interface{}
+type JSON struct{}
+
+var (
+ _ DataFormat = &JSON{}
+)
+
+// NewJSON returns a new JSON encoder
+func NewJSON() *JSON {
+ return &JSON{}
+}
+
+// IsType returns true if the data is JSON encoded
+func (j *JSON) IsType(data string) bool {
+ return strings.HasPrefix(data, "{") && strings.HasSuffix(data, "}")
+}
+
+// Encode encodes the data into JSON format
+func (j *JSON) Encode(data map[string]interface{}) (string, error) {
+ encoded, err := jsoniter.Marshal(data)
+ return string(encoded), err
+}
+
+// Decode decodes the data from JSON format
+func (j *JSON) Decode(data string) (map[string]interface{}, error) {
+ var decoded map[string]interface{}
+ err := jsoniter.Unmarshal([]byte(data), &decoded)
+ return decoded, err
+}
+
+// Name returns the name of the encoder
+func (j *JSON) Name() string {
+ return JSONDataFormat
+}
diff --git a/pkg/fuzz/dataformat/multipart.go b/pkg/fuzz/dataformat/multipart.go
new file mode 100644
index 00000000..658f77b3
--- /dev/null
+++ b/pkg/fuzz/dataformat/multipart.go
@@ -0,0 +1,116 @@
+package dataformat
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "mime"
+ "mime/multipart"
+)
+
+type MultiPartForm struct {
+ boundary string
+}
+
+var (
+ _ DataFormat = &MultiPartForm{}
+)
+
+// NewMultiPartForm returns a new MultiPartForm encoder
+func NewMultiPartForm() *MultiPartForm {
+ return &MultiPartForm{}
+}
+
+// IsType returns true if the data is MultiPartForm encoded
+func (m *MultiPartForm) IsType(data string) bool {
+ // This method should be implemented to detect if the data is multipart form encoded
+ return false
+}
+
+// Encode encodes the data into MultiPartForm format
+func (m *MultiPartForm) Encode(data map[string]interface{}) (string, error) {
+ var b bytes.Buffer
+ w := multipart.NewWriter(&b)
+ if err := w.SetBoundary(m.boundary); err != nil {
+ return "", err
+ }
+
+ for key, value := range data {
+ var fw io.Writer
+ var err error
+ // Add field
+ if fw, err = w.CreateFormField(key); err != nil {
+ return "", err
+ }
+ if _, err = fw.Write([]byte(value.(string))); err != nil {
+ return "", err
+ }
+ }
+
+ w.Close()
+ return b.String(), nil
+}
+
+// ParseBoundary parses the boundary from the content type
+func (m *MultiPartForm) ParseBoundary(contentType string) error {
+ _, params, err := mime.ParseMediaType(contentType)
+ if err != nil {
+ return err
+ }
+ m.boundary = params["boundary"]
+ if m.boundary == "" {
+ return fmt.Errorf("no boundary found in the content type")
+ }
+ return nil
+}
+
+// Decode decodes the data from MultiPartForm format
+func (m *MultiPartForm) Decode(data string) (map[string]interface{}, error) {
+ // Create a buffer from the string data
+ b := bytes.NewBufferString(data)
+ // The boundary parameter should be extracted from the Content-Type header of the HTTP request
+ // which is not available in this context, so this is a placeholder for demonstration.
+ // You will need to pass the actual boundary value to this function.
+ r := multipart.NewReader(b, m.boundary)
+
+ form, err := r.ReadForm(32 << 20) // 32MB is the max memory used to parse the form
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ _ = form.RemoveAll()
+ }()
+
+ result := make(map[string]interface{})
+ for key, values := range form.Value {
+ if len(values) > 1 {
+ result[key] = values
+ } else {
+ result[key] = values[0]
+ }
+ }
+ for key, files := range form.File {
+ fileContents := []interface{}{}
+ for _, fileHeader := range files {
+ file, err := fileHeader.Open()
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ buffer := new(bytes.Buffer)
+ if _, err := buffer.ReadFrom(file); err != nil {
+ return nil, err
+ }
+ fileContents = append(fileContents, buffer.String())
+ }
+ result[key] = fileContents
+ }
+
+ return result, nil
+}
+
+// Name returns the name of the encoder
+func (m *MultiPartForm) Name() string {
+ return "multipart/form-data"
+}
diff --git a/pkg/fuzz/dataformat/raw.go b/pkg/fuzz/dataformat/raw.go
new file mode 100644
index 00000000..70431528
--- /dev/null
+++ b/pkg/fuzz/dataformat/raw.go
@@ -0,0 +1,34 @@
+package dataformat
+
+type Raw struct{}
+
+var (
+ _ DataFormat = &Raw{}
+)
+
+// NewRaw returns a new Raw encoder
+func NewRaw() *Raw {
+ return &Raw{}
+}
+
+// IsType returns true if the data is Raw encoded
+func (r *Raw) IsType(data string) bool {
+ return false
+}
+
+// Encode encodes the data into Raw format
+func (r *Raw) Encode(data map[string]interface{}) (string, error) {
+ return data["value"].(string), nil
+}
+
+// Decode decodes the data from Raw format
+func (r *Raw) Decode(data string) (map[string]interface{}, error) {
+ return map[string]interface{}{
+ "value": data,
+ }, nil
+}
+
+// Name returns the name of the encoder
+func (r *Raw) Name() string {
+ return RawDataFormat
+}
diff --git a/pkg/fuzz/dataformat/xml.go b/pkg/fuzz/dataformat/xml.go
new file mode 100644
index 00000000..0609031b
--- /dev/null
+++ b/pkg/fuzz/dataformat/xml.go
@@ -0,0 +1,62 @@
+package dataformat
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+
+ "github.com/clbanning/mxj/v2"
+)
+
+// XML is an XML encoder
+type XML struct{}
+
+// NewXML returns a new XML encoder
+func NewXML() *XML {
+ return &XML{}
+}
+
+// IsType returns true if the data is XML encoded
+func (x *XML) IsType(data string) bool {
+ return strings.HasPrefix(data, "<") && strings.HasSuffix(data, ">")
+}
+
+// Encode encodes the data into XML format
+func (x *XML) Encode(data map[string]interface{}) (string, error) {
+ var header string
+ if value, ok := data["#_xml_header"]; ok && value != nil {
+ header = value.(string)
+ delete(data, "#_xml_header")
+ }
+ marshalled, err := mxj.Map(data).Xml()
+ if err != nil {
+ return "", err
+ }
+ if header != "" {
+ return fmt.Sprintf("%s?>%s", header, string(marshalled)), nil
+ }
+ return string(marshalled), err
+}
+
+var xmlHeader = regexp.MustCompile(`\<\?(.*)\?\>`)
+
+// Decode decodes the data from XML format
+func (x *XML) Decode(data string) (map[string]interface{}, error) {
+ var prefixStr string
+ prefix := xmlHeader.FindAllStringSubmatch(data, -1)
+ if len(prefix) > 0 {
+ prefixStr = prefix[0][1]
+ }
+
+ decoded, err := mxj.NewMapXml([]byte(data))
+ if err != nil {
+ return nil, err
+ }
+ decoded["#_xml_header"] = prefixStr
+ return decoded, nil
+}
+
+// Name returns the name of the encoder
+func (x *XML) Name() string {
+ return XMLDataFormat
+}
diff --git a/pkg/protocols/common/fuzz/doc.go b/pkg/fuzz/doc.go
similarity index 100%
rename from pkg/protocols/common/fuzz/doc.go
rename to pkg/fuzz/doc.go
diff --git a/pkg/fuzz/execute.go b/pkg/fuzz/execute.go
new file mode 100644
index 00000000..3a86ef7e
--- /dev/null
+++ b/pkg/fuzz/execute.go
@@ -0,0 +1,275 @@
+package fuzz
+
+import (
+ "fmt"
+ "io"
+ "regexp"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/component"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
+ "github.com/projectdiscovery/retryablehttp-go"
+ errorutil "github.com/projectdiscovery/utils/errors"
+ urlutil "github.com/projectdiscovery/utils/url"
+)
+
+var (
+ ErrRuleNotApplicable = errorutil.NewWithFmt("rule not applicable : %v")
+)
+
+// IsErrRuleNotApplicable checks if an error is due to rule not applicable
+func IsErrRuleNotApplicable(err error) bool {
+ if err == nil {
+ return false
+ }
+ if strings.Contains(err.Error(), "rule not applicable") {
+ return true
+ }
+ return false
+}
+
+// ExecuteRuleInput is the input for rule Execute function
+type ExecuteRuleInput struct {
+ // Input is the context args input
+ Input *contextargs.Context
+ // Callback is the callback for generated rule requests
+ Callback func(GeneratedRequest) bool
+ // InteractURLs contains interact urls for execute call
+ InteractURLs []string
+ // Values contains dynamic values for the rule
+ Values map[string]interface{}
+ // BaseRequest is the base http request for fuzzing rule
+ BaseRequest *retryablehttp.Request
+}
+
+// GeneratedRequest is a single generated request for rule
+type GeneratedRequest struct {
+ // Request is the http request for rule
+ Request *retryablehttp.Request
+ // InteractURLs is the list of interactsh urls
+ InteractURLs []string
+ // DynamicValues contains dynamic values map
+ DynamicValues map[string]interface{}
+ // Component is the component for the request
+ Component component.Component
+}
+
+// Execute executes a fuzzing rule accepting a callback on which
+// generated requests are returned.
+//
+// Input is not thread safe and should not be shared between concurrent
+// goroutines.
+func (rule *Rule) Execute(input *ExecuteRuleInput) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("got panic while executing rule: %v", r)
+ }
+ }()
+ if !rule.isInputURLValid(input.Input) {
+ return ErrRuleNotApplicable.Msgf("invalid input url: %v", input.Input.MetaInput.Input)
+ }
+ if input.BaseRequest == nil && input.Input.MetaInput.ReqResp == nil {
+ return ErrRuleNotApplicable.Msgf("both base request and reqresp are nil for %v", input.Input.MetaInput.Input)
+ }
+
+ var finalComponentList []component.Component
+ // match rule part with component name
+ for _, componentName := range component.Components {
+ if rule.partType != requestPartType && rule.Part != componentName {
+ continue
+ }
+ component := component.New(componentName)
+ discovered, err := component.Parse(input.BaseRequest)
+ if err != nil {
+ gologger.Verbose().Msgf("Could not parse component %s: %s\n", componentName, err)
+ continue
+ }
+ if !discovered {
+ continue
+ }
+ // check rule applicable on this component
+ if !rule.checkRuleApplicableOnComponent(component) {
+ continue
+ }
+ finalComponentList = append(finalComponentList, component)
+ }
+
+ if len(finalComponentList) == 0 {
+ return ErrRuleNotApplicable.Msgf("no component matched on this rule")
+ }
+
+ baseValues := input.Values
+ if rule.generator == nil {
+ for _, component := range finalComponentList {
+ evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(baseValues, rule.options.Interactsh)
+ input.Values = generators.MergeMaps(evaluatedValues, baseValues, rule.options.Constants)
+ input.InteractURLs = interactURLs
+ err := rule.executeRuleValues(input, component)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+mainLoop:
+ for _, component := range finalComponentList {
+ iterator := rule.generator.NewIterator()
+ for {
+ values, next := iterator.Value()
+ if !next {
+ continue mainLoop
+ }
+ evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(generators.MergeMaps(values, baseValues), rule.options.Interactsh)
+ input.InteractURLs = interactURLs
+ input.Values = generators.MergeMaps(values, evaluatedValues, baseValues, rule.options.Constants)
+
+ if err := rule.executeRuleValues(input, component); err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ gologger.Warning().Msgf("[%s] Could not execute rule: %s\n", rule.options.TemplateID, err)
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// isInputURLValid returns true if url is valid after parsing it
+func (rule *Rule) isInputURLValid(input *contextargs.Context) bool {
+ if input == nil || input.MetaInput == nil || input.MetaInput.Input == "" {
+ return false
+ }
+ _, err := urlutil.Parse(input.MetaInput.Input)
+ return err == nil
+}
+
+// executeRuleValues executes a rule with a set of values
+func (rule *Rule) executeRuleValues(input *ExecuteRuleInput, ruleComponent component.Component) error {
+ // if we are only fuzzing values
+ if len(rule.Fuzz.Value) > 0 {
+ for _, value := range rule.Fuzz.Value {
+ if err := rule.executePartRule(input, ValueOrKeyValue{Value: value}, ruleComponent); err != nil {
+ if component.IsErrSetValue(err) {
+ // this are errors due to format restrictions
+ // ex: fuzzing string value in a json int field
+ continue
+ }
+ return err
+ }
+ }
+ return nil
+ }
+
+ // if we are fuzzing both keys and values
+ if rule.Fuzz.KV != nil {
+ var gotErr error
+ rule.Fuzz.KV.Iterate(func(key, value string) bool {
+ if err := rule.executePartRule(input, ValueOrKeyValue{Key: key, Value: value}, ruleComponent); err != nil {
+ if component.IsErrSetValue(err) {
+ // this are errors due to format restrictions
+ // ex: fuzzing string value in a json int field
+ return true
+ }
+ gotErr = err
+ return false
+ }
+ return true
+ })
+ // if mode is multiple now build and execute it
+ if rule.modeType == multipleModeType {
+ req, err := ruleComponent.Rebuild()
+ if err != nil {
+ return err
+ }
+ if gotErr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent); gotErr != nil {
+ return gotErr
+ }
+ }
+ return gotErr
+ }
+
+ // something else is wrong
+ return fmt.Errorf("no fuzz values specified")
+}
+
+// Compile compiles a fuzzing rule and initializes it for operation
+func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *protocols.ExecutorOptions) error {
+ // If a payload generator is specified from base request, use it
+ // for payload values.
+ if generator != nil {
+ rule.generator = generator
+ }
+ rule.options = options
+
+ // Resolve the default enums
+ if rule.Mode != "" {
+ if valueType, ok := stringToModeType[rule.Mode]; !ok {
+ return errors.Errorf("invalid mode value specified: %s", rule.Mode)
+ } else {
+ rule.modeType = valueType
+ }
+ } else {
+ rule.modeType = multipleModeType
+ }
+ if rule.Part != "" {
+ if valueType, ok := stringToPartType[rule.Part]; !ok {
+ return errors.Errorf("invalid part value specified: %s", rule.Part)
+ } else {
+ rule.partType = valueType
+ }
+ } else {
+ rule.partType = queryPartType
+ }
+
+ if rule.Type != "" {
+ if valueType, ok := stringToRuleType[rule.Type]; !ok {
+ return errors.Errorf("invalid type value specified: %s", rule.Type)
+ } else {
+ rule.ruleType = valueType
+ }
+ } else {
+ rule.ruleType = replaceRuleType
+ }
+
+ // Initialize other required regexes and maps
+ if len(rule.Keys) > 0 {
+ rule.keysMap = make(map[string]struct{})
+ }
+ for _, key := range rule.Keys {
+ rule.keysMap[strings.ToLower(key)] = struct{}{}
+ }
+ for _, value := range rule.ValuesRegex {
+ compiled, err := regexp.Compile(value)
+ if err != nil {
+ return errors.Wrap(err, "could not compile value regex")
+ }
+ rule.valuesRegex = append(rule.valuesRegex, compiled)
+ }
+ for _, value := range rule.KeysRegex {
+ compiled, err := regexp.Compile(value)
+ if err != nil {
+ return errors.Wrap(err, "could not compile key regex")
+ }
+ rule.keysRegex = append(rule.keysRegex, compiled)
+ }
+ if rule.ruleType != replaceRegexRuleType {
+ if rule.ReplaceRegex != "" {
+ return errors.Errorf("replace-regex is only applicable for replace and replace-regex rule types")
+ }
+ } else {
+ if rule.ReplaceRegex == "" {
+ return errors.Errorf("replace-regex is required for replace-regex rule type")
+ }
+ compiled, err := regexp.Compile(rule.ReplaceRegex)
+ if err != nil {
+ return errors.Wrap(err, "could not compile replace regex")
+ }
+ rule.replaceRegex = compiled
+ }
+ return nil
+}
diff --git a/pkg/protocols/common/fuzz/fuzz.go b/pkg/fuzz/fuzz.go
similarity index 75%
rename from pkg/protocols/common/fuzz/fuzz.go
rename to pkg/fuzz/fuzz.go
index 0cf37a23..c70bc3b2 100644
--- a/pkg/protocols/common/fuzz/fuzz.go
+++ b/pkg/fuzz/fuzz.go
@@ -20,7 +20,7 @@ type Rule struct {
// - "prefix"
// - "postfix"
// - "infix"
- Type string `yaml:"type,omitempty" json:"type,omitempty" jsonschema:"title=type of rule,description=Type of fuzzing rule to perform,enum=replace,enum=prefix,enum=postfix,enum=infix"`
+ Type string `yaml:"type,omitempty" json:"type,omitempty" jsonschema:"title=type of rule,description=Type of fuzzing rule to perform,enum=replace,enum=prefix,enum=postfix,enum=infix,enum=replace-regex"`
ruleType ruleType
// description: |
// Part is the part of request to fuzz.
@@ -28,7 +28,7 @@ type Rule struct {
// query fuzzes the query part of url. More parts will be added later.
// values:
// - "query"
- Part string `yaml:"part,omitempty" json:"part,omitempty" jsonschema:"title=part of rule,description=Part of request rule to fuzz,enum=query"`
+ Part string `yaml:"part,omitempty" json:"part,omitempty" jsonschema:"title=part of rule,description=Part of request rule to fuzz,enum=query,enum=header,enum=path,enum=body,enum=cookie,enum=request"`
partType partType
// description: |
// Mode is the mode of fuzzing to perform.
@@ -71,10 +71,20 @@ type Rule struct {
// - name: Examples of fuzz
// value: >
// []string{"{{ssrf}}", "{{interactsh-url}}", "example-value"}
- Fuzz []string `yaml:"fuzz,omitempty" json:"fuzz,omitempty" jsonschema:"title=payloads of fuzz rule,description=Payloads to perform fuzzing substitutions with"`
-
- options *protocols.ExecutorOptions
- generator *generators.PayloadGenerator
+ // or
+ // x-header: 1
+ // x-header: 2
+ Fuzz SliceOrMapSlice `yaml:"fuzz,omitempty" json:"fuzz,omitempty" jsonschema:"title=payloads of fuzz rule,description=Payloads to perform fuzzing substitutions with"`
+ // description: |
+ // replace-regex is regex for regex-replace rule type
+ // it is only required for replace-regex rule type
+ // examples:
+ // - type: replace-regex
+ // replace-regex: "https?://.*"
+ ReplaceRegex string `yaml:"replace-regex,omitempty" json:"replace-regex,omitempty" jsonschema:"title=replace regex of rule,description=Regex for regex-replace rule type"`
+ replaceRegex *regexp.Regexp `yaml:"-" json:"-"`
+ options *protocols.ExecutorOptions
+ generator *generators.PayloadGenerator
}
// ruleType is the type of rule enum declaration
@@ -85,13 +95,15 @@ const (
prefixRuleType
postfixRuleType
infixRuleType
+ replaceRegexRuleType
)
var stringToRuleType = map[string]ruleType{
- "replace": replaceRuleType,
- "prefix": prefixRuleType,
- "postfix": postfixRuleType,
- "infix": infixRuleType,
+ "replace": replaceRuleType,
+ "prefix": prefixRuleType,
+ "postfix": postfixRuleType,
+ "infix": infixRuleType,
+ "replace-regex": replaceRegexRuleType,
}
// partType is the part of rule enum declaration
@@ -100,11 +112,19 @@ type partType int
const (
queryPartType partType = iota + 1
headersPartType
+ pathPartType
+ bodyPartType
+ cookiePartType
+ requestPartType
)
var stringToPartType = map[string]partType{
"query": queryPartType,
- "headers": headersPartType,
+ "header": headersPartType,
+ "path": pathPartType,
+ "body": bodyPartType,
+ "cookie": cookiePartType,
+ "request": requestPartType, // request means all request parts
}
// modeType is the mode of rule enum declaration
diff --git a/pkg/protocols/common/fuzz/fuzz_test.go b/pkg/fuzz/fuzz_test.go
similarity index 100%
rename from pkg/protocols/common/fuzz/fuzz_test.go
rename to pkg/fuzz/fuzz_test.go
diff --git a/pkg/fuzz/parts.go b/pkg/fuzz/parts.go
new file mode 100644
index 00000000..9b24446b
--- /dev/null
+++ b/pkg/fuzz/parts.go
@@ -0,0 +1,210 @@
+package fuzz
+
+import (
+ "io"
+ "strings"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/component"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
+ "github.com/projectdiscovery/nuclei/v3/pkg/types"
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+// executePartRule executes part rules based on type
+func (rule *Rule) executePartRule(input *ExecuteRuleInput, payload ValueOrKeyValue, component component.Component) error {
+ return rule.executePartComponent(input, payload, component)
+}
+
+// checkRuleApplicableOnComponent checks if a rule is applicable on given component
+func (rule *Rule) checkRuleApplicableOnComponent(component component.Component) bool {
+ if rule.Part != component.Name() {
+ return false
+ }
+ foundAny := false
+ _ = component.Iterate(func(key string, value interface{}) error {
+ if rule.matchKeyOrValue(key, types.ToString(value)) {
+ foundAny = true
+ return io.EOF
+ }
+ return nil
+ })
+ return foundAny
+}
+
+// executePartComponent executes this rule on a given component and payload
+func (rule *Rule) executePartComponent(input *ExecuteRuleInput, payload ValueOrKeyValue, ruleComponent component.Component) error {
+ if payload.IsKV() {
+ // for kv fuzzing
+ return rule.executePartComponentOnKV(input, payload, ruleComponent)
+ } else {
+ // for value only fuzzing
+ return rule.executePartComponentOnValues(input, payload.Value, ruleComponent)
+ }
+}
+
+// executePartComponentOnValues executes this rule on a given component and payload
+// this supports both single and multiple [ruleType] modes
+// i.e if component has multiple values, they can be replaced once or all depending on mode
+func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadStr string, ruleComponent component.Component) error {
+ finalErr := ruleComponent.Iterate(func(key string, value interface{}) error {
+ valueStr := types.ToString(value)
+ if !rule.matchKeyOrValue(key, valueStr) {
+ // ignore non-matching keys
+ return nil
+ }
+
+ var evaluated string
+ evaluated, input.InteractURLs = rule.executeEvaluate(input, key, valueStr, payloadStr, input.InteractURLs)
+ if err := ruleComponent.SetValue(key, evaluated); err != nil {
+ // gologger.Warning().Msgf("could not set value due to format restriction original(%s, %s[%T]) , new(%s,%s[%T])", key, valueStr, value, key, evaluated, evaluated)
+ return nil
+ }
+
+ if rule.modeType == singleModeType {
+ req, err := ruleComponent.Rebuild()
+ if err != nil {
+ return err
+ }
+
+ if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent); qerr != nil {
+ return qerr
+ }
+ // fmt.Printf("executed with value: %s\n", evaluated)
+ err = ruleComponent.SetValue(key, valueStr) // change back to previous value for temp
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ if finalErr != nil {
+ return finalErr
+ }
+
+ // We do not support analyzers with
+ // multiple payload mode.
+ if rule.modeType == multipleModeType {
+ req, err := ruleComponent.Rebuild()
+ if err != nil {
+ return err
+ }
+ if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent); qerr != nil {
+ err = qerr
+ return err
+ }
+ }
+ return nil
+}
+
+// executePartComponentOnKV executes this rule on a given component and payload
+// currently only supports single mode
+func (rule *Rule) executePartComponentOnKV(input *ExecuteRuleInput, payload ValueOrKeyValue, ruleComponent component.Component) error {
+ var origKey string
+ var origValue interface{}
+ // when we have a key-value pair, iterate over only 1 value of the component
+ // multiple values (aka multiple mode) not supported for this yet
+ _ = ruleComponent.Iterate(func(key string, value interface{}) error {
+ if key == payload.Key {
+ origKey = key
+ origValue = value
+ }
+ return nil
+ })
+ // iterate over given kv instead of component ones
+ return func(key, value string) error {
+ var evaluated string
+ evaluated, input.InteractURLs = rule.executeEvaluate(input, key, "", value, input.InteractURLs)
+ if err := ruleComponent.SetValue(key, evaluated); err != nil {
+ return err
+ }
+ if rule.modeType == singleModeType {
+ req, err := ruleComponent.Rebuild()
+ if err != nil {
+ return err
+ }
+
+ if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent); qerr != nil {
+ return err
+ }
+
+ // after building change back to original value to avoid repeating it in furthur requests
+ if origKey != "" {
+ err = ruleComponent.SetValue(origKey, types.ToString(origValue)) // change back to previous value for temp
+ if err != nil {
+ return err
+ }
+ } else {
+ _ = ruleComponent.Delete(key) // change back to previous value for temp
+ }
+ }
+ return nil
+ }(payload.Key, payload.Value)
+}
+
+// execWithInput executes a rule with input via callback
+func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.Request, interactURLs []string, component component.Component) error {
+ request := GeneratedRequest{
+ Request: httpReq,
+ InteractURLs: interactURLs,
+ DynamicValues: input.Values,
+ Component: component,
+ }
+ if !input.Callback(request) {
+ return types.ErrNoMoreRequests
+ }
+ return nil
+}
+
+// executeEvaluate executes evaluation of payload on a key and value and
+// returns completed values to be replaced and processed
+// for fuzzing.
+func (rule *Rule) executeEvaluate(input *ExecuteRuleInput, _, value, payload string, interactshURLs []string) (string, []string) {
+ // TODO: Handle errors
+ values := generators.MergeMaps(input.Values, map[string]interface{}{
+ "value": value,
+ }, rule.options.Options.Vars.AsMap(), rule.options.Variables.GetAll())
+ firstpass, _ := expressions.Evaluate(payload, values)
+ interactData, interactshURLs := rule.options.Interactsh.Replace(firstpass, interactshURLs)
+ evaluated, _ := expressions.Evaluate(interactData, values)
+ replaced := rule.executeRuleTypes(input, value, evaluated)
+ return replaced, interactshURLs
+}
+
+// executeRuleTypes executes replacement for a key and value
+// ex: prefix, postfix, infix, replace , replace-regex
+func (rule *Rule) executeRuleTypes(_ *ExecuteRuleInput, value, replacement string) string {
+ var builder strings.Builder
+ if rule.ruleType == prefixRuleType || rule.ruleType == postfixRuleType {
+ builder.Grow(len(value) + len(replacement))
+ }
+ var returnValue string
+
+ switch rule.ruleType {
+ case prefixRuleType:
+ builder.WriteString(replacement)
+ builder.WriteString(value)
+ returnValue = builder.String()
+ case postfixRuleType:
+ builder.WriteString(value)
+ builder.WriteString(replacement)
+ returnValue = builder.String()
+ case infixRuleType:
+ if len(value) <= 1 {
+ builder.WriteString(value)
+ builder.WriteString(replacement)
+ returnValue = builder.String()
+ } else {
+ middleIndex := len(value) / 2
+ builder.WriteString(value[:middleIndex])
+ builder.WriteString(replacement)
+ builder.WriteString(value[middleIndex:])
+ returnValue = builder.String()
+ }
+ case replaceRuleType:
+ returnValue = replacement
+ case replaceRegexRuleType:
+ returnValue = rule.replaceRegex.ReplaceAllString(value, replacement)
+ }
+ return returnValue
+}
diff --git a/pkg/fuzz/parts_test.go b/pkg/fuzz/parts_test.go
new file mode 100644
index 00000000..d31f0ea0
--- /dev/null
+++ b/pkg/fuzz/parts_test.go
@@ -0,0 +1,2 @@
+// TODO: Write tests
+package fuzz
diff --git a/pkg/fuzz/type.go b/pkg/fuzz/type.go
new file mode 100644
index 00000000..6110b2cd
--- /dev/null
+++ b/pkg/fuzz/type.go
@@ -0,0 +1,80 @@
+package fuzz
+
+import (
+ "encoding/json"
+ "fmt"
+
+ mapsutil "github.com/projectdiscovery/utils/maps"
+ "gopkg.in/yaml.v2"
+)
+
+var (
+ _ json.Marshaler = &SliceOrMapSlice{}
+ _ json.Unmarshaler = &SliceOrMapSlice{}
+ _ yaml.Marshaler = &SliceOrMapSlice{}
+ _ yaml.Unmarshaler = &SliceOrMapSlice{}
+)
+
+type ValueOrKeyValue struct {
+ Key string
+ Value string
+}
+
+func (v *ValueOrKeyValue) IsKV() bool {
+ return v.Key != ""
+}
+
+type SliceOrMapSlice struct {
+ Value []string
+ KV *mapsutil.OrderedMap[string, string]
+}
+
+// UnmarshalJSON implements json.Unmarshaler interface.
+func (v *SliceOrMapSlice) UnmarshalJSON(data []byte) error {
+ // try to unmashal as a string and fallback to map
+ if err := json.Unmarshal(data, &v.Value); err == nil {
+ return nil
+ }
+ err := json.Unmarshal(data, &v.KV)
+ if err != nil {
+ return fmt.Errorf("object can be a key:value or a string")
+ }
+ return nil
+}
+
+// MarshalJSON implements json.Marshaler interface.
+func (v SliceOrMapSlice) MarshalJSON() ([]byte, error) {
+ if v.KV != nil {
+ return json.Marshal(v.KV)
+ }
+ return json.Marshal(v.Value)
+}
+
+// UnmarshalYAML implements yaml.Unmarshaler interface.
+func (v *SliceOrMapSlice) UnmarshalYAML(callback func(interface{}) error) error {
+ // try to unmarshal it as a string and fallback to map
+ if err := callback(&v.Value); err == nil {
+ return nil
+ }
+
+ // try with a mapslice
+ var node yaml.MapSlice
+ if err := callback(&node); err == nil {
+ tmpx := mapsutil.NewOrderedMap[string, string]()
+ // preserve order
+ for _, v := range node {
+ tmpx.Set(v.Key.(string), v.Value.(string))
+ }
+ v.KV = &tmpx
+ return nil
+ }
+ return fmt.Errorf("object can be a key:value or a string")
+}
+
+// MarshalYAML implements yaml.Marshaler interface.
+func (v SliceOrMapSlice) MarshalYAML() (any, error) {
+ if v.KV != nil {
+ return v.KV, nil
+ }
+ return v.Value, nil
+}
diff --git a/pkg/input/README.md b/pkg/input/README.md
new file mode 100644
index 00000000..4e8e5932
--- /dev/null
+++ b/pkg/input/README.md
@@ -0,0 +1,29 @@
+## input
+
+input package contains and provides loading, parsing , validating and normalizing of input data
+
+
+## [transform](./transform.go)
+
+Transform package transforms or normalizes the input data before it is sent to protocol executer this step mainly involves changes like adding default ports (if missing) , validating if input is file or directory or url and adjusting the input accordingly etc.
+
+
+## Provider
+
+Provider package contains the interface that every input format should implement for providing that input format to nuclei.
+
+Currently Nuclei Supports three input providers:
+
+1. SimpleInputProvider = A No-Op provider that takes a list of urls and implements the provider interface.
+
+2. HttpInputProvider = A provider that supports loading and parsing input formats that contain complete Http Data like Entire Request, Response etc. Supported formats include Burp,openapi,swagger,postman,proxify etc.
+
+3. ListInputProvider = Legacy/Default Provider that handles all list type inputs like urls,domains,ips,cidrs,files etc.
+
+
+```go
+func NewInputProvider(opts InputOptions) (InputProvider, error)
+```
+
+This function returns a InputProvider based by appropriately selecting input provider based on the input format (i.e either list or http) and returns the provider that can handle that input format.
+
diff --git a/pkg/input/formats/README.md b/pkg/input/formats/README.md
new file mode 100644
index 00000000..3db9cdc1
--- /dev/null
+++ b/pkg/input/formats/README.md
@@ -0,0 +1,90 @@
+# formats
+
+Formats implements support for passing a number of request source as input providers to nuclei to be tested for fuzzing related issues.
+
+Currently the following formats are implemented -
+
+- Burp Suite XML Request/Response file
+- Proxify JSONL output file
+- OpenAPI Specification file
+- Postman Collection file
+- Swagger Specification file
+
+Each implementation implements either the entire or a subset of the features of the specifications. These can be increased further to add support as new things or requirements are identified.
+
+Refer to the specific code for each implementation to understand supported features of the specs.
+
+
+## OpenAPI Specification File
+
+It is designed to generate HTTP requests based on an OpenAPI 3.0 Schema. Here is how these schema components are processed:
+
+### Servers
+
+The module supports multiple server URLs defined in the `Servers` section of the OpenAPI document. It will send requests to all the server URLs defined in the schema.
+
+### Paths and Operations
+
+The module supports all HTTP methods defined under each path in the `Paths` section. For each operation on a path, HTTP requests are generated and sent to the defined server URL. If the operation cannot generate a valid request, a warning will be logged.
+
+### Parameters
+
+The module recognizes parameters defined in the `query`, `header`, `path`, and `cookie` categories. When generating requests, if the `requiredOnly` flag is true, only the required parameters are included. Otherwise, all parameters, regardless of their required status, are used.
+
+The `generateExampleFromSchema` function is used to generate suitable example data for each parameter from their respective schema definitions.
+
+### RequestBody
+
+The module also comprehends request bodies and supports various media types defined in the `Content` field. Currently, the following content-types are supported:
+
+- `application/json`: The module creates application-specific JSON from the defined example schema.
+
+- `application/xml`: The example schema is converted into xml format using `mxj` library.
+
+- `application/x-www-form-urlencoded`: The example schema is converted into URL-encoded form data.
+
+- `multipart/form-data`: The module supports multipart form-data and differentiates between fields and files using the `binary` format under the property schema.
+
+- `text/plain`: Converts the example schema into string format and send as plain text.
+
+For unsupported media types, no appropriate content type is found for the body. After setting up the body of the request, the module dumps the request and sends it to the defined server URL.
+
+### Example Request Generation
+
+This module converts each operation into one or more example HTTP requests. Each request is dumped into a string format, accompanied by its method, URL, headers, and body. These are send as a callback for further processing.
+
+_Please note: This document does not cover other features of OpenAPI specification like responses, security schemes, links, callbacks, etc. as these are not currently handled by the module._
+
+## Postman Collection file
+
+This module parser Postman Collection JSON files.
+
+### 1. Request Parsing:
+ Able to parse requests detailed in the Postman package. The parser is capable of interpreting the HTTP method, URL, and Body of each request present in the collection.
+
+### 2. Header Parsing:
+ All HTTP headers set in the collection's request are parsed and set in the request.
+
+### 3. Auth Type Parsing:
+ Able to parse and set the `Authentication` options provided in the postman collection in the request headers.
+ Supported types of authentiction:
+
+ 1. **API Key**: In header
+ 2. **Basic**: Setting basic auth through username, password.
+ 3. **Bearer Token**: Involves setting bearer auth using tokens.
+ 4. **No Auth**: No authentication is set.
+
+Note: Not all parts of the Postman Collection specification are supported. This parser does not currently support Postman variables or collection level variables and items. It also does not support more authentication types than detailed above.
+
+### Limitations:
+* Does not support Postman variables
+* Does not support Collection level variables and items
+* Limited Authentication types supported
+
+## Swagger Specification file
+
+Swagger specification file is converted from OpenAPI 2.0 format to OpenAPI 3.0 format. After this, the OpenAPI parser from above is used.
+
+## Burp XML / Proxify JSONL
+
+These modules are generic and parse raw requests from these respective tools.
\ No newline at end of file
diff --git a/pkg/input/formats/burp/burp.go b/pkg/input/formats/burp/burp.go
new file mode 100644
index 00000000..6ad5f548
--- /dev/null
+++ b/pkg/input/formats/burp/burp.go
@@ -0,0 +1,67 @@
+package burp
+
+import (
+ "encoding/base64"
+ "os"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/projectdiscovery/utils/conversion"
+ "github.com/seh-msft/burpxml"
+)
+
+// BurpFormat is a Burp XML File parser
+type BurpFormat struct {
+ opts formats.InputFormatOptions
+}
+
+// New creates a new Burp XML File parser
+func New() *BurpFormat {
+ return &BurpFormat{}
+}
+
+var _ formats.Format = &BurpFormat{}
+
+// Name returns the name of the format
+func (j *BurpFormat) Name() string {
+ return "burp"
+}
+
+func (j *BurpFormat) SetOptions(options formats.InputFormatOptions) {
+ j.opts = options
+}
+
+// Parse parses the input and calls the provided callback
+// function for each RawRequest it discovers.
+func (j *BurpFormat) Parse(input string, resultsCb formats.ParseReqRespCallback) error {
+ file, err := os.Open(input)
+ if err != nil {
+ return errors.Wrap(err, "could not open data file")
+ }
+ defer file.Close()
+
+ items, err := burpxml.Parse(file, true)
+ if err != nil {
+ return errors.Wrap(err, "could not decode burp xml schema")
+ }
+
+ // Print the parsed data for verification
+ for _, item := range items.Items {
+ item := item
+ binx, err := base64.StdEncoding.DecodeString(item.Request.Raw)
+ if err != nil {
+ return errors.Wrap(err, "could not decode base64")
+ }
+ if strings.TrimSpace(conversion.String(binx)) == "" {
+ continue
+ }
+ rawRequest, err := types.ParseRawRequestWithURL(conversion.String(binx), item.Url)
+ if err != nil {
+ return errors.Wrap(err, "could not parse raw request")
+ }
+ resultsCb(rawRequest) // TODO: Handle false and true from callback
+ }
+ return nil
+}
diff --git a/pkg/input/formats/burp/burp_test.go b/pkg/input/formats/burp/burp_test.go
new file mode 100644
index 00000000..330218a9
--- /dev/null
+++ b/pkg/input/formats/burp/burp_test.go
@@ -0,0 +1,33 @@
+package burp
+
+import (
+ "testing"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/stretchr/testify/require"
+)
+
+func TestBurpParse(t *testing.T) {
+ format := New()
+
+ proxifyInputFile := "../testdata/burp.xml"
+
+ var gotMethodsToURLs []string
+
+ err := format.Parse(proxifyInputFile, func(request *types.RequestResponse) bool {
+ gotMethodsToURLs = append(gotMethodsToURLs, request.URL.String())
+ return false
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(gotMethodsToURLs) != 2 {
+ t.Fatalf("invalid number of methods: %d", len(gotMethodsToURLs))
+ }
+ var expectedURLs = []string{
+ "http://localhost:8087/scans",
+ "http://google.com/",
+ }
+ require.ElementsMatch(t, expectedURLs, gotMethodsToURLs, "could not get burp urls")
+}
diff --git a/pkg/input/formats/formats.go b/pkg/input/formats/formats.go
new file mode 100644
index 00000000..af2b4569
--- /dev/null
+++ b/pkg/input/formats/formats.go
@@ -0,0 +1,103 @@
+package formats
+
+import (
+ "errors"
+ "os"
+ "strings"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ fileutil "github.com/projectdiscovery/utils/file"
+ "gopkg.in/yaml.v3"
+)
+
+// ParseReqRespCallback is a callback function for discovered raw requests
+type ParseReqRespCallback func(rr *types.RequestResponse) bool
+
+// InputFormatOptions contains options for the input
+// this can be variables that can be passed or
+// overrides or some other options
+type InputFormatOptions struct {
+ // Variables is list of variables that can be used
+ // while generating requests in given format
+ Variables map[string]interface{}
+ // SkipFormatValidation is used to skip format validation
+ // while debugging or testing if format is invalid then
+ // requests are skipped instead of creating invalid requests
+ SkipFormatValidation bool
+ // RequiredOnly only uses required fields when generating requests
+ // instead of all fields
+ RequiredOnly bool
+}
+
+// Format is an interface implemented by all input formats
+type Format interface {
+ // Name returns the name of the format
+ Name() string
+ // Parse parses the input and calls the provided callback
+ // function for each RawRequest it discovers.
+ Parse(input string, resultsCb ParseReqRespCallback) error
+ // SetOptions sets the options for the input format
+ SetOptions(options InputFormatOptions)
+}
+
+var (
+ DefaultVarDumpFileName = "required_openapi_params.yaml"
+ ErrNoVarsDumpFile = errors.New("no required params file found")
+)
+
+// == OpenAPIParamsCfgFile ==
+// this file is meant to be used in CLI mode
+// to be more interactive and user-friendly when
+// running nuclei with openapi format
+
+// OpenAPIParamsCfgFile is the structure of the required vars dump file
+type OpenAPIParamsCfgFile struct {
+ Var []string `yaml:"var"`
+ OptionalVars []string `yaml:"-"` // this will be written to the file as comments
+}
+
+// ReadOpenAPIVarDumpFile reads the required vars dump file
+func ReadOpenAPIVarDumpFile() (*OpenAPIParamsCfgFile, error) {
+ var vars OpenAPIParamsCfgFile
+ if !fileutil.FileExists(DefaultVarDumpFileName) {
+ return nil, ErrNoVarsDumpFile
+ }
+ bin, err := os.ReadFile(DefaultVarDumpFileName)
+ if err != nil {
+ return nil, err
+ }
+ err = yaml.Unmarshal(bin, &vars)
+ if err != nil {
+ return nil, err
+ }
+ filtered := []string{}
+ for _, v := range vars.Var {
+ v = strings.TrimSpace(v)
+ if !strings.HasSuffix(v, "=") {
+ filtered = append(filtered, v)
+ }
+ }
+ vars.Var = filtered
+ return &vars, nil
+}
+
+// WriteOpenAPIVarDumpFile writes the required vars dump file
+func WriteOpenAPIVarDumpFile(vars *OpenAPIParamsCfgFile) error {
+ f, err := os.OpenFile(DefaultVarDumpFileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ bin, err := yaml.Marshal(vars)
+ if err != nil {
+ return err
+ }
+ _, _ = f.Write(bin)
+ if len(vars.OptionalVars) > 0 {
+ _, _ = f.WriteString("\n # Optional parameters\n")
+ for _, v := range vars.OptionalVars {
+ _, _ = f.WriteString(" # - " + v + "=\n")
+ }
+ }
+ return f.Sync()
+}
diff --git a/pkg/input/formats/json/json.go b/pkg/input/formats/json/json.go
new file mode 100644
index 00000000..fecb1c6b
--- /dev/null
+++ b/pkg/input/formats/json/json.go
@@ -0,0 +1,74 @@
+package json
+
+import (
+ "encoding/json"
+ "io"
+ "os"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+)
+
+// JSONFormat is a JSON format parser for nuclei
+// input HTTP requests
+type JSONFormat struct {
+ opts formats.InputFormatOptions
+}
+
+// New creates a new JSON format parser
+func New() *JSONFormat {
+ return &JSONFormat{}
+}
+
+var _ formats.Format = &JSONFormat{}
+
+// proxifyRequest is a request for proxify
+type proxifyRequest struct {
+ URL string `json:"url"`
+ Request struct {
+ Header map[string]string `json:"header"`
+ Body string `json:"body"`
+ Raw string `json:"raw"`
+ } `json:"request"`
+}
+
+// Name returns the name of the format
+func (j *JSONFormat) Name() string {
+ return "jsonl"
+}
+
+func (j *JSONFormat) SetOptions(options formats.InputFormatOptions) {
+ j.opts = options
+}
+
+// Parse parses the input and calls the provided callback
+// function for each RawRequest it discovers.
+func (j *JSONFormat) Parse(input string, resultsCb formats.ParseReqRespCallback) error {
+ file, err := os.Open(input)
+ if err != nil {
+ return errors.Wrap(err, "could not open json file")
+ }
+ defer file.Close()
+
+ decoder := json.NewDecoder(file)
+ for {
+ var request proxifyRequest
+ err := decoder.Decode(&request)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return errors.Wrap(err, "could not decode json file")
+ }
+
+ rawRequest, err := types.ParseRawRequestWithURL(request.Request.Raw, request.URL)
+ if err != nil {
+ gologger.Warning().Msgf("jsonl: Could not parse raw request %s: %s\n", request.URL, err)
+ continue
+ }
+ resultsCb(rawRequest)
+ }
+ return nil
+}
diff --git a/pkg/input/formats/json/json_test.go b/pkg/input/formats/json/json_test.go
new file mode 100644
index 00000000..b72bf4c1
--- /dev/null
+++ b/pkg/input/formats/json/json_test.go
@@ -0,0 +1,57 @@
+package json
+
+import (
+ "testing"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/stretchr/testify/require"
+)
+
+var expectedURLs = []string{
+ "https://ginandjuice.shop/",
+ "https://ginandjuice.shop/catalog/product?productId=1",
+ "https://ginandjuice.shop/resources/js/stockCheck.js",
+ "https://ginandjuice.shop/resources/js/xmlStockCheckPayload.js",
+ "https://ginandjuice.shop/resources/js/xmlStockCheckPayload.js",
+ "https://ginandjuice.shop/resources/js/stockCheck.js",
+ "https://ginandjuice.shop/catalog/product/stock",
+ "https://ginandjuice.shop/catalog/cart",
+ "https://ginandjuice.shop/catalog/product?productId=1",
+ "https://ginandjuice.shop/catalog/subscribe",
+ "https://ginandjuice.shop/blog",
+ "https://ginandjuice.shop/blog/?search=dadad&back=%2Fblog%2F",
+ "https://ginandjuice.shop/logger",
+ "https://ginandjuice.shop/blog/",
+ "https://ginandjuice.shop/blog/post?postId=3",
+ "https://ginandjuice.shop/about",
+ "https://ginandjuice.shop/my-account",
+ "https://ginandjuice.shop/login",
+ "https://ginandjuice.shop/login",
+ "https://ginandjuice.shop/login",
+ "https://ginandjuice.shop/my-account",
+ "https://ginandjuice.shop/catalog/cart",
+ "https://ginandjuice.shop/my-account",
+ "https://ginandjuice.shop/logout",
+ "https://ginandjuice.shop/",
+ "https://ginandjuice.shop/catalog",
+}
+
+func TestJSONFormatterParse(t *testing.T) {
+ format := New()
+
+ proxifyInputFile := "../testdata/ginandjuice.proxify.json"
+
+ var urls []string
+ err := format.Parse(proxifyInputFile, func(request *types.RequestResponse) bool {
+ urls = append(urls, request.URL.String())
+ return false
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(urls) != len(expectedURLs) {
+ t.Fatalf("invalid number of urls: %d", len(urls))
+ }
+ require.ElementsMatch(t, urls, expectedURLs)
+}
diff --git a/pkg/input/formats/openapi/examples.go b/pkg/input/formats/openapi/examples.go
new file mode 100644
index 00000000..35c4292c
--- /dev/null
+++ b/pkg/input/formats/openapi/examples.go
@@ -0,0 +1,290 @@
+package openapi
+
+import (
+ "fmt"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/pkg/errors"
+)
+
+// From: https://github.com/danielgtaylor/apisprout/blob/master/example.go
+
+func getSchemaExample(schema *openapi3.Schema) (interface{}, bool) {
+ if schema.Example != nil {
+ return schema.Example, true
+ }
+
+ if schema.Default != nil {
+ return schema.Default, true
+ }
+
+ if schema.Enum != nil && len(schema.Enum) > 0 {
+ return schema.Enum[0], true
+ }
+ return nil, false
+}
+
+// stringFormatExample returns an example string based on the given format.
+// http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.3
+func stringFormatExample(format string) string {
+ switch format {
+ case "date":
+ // https://tools.ietf.org/html/rfc3339
+ return "2018-07-23"
+ case "date-time":
+ // This is the date/time of API Sprout's first commit! :-)
+ return "2018-07-23T22:58:00-07:00"
+ case "time":
+ return "22:58:00-07:00"
+ case "email":
+ return "email@example.com"
+ case "hostname":
+ // https://tools.ietf.org/html/rfc2606#page-2
+ return "example.com"
+ case "ipv4":
+ // https://tools.ietf.org/html/rfc5737
+ return "198.51.100.0"
+ case "ipv6":
+ // https://tools.ietf.org/html/rfc3849
+ return "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
+ case "uri":
+ return "https://tools.ietf.org/html/rfc3986"
+ case "uri-template":
+ // https://tools.ietf.org/html/rfc6570
+ return "http://example.com/dictionary/{term:1}/{term}"
+ case "json-pointer":
+ // https://tools.ietf.org/html/rfc6901
+ return "#/components/parameters/term"
+ case "regex":
+ // https://stackoverflow.com/q/3296050/164268
+ return "/^1?$|^(11+?)\\1+$/"
+ case "uuid":
+ // https://www.ietf.org/rfc/rfc4122.txt
+ return "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
+ case "password":
+ return "********"
+ case "binary":
+ return "sagefuzzertest"
+ }
+ return ""
+}
+
+// excludeFromMode will exclude a schema if the mode is request and the schema
+// is read-only
+func excludeFromMode(schema *openapi3.Schema) bool {
+ if schema == nil {
+ return true
+ }
+
+ if schema.ReadOnly {
+ return true
+ }
+ return false
+}
+
+// isRequired checks whether a key is actually required.
+func isRequired(schema *openapi3.Schema, key string) bool {
+ for _, req := range schema.Required {
+ if req == key {
+ return true
+ }
+ }
+
+ return false
+}
+
+type cachedSchema struct {
+ pending bool
+ out interface{}
+}
+
+var (
+ // ErrRecursive is when a schema is impossible to represent because it infinitely recurses.
+ ErrRecursive = errors.New("Recursive schema")
+
+ // ErrNoExample is sent when no example was found for an operation.
+ ErrNoExample = errors.New("No example found")
+)
+
+func openAPIExample(schema *openapi3.Schema, cache map[*openapi3.Schema]*cachedSchema) (out interface{}, err error) {
+ if ex, ok := getSchemaExample(schema); ok {
+ return ex, nil
+ }
+
+ cached, ok := cache[schema]
+ if !ok {
+ cached = &cachedSchema{
+ pending: true,
+ }
+ cache[schema] = cached
+ } else if cached.pending {
+ return nil, ErrRecursive
+ } else {
+ return cached.out, nil
+ }
+
+ defer func() {
+ cached.pending = false
+ cached.out = out
+ }()
+
+ // Handle combining keywords
+ if len(schema.OneOf) > 0 {
+ var ex interface{}
+ var err error
+
+ for _, candidate := range schema.OneOf {
+ ex, err = openAPIExample(candidate.Value, cache)
+ if err == nil {
+ break
+ }
+ }
+ return ex, err
+ }
+ if len(schema.AnyOf) > 0 {
+ var ex interface{}
+ var err error
+
+ for _, candidate := range schema.AnyOf {
+ ex, err = openAPIExample(candidate.Value, cache)
+ if err == nil {
+ break
+ }
+ }
+ return ex, err
+ }
+ if len(schema.AllOf) > 0 {
+ example := map[string]interface{}{}
+
+ for _, allOf := range schema.AllOf {
+ candidate, err := openAPIExample(allOf.Value, cache)
+ if err != nil {
+ return nil, err
+ }
+
+ value, ok := candidate.(map[string]interface{})
+ if !ok {
+ return nil, ErrNoExample
+ }
+
+ for k, v := range value {
+ example[k] = v
+ }
+ }
+ return example, nil
+ }
+
+ switch {
+ case schema.Type == "boolean":
+ return true, nil
+ case schema.Type == "number", schema.Type == "integer":
+ value := 0.0
+
+ if schema.Min != nil && *schema.Min > value {
+ value = *schema.Min
+ if schema.ExclusiveMin {
+ if schema.Max != nil {
+ // Make the value half way.
+ value = (*schema.Min + *schema.Max) / 2.0
+ } else {
+ value++
+ }
+ }
+ }
+
+ if schema.Max != nil && *schema.Max < value {
+ value = *schema.Max
+ if schema.ExclusiveMax {
+ if schema.Min != nil {
+ // Make the value half way.
+ value = (*schema.Min + *schema.Max) / 2.0
+ } else {
+ value--
+ }
+ }
+ }
+
+ if schema.MultipleOf != nil && int(value)%int(*schema.MultipleOf) != 0 {
+ value += float64(int(*schema.MultipleOf) - (int(value) % int(*schema.MultipleOf)))
+ }
+
+ if schema.Type == "integer" {
+ return int(value), nil
+ }
+ return value, nil
+ case schema.Type == "string":
+ if ex := stringFormatExample(schema.Format); ex != "" {
+ return ex, nil
+ }
+ example := "string"
+
+ for schema.MinLength > uint64(len(example)) {
+ example += example
+ }
+
+ if schema.MaxLength != nil && *schema.MaxLength < uint64(len(example)) {
+ example = example[:*schema.MaxLength]
+ }
+ return example, nil
+ case schema.Type == "array", schema.Items != nil:
+ example := []interface{}{}
+
+ if schema.Items != nil && schema.Items.Value != nil {
+ ex, err := openAPIExample(schema.Items.Value, cache)
+ if err != nil {
+ return nil, fmt.Errorf("can't get example for array item: %+v", err)
+ }
+
+ example = append(example, ex)
+
+ for uint64(len(example)) < schema.MinItems {
+ example = append(example, ex)
+ }
+ }
+ return example, nil
+ case schema.Type == "object", len(schema.Properties) > 0:
+ example := map[string]interface{}{}
+
+ for k, v := range schema.Properties {
+ if excludeFromMode(v.Value) {
+ continue
+ }
+
+ ex, err := openAPIExample(v.Value, cache)
+ if err == ErrRecursive {
+ if isRequired(schema, k) {
+ return nil, fmt.Errorf("can't get example for '%s': %+v", k, err)
+ }
+ } else if err != nil {
+ return nil, fmt.Errorf("can't get example for '%s': %+v", k, err)
+ } else {
+ example[k] = ex
+ }
+ }
+
+ if schema.AdditionalProperties.Has != nil && schema.AdditionalProperties.Schema != nil {
+ addl := schema.AdditionalProperties.Schema.Value
+
+ if !excludeFromMode(addl) {
+ ex, err := openAPIExample(addl, cache)
+ if err == ErrRecursive {
+ // We just won't add this if it's recursive.
+ } else if err != nil {
+ return nil, fmt.Errorf("can't get example for additional properties: %+v", err)
+ } else {
+ example["additionalPropertyName"] = ex
+ }
+ }
+ }
+ return example, nil
+ }
+ return nil, ErrNoExample
+}
+
+// generateExampleFromSchema creates an example structure from an OpenAPI 3 schema
+// object, which is an extended subset of JSON Schema.
+//
+// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#schemaObject
+func generateExampleFromSchema(schema *openapi3.Schema) (interface{}, error) {
+ return openAPIExample(schema, make(map[*openapi3.Schema]*cachedSchema)) // TODO: Use caching
+}
diff --git a/pkg/input/formats/openapi/generator.go b/pkg/input/formats/openapi/generator.go
new file mode 100644
index 00000000..090b761c
--- /dev/null
+++ b/pkg/input/formats/openapi/generator.go
@@ -0,0 +1,461 @@
+package openapi
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "os"
+ "strings"
+
+ "github.com/clbanning/mxj/v2"
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+ httpTypes "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/projectdiscovery/nuclei/v3/pkg/types"
+ errorutil "github.com/projectdiscovery/utils/errors"
+ "github.com/projectdiscovery/utils/generic"
+ mapsutil "github.com/projectdiscovery/utils/maps"
+ "github.com/valyala/fasttemplate"
+)
+
+const (
+ globalAuth = "globalAuth"
+)
+
+// GenerateRequestsFromSchema generates http requests from an OpenAPI 3.0 document object
+func GenerateRequestsFromSchema(schema *openapi3.T, opts formats.InputFormatOptions, callback formats.ParseReqRespCallback) error {
+ if len(schema.Servers) == 0 {
+ return errors.New("no servers found in openapi schema")
+ }
+
+ // new set of globalParams obtained from security schemes
+ globalParams := openapi3.NewParameters()
+
+ if len(schema.Security) > 0 {
+ params, err := GetGlobalParamsForSecurityRequirement(schema, &schema.Security)
+ if err != nil {
+ return err
+ }
+ globalParams = append(globalParams, params...)
+ }
+
+ // validate global param requirements
+ for _, param := range globalParams {
+ if val, ok := opts.Variables[param.Value.Name]; ok {
+ param.Value.Example = val
+ } else {
+ // if missing check for validation
+ if opts.SkipFormatValidation {
+ gologger.Verbose().Msgf("openapi: skipping all requests due to missing global auth parameter: %s\n", param.Value.Name)
+ return nil
+ } else {
+ // fatal error
+ gologger.Fatal().Msgf("openapi: missing global auth parameter: %s\n", param.Value.Name)
+ }
+ }
+ }
+
+ missingVarMap := make(map[string]struct{})
+ optionalVarMap := make(map[string]struct{})
+ missingParamValueCallback := func(param *openapi3.Parameter, opts *generateReqOptions) {
+ if !param.Required {
+ optionalVarMap[param.Name] = struct{}{}
+ return
+ }
+ missingVarMap[param.Name] = struct{}{}
+ }
+
+ for _, serverURL := range schema.Servers {
+ pathURL := serverURL.URL
+
+ for path, v := range schema.Paths.Map() {
+ // a path item can have parameters
+ ops := v.Operations()
+ requestPath := path
+ for method, ov := range ops {
+ if err := generateRequestsFromOp(&generateReqOptions{
+ requiredOnly: opts.RequiredOnly,
+ method: method,
+ pathURL: pathURL,
+ requestPath: requestPath,
+ op: ov,
+ schema: schema,
+ globalParams: globalParams,
+ reqParams: v.Parameters,
+ opts: opts,
+ callback: callback,
+ missingParamValueCallback: missingParamValueCallback,
+ }); err != nil {
+ gologger.Warning().Msgf("Could not generate requests from op: %s\n", err)
+ }
+ }
+ }
+ }
+
+ if len(missingVarMap) > 0 && !opts.SkipFormatValidation {
+ gologger.Error().Msgf("openapi: Found %d missing parameters, use -skip-format-validation flag to skip requests or update missing parameters generated in %s file,you can also specify these vars using -var flag in (key=value) format\n", len(missingVarMap), formats.DefaultVarDumpFileName)
+ gologger.Verbose().Msgf("openapi: missing params: %+v", mapsutil.GetSortedKeys(missingVarMap))
+ if config.CurrentAppMode == config.AppModeCLI {
+ // generate var dump file
+ vars := &formats.OpenAPIParamsCfgFile{}
+ for k := range missingVarMap {
+ vars.Var = append(vars.Var, k+"=")
+ }
+ vars.OptionalVars = mapsutil.GetSortedKeys(optionalVarMap)
+ if err := formats.WriteOpenAPIVarDumpFile(vars); err != nil {
+ gologger.Error().Msgf("openapi: could not write params file: %s\n", err)
+ }
+ // exit with status code 1
+ os.Exit(1)
+ }
+ }
+
+ return nil
+}
+
+type generateReqOptions struct {
+ // requiredOnly specifies whether to generate only required fields
+ requiredOnly bool
+ // method is the http method to use
+ method string
+ // pathURL is the base url to use
+ pathURL string
+ // requestPath is the path to use
+ requestPath string
+ // schema is the openapi schema to use
+ schema *openapi3.T
+ // op is the operation to use
+ op *openapi3.Operation
+ // post request generation callback
+ callback formats.ParseReqRespCallback
+
+ // global parameters
+ globalParams openapi3.Parameters
+ // requestparams map
+ reqParams openapi3.Parameters
+ // global var map
+ opts formats.InputFormatOptions
+ // missingVar Callback
+ missingParamValueCallback func(param *openapi3.Parameter, opts *generateReqOptions)
+}
+
+// generateRequestsFromOp generates requests from an operation and some other data
+// about an OpenAPI Schema Path and Method object.
+//
+// It also accepts an optional requiredOnly flag which if specified, only returns the fields
+// of the structure that are required. If false, all fields are returned.
+func generateRequestsFromOp(opts *generateReqOptions) error {
+ req, err := http.NewRequest(opts.method, opts.pathURL+opts.requestPath, nil)
+ if err != nil {
+ return errors.Wrap(err, "could not make request")
+ }
+
+ reqParams := opts.reqParams
+ if reqParams == nil {
+ reqParams = openapi3.NewParameters()
+ }
+ // add existing req params
+ reqParams = append(reqParams, opts.op.Parameters...)
+ // check for endpoint specific auth
+ if opts.op.Security != nil {
+ params, err := GetGlobalParamsForSecurityRequirement(opts.schema, opts.op.Security)
+ if err != nil {
+ return err
+ }
+ reqParams = append(reqParams, params...)
+ } else {
+ reqParams = append(reqParams, opts.globalParams...)
+ }
+
+ query := url.Values{}
+ for _, parameter := range reqParams {
+ value := parameter.Value
+
+ // paramValue or default value to use
+ var paramValue interface{}
+
+ // accept override from global variables
+ if val, ok := opts.opts.Variables[value.Name]; ok {
+ paramValue = val
+ } else if value.Schema.Value.Default != nil {
+ paramValue = value.Schema.Value.Default
+ } else if value.Schema.Value.Example != nil {
+ paramValue = value.Schema.Value.Example
+ } else if value.Schema.Value.Enum != nil && len(value.Schema.Value.Enum) > 0 {
+ paramValue = value.Schema.Value.Enum[0]
+ } else {
+ if !opts.opts.SkipFormatValidation {
+ if opts.missingParamValueCallback != nil {
+ opts.missingParamValueCallback(value, opts)
+ }
+ // skip request if param in path else skip this param only
+ if value.Required {
+ // gologger.Verbose().Msgf("skipping request [%s] %s due to missing value (%v)\n", opts.method, opts.requestPath, value.Name)
+ return nil
+ } else {
+ // if it is in path then remove it from path
+ opts.requestPath = strings.Replace(opts.requestPath, fmt.Sprintf("{%s}", value.Name), "", -1)
+ if !opts.opts.RequiredOnly {
+ gologger.Verbose().Msgf("openapi: skipping optional param (%s) in (%v) in request [%s] %s due to missing value (%v)\n", value.Name, value.In, opts.method, opts.requestPath, value.Name)
+ }
+ continue
+ }
+ }
+ exampleX, err := generateExampleFromSchema(value.Schema.Value)
+ if err != nil {
+ // when failed to generate example
+ // skip request if param in path else skip this param only
+ if value.Required {
+ gologger.Verbose().Msgf("openapi: skipping request [%s] %s due to missing value (%v)\n", opts.method, opts.requestPath, value.Name)
+ return nil
+ } else {
+ // if it is in path then remove it from path
+ opts.requestPath = strings.Replace(opts.requestPath, fmt.Sprintf("{%s}", value.Name), "", -1)
+ if !opts.opts.RequiredOnly {
+ gologger.Verbose().Msgf("openapi: skipping optinal param (%s) in (%v) in request [%s] %s due to missing value (%v)\n", value.Name, value.In, opts.method, opts.requestPath, value.Name)
+ }
+ continue
+ }
+ }
+ paramValue = exampleX
+ }
+ if opts.requiredOnly && !value.Required {
+ // remove them from path if any
+ opts.requestPath = strings.Replace(opts.requestPath, fmt.Sprintf("{%s}", value.Name), "", -1)
+ continue // Skip this parameter if it is not required and we want only required ones
+ }
+
+ switch value.In {
+ case "query":
+ query.Set(value.Name, types.ToString(paramValue))
+ case "header":
+ req.Header.Set(value.Name, types.ToString(paramValue))
+ case "path":
+ opts.requestPath = fasttemplate.ExecuteStringStd(opts.requestPath, "{", "}", map[string]interface{}{
+ value.Name: types.ToString(paramValue),
+ })
+ case "cookie":
+ req.AddCookie(&http.Cookie{Name: value.Name, Value: types.ToString(paramValue)})
+ }
+ }
+ req.URL.RawQuery = query.Encode()
+ req.URL.Path = opts.requestPath
+
+ if opts.op.RequestBody != nil {
+ for content, value := range opts.op.RequestBody.Value.Content {
+ cloned := req.Clone(req.Context())
+
+ example, err := generateExampleFromSchema(value.Schema.Value)
+ if err != nil {
+ continue
+ }
+
+ // var body string
+ switch content {
+ case "application/json":
+ if marshalled, err := json.Marshal(example); err == nil {
+ // body = string(marshalled)
+ cloned.Body = io.NopCloser(bytes.NewReader(marshalled))
+ cloned.ContentLength = int64(len(marshalled))
+ cloned.Header.Set("Content-Type", "application/json")
+ }
+ case "application/xml":
+ exampleVal := mxj.Map(example.(map[string]interface{}))
+
+ if marshalled, err := exampleVal.Xml(); err == nil {
+ // body = string(marshalled)
+ cloned.Body = io.NopCloser(bytes.NewReader(marshalled))
+ cloned.ContentLength = int64(len(marshalled))
+ cloned.Header.Set("Content-Type", "application/xml")
+ } else {
+ gologger.Warning().Msgf("openapi: could not encode xml")
+ }
+ case "application/x-www-form-urlencoded":
+ if values, ok := example.(map[string]interface{}); ok {
+ cloned.Form = url.Values{}
+ for k, v := range values {
+ cloned.Form.Set(k, types.ToString(v))
+ }
+ encoded := cloned.Form.Encode()
+ cloned.ContentLength = int64(len(encoded))
+ // body = encoded
+ cloned.Body = io.NopCloser(strings.NewReader(encoded))
+ cloned.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ }
+ case "multipart/form-data":
+ if values, ok := example.(map[string]interface{}); ok {
+ buffer := &bytes.Buffer{}
+ multipartWriter := multipart.NewWriter(buffer)
+ for k, v := range values {
+ // This is a file if format is binary, otherwise field
+ if property, ok := value.Schema.Value.Properties[k]; ok && property.Value.Format == "binary" {
+ if writer, err := multipartWriter.CreateFormFile(k, k); err == nil {
+ _, _ = writer.Write([]byte(types.ToString(v)))
+ }
+ } else {
+ _ = multipartWriter.WriteField(k, types.ToString(v))
+ }
+ }
+ multipartWriter.Close()
+ // body = buffer.String()
+ cloned.Body = io.NopCloser(buffer)
+ cloned.ContentLength = int64(len(buffer.Bytes()))
+ cloned.Header.Set("Content-Type", multipartWriter.FormDataContentType())
+ }
+ case "text/plain":
+ str := types.ToString(example)
+ // body = str
+ cloned.Body = io.NopCloser(strings.NewReader(str))
+ cloned.ContentLength = int64(len(str))
+ cloned.Header.Set("Content-Type", "text/plain")
+ case "application/octet-stream":
+ str := types.ToString(example)
+ if str == "" {
+ // use two strings
+ str = "string1\nstring2"
+ }
+ if value.Schema != nil && generic.EqualsAny(value.Schema.Value.Format, "bindary", "byte") {
+ cloned.Body = io.NopCloser(bytes.NewReader([]byte(str)))
+ cloned.ContentLength = int64(len(str))
+ cloned.Header.Set("Content-Type", "application/octet-stream")
+ } else {
+ // use string placeholder
+ cloned.Body = io.NopCloser(strings.NewReader(str))
+ cloned.ContentLength = int64(len(str))
+ cloned.Header.Set("Content-Type", "text/plain")
+ }
+ default:
+ gologger.Verbose().Msgf("openapi: no correct content type found for body: %s\n", content)
+ // LOG: return errors.New("no correct content type found for body")
+ continue
+ }
+
+ dumped, err := httputil.DumpRequestOut(cloned, true)
+ if err != nil {
+ return errors.Wrap(err, "could not dump request")
+ }
+
+ rr, err := httpTypes.ParseRawRequestWithURL(string(dumped), cloned.URL.String())
+ if err != nil {
+ return errors.Wrap(err, "could not parse raw request")
+ }
+ opts.callback(rr)
+ continue
+ }
+ }
+ if opts.op.RequestBody != nil {
+ return nil
+ }
+
+ dumped, err := httputil.DumpRequestOut(req, true)
+ if err != nil {
+ return errors.Wrap(err, "could not dump request")
+ }
+
+ rr, err := httpTypes.ParseRawRequestWithURL(string(dumped), req.URL.String())
+ if err != nil {
+ return errors.Wrap(err, "could not parse raw request")
+ }
+ opts.callback(rr)
+ return nil
+}
+
+// GetGlobalParamsForSecurityRequirement returns the global parameters for a security requirement
+func GetGlobalParamsForSecurityRequirement(schema *openapi3.T, requirement *openapi3.SecurityRequirements) ([]*openapi3.ParameterRef, error) {
+ globalParams := openapi3.NewParameters()
+ if len(schema.Components.SecuritySchemes) == 0 {
+ return nil, errorutil.NewWithTag("openapi", "security requirements (%+v) without any security schemes found in openapi file", schema.Security)
+ }
+ found := false
+ // this api is protected for each security scheme pull its corresponding scheme
+schemaLabel:
+ for _, security := range *requirement {
+ for name := range security {
+ if scheme, ok := schema.Components.SecuritySchemes[name]; ok {
+ found = true
+ param, err := GenerateParameterFromSecurityScheme(scheme)
+ if err != nil {
+ return nil, err
+
+ }
+ globalParams = append(globalParams, &openapi3.ParameterRef{Value: param})
+ continue schemaLabel
+ }
+ }
+ if !found && len(security) > 1 {
+ // if this is case then both security schemes are required
+ return nil, errorutil.NewWithTag("openapi", "security requirement (%+v) not found in openapi file", security)
+ }
+ }
+ if !found {
+ return nil, errorutil.NewWithTag("openapi", "security requirement (%+v) not found in openapi file", requirement)
+ }
+
+ return globalParams, nil
+}
+
+// generateExampleFromSchema generates an example from a schema object
+func GenerateParameterFromSecurityScheme(scheme *openapi3.SecuritySchemeRef) (*openapi3.Parameter, error) {
+ if !generic.EqualsAny(scheme.Value.Type, "http", "apiKey") {
+ return nil, errorutil.NewWithTag("openapi", "unsupported security scheme type (%s) found in openapi file", scheme.Value.Type)
+ }
+ if scheme.Value.Type == "http" {
+ // check scheme
+ if !generic.EqualsAny(scheme.Value.Scheme, "basic", "bearer") {
+ return nil, errorutil.NewWithTag("openapi", "unsupported security scheme (%s) found in openapi file", scheme.Value.Scheme)
+ }
+ if scheme.Value.Name == "" {
+ return nil, errorutil.NewWithTag("openapi", "security scheme (%s) name is empty", scheme.Value.Scheme)
+ }
+ // create parameters using the scheme
+ switch scheme.Value.Scheme {
+ case "basic":
+ h := openapi3.NewHeaderParameter(scheme.Value.Name)
+ h.Required = true
+ h.Description = globalAuth // differentiator for normal variables and global auth
+ return h, nil
+ case "bearer":
+ h := openapi3.NewHeaderParameter(scheme.Value.Name)
+ h.Required = true
+ h.Description = globalAuth // differentiator for normal variables and global auth
+ return h, nil
+ }
+
+ }
+ if scheme.Value.Type == "apiKey" {
+ // validate name and in
+ if scheme.Value.Name == "" {
+ return nil, errorutil.NewWithTag("openapi", "security scheme (%s) name is empty", scheme.Value.Type)
+ }
+ if !generic.EqualsAny(scheme.Value.In, "query", "header", "cookie") {
+ return nil, errorutil.NewWithTag("openapi", "unsupported security scheme (%s) in (%s) found in openapi file", scheme.Value.Type, scheme.Value.In)
+ }
+ // create parameters using the scheme
+ switch scheme.Value.In {
+ case "query":
+ q := openapi3.NewQueryParameter(scheme.Value.Name)
+ q.Required = true
+ q.Description = globalAuth // differentiator for normal variables and global auth
+ return q, nil
+ case "header":
+ h := openapi3.NewHeaderParameter(scheme.Value.Name)
+ h.Required = true
+ h.Description = globalAuth // differentiator for normal variables and global auth
+ return h, nil
+ case "cookie":
+ c := openapi3.NewCookieParameter(scheme.Value.Name)
+ c.Required = true
+ c.Description = globalAuth // differentiator for normal variables and global auth
+ return c, nil
+ }
+ }
+ return nil, errorutil.NewWithTag("openapi", "unsupported security scheme type (%s) found in openapi file", scheme.Value.Type)
+}
diff --git a/pkg/input/formats/openapi/openapi.go b/pkg/input/formats/openapi/openapi.go
new file mode 100644
index 00000000..afbe379f
--- /dev/null
+++ b/pkg/input/formats/openapi/openapi.go
@@ -0,0 +1,39 @@
+package openapi
+
+import (
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+)
+
+// OpenAPIFormat is a OpenAPI Schema File parser
+type OpenAPIFormat struct {
+ opts formats.InputFormatOptions
+}
+
+// New creates a new OpenAPI format parser
+func New() *OpenAPIFormat {
+ return &OpenAPIFormat{}
+}
+
+var _ formats.Format = &OpenAPIFormat{}
+
+// Name returns the name of the format
+func (j *OpenAPIFormat) Name() string {
+ return "openapi"
+}
+
+func (j *OpenAPIFormat) SetOptions(options formats.InputFormatOptions) {
+ j.opts = options
+}
+
+// Parse parses the input and calls the provided callback
+// function for each RawRequest it discovers.
+func (j *OpenAPIFormat) Parse(input string, resultsCb formats.ParseReqRespCallback) error {
+ loader := openapi3.NewLoader()
+ schema, err := loader.LoadFromFile(input)
+ if err != nil {
+ return errors.Wrap(err, "could not decode openapi 3.0 schema")
+ }
+ return GenerateRequestsFromSchema(schema, j.opts, resultsCb)
+}
diff --git a/pkg/input/formats/openapi/openapi_test.go b/pkg/input/formats/openapi/openapi_test.go
new file mode 100644
index 00000000..f48385a8
--- /dev/null
+++ b/pkg/input/formats/openapi/openapi_test.go
@@ -0,0 +1,63 @@
+package openapi
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/stretchr/testify/require"
+)
+
+const baseURL = "http://hackthebox:5000"
+
+var methodToURLs = map[string][]string{
+ "GET": {
+ "{{baseUrl}}/createdb",
+ "{{baseUrl}}/",
+ "{{baseUrl}}/users/v1/John.Doe",
+ "{{baseUrl}}/users/v1",
+ "{{baseUrl}}/users/v1/_debug",
+ "{{baseUrl}}/books/v1",
+ "{{baseUrl}}/books/v1/bookTitle77",
+ },
+ "POST": {
+ "{{baseUrl}}/users/v1/register",
+ "{{baseUrl}}/users/v1/login",
+ "{{baseUrl}}/books/v1",
+ },
+ "PUT": {
+ "{{baseUrl}}/users/v1/name1/email",
+ "{{baseUrl}}/users/v1/name1/password",
+ },
+ "DELETE": {
+ "{{baseUrl}}/users/v1/name1",
+ },
+}
+
+func TestOpenAPIParser(t *testing.T) {
+ format := New()
+
+ proxifyInputFile := "../testdata/openapi.yaml"
+
+ gotMethodsToURLs := make(map[string][]string)
+
+ err := format.Parse(proxifyInputFile, func(rr *types.RequestResponse) bool {
+ gotMethodsToURLs[rr.Request.Method] = append(gotMethodsToURLs[rr.Request.Method],
+ strings.Replace(rr.URL.String(), baseURL, "{{baseUrl}}", 1))
+ return false
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(gotMethodsToURLs) != len(methodToURLs) {
+ t.Fatalf("invalid number of methods: %d", len(gotMethodsToURLs))
+ }
+
+ for method, urls := range gotMethodsToURLs {
+ if len(urls) != len(methodToURLs[method]) {
+ t.Fatalf("invalid number of urls for method %s: %d", method, len(urls))
+ }
+ require.ElementsMatch(t, urls, methodToURLs[method], "invalid urls for method %s", method)
+ }
+}
diff --git a/pkg/input/formats/swagger/swagger.go b/pkg/input/formats/swagger/swagger.go
new file mode 100644
index 00000000..2828bb29
--- /dev/null
+++ b/pkg/input/formats/swagger/swagger.go
@@ -0,0 +1,69 @@
+package swagger
+
+import (
+ "encoding/json"
+ "os"
+ "path"
+
+ "github.com/getkin/kin-openapi/openapi2"
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats/openapi"
+ "gopkg.in/yaml.v2"
+
+ "github.com/getkin/kin-openapi/openapi2conv"
+)
+
+// SwaggerFormat is a Swagger Schema File parser
+type SwaggerFormat struct {
+ opts formats.InputFormatOptions
+}
+
+// New creates a new Swagger format parser
+func New() *SwaggerFormat {
+ return &SwaggerFormat{}
+}
+
+var _ formats.Format = &SwaggerFormat{}
+
+// Name returns the name of the format
+func (j *SwaggerFormat) Name() string {
+ return "swagger"
+}
+
+func (j *SwaggerFormat) SetOptions(options formats.InputFormatOptions) {
+ j.opts = options
+}
+
+// Parse parses the input and calls the provided callback
+// function for each RawRequest it discovers.
+func (j *SwaggerFormat) Parse(input string, resultsCb formats.ParseReqRespCallback) error {
+ file, err := os.Open(input)
+ if err != nil {
+ return errors.Wrap(err, "could not open data file")
+ }
+ defer file.Close()
+
+ schemav2 := &openapi2.T{}
+ ext := path.Ext(input)
+
+ if ext == ".yaml" || ext == ".yml" {
+ err = yaml.NewDecoder(file).Decode(schemav2)
+ } else {
+ err = json.NewDecoder(file).Decode(schemav2)
+ }
+ if err != nil {
+ return errors.Wrap(err, "could not decode openapi 2.0 schema")
+ }
+ schema, err := openapi2conv.ToV3(schemav2)
+ if err != nil {
+ return errors.Wrap(err, "could not convert openapi 2.0 schema to 3.0")
+ }
+ loader := openapi3.NewLoader()
+ err = loader.ResolveRefsIn(schema, nil)
+ if err != nil {
+ return errors.Wrap(err, "could not resolve openapi schema references")
+ }
+ return openapi.GenerateRequestsFromSchema(schema, j.opts, resultsCb)
+}
diff --git a/pkg/input/formats/swagger/swagger_test.go b/pkg/input/formats/swagger/swagger_test.go
new file mode 100644
index 00000000..601c20d9
--- /dev/null
+++ b/pkg/input/formats/swagger/swagger_test.go
@@ -0,0 +1,34 @@
+package swagger
+
+import (
+ "testing"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/stretchr/testify/require"
+)
+
+func TestSwaggerAPIParser(t *testing.T) {
+ format := New()
+
+ proxifyInputFile := "../testdata/swagger.yaml"
+
+ var gotMethodsToURLs []string
+
+ err := format.Parse(proxifyInputFile, func(request *types.RequestResponse) bool {
+ gotMethodsToURLs = append(gotMethodsToURLs, request.URL.String())
+ return false
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(gotMethodsToURLs) != 2 {
+ t.Fatalf("invalid number of methods: %d", len(gotMethodsToURLs))
+ }
+
+ expectedURLs := []string{
+ "https://localhost/users",
+ "https://localhost/users/1?test=asc",
+ }
+ require.ElementsMatch(t, gotMethodsToURLs, expectedURLs, "could not get swagger urls")
+}
diff --git a/pkg/input/formats/testdata/burp.xml b/pkg/input/formats/testdata/burp.xml
new file mode 100644
index 00000000..84796341
--- /dev/null
+++ b/pkg/input/formats/testdata/burp.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]>
+
+ -
+
Sat Sep 30 20:11:32 IST 2023
+
+ localhost
+ 8087
+ http
+
+
+ null
+
+ 200
+ 152
+ JSON
+
+
+
+ -
+
Sat Sep 30 20:08:54 IST 2023
+
+ google.com
+ 80
+ http
+
+
+ null
+
+ 301
+ 792
+ HTML
+
+
+
+
\ No newline at end of file
diff --git a/pkg/input/formats/testdata/ginandjuice.proxify.json b/pkg/input/formats/testdata/ginandjuice.proxify.json
new file mode 100644
index 00000000..64282b66
--- /dev/null
+++ b/pkg/input/formats/testdata/ginandjuice.proxify.json
@@ -0,0 +1,26 @@
+{"timestamp":"2023-09-07T21:03:38+05:30","url":"https://ginandjuice.shop/","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Cache-Control":"max-age=0","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=K3apVBuA9VPgjvRhmuEIK81dRquSyRPC8gXbOq4toRUpky4GpcmmPzP2j1c7KVfskcjCGih6K1kxXVYeKlClX5Rx60P+G6gHWE6hNhos6T/CuvhaP5uLb0BZgaZ7; AWSALBCORS=K3apVBuA9VPgjvRhmuEIK81dRquSyRPC8gXbOq4toRUpky4GpcmmPzP2j1c7KVfskcjCGih6K1kxXVYeKlClX5Rx60P+G6gHWE6hNhos6T/CuvhaP5uLb0BZgaZ7","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"none","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/","scheme":"https"},"raw":"GET / HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nCache-Control: max-age=0\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=K3apVBuA9VPgjvRhmuEIK81dRquSyRPC8gXbOq4toRUpky4GpcmmPzP2j1c7KVfskcjCGih6K1kxXVYeKlClX5Rx60P+G6gHWE6hNhos6T/CuvhaP5uLb0BZgaZ7; AWSALBCORS=K3apVBuA9VPgjvRhmuEIK81dRquSyRPC8gXbOq4toRUpky4GpcmmPzP2j1c7KVfskcjCGih6K1kxXVYeKlClX5Rx60P+G6gHWE6hNhos6T/CuvhaP5uLb0BZgaZ7\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: none\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2127","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:38 GMT","Set-Cookie":"AWSALB=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi; Expires=Thu, 14 Sep 2023 15:33:38 GMT; Path=/, AWSALBCORS=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi; Expires=Thu, 14 Sep 2023 15:33:38 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffd\u001a\ufffdr\ufffd8\ufffd\ufffd=\ufffd\ufffdwGa\u0006\ufffdMR\ufffdtHrs\ufffd@\ufffd\n-\u0003\u0003s\ufffdad[\ufffdUd\ufffdXr\ufffd\u001f\ufffd^\ufffd\ufffd\ufffdV\ufffd\ufffd:\ufffd\u001d;\ufffd\ufffdp3t:m$\ufffd\ufffdV\ufffd\ufffdRF?\ufffd]\ufffd\ufffd\ufffd\ufffd\ufffd\t\ufffdU\ufffd\u0026?\ufffd\ufffd?\u0004?\ufffd\ufffd\ufffd\ufffd~4CF\ufffd'\u0014gd:\ufffd2\"E\ufffd\u0005Dz\u000c\ufffd\u001a\ufffdd^ \ufffd'\u0003\ufffd_\ufffds3у\t\ufffd\u00116\ufffd\ufffd`DƄ\ufffd6b\ufffd\u0004\u0010\ufffdo\ufffdLB\ufffd\u0013H\ufffdㄌ\ufffd\u0019%\ufffdTd\ufffdA\ufffd\ufffd\ufffdp5v\ufffd4T\ufffd8$3\u001a\u0010\ufffd\u000c\ufffd\ufffd\\\ufffd\ufffd\u0005\u000ea\u0007F\ufffd\\8\u0015j2\ufffdh\ufffd\ufffd̂\ufffdSa\ufffdZ\ufffd\u0000\u0007\ufffd\u0007\ufffd\u0008\u0013i\u0002\ufffd{\ufffdҙ\ufffd\u003c\ufffdѝ\ufffd\u001b\ufffdd\u00072\ufffdH\ufffdd\ufffd|Q\ufffd5\ufffda;\ufffd\ufffdQ\ufffd\u003c\ufffd\u0019\ufffd\u003e\ufffd\ufffdc\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdɹH\u0008r\ufffd3\ufffd\ufffd\u001d\ufffd\ufffd\ufffdЋ\u001c\ufffd\ufffd\ufffd\ufffd\"\u001dy\u0016\ufffdjQ\ufffd\ufffd\u0017a\ufffdx\ufffd\ufffd4\ufffd\u0010\u000c\ufffd\u000c\ufffdp\ufffdT5^\u0011\ufffd=\n\t\u0014\u0015\u001c\u0005\u000cK9v\ufffd\ufffd\ufffd!\ufffd\ufffd\ufffd\ufffd\u001a\ufffdAJ7\ufffd\ufffd\ufffdۘJ\u0004\ufffd\u0018\ufffd\ufffdQ\ufffddX\u0011V\ufffdY\ufffd8|\u0006\ufffd\ufffd9\ufffd\u0011\ufffd\ufffdh\ufffdͮ\ufffd\u000f\ufffd8\t\ufffdTdH\u0011\ufffd(\ufffd4\ufffd\u001d\ufffd\ufffd\ufffd\ufffd\u0002\ufffd2\ufffd\n;\ufffd\ufffd\u0002s\ufffdW\ufffd\ufffdH\ufffdxy\u0014m\ufffd\u000e\u0012\u003c\u0011`T\ufffdL\ufffdi\ufffd㡘\ufffd\u003e~\ufffd\ufffdGc\ufffd_.\ufffd\ufffd\ufffd\ufffd`e5\ufffd\ufffd\ufffd\ufffdЮ.\ufffda\ufffdW\ufffd\ufffdV\ufffd\ufffdt\ufffd\ufffd)\ufffd[\ufffd\ufffd\ufffd\u001dT\ufffdke8\\\u001d\u001e\ufffdCL\ufffd\ufffd\u001a#\ufffd\ufffd\ufffd\ufffdb\ufffd\ufffd\ufffd?{\ufffd\ufffd\ufffd)\ufffd¦\ufffd3Ƃ\ufffdx|po\ufffd+#X\ufffd\u000cz \ufffdT\ufffd\ufffd\u001f\ufffd\ufffd\ufffdA\ufffdܰf\ufffdș\\\ufffd\n\u0015`֨\ufffd\u0003R\u0002\ufffd\ufffd\u0018\ufffd\ufffd\u000c\u0026\r\ufffd\ufffd1\u0017o\ufffd^\u0000\ufffdZ\ufffdV[\u003c\ufffdf\ufffd\ufffdltPCV\ufffd\ufffd\u0005\ufffd!\u0005S\u0000\ufffd\ufffd\ufffd\u0011\ufffdQ\ufffd\ufffd\ufffd!SCN\ufffd\ufffd\ufffd2\u0011\t\ufffdS\ufffdo \ufffdᆅ\u001bR\ufffda\ufffd\u0016\ufffd\u000c\u000e\ufffd\r\ufffd,!r\ufffd0m\ufffd\ufffd\ufffd\ufffd\t\ufffdtXm\ufffd\u0012\ufffd\u0019MpV\ufffdQ\ufffd\ufffdn\ufffdd\ufffd\u001d\ufffd\u0000\ufffd\ufffd\ufffd~\ufffd\u0014\u0004\u0005+P\ufffd\u0003\ufffd\ufffd '\ufffd\ufffdL\ufffdy\ufffdd\ufffdPV\ufffdy]6\ufffd=w\ufffda\ufffd1\ufffd\ufffd\ufffd\ufffd¾ȕ3\ufffd\ufffd~\ufffdDV|#\ufffdF^\ufffdnmB\ufffd\ufffd\ufffd\ufffd{6\"\u001c\u0004\"\ufffdʥAE*I\ufffd\ufffd\ufffd\ufffd\u001d\ufffd,\ufffd\ufffd \ufffd-\u0016o\ufffd)Xx\ufffd\ufffd\u0001\ufffd\u0002\ufffd\u0007п\ufffd\ufffd\u0004\ufffd\u0005d\ufffdd5\ufffd.\ufffd-\ufffd\ufffd\rp\ufffdco\u001e\ufffd\u001c\ufffd\u0007\ufffd\u0010\u0011\ufffd\ufffd3džn'\ufffd\ufffd/\ufffd/\u000bT~\ufffd\u0013\ufffd\ufffd\ufffdݝ\ufffdW\u0018l\ufffd\ufffd5k-\u0003\ufffd\ufffdW\ufffd\ufffd\ufffd\ufffdwXf\ufffd\ufffd֫Q\ufffd\ufffd\ufffdP\ufffd\ufffdn;\u001f\ufffd\ufffd\ufffd\ufffd\u0012Q\ufffd\u0008\ufffd\ufffdWf3\u001aE\ufffdB\ufffd\ufffdY\u001e\ufffdq\u0000\ufffd\ufffd6*\ufffd\ufffdƼאyk\ufffdk\ufffd\ufffd5(\ufffd\ufffd\ufffdPѝH\u000c\u0005vK\u0015\ufffd@\ufffd^\ufffd\ufffd\ufffd\u0002\ufffd\u0026\ufffd;\ufffd\ufffd\u000c\ufffd\r\ufffdKA\u000bE\ufffde\ufffd[F\ufffd\u0026D\ufffd.7\ufffd\ufffd\ufffdl\n\r[+m\ufffd\ufffd7\n\ufffd\ufffd\ufffd\"g?n\ufffd\ufffd\ufffd\u0000\u0006aƠ\ufffdhI\ufffd\r\u0015\ufffd\u0006\ufffd\ufffd\u001bY\u0010\ufffdʈfb\u001b\ufffd\u00151/\ufffdζv\u0026+\ufffd\ufffd\ufffd\u0014\ufffd:\u0005\ufffd\u0005\ufffdR\ufffd\ufffd\ufffd\u0000\ufffd\ufffd\ufffdV\u0013h\u0012\ufffd(4\u001b\ufffdAe)\ufffd{\ufffd\ufffd\u0010\ufffdX\"h\u003c\u0019\ufffd;\u001a\n\ufffdc(\"\ufffd\ufffd\u0012\ufffd)\ufffd(w\ufffd۶\ufffdҒ\ufffdvG\ufffd\u0004\ufffd\u001fyǺ\u001a\ufffd\ufffdY9-\ufffd\ufffd\u0000\ufffd\u0014\ufffd?ڒ=\ufffd%\u001d:F; 3\ufffdr\ufffdu\u0019\ufffd\u0010'$\ufffd\ufffd\ufffd\u0016eո\u001b[\ufffd\u0026+-m\ufffd\u0002\ufffd\ufffd\ufffdJ\ufffd\ufffdx\u0019N\ufffd\ufffd\ufffd\ufffd\u0005\u001b%\ufffd\ufffd0\ufffd\ufffd\ufffdJV\ufffd(\ufffd?\u000f\ufffd\ufffd\u000et\u000c-\ufffdD\ufffd%\ufffdIW\ufffd\ufffd\ufffd\u0016\u0014\ufffd6\ufffd^\n\ufffdꦞ|$!\ufffdg\ufffd\ufffd\u003c\ufffd\ufffdW\u003c\ufffd\\-\ufffd\ufffd\u0013\ufffd\ufffdNE\ufffd\t\ufffd\ufffd \u0004\u000ew\ufffdy#\ufffdfX_+\u000cw\ufffd\ufffd\ufffd\ufffd\ufffdT\u0005\ufffd0~\u001d\u001e\ufffd\u001e\u001c6\ufffd\ufffd\ufffdT\ufffd\ufffd\ufffd\ufffdԐ\ufffd\ufffdɮĺ\u0015\u0002\u001d,`\ufffd'\u000b\ufffd\ufffdwT\ufffd\r\ufffd\ufffdo\u001d\u001d/\ufffd\ufffdQ\ufffd\ufffd\ufffd*\ufffd\ufffdQ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdR\ufffd\ufffd\ufffd\n\ufffd\ufffdT\ufffdK\ufffdg\u000c\u0017\ufffd\ufffd\ufffd\ufffd\ufffdA\ufffd\ufffd\ufffd\ufffdTsKYeA\ufffd'\ufffdu#\ufffdWU\ufffd\ufffdZv\ufffd\ufffd\u000c\ufffd\ufffd\ufffdK\ufffd\\CsSю\ufffd\ufffd\ufffd@\ufffd\ufffd\ufffdC\ufffd\ufffd^\ufffdd\ufffdKX\ufffd=\ufffd]\ufffd\ufffd\ufffdޅ\ufffd\ufffd\ufffd\ufffdOt\ufffdiV\ufffd3\\\ufffdm\u000fZ9[1\u001e\ufffd!]\ufffd\ufffdF\ufffdm\u001c\u001b\ufffd\ufffda\u0007\ufffd\ufffdj\u0012\u0006\ufffd\ufffd\n\ufffd\ufffd\ufffd@\ufffd;\u0008\ufffd-\u0014\ufffd\ufffd\"I\u0019\ufffdBj/\"=\ufffd\ufffd\"\ufffd\ufffd\ufffd\ufffd\ufffd\u0007\ufffd\ufffda\ufffd\ufffd|\ufffd['l\ufffd+\ufffd\ufffd\n\u0001=\ufffd;Ϡ\ufffd\ufffdon\ufffd*R\ufffd\ufffdԤnRfd\ufffdoD\ufffdܛo\ufffd\u0004\ufffd\u0011\ufffd\u00168\ufffd\u0002^\u0011H\u001f(\ufffdҾ0a\ufffd\\$s_\ufffd\ufffd\u003eA\\̷\ufffd\t\ufffd\ufffd/\u0004\ufffdo\ufffd\ufffd\ufffd\ufffd\ufffdoNC\ufffd\u0002\ufffd$9\ufffdn\ufffd\ufffd\ufffd\u0010\ufffd!\ufffd6\ufffd\ufffd\u0014s\ufffd0\ufffd\ufffdo^\ufffdȗ\ufffd\ufffd\ufffd\ufffd`'2\ufffd\ufffd\ufffd\u0012bX?}\u0018n\u0000\u000eV\ufffdc(\ufffd\ufffd\ufffd(\u0010\ufffda_d\ufffd߀\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdt\u001b\ufffd7ʃ\ufffdW\ufffd\ufffda_A\ufffds-\u000fj\u001e\u0011kem\ufffd\u0000\u0017\ufffd\ufffd\ufffd\ufffdA!\ufffd\u00057!*\u0016\ufffd5\ufffdQ\ufffdNac\u0003\ufffd\ufffd\ufffd\ufffd@\ufffd\ufffdP\ufffd\ufffd\n\ufffd\ufffd9\ufffd\u0019\ufffd\ufffd摔$\ufffd\u0017\ufffdK\ufffd\ufffd\u0008\ufffd\u001d\ufffdX\ufffdP7\ufffdO\ufffd\u0014\u000eC8m[\ufffdSKމi\u0018\u0012\ufffd\ufffdó̦\u000eҭ\u001e\u000c\ufffdtv\ufffd\ufffd\ufffdɻ\ufffd\ufffd\ufffd_\u001f\u001e\ufffdǟs\ufffd䃺\u000e/_\ufffd\ufffd\ufffd\ufffd\ufffde\ufffd~e@Y\ufffd\u00035ۂH\u0012\ufffd\u0026o\u0016\ufffd\u0019yv\ufffd6\ufffd\ufffd\ufffd\ufffdQX \ufffdTp\ufffd\ufffd\ufffd\ufffd\u001fK\ufffdf\ufffdn9a\ufffd\ufffd$\ufffd✂\u0007\ufffd\u0006\ufffd\ufffd\ufffdSC\ufffd̰t\u0017\ufffd\ufffd\ufffd{\ufffd\ufffd\ufffdN\ufffd\ufffdMʧ\ufffds\u0019ٟ\u000c\u000e\u0003?\ufffd\"\u001d\t\n\u0015C\ufffd\u0007\u003e\ufffd\ufffd\ufffd_\ufffd{\ufffd\ufffd\ufffd\ufffdU\u0016\ufffd\ufffdn\ufffdB\ufffdg\ufffd\ufffd\ufffd3\ufffd\ufffd\ufffd\u0018\ufffd V\ufffd\u003c\ufffd^\ufffd\u001a\ufffd\ufffd\ufffdU\ufffd.\ufffd.\ufffd\ufffdd\u001a\ufffd6\u0015\u0003\ufffdv\ufffd\ufffd\ufffdȊl*V\u0007D)\t]\ufffd~\ufffd\ufffd5\ufffdU\ufffdP\ufffdvۂ\ufffd\ufffdN;\ufffd\ufffd\ufffd?Ӕ\ufffd;;*\ufffd\ufffd^_\ufffd\ufffd;5}\ufffd\ufffd\ufffdo\u000b\ufffd\ufffdL!\ufffd@4#\u0026\ufffd\ufffd9\u0003!2\ufffd\u0005\ufffd\ufffd\ufffdv\u0007\ufffd:T\u0000\ufffd+\ufffd\ufffd\ufffd\ufffd\ufffd\u0007\ufffd\ufffdh\u0014\ufffdR\ufffd\ufffd\ufffd\ufffdȹ\ufffd\ufffd7\u000fԝ\ufffd\ufffd\tL\ufffd\ufffdG_\ufffd\u000e\ufffd\u0015Pxc)\ufffd\u000b\u0015\ufffd\ufffd\ufffd\ufffd\ufffd-Ǘ'm\ufffd\ufffdo\ufffdsj\u000b\u00128\ufffd|\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdc{\"E\u0000\u001a\ufffdhy\u0004m\u0013ޏW\ufffdo\ufffdݏW\ufffd\ufffd\ufffd\ufffd\ufffdg\ufffd-\ufffdڃ\ufffdڰ\ufffd(\ufffd\ufffdejS\ufffdu\ufffdͪ\u0014\ufffd\ufffd\u0008\ufffd\ufffdO\ufffd\u0012ͷ\u0016\ufffd\u0003*%\u0016\ufffd\ufffd(\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2127\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:38 GMT\r\nSet-Cookie: AWSALB=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi; Expires=Thu, 14 Sep 2023 15:33:38 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi; Expires=Thu, 14 Sep 2023 15:33:38 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:43+05:30","url":"https://ginandjuice.shop/catalog/product?productId=1","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi; AWSALBCORS=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi","Referer":"https://ginandjuice.shop/","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/catalog/product","scheme":"https"},"raw":"GET /catalog/product?productId=1 HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi; AWSALBCORS=Pg2tRxpbJS4v1ZtiZEW7wdRuiV8VAiZ3b3l3tQPQqlbmlzdtxR43DjPK5Jy+fdqkGwxM1KZJ4rYEZno7EU9fm5zKFOYXkqdmZLntqAPODwer/3D3AJPY82NCJZfi\r\nReferer: https://ginandjuice.shop/\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2461","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:43 GMT","Set-Cookie":"AWSALB=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; Expires=Thu, 14 Sep 2023 15:33:43 GMT; Path=/, AWSALBCORS=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; Expires=Thu, 14 Sep 2023 15:33:43 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdZ\ufffdr\ufffd6\u0012\ufffdާ@y\ufffd(\ufffd1ES\ufffd\u001b\ufffd\"\ufffd\ufffd8Nz\ufffd\u0013k\ufffd\\\ufffdޗ\u000cDB$b\ufffd`\u0008P\ufffd2\ufffdB\ufffd\u001a\ufffdd\ufffd\u0000H\ufffd\ufffdH\ufffd\ufffd\ufffd\ufffd~\ufffd\ufffdc\ufffd\ufffd\ufffd\ufffd\u0002\ufffd\ufffdbw\ufffdѷ/o.\ufffd\ufffd1\ufffdB\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd|!\ufffd\ufffd\"\ufffd\u0003\ufffdS?2\ufffdܡ(#\ufffd\ufffd\ufffd\u0011\ufffd\ufffd\ufffd'\ufffdax\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdp\ufffd\ufffd\ufffd7\ufffd']Ї\u0002\ufffd\u00116\u0016rɈ\ufffd\u0008\ufffdm`\n\u0002\u0000\ufffd-\ufffd\ufffdd?@L$F\t\ufffd\ufffdؚS\ufffdHy\u0026-\ufffd\ufffdD\ufffdD\ufffd\ufffd\u0005\rd4\u000eȜ\ufffd\ufffd\ufffd\u000f'(\u0017$\ufffdAB\u0018\ufffd\ufffdq\n\ufffd\ufffd3\ufffdJ$2lU\u0004\ufffd(\ufffd\u0001\ufffd\ufffd\u000fH\ufffd\ufffd4\u0006\ufffd\ufffdGay#\ufffd\ufffd\ufffd\u000ea\u0007\u003c\u003e\u0000F.S\ufffd\ufffd$\ufffd\ufffd\ufffd\ufffd\ufffdؔZu\ufffd8\ts\ufffd\ufffd\u000f\ufffd\ufffd\ufffd~ڄ*\ufffdděЄ\ufffd4e\u0004]\u0005TR\ufffd\ufffdK\ufffd\ufffdIL\u0019\ufffd\ufffd$\ufffdA\ufffdK\ufffd\ufffd\ufffd\u0026\ufffd\u0011\ufffd\ufffdg\ufffd\ufffd\u001c\ufffd\u000f\ufffdF\u003c\u001d9\u0006\ufffd0\ufffdYSc4\ufffd\ufffd\u0012%\ufffd\r\ufffd\ufffd\u0001\u0003:G4\u0018[UFT\u0016\ufffdL\ufffd\ufffdZ\u0008\ufffda!Ɩ\ufffd\ufffd\u001d\u0010#=\ufffdluН\ufffd\ufffd2\ufffdy\u0017Q\ufffd\ufffd\u000f\ufffd\ufffd0:%\u0019\ufffd\ufffd-\ufffd\u003cg\t\ufffd\ufffd\rG\u000b2Ej\ufffd\ufffd\ufffdzT\u0018\ufffd\ufffd\t\tЌgH\u0012!i\u0012\ufffdF\ufffd\ufffd\ufffdH\ufffd\ufffd\u001d)\ufffdri\ufffd\ufffdT\ufffdL\ufffdk\u0005\u0018\ufffd\u0014\ufffd\ufffd\ufffd\ufffdm!\ufffd\ufffd\u001cH\u0007\ufffdM2E\ufffd$\ufffd\ufffd\ufffd\ufffd\u000f\ufffd.\u001a#wU\ufffd盵\ufffd\ufffd\ufffd\u0018\ufffd\ufffd\ufffdCS[VCiR\ufffd\u003e\ufffd蜧c\ufffd\ufffd\ufffd\ufffd\ufffdЏ\u001e\ufffd\ufffdX\u001b\ufffd\ufffd\ufffddz'\ufffd\ufffdb\ufffd\ufffd\u0008K\u003e}ܻ\u001e\ufffd\ufffd\u003eg~\ufffd\ufffd\ufffd\ufffd\ufffdi\ufffd\ufffd11\u001e\ufffd\ufffd\ufffdFe\u0004+\ufffda\u001f\ufffd$\u00158\ufffd\u0019\ufffd)\u001bԔ\rk\ufffd\ufffd,o\ufffdK\ufffd\u0004ڣb\u001f\ufffd\ufffdHFDoݷ@yX\ufffd\u001a\ufffd8[|\ufffd\ufffd\ufffdu{\ufffd\ufffd3\ufffd}\ufffd\u0007\ufffd\ufffd\ufffd*z\ufffd\ufffd\ufffd\ufffd`Ы\ufffd\ufffd\ufffd#l\ufffd\\ϩ\ufffd\ufffd\ufffd\u0013\ufffd\ufffdٌ\ufffd\u001c\ufffd\u0018\ufffd\u001b`\u001d\ufffdP\ufffd\ufffd\ufffd\nk\ufffdȧ\ufffd$\ufffda\ufffdU\ufffd\ufffd\ufffdԆ\ufffd4Ԝ\ufffd\u000b\ufffdUd\u0017(\ufffdh\ufffd\ufffd\ufffdy\ufffdQ\ufffd\u001dHF\ufffd\u001b醸\u001cz\ufffdK\t[\ufffd\u0018\ufffdK\u0012Xfe-\u0007(\ufffda\ufffd\ufffd\"Ƅ\ufffd\ufffd\ufffd\ufffd\ufffdu\ufffdH\ufffd\ufffdb\ufffd\ufffd\ufffdj\ufffd^\ufffd\ufffd?\ufffdXx\ufffdsiy7J\ufffd$ϖ\u000f$\ufffd\ufffd\ufffd\ufffd\ufffd\\\u0002e\ufffdI\ufffd\ufffdل}\ufffd牴\ufffd_Y\ufffdxi\u0017\ufffdp\ufffd\ufffdy\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdc\u0017\ufffd\u001e\ufffd/\ufffdZ\ufffd\ufffdC\ufffd\ufffdm`\ufffd\ufffdBgu\u001a+\ufffd.\ufffd[,O\ufffd\ufffd\u0007M{w\ufffd[t\ufffdN\ufffd\ufffd\ufffd\ufffd\u0026\ufffd%ָ\ufffdX\ufffdu\ufffd~\ufffdD\ufffd\ufffd\ufffd$z;\ufffd\ufffd\ufffd}\u0001a}\ufffdm\ufffd\ufffd0|\ufffd\ufffdQ|UG\ufffdiq\u0014vd\ufffdꪩ\ufffdF?\ufffd\ufffd\ufffd\ufffd\\Q|[\ufffd0d\u0004F\ufffd\u001b\ufffd\u0019\rC\ufffd*\ufffd٬\u0026\ufffd\ufffd\u0000\ufffd\u001dk\ufffdFN\ufffd\u0001\ufffdp\u0004\ufffd\u0014\ufffd8\u0016[\ufffd\ufffd\ufffd\u000c\u001e\ufffd\nY\ufffd\ufffd\ufffd1\ufffdݰSsf\ufffd\ufffd\ufffd1\u001c\ufffd\ufffd-^\u001f\ufffd֪\u001d\ufffd\ufffdv\n[\ufffd`?G\ufffd\ufffd\ufffdV\ufffdK:+\ufffd\ufffd\ufffd\u001c7utLuC\ufffdھO!\ufffd\t\ufffd,\ufffd\ufffd\ufffdl\ufffdR\ufffd\ufffdM\ufffd\u001c\ufffd\ufffd\ufffdǤ}[7{պ\u0000\ufffd\u0000\ufffd\u0001Qs\ufffdf.moZ\ufffd\ufffdn\ufffdht\ufffdV-h\u001cn\ufffd\ufffdZ\ufffdXP?8\ufffdmt\ufffd\u0016\ufffd](\u001e\ufffd\ufffd\ufffd\ufffd\ufffd@\ufffd\u003c\ufffdi\u0012\ufffd\ufffd\ufffd(v4ܻ\ufffdP\ufffd'\ufffd\ufffd\u001e\ufffd\u001aǁS\u000b*\n\ufffd$m\ufffdW߷C'\ufffd\ufffd\ufffd\ufffd\ufffd~\ufffd\ufffd\ufffd\ufffdG9;\ufffd\ufffd\ufffdm\ufffd\n\n\ufffdo\u00263\ufffd\ufffd\u0012\u001dFۘ\ufffd\ufffd\ufffd}\ufffd+\ufffdS¼\ufffd\ufffdN\ufffd\u00189\ufffd\ufffd\ufffdo\ufffd\ufffd\ufffdAA\u0013\ufffd \ufffdLjјBD\ufffd\ufffdm\ufffd`\ufffdK\ufffdR('\u0008\u001c\u00064\ufffd\ufffd\u001d\ufffd.Q\ufffdS\ufffd*\ufffd\ufffd2\ufffdIp\ufffd\ufffd\u001fJ\ufffd\u0002\ufffd\ufffd\ufffd\ufffdC\ufffd\u0005\ufffd\ufffdy\ufffdc4\ufffdr*\ufffdG\ufffd\u00029A\ufffddVY\u0012\n\ufffdj\ufffd\u0011\u0015\ufffdf\ufffdm\u0013\ufffd.xƂ\u003ez\u001fa\ufffd\u0002NDғHb\u0001\ufffd\ufffd\ufffdH\t\u0006W\ufffd\ufffd\ufffd\ufffd\u0010\ufffd\ufffd\u0015I\u0011\u000e\u0002\u0012\ufffd\u0008C}\ufffd\ufffdD\ufffdI\ufffd1\u0004q\ufffdBE3\u001aF\u0000\ufffd0yB\u0010\ufffd\ufffd:o\ufffd\u0006\ufffdxhN\u0004\u000c\u0008rD*\ufffd\ufffd\ufffd\ufffd\ufffdH\u0007s\ufffdr\ufffdB\ufffd\u0003(\ufffdy\u0018\ufffduH\u000c\u000b88?}s\ufffd\ufffd\ufffd\ufffd\u0001\ufffd\u003c\ufffd\ufffd\u0005~]|\ufffd\ufffd\ufffd\ufffdm'd\u003e\ufffd\u0017\u0010_\ufffdw\ufffd\u001f\u0011\ufffd\ufffd\u000b/`^\ufffd\ufffd\u001d\ufffd~\ufffd\ufffd\ufffd+(\ufffd\ufffd\ufffdS\u000b_\ufffd{\nEwtC\u000b\ufffd\u0004\ufffd\u0008\ufffd\u00267\ufffd\ufffd:*ވ\u0026),eF\u003e\ufffd4\u0003\u0002\ufffd\ufffd[Da'\ufffd\ufffd2\ufffd\ufffdb\ufffdB\ufffd9\ufffd,\ufffd\u0012\ufffd+\ufffd\tU\u000b\u001c\u0015f\u0011@9\ufffd5\ufffdZ/\ufffd\ufffd\"\ufffd͓\ufffd\ufffdonj\ufffd\u0018j\u0000P\u0013\ufffdQq4\ufffd\u0010\ufffd\ufffdP\ufffd\u000f\ufffdI\ufffdKjm:\ufffd.B\ufffd=\"\ufffd\ufffd\ufffd[[!\ufffd\ufffd\ufffd\ufffd4\u0017F\ufffd)\ufffd\ufffd\ufffd*\ufffdu5훬\ufffd\ufffd\ufffd\ufffdI\ufffd\ufffdl\ufffd\ufffdS\ufffd\ufffd1\ufffd]\ufffdN\ufffd\ufffdq\u001c4\ufffdr\ufffd\u0000}-\ufffd\u0001\ufffd\u0007\ufffd\ufffd\ufffd \ufffd\ufffd\ufffd\ufffd\ufffd`\ufffd\ufffd\ufffdK諔\ufffd\ufffd\ufffd\ufffdЦTl\ufffd\ufffdG\ufffd\ufffd\ufffdj\ufffd\ufffd+\ufffd.h\ufffd\u003e\u0010.\u0014Ҭ\ufffd\ufffd\ufffdz\ufffd\ufffd_\ufffd]%.LE\ufffd,}\ufffdO9N$\ufffd\ufffd\ufffdzL=NY~\ufffd-)\ufffdh\ufffd\ufffd\u0000\ufffd\ufffd\u001b\u003c\ufffd%\ufffd\ufffdG\ufffd\ufffdY\ufffd\ufffd\ufffd \ufffd\ufffdw~4\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd O-\ufffd\ufffd\ufffd \u0017\ufffdwq4\ufffd\u000f\ufffd\ufffd\ufffd\ufffd \ufffd\ufffd幧\ufffd\ufffd\ufffd\u0001\ufffd\u001e\ufffdZ\u0017h\ufffd\u001e\ufffd[\u0017\ufffd\ufffd\u001e\ufffd\\\u0017\ufffd\ufffd\u001e\ufffd]\u0017\ufffd\ufffd\u001e\ufffd\ufffd#\u000ecs\u0016\u0017f\ufffd8t\ufffd\u0007\ufffd\ufffd\ufffd\ufffd\ufffd~\ufffd\ufffd#I\ufffd\u000c\ufffd\u0007\ufffdKM\ufffd\ufffd\ufffdd\ufffdo\ufffd\\̰%A\ufffd\u0026\ufffd\ufffd[\ufffd\ufffd˪\ufffd^MW[\ufffd\ufffdЌs\u0008@\ufffdE\u0006\u0001G}\u001ei+\ufffda:4\ufffd\ufffdv\ufffd\u0019\ufffdi\ufffd\ufffdyJ\ufffd}|}A\ufffd/\u001b\u0011\r\ufffd\ufffdd\u000e\ufffdSL\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u001a\ufffd\ufffd\u001c\ufffd)QA\ufffdȁV\ufffd\u0010\ufffd\ufffd3\ufffd\ufffdh\u0015\ufffd-h@\ufffdJ\ufffd\ufffd\t\u001c\ufffd\ufffd\ufffdtĤ\u0002B\u001d\ufffd\ufffd\u0019N P\ufffdʼn\u000e\ufffdȽ\ufffdrA\ufffd0\u0012Y\u0008\ufffd\ufffd4\u0010\ufffd\ufffd\ufffdQK\u0003\ufffd\ufffdF\ufffd\ufffd@\ufffd \ufffd\ufffds\u0006\ufffd,\ufffdt:M\ufffdP3\u0006\ufffd\ufffd\ufffd7\ufffd\ufffd\ufffdp\ufffd-\u001f\ufffd\ufffd\ufffd[\ufffd\u0000/\ufffd\ufffd\ufffd\ufffd[_}\ufffd\ufffdҫ\ufffd*\u0000J\ufffdeԔr!\ufffd\ufffd\ufffd@k\rЖ\ufffd\ufffd\ufffd\ufffd ئ̸-\ufffdgʰO\"\ufffd\u0002u\ufffd}\ufffd\ufffd\ufffd\t\ufffdٶ\ufffd\ufffdt\ufffd\ufffd|\ufffd\ufffdV\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdY\ufffd\ufffdՕ{u\ufffdy\"\ufffdӋ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd~{5\ufffdo_\ufffd\ufffdWX\ufffd-\ufffdP1|\ufffdm\ufffd2햮=\ufffd\ufffd\ufffdZo\ufffd\ufffd\ufffd\ufffd'\ufffd)i\u0013r#\ufffd\ufffd\ufffd5\ufffdw\ufffd\u000c}\ufffd\u0005)m%\ufffd\ufffdgԿ+\ufffd/5\ufffdK-\ufffdc\ufffd\ufffdD\u003eQ\ufffd\ufffdپ\ufffd\ufffdI\ufffd\u0019\ufffd\u001aIG\ufffd78\ufffd\u000e\ufffdt\ufffd\ufffd%X\ufffdLG\u0008:\ufffd\ufffdq\ufffd\u001b=\ufffd\ufffd\ufffdfwE\u0018\u0016{\ufffd.\ufffd\u000b%\ufffd\ufffd\ufffd\ufffdS\ufffd\rR)\ufffd\u003c\tڳ\ufffd\u001b\ufffd\ufffd\u000e\ufffd\ufffd\u0005\ufffdj\u0013VBC\ufffd\ufffd\ufffd@\ufffd\u0019\ufffd\u000bvdcm*\ufffd\u0003PJ\u0002\u001b\ufffdߝ\ufffd\ufffdf\ufffd*T\ufffd\ufffd\u003ec\ufffd3\ufffd\u0001MS\ufffdy\ufffd\ufffd\ufffdJi\td\ufffdWN\ufffdΰ\ufffd\u0017\ufffdR\ufffd\ufffd\ufffd\n\u001bє\ufffd5#ڪ\ufffd2݂g\ufffd\r\ufffd\ufffdTVG\ufffd\ufffd4\ufffd1\ufffd\ufffdb\ufffd\ufffdN=غL%\ufffd\u000ePo\ufffd\ufffd\ufffdX\ufffd\u000b2\ufffd\ufffdH\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0017\rN\u0007C4\u0001\ufffd[\ufffd\ufffd\ufffde\ufffd\ufffd0\ufffd\ufffdn\ufffd\u001af[̴\ufffd:\ufffd\ufffdϩuH`\ufffd\ufffd\u0003ܒ\ufffd\ufffd\ufffd\u000cZ\ufffdbV\u0019K\ufffdÎ^\ufffd\ufffd|жx\ufffdV\ufffd\ufffdb\ufffd\ufffdZMm\ufffd\ufffd\u0017\ufffd\ufffd\ufffd\ufffd֍\ufffd\ufffdc\ufffdwj\ufffdL;\ufffd\ufffd\ufffd\ufffd]\ufffd\u0014N%\u001e,\ufffdo\ufffdl\ufffd\ufffd\u0017\ufffd\u001fZ\ufffdMaw,\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2461\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:43 GMT\r\nSet-Cookie: AWSALB=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; Expires=Thu, 14 Sep 2023 15:33:43 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; Expires=Thu, 14 Sep 2023 15:33:43 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:46+05:30","url":"https://ginandjuice.shop/resources/js/stockCheck.js","request":{"header":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; AWSALBCORS=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g","Referer":"https://ginandjuice.shop/catalog/product?productId=1","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"script","Sec-Fetch-Mode":"no-cors","Sec-Fetch-Site":"same-origin","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/resources/js/stockCheck.js","scheme":"https"},"raw":"GET /resources/js/stockCheck.js HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; AWSALBCORS=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g\r\nReferer: https://ginandjuice.shop/catalog/product?productId=1\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: script\r\nSec-Fetch-Mode: no-cors\r\nSec-Fetch-Site: same-origin\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Cache-Control":"public, max-age=3600","Content-Encoding":"gzip","Content-Length":"420","Content-Type":"application/javascript; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:46 GMT","Set-Cookie":"AWSALB=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/, AWSALBCORS=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdR\ufffdn\ufffd0\u000c\ufffd\ufffd+8]*\ufffd\ufffd\ufffdm7\u0017n\ufffd\ufffd\u001d6\ufffd\ufffda\ufffd\u000f(\u00163\u000bu\ufffd\ufffd\ufffd\ufffd\u0019A\ufffd}\ufffd\ufffd\u0006uS\ufffd\u0004\u000cX\ufffd\ufffd\ufffd\u0013\ufffdlh\ufffd\u001a=\ufffd\ufffd\ufffdn:\ufffd߯\ufffd\u000f\ufffdU\ufffd\ufffd\u003c.Zl\u001e\ufffd\ufffd~\ufffd\ufffd\ufffdX{\ufffd\ufffdӷ.\u0012z\ufffd\ufffd$-\ufffd\u000cV\ufffd7\ufffd\ufffd\ufffdX\ufffd\ufffd\u00048\u001ai\ufffd\u0017\nM\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdw\ufffdD\ufffd\ufffd\u001a\ufffd\rV\u00153x%i2\ufffd$=nA\ufffd_\u001b2\ufffd\ufffd(.2;\ufffd\ufffd\u001eE\ufffd5\ufffdL\ufffdH3\ufffd\ufffd\ufffd\ufffdI\ufffd\ufffd\ufffd\ufffd\ufffd\u0019l\u000c\ufffd3\ufffd\ufffdu\u0010\u0019|$\ufffd\ufffd\ufffd\u0001jЬ\u0000c\u0001\ufffd%\ufffd?\ufffdk\ufffd\ufffd:\ufffd+\ufffd\ufffd\ufffd\u000e\ufffd\nVHM\ufffd\u000f\ufffdD\ufffd0Av\ufffd\ufffd\ufffd5Gx\ufffd\ufffdb\u001f+\ufffd\ufffd\ufffd\"x\ufffd0\ufffd?\u000c\u001b\u003c\ufffd`\ufffd\ufffd\r۲\u0019Q\u0001aL\ufffd\u000cv\ufffdX\ufffd\ufffd\u0005cu\ufffd\ufffd\ufffdf\ufffd\ufffd4͔Ԣ\ufffd\ufffd\ufffd\ufffd\u0011\ufffdH\ufffd\ufffdܿ\ufffdO\ufffd\ufffdѤ\ufffd\\D\ufffd\ufffd\ufffd\u003e\ufffd\ufffdt\ufffdxg\ufffd4\u0015\ufffd'\ufffd\u000f\ufffd\u0019(H\ufffdQT\ufffd\u0011G\u0005j\u0011Rg\ufffd\u0007\u001aW\t\ufffdp\ufffd\ufffd\ufffdv\ufffd\ufffd\ufffdt\ufffd\ufffd\ufffd\ufffd_\u0018\ufffd#\ufffd`\ufffdٶ\ufffd\u001f~\ufffd\ufffdks\ufffd\u000b\ufffd\ufffdȃ\ufffd\ufffd\u0004\ufffd\ufffd\ufffd\u00078\ufffd\ufffdb\ufffd\\;\ufffd\ufffd\ufffdm\ufffd\u0000\ufffd\u000e\u001b\ufffd8\u0003\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 420\r\nCache-Control: public, max-age=3600\r\nContent-Encoding: gzip\r\nContent-Type: application/javascript; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:46 GMT\r\nSet-Cookie: AWSALB=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:46+05:30","url":"https://ginandjuice.shop/resources/js/xmlStockCheckPayload.js","request":{"header":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; AWSALBCORS=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g","Referer":"https://ginandjuice.shop/catalog/product?productId=1","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"script","Sec-Fetch-Mode":"no-cors","Sec-Fetch-Site":"same-origin","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/resources/js/xmlStockCheckPayload.js","scheme":"https"},"raw":"GET /resources/js/xmlStockCheckPayload.js HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g; AWSALBCORS=Bw29bzxm1ZFCqwAsdTUat6udxhYzHJE8Aw2bx6njc30OZmjrKCbp0DgE11GbzOh9pBT4AdR8D0cQN23zLa91oF0u5g/d1YCSaToyLqB6++toCM6Ie1Xj8dPErU8g\r\nReferer: https://ginandjuice.shop/catalog/product?productId=1\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: script\r\nSec-Fetch-Mode: no-cors\r\nSec-Fetch-Site: same-origin\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Cache-Control":"public, max-age=3600","Content-Encoding":"gzip","Content-Length":"230","Content-Type":"application/javascript; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:46 GMT","Set-Cookie":"AWSALB=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/, AWSALBCORS=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffdU\ufffd͎\ufffd0\u0010\ufffd\ufffd}\ufffd\t\u00170dAo\ufffd z\ufffd\ufffd'Г\ufffd0)\ufffdn\u0003\ufffdM)(1\ufffd\ufffd\u001d]\u000e\ufffd\ufffdL~\ufffd\ufffd\ufffd)ݘ[!\ufffd\ufffd\ufffd\ufffdq\ufffd\u00045\ufffdhm\ufffd$zety\ufffd\ufffdi%D;j\ufffd7X\ufffd{\ufffdM֠\ufffd\u0015\u003c\u0004\ufffd\ufffd\ufffdAбu\ufffd\ufffde\"7\u0004q\ufffdl\ufffdu\u0002\ufffd\ufffdi\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdw!\ufffd},\ufffd\ufffd4x#\ufffd\ufffd?\ufffd\u001d\ufffd7k\ufffd\ufffd8עr`Z\ufffd\ufffd\"\ufffd\ufffd\u0014\r\ufffdji^\ufffd;\ufffdC;k\ufffd\ufffdK\u0015\ufffd\t\ufffd\ufffd\u0016\ufffd\ufffd\ufffd\ufffdG\ufffd)\ufffd\ufffd\ufffd\u001c\ufffd\u001d\ufffd\u001fK\ufffd\ufffde\ufffd\u003e\ufffdO\u0011?_\ufffd\ufffd3s\ufffdG\ufffdYR\ufffd\ufffd\u000b\ufffd\ufffd\ufffd\ufffdd\u0001\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 230\r\nCache-Control: public, max-age=3600\r\nContent-Encoding: gzip\r\nContent-Type: application/javascript; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:46 GMT\r\nSet-Cookie: AWSALB=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+; Expires=Thu, 14 Sep 2023 15:33:46 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:46+05:30","url":"https://ginandjuice.shop/resources/js/xmlStockCheckPayload.js","request":{"header":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+; AWSALBCORS=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"none","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/resources/js/xmlStockCheckPayload.js","scheme":"https"},"raw":"GET /resources/js/xmlStockCheckPayload.js HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+; AWSALBCORS=FIbJDpsPHxD3iVXrbXy2p7UvQ9uAlbRSlw874/GWrsFNOxfbOd0u7+85vW0SZs9YGmUcYmxZmmOgurXrLi0df6YnHYB3ewMFh94Jk5QX+F+cQRPIP+zU0iZTIiE+\r\nSec-Fetch-Dest: empty\r\nSec-Fetch-Mode: cors\r\nSec-Fetch-Site: none\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Cache-Control":"public, max-age=3600","Content-Encoding":"gzip","Content-Length":"230","Content-Type":"application/javascript; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:47 GMT","Set-Cookie":"AWSALB=Og/rMkIG6TdnxmKZZY/dHf/nbCJoVtem7Xf2gR2asoHlHQ4cRDVDhCHAELX8TKOz9FBJ38LxoNlB7BQHKwTbaHIhExVtj6B34UaUrguamGInLdvBYBiSoYTHu7x3; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/, AWSALBCORS=Og/rMkIG6TdnxmKZZY/dHf/nbCJoVtem7Xf2gR2asoHlHQ4cRDVDhCHAELX8TKOz9FBJ38LxoNlB7BQHKwTbaHIhExVtj6B34UaUrguamGInLdvBYBiSoYTHu7x3; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffdU\ufffd͎\ufffd0\u0010\ufffd\ufffd}\ufffd\t\u00170dAo\ufffd z\ufffd\ufffd'Г\ufffd0)\ufffdn\u0003\ufffdM)(1\ufffd\ufffd\u001d]\u000e\ufffd\ufffdL~\ufffd\ufffd\ufffd)ݘ[!\ufffd\ufffd\ufffd\ufffdq\ufffd\u00045\ufffdhm\ufffd$zety\ufffd\ufffdi%D;j\ufffd7X\ufffd{\ufffdM֠\ufffd\u0015\u003c\u0004\ufffd\ufffd\ufffdAбu\ufffd\ufffde\"7\u0004q\ufffdl\ufffdu\u0002\ufffd\ufffdi\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdw!\ufffd},\ufffd\ufffd4x#\ufffd\ufffd?\ufffd\u001d\ufffd7k\ufffd\ufffd8עr`Z\ufffd\ufffd\"\ufffd\ufffd\u0014\r\ufffdji^\ufffd;\ufffdC;k\ufffd\ufffdK\u0015\ufffd\t\ufffd\ufffd\u0016\ufffd\ufffd\ufffd\ufffdG\ufffd)\ufffd\ufffd\ufffd\u001c\ufffd\u001d\ufffd\u001fK\ufffd\ufffde\ufffd\u003e\ufffdO\u0011?_\ufffd\ufffd3s\ufffdG\ufffdYR\ufffd\ufffd\u000b\ufffd\ufffd\ufffd\ufffdd\u0001\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 230\r\nCache-Control: public, max-age=3600\r\nContent-Encoding: gzip\r\nContent-Type: application/javascript; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:47 GMT\r\nSet-Cookie: AWSALB=Og/rMkIG6TdnxmKZZY/dHf/nbCJoVtem7Xf2gR2asoHlHQ4cRDVDhCHAELX8TKOz9FBJ38LxoNlB7BQHKwTbaHIhExVtj6B34UaUrguamGInLdvBYBiSoYTHu7x3; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=Og/rMkIG6TdnxmKZZY/dHf/nbCJoVtem7Xf2gR2asoHlHQ4cRDVDhCHAELX8TKOz9FBJ38LxoNlB7BQHKwTbaHIhExVtj6B34UaUrguamGInLdvBYBiSoYTHu7x3; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:46+05:30","url":"https://ginandjuice.shop/resources/js/stockCheck.js","request":{"header":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg; AWSALBCORS=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"none","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/resources/js/stockCheck.js","scheme":"https"},"raw":"GET /resources/js/stockCheck.js HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg; AWSALBCORS=30LBKfbh2Lt0gdYEB/KlscXoCMozAKMWv5H8QdDbvd2tyRAQtUSxv6TIpUDkNZjWUApcBBe5s3QgdnwKvYJdI5qhmWtR1ZZu5JLJR+b2ysTEDXFnAafJVsgArarg\r\nSec-Fetch-Dest: empty\r\nSec-Fetch-Mode: cors\r\nSec-Fetch-Site: none\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Cache-Control":"public, max-age=3600","Content-Encoding":"gzip","Content-Length":"420","Content-Type":"application/javascript; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:47 GMT","Set-Cookie":"AWSALB=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/, AWSALBCORS=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdR\ufffdn\ufffd0\u000c\ufffd\ufffd+8]*\ufffd\ufffd\ufffdm7\u0017n\ufffd\ufffd\u001d6\ufffd\ufffda\ufffd\u000f(\u00163\u000bu\ufffd\ufffd\ufffd\ufffd\u0019A\ufffd}\ufffd\ufffd\u0006uS\ufffd\u0004\u000cX\ufffd\ufffd\ufffd\u0013\ufffdlh\ufffd\u001a=\ufffd\ufffd\ufffdn:\ufffd߯\ufffd\u000f\ufffdU\ufffd\ufffd\u003c.Zl\u001e\ufffd\ufffd~\ufffd\ufffd\ufffdX{\ufffd\ufffdӷ.\u0012z\ufffd\ufffd$-\ufffd\u000cV\ufffd7\ufffd\ufffd\ufffdX\ufffd\ufffd\u00048\u001ai\ufffd\u0017\nM\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdw\ufffdD\ufffd\ufffd\u001a\ufffd\rV\u00153x%i2\ufffd$=nA\ufffd_\u001b2\ufffd\ufffd(.2;\ufffd\ufffd\u001eE\ufffd5\ufffdL\ufffdH3\ufffd\ufffd\ufffd\ufffdI\ufffd\ufffd\ufffd\ufffd\ufffd\u0019l\u000c\ufffd3\ufffd\ufffdu\u0010\u0019|$\ufffd\ufffd\ufffd\u0001jЬ\u0000c\u0001\ufffd%\ufffd?\ufffdk\ufffd\ufffd:\ufffd+\ufffd\ufffd\ufffd\u000e\ufffd\nVHM\ufffd\u000f\ufffdD\ufffd0Av\ufffd\ufffd\ufffd5Gx\ufffd\ufffdb\u001f+\ufffd\ufffd\ufffd\"x\ufffd0\ufffd?\u000c\u001b\u003c\ufffd`\ufffd\ufffd\r۲\u0019Q\u0001aL\ufffd\u000cv\ufffdX\ufffd\ufffd\u0005cu\ufffd\ufffd\ufffdf\ufffd\ufffd4͔Ԣ\ufffd\ufffd\ufffd\ufffd\u0011\ufffdH\ufffd\ufffdܿ\ufffdO\ufffd\ufffdѤ\ufffd\\D\ufffd\ufffd\ufffd\u003e\ufffd\ufffdt\ufffdxg\ufffd4\u0015\ufffd'\ufffd\u000f\ufffd\u0019(H\ufffdQT\ufffd\u0011G\u0005j\u0011Rg\ufffd\u0007\u001aW\t\ufffdp\ufffd\ufffd\ufffdv\ufffd\ufffd\ufffdt\ufffd\ufffd\ufffd\ufffd_\u0018\ufffd#\ufffd`\ufffdٶ\ufffd\u001f~\ufffd\ufffdks\ufffd\u000b\ufffd\ufffdȃ\ufffd\ufffd\u0004\ufffd\ufffd\ufffd\u00078\ufffd\ufffdb\ufffd\\;\ufffd\ufffd\ufffdm\ufffd\u0000\ufffd\u000e\u001b\ufffd8\u0003\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 420\r\nCache-Control: public, max-age=3600\r\nContent-Encoding: gzip\r\nContent-Type: application/javascript; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:47 GMT\r\nSet-Cookie: AWSALB=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn; Expires=Thu, 14 Sep 2023 15:33:47 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:48+05:30","url":"https://ginandjuice.shop/catalog/product/stock","request":{"header":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Content-Length":"107","Content-Type":"application/xml","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn; AWSALBCORS=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn","Origin":"https://ginandjuice.shop","Referer":"https://ginandjuice.shop/catalog/product?productId=1","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"POST","path":"/catalog/product/stock","scheme":"https"},"body":"\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\u003cstockCheck\u003e\u003cproductId\u003e1\u003c/productId\u003e\u003cstoreId\u003e1\u003c/storeId\u003e\u003c/stockCheck\u003e","raw":"POST /catalog/product/stock HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nContent-Length: 107\r\nContent-Type: application/xml\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn; AWSALBCORS=SPTiMN+mfMtStgumCVLwgd1VcPfrsYrAnqZCYHHQ7TRAPgUCdr/rOizYyvCKNzNUwzB293sDNclHBUdj6U5My2LYYFltNmVa4PiV/kqZAshwIro9uPCI5+IPobxn\r\nOrigin: https://ginandjuice.shop\r\nReferer: https://ginandjuice.shop/catalog/product?productId=1\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: empty\r\nSec-Fetch-Mode: cors\r\nSec-Fetch-Site: same-origin\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"23","Content-Type":"text/plain; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:49 GMT","Set-Cookie":"AWSALB=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb; Expires=Thu, 14 Sep 2023 15:33:49 GMT; Path=/, AWSALBCORS=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb; Expires=Thu, 14 Sep 2023 15:33:49 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd32\ufffd\u0000\u0000\u0003\u0004\ufffd\u001d\u0003\u0000\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 23\r\nContent-Encoding: gzip\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:49 GMT\r\nSet-Cookie: AWSALB=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb; Expires=Thu, 14 Sep 2023 15:33:49 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb; Expires=Thu, 14 Sep 2023 15:33:49 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:50+05:30","url":"https://ginandjuice.shop/catalog/cart","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Cache-Control":"max-age=0","Connection":"close","Content-Length":"36","Content-Type":"application/x-www-form-urlencoded","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb; AWSALBCORS=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb","Origin":"https://ginandjuice.shop","Referer":"https://ginandjuice.shop/catalog/product?productId=1","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"POST","path":"/catalog/cart","scheme":"https"},"body":"productId=1\u0026redir=PRODUCT\u0026quantity=1","raw":"POST /catalog/cart HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nCache-Control: max-age=0\r\nConnection: close\r\nContent-Length: 36\r\nContent-Type: application/x-www-form-urlencoded\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb; AWSALBCORS=II4xh/SWIyNVdqMNb9xxg7whOOfkjlkAp/GSV7a/7p/GoE6na6h0XovVJJpRLDJ4YojSVX+O84vR+vPs4ggyEa6K4A6+mHsWdAKVQpgy7EKXsvJsKwR1+SmmUThb\r\nOrigin: https://ginandjuice.shop\r\nReferer: https://ginandjuice.shop/catalog/product?productId=1\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"0","Date":"Thu, 07 Sep 2023 15:33:50 GMT","Location":"/catalog/product?productId=1","Set-Cookie":"AWSALB=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg; Expires=Thu, 14 Sep 2023 15:33:50 GMT; Path=/, AWSALBCORS=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg; Expires=Thu, 14 Sep 2023 15:33:50 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"raw":"HTTP/1.1 302 Found\r\nConnection: close\r\nContent-Length: 0\r\nContent-Encoding: gzip\r\nDate: Thu, 07 Sep 2023 15:33:50 GMT\r\nLocation: /catalog/product?productId=1\r\nSet-Cookie: AWSALB=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg; Expires=Thu, 14 Sep 2023 15:33:50 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg; Expires=Thu, 14 Sep 2023 15:33:50 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:51+05:30","url":"https://ginandjuice.shop/catalog/product?productId=1","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Cache-Control":"max-age=0","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg; AWSALBCORS=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg","Referer":"https://ginandjuice.shop/catalog/product?productId=1","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/catalog/product","scheme":"https"},"raw":"GET /catalog/product?productId=1 HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nCache-Control: max-age=0\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg; AWSALBCORS=HED+UhOe9ddVq10zx/UgyutiRdCjvmuRvh+sa/qbQGY3nnK226bQ0Jf/chpK1rFMWxQnmPtGS5sFVIOS6VzeIswsOCe/5rsJYczuq2C6wKHJXXi2MyIqRMNqclZg\r\nReferer: https://ginandjuice.shop/catalog/product?productId=1\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2459","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:51 GMT","Set-Cookie":"AWSALB=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB; Expires=Thu, 14 Sep 2023 15:33:51 GMT; Path=/, AWSALBCORS=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB; Expires=Thu, 14 Sep 2023 15:33:51 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdZ\ufffdr\ufffd6\u0012\ufffdާ@y\ufffd(\ufffd1ES\ufffd\ufffd\ufffd\"\ufffd\ufffd\ufffdiz\ufffdc\ufffdu\ufffd\ufffdݗ\u000cDB\u0014b\ufffd`\u0008P\ufffd2\ufffdB\ufffd\u001a\ufffdd\ufffd\u0000H\ufffd\ufffdH\ufffd2\ufffd\ufffd~\ufffd\ufffdc\ufffd\ufffd\ufffd\ufffd\u0002\ufffd\ufffdbw\ufffdѷ\u0017\ufffd\ufffd\ufffd\ufffdu\ufffd\u001a\ufffddļoF\ufffd\u000b\ufffdg4#80?\ufffd#\ufffd\ufffd\u001d\ufffd\ufffdd:vR\"x\ufffd\ufffdD8\u000cOT3\ufffd:\ufffd\u0010\ufffd\ufffdq\ufffd\ufffd\ufffd\ufffd\u000b\ufffdP\ufffdR\ufffd\ufffdB.\u0019\u00113Bd\u0013\ufffd\ufffd\u0000@q\u000b0\u0011\ufffd\u000f\u0010\u0011\ufffdQ\ufffd#2\ufffd\ufffd\ufffd,\u0012\ufffdJ\u000b\ufffd\u003c\ufffd$\ufffdckA\u00039\u001b\u0007dN}b\ufffd\ufffd#\ufffd\t\ufffd\ufffd !\ufffd\ufffd\ufffd8\ufffdV\tM\ufffd)M$\u0012\ufffd?\ufffdJ\u0002}\u0012\ufffd\ufffd}\ufffd\u0007$\ufffdx\u0012\u0001x\ufffd\ufffd\ufffd\ufffd\ufffdcz\ufffd\ufffd\ufffd\u0003\u001e\u001d\u0000#\ufffd\t\ufffdL\ufffd{\ufffd|\ufffdslJ\ufffd*t\u001c\ufffd\u0019\ufffd\ufffdG\ufffd~n?\ufffdC\ufffdT2\ufffd\ufffdИ\ufffd$a\u0004\ufffd\u000e\ufffd\ufffd\u003cF\ufffdܿ\ufffd\ufffd2d\ufffd\ufffd\ufffd\u0007\ufffd/\ufffd\ufffd\u001b\u001a\ufffd'8J^\ufffd_2X?t;\ufffd\ufffd\ufffd1\u0010\ufffd\u0019Κ\u001a\ufffd\t\u000f\ufffd(\u000em\u0000.\r\u0018\ufffd9\ufffd\ufffd\ufffd*3\ufffd\ufffd\ufffdf\ufffd\ufffd\ufffdB\ufffd\u000c\u000b1\ufffd\u000c\ufffd\ufffd\ufffd\u0018\ufffd\ufffdf\ufffd\ufffd\ufffd\ufffd얩\ufffd\ufffd\u0019\u0015\u0008\ufffd0\n\u0008\ufffd\u0013\ufffdbI\ufffd\u0012\ufffd3\u0016\ufffdo\ufffdp\ufffd \u0013\ufffd\u0026O}\ufffdG\ufffdqh\u0018\ufffd\u0000My\ufffd$\u0011\ufffdơj\ufffd$\ufffd\ufffd\ufffdeё2*\ufffd\ufffdHM\u0005\ufffdD\ufffdR\ufffd\ufffdH\ufffdj*\ufffd\ufffd\u0016\ufffdqāt\ufffd\ufffd$U\ufffd\ufffd\u0003\ufffd\ufffd\ufffdx\ufffd\ufffd1rW\ufffd|\ufffdY;ب\ufffd\ufffd\ufffd\\;4\ufffdE5\ufffd\ufffd\ufffd\ufffdY2\ufffd\ufffd\u0014=-\u000f\ufffd\ufffd\t*\ufffd\ufffd\ufffd8\ufffd|\u003cy\ufffd\u0018\ufffdWk\ufffd\ufffd䓧\ufffd\ufffd\ufffd\ufffd\ufffdɛS\ufffdG?Q\ufffd\ufffd\u003e\t\ufffd0\ufffd/\ufffd\ufffdը\ufffd`%3\ufffd\u0003\ufffd\ufffd\u0004\ufffd\ufffdD;e\ufffd\ufffd\ufffdaEى\ufffd\ufffdd\u0012-\ufffd\ufffd(\ufffd\u0007$9\ufffd3\ufffd\ufffd\ufffd[\ufffd\u003c,\u0005]\ufffd-\ufffd@Cú\ufffd\\\ufffd\u0019ھ\ufffd\u0003\ufffd*`\u0015\ufffdMSer0\ufffdUZ\ufffd\ufffd\u00116V\ufffd\ufffdT\ufffdT\ufffd\tm\ufffdl\ufffdC\u000ez\u000c\ufffd5\ufffd\u000e\ufffd\ufffdXCi\ufffd\ufffd\u001b\ufffd\ufffd}b\\3̪E\ufffd\njC[\u001ajNع\ufffd*\ufffd\u000b\ufffd\ufffd4\ufffd\ufffd\ufffd\u003cU(\ufffd\u000e$\ufffd͍tC\\\u000c=ɤ\ufffd-R\u000c\ufffd%\t,\ufffd\ufffd\ufffd\u0003\u0014Ű`@\u0011c\ufffdD\ufffd\ufffdl\ufffd:m$x\ufffd\ufffd+\ufffd\u0026Z\ufffdW\ufffd\ufffdO%\u0016\ufffd\ufffdLZR(\ufffd\ufffd\ufffd#\t7r2֙K\ufffd\ufffd\u003c\u000e\ufffd2\ufffd\ufffd\ufffd\ufffd,\ufffd6\ufffdK\ufffd\u0012-\ufffd\ufffd\u001c\ufffdQ1\u000f\ufffd\u0011\u0018\ufffd\ufffdr}\ufffd\u0002\ufffdC\ufffd\u0005]\ufffd\ufffd}h\ufffd\ufffd\rL\ufffd_\ufffd\ufffdNc\ufffd\ufffdfy\ufffd\ufffdi\ufffd\ufffd\ufffdi\ufffdN\ufffd\u000e\ufffd\ufffd_\ufffd\u0010Ѹ\ufffd\ufffd\u001a\ufffd\u0015k\ufffd\ufffd\ufffd\ufffd\ufffd(\ufffd\ufffd\ufffdDo\ufffdv{\ufffd\u0007\u0010\ufffd\ufffd\ufffd\u0016[s\ufffd\ufffd\ufffd\u001a\ufffdWu\u0004\ufffd\ufffdQؒ\ufffd\ufffd\ufffd\ufffd\ufffd\u001a\ufffdp\ufffdrI\ufffdm\ufffdÐ\u0011\u0018\ro\ufffd\ufffd4\u000c\ufffd\ufffdhf\ufffd\ufffdL\ufffd\u0003\ufffd\ufffd\ufffd*\ufffd\ufffd\ufffd\u0003\ufffd\ufffd\u0008\ufffd(\ufffdp,\ufffdZ\ufffd\ufffd\u0019\u003c\u0016\u0015\ufffd\ufffd\ufffd\ufffd\"\u0002\ufffda'\ufffd\ufffdj\ufffd\ufffd#8\ufffdW'y\ufffd[\ufffd\u003e\ufffd\ufffdU;\ufffd\ufffd\ufffd\u0004\ufffd\ufffd\ufffd~\ufffd\ufffd\ufffd]\ufffd\u003e\ufffdt\ufffd;ǹ9\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdڵ}\ufffd@\ufffd\u0013\ufffdi\u0016M\ufffd\ufffdp\ufffd\n\ufffd\ufffdd9\ufffd\ufffd3\ufffdH\ufffd\ufffdn\ufffd\ufffdt\u0001\ufffd\u0001\ufffd\u0003\ufffd\ufffd\ufffd\ufffd\\\ufffd\ufffd\ufffd\ufffd\ufffdQ\ufffd\ufffd\ufffdZ\ufffd(\ufffd³\ufffd\ufffd\u0016\ufffd\ufffd~p\ufffd\ufffd\ufffd\ufffd-\n\ufffd\ufffd?\n')\ufffd\ufffd\ufffd\ufffdy\ufffd\ufffd8\ufffd'W\ufffd\ufffd\ufffdR\ufffd\ufffdp\ufffd\ufffdB\ufffd\ufffdp\ufffdz\ufffdr\u001c\u0007N-\ufffd(Ē\ufffd\ufffd_u\ufffd\u0016\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdq\u000b;[\u001d\ufffd\ufffd\ufffdS\ufffd\ufffd\ufffd*ȭ\ufffd\ufffd̰\ufffdJ\ufffd\u0018mc\ufffd\ufffd#\ufffd\ufffd\ufffd\u000cO\u0008\ufffd.֝\ufffd1rLYs\ufffdĻ\ufffd\ufffd\ufffdƘA\ufffd\ufffd\u0011\ufffd\u0011\ufffd\ufffd\u0000\ufffd\ufffd\u000c\ufffd\u0008\ufffd\\\ufffdP\ufffd\u00108\u000ch\ufffd\ufffd;4Y\ufffd\ufffd'*U\u0002\ufffde\ufffd\ufffd\ufffd\u0008\ufffd?\u0014\ufffd\u00054'\u0011\ufffd\ufffd\ufffd\u000b*g\ufffd)\ufffd\ufffd4ͨD\ufffdT\n\ufffd\u0008\ufffd\ufffdYeI(\ufffd\ufffdYJT(\ufffd\u0002\ufffdM|\ufffd\ufffd)\u000b\ufffd\ufffd\ufffd\u000cK\u0014p\"\ufffd\ufffdD\u0012\u000b\ufffdg'DJ0\ufffdz\u0014%\ufffd\ufffd\u0000\r\ufffdH\ufffdp\u0010\ufffd\ufffdG\u0018\ufffd\ufffd\u0017\ufffd#\ufffd@z\ufffd!\ufffd\ufffd\u0015*\ufffd\ufffdp\u00060\n\ufffd\ufffd\u0004\ufffd\ufffd\ufffd\ufffd\u0016j@\ufffd\ufffd\ufffdD\ufffd\ufffd \ufffdL\ufffd\ufffdTT\u001c\u001a\ufffd`.R.Q\ufffdy\u0000\ufffd\u003c\u000bg}\u001d\u0012\ufffd\u0002\u000eN\ufffd\ufffd]\ufffd\ufffd w\ufffdn\ufffd\ufffd\ufffd¯\u0017ߡ\ufffdW\ufffd\ufffd̝y\u0001\ufffd\ufffdg\ufffd3\ufffdߵ\ufffd\u0005\ufffd+2\ufffd#\ufffd\ufffd\\u\ufffd\t\ufffd,\ufffd\ufffd\ufffd\ufffd\ufffd\\\ufffd\u001d\ufffd\ufffdB\u0011\ufffd)B\ufffd\ufffd\ufffd\ufffd\ufffd-\u0015oD\ufffd\u0004\ufffd2%\ufffd3\ufffd\u0002\u0001L\ufffdmFa'\ufffd\ufffd2\ufffd\ufffd|\ufffdB\ufffd9\ufffd,\ufffd\u0012\ufffd-\ufffd\tUs\u001c\u0015f\u0011@9\ufffd5\ufffdZ/\ufffd\ufffd\"\ufffd\ufffd〃onj\u001e\u000c5\u0000\ufffd\u001b\ufffdR\ufffd\u0019i\u0008H\ufffd(\ufffd\u0007ʤ\ufffd%\ufffd6-[硿\ufffd\u001e\ufffdM@ݭ\ufffd\ufffd\ufffd\ufffdLA\ufffd\u000b#\ufffd\u0014\ufffdq]\u0015\ufffdښ\ufffdMV\ufffdFDƤ\ufffd\ufffd6\ufffd\ufffd)\ufffd\ufffd\ufffdݮpo\ufffd\ufffdq\u001c\ufffd\ufffdr\u001f\ufffd\ufffd\u0016\ufffd\u0000̃\ufffd\\G\u0010\ufffdf\ufffdWs\ufffdz\ufffd\ufffd9\ufffdUJ^\ufffd\ufffdFhS(\ufffd\ufffd\ufffd\u000ejm\ufffd\ufffd(\ufffdJ\ufffds\u001a\ufffd\ufffd\ufffd\u000b\ufffd4\ufffd1o~\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdĹ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd9ñ\ufffdr\ufffd[\ufffd\ufffd\ufffd)ʻؒ\"\ufffd\ufffdB\ufffd\ufffd\ufffd\ufffd\u001b\u003c\ufffd%\ufffd\ufffd\ufffdAN,\ufffd\ufffd3ȩ\ufffd\ufffdv\u0006\ufffd\ufffd\ufffd\ufffd\ufffd\u000c\ufffd\ufffd\ufffd\ufffdw\u0006yay/:\ufffd\ufffd`y?t\u0006q\ufffd-\ufffd=\ufffd\u000e\u0003\u0007\ufffd\ufffd.\ufffd\ufffd\ufffd\ufffd[\u0017\ufffd\ufffdvg\ufffd\u000b\ufffdu\ufffds\ufffd\u0005\ufffd\ufffd\u0007\ufffd\ufffd\ufffdal\ufffd\ufffd\ufffdl\ufffd\ufffd\ufffdY\u0010(\ufffdX\ufffd\ufffd\ufffd=\ufffd\u000f\u003e\ufffd\ufffdͰ}\ufffd\ufffdT\ufffdj\ufffdL\ufffd\ufffd\u0001\ufffd\ufffd\u000c\u001b\u0012dMB\ufffd\ufffd婼\ufffd\ufffd\ufffdUw\ufffdUJ\rM9\ufffd\u0000\ufffd^\ufffd\u0010pT瑶R\u0018\ufffdC]\u001eh\u0017\ufffd\ufffd\ufffdv\ufffd꧴\ufffd\ufffd\ufffd\u0017\ufffd\ufffd\ufffd\u0011\ufffd\ufffdwE\ufffd\u00109ET\ufffd+^\ufffdn\ufffd\ufffd{ʑ\ufffd\u0010\u0015č\u001chU\u000f\ufffdx\ufffdp\u0008\ufffdV\ufffdق\u0006\u0004\ufffd$\\\u0016\ufffd1\ufffd\ufffdTGL* \ufffd\u0001\u001f\ufffd\ufffd\u0018\u0002e_\u001c\ufffd0\ufffd\ufffd\ufffd,\u0013t\u000e#\ufffd\ufffd\ufffd\u0008L\u00031\ufffd\ufffd\u001e\ufffd4\ufffd\u000ej\ufffd\ufffd\n\u0004\u000b\u0002O\u003eg\u0010\ufffd\ufffdT\ufffdӄ\t5#\ufffd\ufffd\ufffd{ë\ufffd\u000f\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd^\ufffd\u0005xq\ufffd\u0016^\ufffd\ufffd\u0012\ufffd\ufffdk\ufffd\ufffd^\u0005T\u0001P\ufffd.\ufffd\ufffd\ufffd\u000b\ufffd\u0017\ufffd\u0004Zk\ufffd\ufffd\ufffdM\ufffd\u0004\ufffd6e\ufffdm1?\u0013\ufffd}2\ufffd,P\u0017߯u\u00118\ufffd0ۦ\ufffd\ufffd6њ/\ufffd\ufffd*P{\ufffdk\ufffd\ufffd%\ufffdE\ufffd\ufffdW\ufffd\ufffd\ufffd\ufffd*\ufffd;\ufffd\ufffdno\ufffdr\u001d\\}Β\ufffd\ufffdrK\ufffde\u0010J\ufffdϻ-V\ufffd\ufffd\ufffd5'\ufffd\ufffdZ\ufffd\r\ufffdy\ufffd\ufffd\ufffd6%MBn\ufffd~u\ufffdz\ufffdn\ufffd\ufffdϸ \ufffd\ufffd\u0004\ufffd\ufffd\ufffd\ufffdwy\ufffd\ufffdƾ\ufffd\"=\u0005m\ufffd\ufffd3\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd4\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0006\ufffd߁\ufffdN\ufffd\ufffd\u0004K\ufffd\ufffd\u0008A\ufffd\ufffd:\ufffdU\ufffd'پ\ufffd\ufffd\ufffd\u0008\ufffd|o\ufffd\ufffdz\ufffd\ufffd68\u0010w\ufffdo\ufffdA*%\ufffd\ufffdAsvs\u00036߁\u0002:\ufffd]m\ufffdJh\ufffd\ufffd\ufffd\u0018(5\ufffd?`G6֦\ufffd:\u0000\ufffd$\ufffd\ufffd\ufffd\ufffdY[kV\ufffdB\ufffd\ufffd\ufffd3\ufffd;#\u001d\ufffd4\ufffdΒ\ufffd-UJK 3\ufffdr*t\ufffdM\ufffd\ufffd\ufffd\ufffd\ufffduT؈\u0026\u0004\ufffd\u0019\ufffdVE\ufffd\ufffd\u0016\u003cUo\ufffd5\ufffd\ufffdZ\nդ\ufffd\ufffdQ\ufffd\u0006K\ufffdu\ufffd\ufffd֥*\ufffdw\ufffdz\ufffd\ufffd\ufffd\ufffdB_\ufffd\ufffd7DZ-\ufffdN\ufffd\ufffd\ufffd\ufffdhp\u003c\u0018\ufffd\u001b@\ufffd5\u0008\ufffdR\u0006\ufffd\u00163;\ufffdf\ufffdf\ufffd\ufffdLk\ufffd\ufffd\ufffd\ufffd\ufffdJ\ufffd\u0004f\ufffd8\ufffd-\ufffdZ\ufffdg\ufffdp\u0017\ufffd\ufffdXr\u001fv\ufffd\ufffd\ufffd僦\ufffd\ufffd뵚\ufffd\u0017\ufffd\ufffd\ufffdj*k\u000f\ufffd\ufffd\ufffd\ufffd\u0015\ufffdn\ufffd\ufffd\u001ek\ufffdS\ufffdd\ufffdI5/\ufffdp*\ufffd`\ufffd}\u0003g\ufffd~\ufffd\ufffd\ufffdf\u0001L\\w,\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2459\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:51 GMT\r\nSet-Cookie: AWSALB=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB; Expires=Thu, 14 Sep 2023 15:33:51 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB; Expires=Thu, 14 Sep 2023 15:33:51 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:03:58+05:30","url":"https://ginandjuice.shop/catalog/subscribe","request":{"header":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Content-Length":"69","Content-Type":"application/json;charset=UTF-8","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB; AWSALBCORS=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB","Origin":"https://ginandjuice.shop","Referer":"https://ginandjuice.shop/catalog/product?productId=1","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"POST","path":"/catalog/subscribe","scheme":"https"},"body":"{\"email\":\"eqeq@gfmail.com\",\"csrf\":\"GQrKlppDdKQale2DNpk4mASSUzOdNqup\"}","raw":"POST /catalog/subscribe HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nContent-Length: 69\r\nContent-Type: application/json;charset=UTF-8\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB; AWSALBCORS=pP/J8f16lsfhCBOQLxBx2gL95pTIbJWbhm+SWYXVZJslAfv/IqAnVRqRQjThWb4kOcgB3DvGx/sZN+IBBSlkzBdNXp6NZQNUwkZFyEyYez/+H3CGY/gr8tlR6yEB\r\nOrigin: https://ginandjuice.shop\r\nReferer: https://ginandjuice.shop/catalog/product?productId=1\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: empty\r\nSec-Fetch-Mode: cors\r\nSec-Fetch-Site: same-origin\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"68","Content-Type":"application/json; charset=utf-8","Date":"Thu, 07 Sep 2023 15:33:58 GMT","Set-Cookie":"AWSALB=2SKCWqUz3j0AasFKb1dBCnRQrU3mM16R6pX5fClkcKjvp9b8dRFcFCYjXp5pHaVHN6uVcVD0B4tt7MAs81yd5Unvr/oSF0i53t8n7wjb/pw+/XRO6yEaCLu2sCW1; Expires=Thu, 14 Sep 2023 15:33:58 GMT; Path=/, AWSALBCORS=2SKCWqUz3j0AasFKb1dBCnRQrU3mM16R6pX5fClkcKjvp9b8dRFcFCYjXp5pHaVHN6uVcVD0B4tt7MAs81yd5Unvr/oSF0i53t8n7wjb/pw+/XRO6yEaCLu2sCW1; Expires=Thu, 14 Sep 2023 15:33:58 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdVJ\ufffd/-\ufffd\ufffdS\ufffdR\ufffd\ufffd\ufffdS\ufffd\n\ufffdtv5\ufffd0\u0008P\ufffdQJ\ufffdM\ufffd\ufffd\u0001\ufffd\ufffd\u0016\ufffd\u0016:\ufffd\ufffd\ufffdxz\ufffd\ufffd\ufffdJ\ufffd\u0000-/{\ufffd4\u0000\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 68\r\nContent-Encoding: gzip\r\nContent-Type: application/json; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:33:58 GMT\r\nSet-Cookie: AWSALB=2SKCWqUz3j0AasFKb1dBCnRQrU3mM16R6pX5fClkcKjvp9b8dRFcFCYjXp5pHaVHN6uVcVD0B4tt7MAs81yd5Unvr/oSF0i53t8n7wjb/pw+/XRO6yEaCLu2sCW1; Expires=Thu, 14 Sep 2023 15:33:58 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=2SKCWqUz3j0AasFKb1dBCnRQrU3mM16R6pX5fClkcKjvp9b8dRFcFCYjXp5pHaVHN6uVcVD0B4tt7MAs81yd5Unvr/oSF0i53t8n7wjb/pw+/XRO6yEaCLu2sCW1; Expires=Thu, 14 Sep 2023 15:33:58 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:03+05:30","url":"https://ginandjuice.shop/blog","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=2rYKe8I1LwfOtI/423ImCGauGOtHRl2cXGdbbyWcVzzI5FqsI0s8Rij7fJUDNtQn4HPmweWUufw1GsgLXkGVie58e4PGUBD4je7UWtZobziKhxVouiWJeEFiNMkR; AWSALBCORS=2rYKe8I1LwfOtI/423ImCGauGOtHRl2cXGdbbyWcVzzI5FqsI0s8Rij7fJUDNtQn4HPmweWUufw1GsgLXkGVie58e4PGUBD4je7UWtZobziKhxVouiWJeEFiNMkR","Referer":"https://ginandjuice.shop/catalog/product?productId=1","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/blog","scheme":"https"},"raw":"GET /blog HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=2rYKe8I1LwfOtI/423ImCGauGOtHRl2cXGdbbyWcVzzI5FqsI0s8Rij7fJUDNtQn4HPmweWUufw1GsgLXkGVie58e4PGUBD4je7UWtZobziKhxVouiWJeEFiNMkR; AWSALBCORS=2rYKe8I1LwfOtI/423ImCGauGOtHRl2cXGdbbyWcVzzI5FqsI0s8Rij7fJUDNtQn4HPmweWUufw1GsgLXkGVie58e4PGUBD4je7UWtZobziKhxVouiWJeEFiNMkR\r\nReferer: https://ginandjuice.shop/catalog/product?productId=1\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2646","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:04 GMT","Set-Cookie":"AWSALB=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2; Expires=Thu, 14 Sep 2023 15:34:04 GMT; Path=/, AWSALBCORS=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2; Expires=Thu, 14 Sep 2023 15:34:04 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdZ\ufffdn\ufffd8\u0016\ufffd\ufffd\ufffd`\ufffdئ\u0005b{\ufffd\ufffd\ufffd\u0005j{п\ufffd\ufffdh\ufffd\ufffd\ufffdآ{S\ufffd\u0012m1\ufffdH\ufffdH\ufffd\ufffdݾ\ufffd\u003e¾\ufffd\u003e\ufffd\u003e\ufffd~\ufffd\ufffd\u001d\ufffd_i\u001b\ufffd\u0017S\u0014\ufffdD\u001e\u001e\u001e\ufffd|\u003c\ufffd\ufffdދw\ufffd?|z\ufffd\ufffd\ufffd.S\ufffd\ufffd\u0006\ufffd\ufffd\ufffd\ufffd \u0015\u003c\t\ufffd\ufffdUI}\ufffd\ufffdBL\ufffd\ufffdBXS\u0016\ufffd\ufffd=\ufffd\ufffdD\u0026\ufffd^lm\ufffd\ufffd\\_\ufffd\ufffd}C\u0017\r\ufffd\u0010jh]\ufffd\ufffdM\ufffdp\ufffd\ufffd\u0011\u000b0\ufffdϔ\ufffd~\ufffd\ufffdKH\ufffd\ufffd\ufffd\u000c2\ufffd8\ufffd\u003c\u0013\ufffdh\u0026\ufffd\u003c7\ufffd\ufffdXl\ufffd\u0013\ufffd\r\ufffd\ufffdL\\:L\ufffdLƢ\ufffd_\ufffdYiE\ufffd\ufffd\u00021\ufffd\u0012Cm\ufffd\u00067\u001b\u00172w\ufffd\u0016\ufffd0j\u0008te\ufffd\ufffdc\ufffd\u0005'\ufffdL\ufffd\ufffdy\ufffd\ufffdF\ufffdA/\ufffdhϢ\ufffd\ufffd\ufffd\u0016l\\\ufffdceN|q\ufffd+\u003e\ufffd\ufffd5\ufffdƝ\ufffdi\ufffdx\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd.\ufffdN:%F\ufffd\u0016\ufffda\ufffd\ufffdf\ufffdy\ufffd?a\ufffdK\ufffd\u000f\ufffdLM\u003e\ufffd\u0005\ufffd\u0000\ufffd\ufffd\rr\u0006c\ufffdTLO;\u003c\ufffd\u001b\u000c\u00139c2\u0019FM\ufffd464,E\ufffdN\u001a\ufffdbŭ\u001dF\u0001f\ufffdD\u0004\ufffdг6\ufffd\u000f\ufffd7\ufffd\ufffd߇TZ\ufffd\ufffd\ufffd%Bɱ(\ufffd\u0013\ufffdb\ufffdRi\u003cC\ufffdl.\ufffd\u000c2*\u0019s?+\ufffd\ufffdS-\u001261\u0005s\ufffd:\ufffd\ufffdDt_\ufffdm\ufffdd1P*\ufffd\ufffd\ufffdDKA\ufffd\ufffdn\u0015``s\ufffd\\\n\ufffd7bFg\u0006\ufffd\ufffd2EA\ufffdӉ\ufffdw?\ufffd\ufffdgC\ufffd_v\ufffd\ufffdj\ufffd\ufffdJo\ufffd\ufffdf\ufffdi\ufffd]t\ufffdU7\ufffd\ufffdV\u0006\ufffd\ufffd0\ufffd\u0013\ufffd\ufffd9\ufffd\ufffd\ufffd\ufffd9\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdC\ufffdL\ufffd[CƝ\u0019?8zs\ufffd\ufffd\ufffd\ufffd\ufffd#\u0015g\ufffdI\ufffd\ufffdK\ufffd\ufffdR*\ufffd\u000f\ufffdG\u000f\ufffd\ufffd*\ufffdIf\ufffdA8\ufffd`\ufffd\ufffd6\ufffdN\ufffd\ufffd\ufffdni;\ufffdF\ufffdK\ufffd*\ufffd\ufffd\ufffdz`\ufffd0\ufffd\n\ufffd\ufffd{\ufffd4\ufffd\u000b\\zkx\u0001a@\ufffd^,\u001e\u0005\ufffd\u003e\ufffd\u0013\u001dmaK\ufffd\u000e\ufffddR\ufffd\u0004\ufffdv\\\u000ex\ufffdbG\ufffd-l\ufffd\ufffd\ufffdup\u0010\r\ufffd)\ufffdw\ufffd\ufffd\ufffd\u001d\u001d7\ufffd\ufffd\ufffd\ufffd\u001c\ufffdϏ\ufffd|\ufffd4K\ufffdR-\ufffd\rZ9\ufffd\ufffd\ufffd\ufffd\u0007\ufffd\ufffdnY^Ȍ\u0017Ux\ufffdrp7X*y\ufffd\ufffd\u0013\ufffd\ufffd\ufffd\ufffd\ufffd9\u0018\ufffd\ufffd\ufffdQ\u000f\ufffd\ufffd\ufffd' \ufffd0I\u0019;\ufffdsSV\ufffd\ufffd\ufffdL\ufffd\ufffd\ufffd1\ufffd\ufffdD\ufffd\u0014s\ufffde$\ufffd\ufffd#ȷ\u0014\ufffd\ufffdM\ufffd\ufffd\ufffd;:P\ufffd\u0014\ufffdw\u0012n\ufffd+\ufffd7c\t\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdؔ\ufffdud\ufffdؕ\ufffd\ufffd\ufffd\ufffdp\ufffdv6\u001d\r`\ufffd\u0016\ufffd7n\u0015P\ufffd\ufffd\u000f\ufffd.軠\ufffd\ufffd\nO\ufffd_\u000c\u0026oK|\ufffdlo\ufffd=\ufffd\u0008o\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd7\ufffd\u0002\ufffdn-\ufffd\ufffd\ufffd\n\ufffdw+\ufffdE\ufffd\ufffd\ufffd;\u0012\ufffd0\ufffd\ufffd\ufffd\ufffd\n\ufffdƼXCkm\u0001{\ufffdCx%\u0017د]aK\ufffd\ufffdP\u000f\ufffd\u001b\ufffd\ufffd\ufffdm\ufffd%7\u000e~Ǚ\ufffdT\t\ufffd\ufffdWZ\u000b9\ufffdR\ufffd\u0018V\ufffd\\\ufffd\ufffd\u0017\ufffd\ufffd\ufffdVi\ufffd\ufffd\ufffd\u0000w\ufffd\ufffd-\ufffd[\u0002\ufffd5*\ufffd\ufffd\u0011\ufffdPJ\u0012\ufffd\ufffd\ufffdp8\ufffd\ufffd^:\ufffdm\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdt\u0008\ufffd;9\ufffd\ufffd\ufffdd\u000e\ufffd\ufffd]n\ufffdqrR\ufffdõ\u0005\ufffd5\ufffd\u0017\ufffdw\ufffd\ufffd\ufffd\u000e\u000e\u000f;\ufffd\ufffd\ufffd\ufffd\ufffdh5?ID\ufffd\u000b\ufffd!39jd\u0026{\u0006X\ufffd\ufffd8\ufffd\ufffd\u0002N\ufffdFm\ufffdze_\ufffd\ufffd=`@:\ufffd\ufffd\ufffdА\ufffdw\ufffd=\ufffd\\25\ufffd\ufffd\ufffd\ufffd\u000f\u0007`\u0026u^ֹ\u0019\ufffdf,W\u003c\u0016\ufffdQع\ufffdѥ\ufffd\ufffdǬĶ\ufffd\ufffd\u001e\ufffd\u0004u]\ufffd\u0026\ufffdT\u0026\ufffdЁn\ufffd\ufffdk6\ufffd\ufffd\u0014uX\ufffd;\ufffd\u0019\u0007uL\ufffd9\ufffdr\ufffdIW\ufffdB\ufffd\u0018\u0005\ufffd\u0006\ufffd\ufffdu\ufffd\t\ufffd]\ufffd\u0005\ufffd\ufffd\u0011\ufffd\ufffd{\r\ufffd$7ܺu{doB\ufffd\ufffd\ufffdf?=o\u0006[=\ufffd\ufffd\ufffd\ufffd\ufffd'\ufffdSX\u0012\ufffdM\ufffd\ufffd\ufffd[\ufffd^\ufffd\ufffdohm\ufffdQ\ufffd*\ufffdF\ufffd\ufffd\ufffd =\u0019=e\ufffdsYT\ufffd\u0005G\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdaI\ufffd$\ufffd\u001e{\ufffd\u000be,KE!\u0018\ufffd\ufffd\ufffdv\ufffd9\ufffds\ufffd|\n#\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdS\ufffdX\ufffd\u003cUPj\ufffdD\ufffd\ufffdB\u0001\ufffd\ufffdO\u0006\n\ufffd\ufffd\ufffd\ufffd.\ufffd\u003e\ufffd|,\ufffd\n\ufffd\ufffdW\u000bvr\ufffd:F9%\ufffd\ufffd\ufffd1Ȕ\ufffdr\ufffd\ufffd\ufffd;a\ufffd\ufffd:\ufffd\ufffdX\ufffdI\ufffdLX\u0004\ufffd]vi\ufffd\u000fx\ufffd\u0018\u0019t\ufffd\u001a-X̕\u0002B7\ufffd\ufffd\ufffdm_\ufffd}a|l\ufffd\ufffd\ufffd\u003eu\ufffd]\ufffd9\ufffd\ufffd\ufffd\ufffd\ufffd;\ufffd\ufffd\ufffd\ufffd\u000f!g\ufffd\u0010r\ufffd\u0012!\u001f\ufffd\ufffd\ufffd\u0026\ufffd\ufffd\ufffd\u0014\ufffd\u001c\ufffd\u0008B\u00162\ufffd\ufffd\ufffd\ufffd{d\ufffd\u0005\ufffd(\u0005\ufffdq\ufffd~\ufffd\\\ufffdj\u001d\u0019\ufffdK\ufffd\ufffd\u000c\n2\ufffd\ufffd\u0000\ufffdt\ufffd\ufffd\ufffdHk\ufffd'K\ufffdL\ufffd\ufffd\ufffd\u001d\ufffd\ufffdf\u000e8\u0019F9r\ufffd\ufffdj\u003cI\ufffdLI\ufffd\ufffd\ufffd\ufffd\ufffdz\u000e4\ufffd\ufffdע˞\ufffdj\ufffd+\u0010\ufffd\u0005\ufffd\u0000uW\ufffd\ufffd\u0003 9\ufffd\ufffd\u0017\ufffd\ufffd\u0001\ufffdㅠ\u0004\ufffd\ufffd\ufffd\ufffd*\ufffd\u0000Ew\u0000\ufffd\ufffd\u001f\u000f:\ufffd[A\ufffd\ufffd-t\n@\ufffd\ufffdq\u001b\ufffd\u0002\ufffdU\ufffd\ufffdL\u001b\ufffd\u001e*}ivn\u0015\ufffd\ufffd\ufffdD\ufffd\ufffdQ\u0018 \ufffd\u003cS\u0004C\u0003\u0013Q\u0008\ufffd:`(\ufffd\ufffd֡\ro4\ufffd\ufffd\ufffdN\ufffd\n(,\ufffd\ufffdMq\r\ufffd\u0000@\r\ufffdd\u0015\ufffd\ufffd\ufffdZ\u0018\ufffd\ufffdS\u001d\u000e\ufffdx\ufffd\u00263\ufffd\u0015\ufffd\ufffdA\u000fH\ufffd\u0014S\u003e\u0013`}\u0007\u0018y\ufffd\ufffda\ufffd\ufffd\u0015F\u001e\ufffd¼|He\ufffd\ufffd\ufffd\ufffd\u0010\ufffd\ufffd\u0013JM\u0026\ufffd\u000by\ufffd\ufffdy\ufffdpx\ufffdo^I\ufffd+\ufffdֲ\ufffd,\\J6\u0006ˆ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd%A\ufffd\ufffd}\u0012\ufffd\ufffd\u0013*\ufffdѠ2\ufffd\ufffd|\ufffdu\u0012,\u0011\ufffd\u000bo\ufffd\ufffd\ufffdJ\ufffdK\ufffdDL\ufffd\u000e\u0006\ufffd\u0011Z\ufffd\ufffd\u0002x\ufffd\ufffd\"\ufffd\ufffd\ufffd0\ufffd\ufffd\u0013ai*\u000b5)`^\u0012\ufffd'd\u0013\ufffd\u0015\ufffd\ufffd\ufffd\u0003\ufffd\ufffd\ufffdx\ufffdy\ufffd\n0\ufffd\ufffd\ufffd\ufffdc\ufffd\u000b$\u0008\u0006J\ufffd\ufffd\u0015?s\u0010?\ufffd\u0013\u001f\ufffdx+\ufffd\ufffdcz\u0001X\ufffd\ufffd\ufffdR\u0005t\ufffd\ufffd.2E\ufffd,\u0003\ufffd\ufffd\ufffdK\ufffd\u000bN\u000e\u0008:!.ށ\ufffd0\ufffd\ufffd\u0006\t;\ufffd\u0026\u000f¼\ufffd~/%\u000b1\u0016\u0008|9+|DC\ufffd\u0007\ufffdS\u0011\ufffd\u0015r`\ufffd,\ufffd9\ufffd\u0007A\u0016\u0000\ufffd\ufffd;\t\ufffd\u0000\u0019E3\ufffd\ufffd\ufffd5\ufffd\ufffd\u0019H\ufffd\u0003\ufffd\u003c\ufffd\ufffd\ufffd\ufffdo\u0005\ufffd\ufffd\ufffd\ufffd\ufffd\u0010\ufffdǕ\ufffdH\u001c\ufffdJP\u0001\ufffdJo\ufffd\ufffd\ufffdB3:\u0016В\ufffd'o\ufffd\ufffd:\ufffd\ufffd\ufffd\ufffdCX\u0003\ufffd\u0015\ufffd0\ufffd\ufffdB\ufffd7P\ufffd\ufffd\ufffd\ufffdC\ufffd\ufffd|aPV\ufffdR\ufffd37\ufffdJ\ufffd-\ufffd\u000b~i\"\ufffd\ufffd\ufffd\ufffd\r\ufffd\ufffd\ufffd;\ufffd\ufffd\ufffdW\ufffd\ufffdx\t\ufffd\ufffd0E\ufffd\ufffd\ufffdp\u000f\u0004\ufffd\ufffd\u00001\ufffd=\ufffdV\ufffd\ufffd\ufffdon@nb\u000cNog^Pֱ\ufffdҰ\ufffd
\u0001\ufffd*\u0005\ufffd\ufffd\ufffd\ufffdPyjϒ6\ufffd\ufffd\ufffd\ufffdl\ufffd!\u0000\u001a\ufffd\n\ufffds2\u0004\ufffd\ufffd\ufffd/\ufffd\ufffdrLՀ\ufffd\u0000\u0010\ufffd\u00071\ufffd\u001a0et\ufffd\ufffd\ufffdF%s\u0000\u0016\ufffdͲRKW\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdו\ufffd\ufffd\ufffdk\ufffd#F\u001cC\u003eN|\ufffdUi%\ufffd\ufffd\ufffd\ufffd\ufffd6b\ufffd8]Hyi@\ufffd\u001e\ufffd\ufffd\u0016\ufffd\n\ufffd\ufffdF)\ufffd\ufffd\ufffd\u0017\\\ufffdN\ufffd3 \ufffd\u0000\ufffd\ufffd\ufffdB\u0016\ufffd}k\ufffd-J!˽\ufffd7\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0017YD'\ufffdw\ufffd\ufffdG\ufffd-Qh\ufffdK\"7U\ufffd\u001b\u0006\ufffd\ufffd\"\ufffd\ufffdg)\u000b\ufffd\u0001\ufffd\u001a!\ufffd\ufffd\ufffdP\ufffd\u0008\ufffd\ufffdRI\ufffd\ufffd7\ufffd$\ufffdj\u000f\ufffd\ufffd\ufffd\ufffd\ufffdB\ufffd$\ufffd\ufffd\u0000\ufffdm1\ufffd\u0016\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd~\u001e\ufffd\ufffd\ufffd.Ӌ\ufffd\ufffd^O\ufffd\ufffd\ufffd\ufffdwo\ufffdx\ufffd\ufffd˖E\ufffd\ufffd\ufffdt\ufffd\ufffd2\ufffd\\\ufffdL\ufffd\ufffd\ufffd!\ufffd@{\ufffd\u0015F\u0001\ufffdѝ\ufffdrHȕ\ufffd\ufffd\u001f\ufffd\ufffd|\u001fXa\ufffd\u0000Bt\u0016\ufffd4:V2\ufffd\ufffd\ufffd\ufffd{\ufffd/\ufffdH\u000fp\u001a\ufffd{H'\ufffdЪ\ufffd\ufffd)\ufffdĴ\ufffdяN\ufffd\ufffd\ufffd\ufffd\ufffd\ufffds:ad\t*\ufffd[\ufffd\u0014![͞\ufffd\ufffd\\\ufffd\ufffd\u0008\ufffd\ufffdn\ufffd\ufffd\ufffd2\ufffd\u0004\u003e\ufffd(l\ufffdw\ufffd\u0013S\ufffd\u0004R\ufffdނ\ufffd£Ԭk\ufffdK%,\ufffdFצb\ufffd\u001a\ufffd\ufffd\n\ufffd\ufffd\ufffdM\u0003u`*Eҁ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdc\ufffd\ufffd\ufffdo\ufffdt\u000b\ufffd|\ufffd4\ufffdU\u0015\nUaz\ufffd\ufffd\ufffdg\u0001\ufffd\ufffdJN\ufffd\u001b!\ufffdC\ufffd8\ufffd\ufffd\ufffd\ufffd\n\ufffdy\nS\ufffdWK{m\ufffd-\ufffd:tr{ᠶ\u000b\ufffd\u0016^\u000f\ufffd\ufffd\ufffd\ufffd-\ufffd7}\ufffdd\ufffd\ufffd\ufffd\ufffd6\ufffdj\ufffd\ufffd\ufffd\ufffd\ufffd\ufffda'?\ufffd\ufffd\ufffd\ufffd\ufffdp\u00198\ufffd7.\ufffd\ufffdX\ufffd\ufffd\ufffdKv\ufffd\ufffd^\ufffd\ufffd;\ufffd\ufffdq\ufffdր\u0004\ufffd\ufffd\ufffd\",y\ufffd\ufffd|nY\ufffd\ufffd\ufffdR\ufffd7\u0007n\ufffd\u000fm\ufffd\u001f\ufffdZ|7\ufffd\ufffd\ufffd\ufffd\ufffd{\ufffdjn\ufffd\u0015֮1\ufffd^wD\ufffd\ufffd\ufffd\ufffd 5|\ufffd\ufffd\u0019\ufffd\ufffd+\ufffd\ufffd\u001a\ufffd\u0004\ufffd\ufffd\ufffdI\ufffd?\ufffd\ufffd%C\ufffd*\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2646\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:04 GMT\r\nSet-Cookie: AWSALB=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2; Expires=Thu, 14 Sep 2023 15:34:04 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2; Expires=Thu, 14 Sep 2023 15:34:04 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:07+05:30","url":"https://ginandjuice.shop/blog/?search=dadad\u0026back=%2Fblog%2F","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2; AWSALBCORS=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2","Referer":"https://ginandjuice.shop/blog","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/blog/","scheme":"https"},"raw":"GET /blog/?search=dadad\u0026back=%2Fblog%2F HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2; AWSALBCORS=+kt6Ib2lLrBXa4YCECeKwNyIl2PFt7T1knMc4Ed88f+NSWWr4GdaZPWIqyaJBNi2eoCbLJMcYgimR45FELKCqRmtTLdXLFD6x+MBEnFw43yIfk3L1QGW79pv1ip2\r\nReferer: https://ginandjuice.shop/blog\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2075","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:07 GMT","Set-Cookie":"AWSALB=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s; Expires=Thu, 14 Sep 2023 15:34:07 GMT; Path=/, AWSALBCORS=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s; Expires=Thu, 14 Sep 2023 15:34:07 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdZ͒\ufffd6\u0012\ufffd\ufffd)`\ufffd\ufffd\u001cUB13\ufffd\ufffd\u000f#jk\ufffd\ufffdz+5v\ufffd;\ufffd\ufffd\ufffd\ufffd\ufffd@\ufffd\ufffd\u0007$\u0018\u0000\ufffd\ufffd\ufffd\ufffd\u0003\ufffd5\ufffddi\u0000$EI\ufffdH\ufffd\ufffdj\u000f\ufffd]%\u0012@7\u001a\ufffd\u000f\ufffd_C3{\ufffd\ufffd\ufffd'\ufffdz\ufffd\u000c\ufffdt\ufffd\ufffd_\ufffd\ufffd\u0017\ufffd\ufffdlEq\ufffd\u001e\ufffd+g\ufffd\u001dZI\ufffd\ufffdBI\ufffd($\ufffd*\ufffdxa\ufffdQ\u0019\u0012\ufffdBEp\ufffd\ufffd\ufffd\ufffd6L\ufffd\u0001I\ufffd#\ufffdKNՊR=\ufffd̨\u0000\ufffdꚋ\ufffd#\ufffdo\ufffd\ufffd\ufffd\u001eW\ufffdR\ufffdQ\ufffdS\u001aykF7\ufffd\ufffd\ufffdCDd\ufffdf:\ufffd6,֫(\ufffdkFh`_\ufffdF\ufffd\ufffd2\ufffd\u0005\ufffd\u000c\ufffdF\ufffd\ufffdZ\ufffd\u0014\ufffd,\ufffdHI\u0012y-\ufffd\ufffd+x\ufffdDOA\u0013\ufffd\"OA\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdI\ufffdW\u0011\ufffd\"=A\ufffd.sX\ufffd\ufffd\ufffd:|\ufffd\ufffdصz]\ufffdq\ufffd\u0014\u001c\ufffdw\ufffd\ufffd\ufffd\ufffdq\ufffdV\ufffd4\ufffd\ufffd\ufffd,C\u000fq\ufffd_\ufffd\ufffd\np\u000c\ufffd]\ufffd|\u0016\ufffd\u003e\ufffd\ufffdp\u000b\ufffd\ufffdB\ufffd%ʒ\u0000\ufffdyKS\ufffdֈő\ufffdFJ˓n\r\ufffdh\u00262D8V*\ufffd\u001c\ufffd\ufffd\ufffd:\ufffd\ufffdgO\ufffd\n\ufffd\ufffdm\ufffd\ufffdz\ufffd\u0014\ufffd\ufffd\u0018Ŕ\ufffd\u0005\ufffdXS^\ufffdu\ufffd3x\ufffd\ufffdD\u001b\ufffd@`#g\u0004\ufffdYa\u001e\ufffdd4FK!\ufffd\ufffdJ\ufffd,1\ufffd\u001ef\u000b\ufffd_Ղ\ufffd3]\ufffd\u0026\ufffd\u0014hS\ufffdN\u0003f*\ufffd\ufffdR\u000cl=$\ufffdT\u0000\ufffd`\u0017\ufffd4X\ufffdb\ufffd\ufffd\ufffd{w\ufffd\"t\ufffdt\ufffd\ufffdn\ufffd\ufffdNo\n\ufffd\ufffd\ufffdK\ufffd[wCk\ufffd\ufffd~\ufffd#\\\ufffd\ufffdǖ\ufffd\ufffd=\ufffdÇ\ufffd=\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\t\ufffd\ufffd\ufffdV\ufffd\ufffd\u0016\ufffd3\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdo9I\ufffd\ufffd\ufffd\ufffd\ufffdy\ufffd\ufffds\ufffd\ufffd\"\ufffd\ufffd\ufffd)66\ufffd\u003ePM[\ufffdί\ufffdA\ufffdEG\ufffdeG\ufffd#o\ufffd\ufffdШ\u0004\u003c\ufffdj\u001f\ufffd\u0016H\ufffd\ufffdݺ\u0007\ufffdep\u0007\\\ufffd=\ufffd\ufffd@\ufffd\ufffd\ufffdX\ufffd\u001dl\ufffd\ufffdD~\ufffdZ\u0003o7\ufffd\ufffd\u0012\ufffd`X7.g/?\ufffdPӡN٘\u0016@`\u0014p@\ufffd\ufffdGm\ufffd{:\ufffd\ufffd\ufffd\ufffd\r\u0006\ufffd\ufffd2\u0019\u0019Q\ufffd\u001a\ufffd0\ufffd%\u0016\u0013Au`\r\ufffd\u0015\ufffd%K\ufffd,\ufffd[\ufffd\ufffd=P\ufffd\ufffd\ufffd ;\u0010\ufffdS/\n\ufffd!(8\ufffdz! \u0013\ufffd\ufffd\u0000\u0019R\ufffd\u0005Ѫ\ufffd);\ufffd\ufffd1\u0013\ufffdu\ufffd\ufffd\ufffdh\u001a7f.\ufffd\ufffd\u0026\ufffd\ufffd?\ufffdט\ufffd\u0017\ufffd\ufffd\ufffd\ufffd{s\ufffd\ufffd\ufffd\ufffd'2n\u0016\u0016\ufffd\ufffd\ufffd\u0004\ufffdQd\ufffdgF\u0013\u0026D\u0014\ufffd\u000e\u0018iy%-\ufffd\ufffd\u001d\ufffd\ufffdZ'\ufffd\u0019\u0004\ufffd\ufffds\ufffdO\u0001\ufffd\ufffd\ufffd\u0002\ufffdz\ufffd\u0014F\ufffd\ufffd\u0013\ufffd/\u0008\ufffd4k\ufffd\ufffdqo\ufffd\ufffdq\u0003OZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd^\ufffd\ufffdH\u0010\ufffdF[l\ufffd\ufffdB\ufffd\ufffd5\ufffdE\ufffd\ufffd\ufffd\ufffdd\ufffd0\ufffd\ufffd\ufffd\ufffd\u0000\ufffd\u0012,\ufffd\ufffdZE\ufffd\ufffd\ufffd\u0018\ufffd\ufffd\u0014x^\ufffd\ufffd5\ufffd\u0016\ufffd[\ufffd\ufffd\ufffdv\ufffd\ufffd[\u0007?\ufffd\"I8\ufffd\ufffd\ufffdN\ufffddIb\ufffd\ufffd[M\ufffd\ufffd\ufffd\u0017\ufffd\ufffdc\ufffd\ufffd,\ufffdM\ufffd=)\ufffd\ufffd\ufffd\ufffdX썲\ufffd\u0019\u0018\ufffd\ufffdE\\R8J\ufffdS\ufffd\ufffdM\ufffd\ufffdb\ufffd\ufffdL\ufffd5\ufffd\ufffd\u0002\u00079\ufffdnOȜ\ufffd0\ufffd8\\h\ufffd\ufffd\ufffdp\u0015\ufffd\ufffd\u0004C\ufffdݧ\ufffd\ufffdJp\ufffd\ufffdÎ\ufffde\ufffd\ufffd[\ufffd\ufffd4\ufffd\u0012\ufffdP\ufffd\ufffd\ufffd\ufffd䈀\ufffdX\ufffd\u0015\u0004)\ufffdɞT\ufffd\ufffd;~u\ufffdG\ufffd\u0000\ufffd@\n\ufffdĈD6y\ufffd\u0008\ufffdȕ\ufffd\ufffd\ufffd\ufffd^\u000f\ufffd\ufffdeyQ\u0015e\ufffd\u0026C9DŽ\ufffd\u0004\u0007\ufffdE\ufffd\ufffd\ufffd\ufffdrV\ufffdv:\ufffd\ufffd\ufffd2u\u0026\ufffd5\ufffd\ufffd\ufffd\ufffd\u0018\ufffd\ufffd\ufffdΖ\ufffd\u0015\ufffdc\ufffd9\ufffd\u0005\u0026w\ufffd\ufffd\ufffds O\ufffd*\ufffdb5\ufffdb\ufffd2]\ufffd\ufffdu̝\ufffd\ufffd\ufffdz=r^\ufffd\ufffd\ufffd\ufffd\ufffdɯ\ufffd\ufffdc;e\u003e\ufffd\"s\ufffd\ufffd%\ufffd\ufffdYt\ufffdKAe9A\ufffd;\ufffd\ufffdX\ufffd\ufffdV\ufffd\u001b\ufffd4=\ufffdg,M\u000e\n\ufffd*\ufffdY倞\ufffd-\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0014x\ufffdWv\ufffd\ufffd|o\ufffdO\ufffdz\ufffd\ufffd\ufffd\ufffdg\ufffd%\ufffd*\ufffd`:\ufffd\ufffd\u0006\ufffd\ufffd\ufffd\u001b\ufffd\ufffdW\u0006\ufffd\ufffd.\ufffd\ufffd\ufffdj\ufffdf\ufffdL\ufffd\t\ufffdg\ufffd{;65[\ufffd\ufffdơ\ufffdN]\ufffdI\ufffd\ufffd\u00064`kJ\ufffdL\u0004\ufffd\ufffd\ufffd\ufffdc\ufffd\ufffd\u001d\ufffdF\t\ufffd\u000b\ufffdIk0\ufffd%6\ufffd(\ufffd\ufffd\ufffd\ufffd\ufffd\\\ufffd[o5\u0026\ufffd.\ufffd\ufffdB\ufffd\ufffd\u0001z)\ufffd\ufffd\u0000-\ufffds\ufffd\u0010\ufffd.\ufffd͟_\ufffdQ\ufffdE\ufffdk\ufffd\ufffd5EE\ufffd\u0002DV\u0014\ufffd\ufffd\ufffd\u000b*\ufffd\ufffd\ufffd{\u0008s%\u0001 \u0002\u0013\ufffdi$\u0026L\ufffd*Nh\u0003\ufffd週C\ufffd[WB\ufffd0,ۄ\ufffdVЩ\ufffd\ufffd/}(\ufffd\tg\ufffd.\ufffd\ufffd\ufffd\u001c\ufffd\\\ufffd\ufffd\ufffdt\ufffda\ufffdg\ufffd\ufffd\ufffd%A\u0017\ufffd\ufffd\ufffdn\ufffd\ufffd\ufffd\ufffd\ufffd\t\ufffd\ufffdWT\ufffdHW\ufffd\ufffdڄ4(\ufffd\u0007\ufffd\ufffd\ufffd\ufffdqo\u0000\u001a\ufffd\ufffd\ufffd\ufffd\ufffd-\ufffd\u0000\ufffd\u0007\u001b\ufffd\ufffd\ufffd;\u0011\ufffd\u001d\u0005'ЗH\u000f5s\ufffd4\ufffd\ufffdȒ\u000ee\ufffd\ufffdT:v\ufffd\u0000\ufffd/a\ufffd$J\ufffdr\ufffdb\ufffd\u0003\ufffd \ufffd\ufffdc\ufffd\ufffdpN7\ufffd1;\ufffd\ufffd\ufffd\t\ufffd!s\ufffd\ufffd\u0011\ufffd\ufffd\u001b\u0016SDD\ufffd\u0016\u0019\ufffd%\u0012K\ufffdp\ufffdp\u0016\ufffd\ufffd\ufffd\ufffdp\ufffd3\ufffdh\ufffd\ufffd\ufffdWj\ufffd\ufffd\ufffdB\u0019\ufffd\u0003(\u0014\ufffd\ufffd*\ufffd\ufffd\ufffd\ufffdXk`\ufffd\ufffd\ufffd4\u0017F\ufffd\ufffd\u001b\u0011\ufffdCY*-Z\ufffd\ufffdhN\ufffd\ufffdӃ[\ufffd]\ufffd\ufffd3\ufffdz\ufffd/!\ufffd\u000e3\ufffd\ufffd\ufffd\ufffdⲖ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdb\ufffd\ufffdAE\u0008\ufffd\\(]5U\ufffdaKʷ\nF\ufffd\u0006I)\ufffd\ufffd\ufffdK\ufffd\u0014\ufffd\u001fwy\ufffd=\ufffd\ufffd\ufffd\ufffd\ufffd6\ufffd8\ufffd\ufffd\u000e\u0006\ufffd.\ufffd\ufffd#\u0012^u3N\ufffd\\z5\ufffdx\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\t}\ufffd\ufffd\ufffd\ufffd}|\ufffdCI\ufffde\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u000bzw\ufffdf$\ufffdث\ufffdZ\ufffdc~[{f\u000c\ufffd\u0018\nc\ufffd\ufffdvà\ufffdˁƺ\ufffd\u00132I%\ufffd\ufffd\u0007VH\ufffdP4\ufffd\ufffdY\u0007K\ufffd\ufffd\ufffd\ufffd~jM:\ufffdasbN\ufffdЪ\ufffd\ufffdɲ\ufffd\u0018a\ufffd\ufffd\u00062~\ufffd\ufffd\ufffd\ufffd\ufffd.\ufffd\ufffd\u0004\ufffd^Aj\ufffd\ufffd\ufffd\ufffdf\ufffdͥ\ufffd\ufffd\ufffdzuY\ufffdM^\ufffdK\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd1\u0010\ufffd\ufffd\ufffd\ufffd\ufffd\u0004\ufffd\ufffd\u000eԪ+\ufffd\ufffd\u00264FC\ufffd\ufffd\ufffd@\ufffd\ufffd\ufffd\u0003vd\ufffd7-ԁRF\ufffd\u0000\ufffdߝ\ufffd\ufffd\ufffdV\u0017\ufffd\ufffd\ufffd\u0018\ufffd\ufffd\ufffdt\ufffd\ufffd|\ufffd\ufffd\u003c\ufffd%P\t\ufffd\ufffd\ufffdޤS{kn~\ufffd\ufffd\r\ufffdx\u0002\ufffd\u003eZP\ufffdf\ufffdF\u0015\ufffdfG\u0008i~\ufffd;\u001akO0j\u0004?1\ufffdb\u001cE\ufffd\ufffd\u001el\ufffdd\ufffdj\u0008\ufffdmQ\ufffd\ufffd\ufffd\ufffd\ufffdK\u0005{\ufffd\u003e\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd;\ufffd\ufffd\ufffd\ufffd\u0012\ufffd\u0002\r\ufffdN\u0003\ufffd\ufffd\ufffdG0\ufffd\ufffdr|\ufffd\ufffd\ufffd+\ufffd~\ufffd\ufffdIH`\ufffd\ufffd\u0013h\ufffd\ufffd\ufffdnv$\ufffdW\ufffd\ufffd\ufffd\ufffd\u000c\\\ufffd\u000e9ﯟ\"\u003e\ufffdu\ufffd\u0014\ufffd\ufffd/\ufffd\ufffdk\ufffd\ufffd[\ufffd\ufffd\ufffd\u001ev\ufffd\u000e\ufffd%\ufffd\ufffd\ufffd\u0018\u000e\ufffd)d%\u0011\ufffd\ufffd/ 7ڿ\ufffd\ufffd\u0013o\u0004\ufffdo\ufffd!\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2075\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:07 GMT\r\nSet-Cookie: AWSALB=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s; Expires=Thu, 14 Sep 2023 15:34:07 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s; Expires=Thu, 14 Sep 2023 15:34:07 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:08+05:30","url":"https://ginandjuice.shop/logger","request":{"header":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Content-Length":"34","Content-Type":"text/plain;charset=UTF-8","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s; AWSALBCORS=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s","Origin":"https://ginandjuice.shop","Referer":"https://ginandjuice.shop/blog/?search=dadad\u0026back=%2Fblog%2F","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"POST","path":"/logger","scheme":"https"},"body":"{\"search\":\"dadad\",\"back\":\"/blog/\"}","raw":"POST /logger HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nContent-Length: 34\r\nContent-Type: text/plain;charset=UTF-8\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s; AWSALBCORS=ZJm/2Bx+PPBvRylO0Q4ANLyMc0beelNKLpyYHasVfthZ3FRdadKIrIFFGUK658OSRpW4bg89XZl70Af+XA6qbw2pno1/pPHTdoRXm4gW2bRwl59JyYaXuecXXx4s\r\nOrigin: https://ginandjuice.shop\r\nReferer: https://ginandjuice.shop/blog/?search=dadad\u0026back=%2Fblog%2F\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: empty\r\nSec-Fetch-Mode: cors\r\nSec-Fetch-Site: same-origin\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"0","Date":"Thu, 07 Sep 2023 15:34:08 GMT","Set-Cookie":"AWSALB=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g; Expires=Thu, 14 Sep 2023 15:34:08 GMT; Path=/, AWSALBCORS=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g; Expires=Thu, 14 Sep 2023 15:34:08 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 0\r\nContent-Encoding: gzip\r\nDate: Thu, 07 Sep 2023 15:34:08 GMT\r\nSet-Cookie: AWSALB=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g; Expires=Thu, 14 Sep 2023 15:34:08 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g; Expires=Thu, 14 Sep 2023 15:34:08 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:10+05:30","url":"https://ginandjuice.shop/blog/","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g; AWSALBCORS=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g","Referer":"https://ginandjuice.shop/blog/?search=dadad\u0026back=%2Fblog%2F","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/blog/","scheme":"https"},"raw":"GET /blog/ HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g; AWSALBCORS=JGWQqbBbFYF0Ruume5uOLTakW9Tzw1jCFErY/0i5fb/9LxF9/fQL7ULoDMACjp2MTQT5l73mWyrEKN3g8afgJLXwSSzXbEsrTwBpQ0FUsHhnjYm0/64kwA590M8g\r\nReferer: https://ginandjuice.shop/blog/?search=dadad\u0026back=%2Fblog%2F\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2651","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:10 GMT","Set-Cookie":"AWSALB=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+; Expires=Thu, 14 Sep 2023 15:34:10 GMT; Path=/, AWSALBCORS=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+; Expires=Thu, 14 Sep 2023 15:34:10 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdZێۺ\u0015}?_\ufffd\ufffdh\u0026\u0001\ufffd֙KrZ\ufffd\ufffdAng2An\ufffd\u0004Mӗ\ufffd\ufffdh\ufffd\u0019\ufffdTEʎ\ufffd\ufffd\ufffd\ufffd'\ufffd7\ufffd)\ufffd\ufffd\ufffdM\ufffd\u001e\ufffd\ufffd\ufffd\u0026\ufffd\u0000y8A0\ufffd\ufffd\ufffd\ufffdM\ufffd\ufffd}\ufffd\u0006w\ufffd\ufffd}\ufffd\ufffd\ufffd\ufffd\ufffd,s\ufffd\u001a\ufffd4\u0008?\u000c\ufffd\u0006\ufffd\ufffdix\ufffd\ufffdJ\ufffdK\ufffd\ufffdb2\ufffdKaMU\u0026\ufffdƊ\ufffd\ufffdL\ufffdqbml\u0013\ufffd_\ufffd\u0017\ufffd\ufffd\ufffd\u0006V\n5\ufffd\ufffdV\ufffdfB\ufffd}̈\u0005\u0018\ufffd'\ufffdL\ufffda\ufffd\u0005\ufffd\ufffd\ufffdn\u0006\ufffdp\ufffdi\ufffd\ufffda4\ufffdb^\ufffd\ufffdE,1\ufffd\t\ufffd\ufffd\ufffd\\\ufffd.\u001b\ufffdb\u0026\u0013\ufffd\ufffd/\ufffd\ufffd\ufffd\ufffd\ufffda\ufffd\ufffdA\ufffd\ufffd6Q\ufffd\ufffdMJY8f\ufffdd\u0018\ufffd\u0004\ufffdl\ufffd\ufffd\u0013\ufffd\u0007'\ufffdL\ufffd\ufffdy\ufffd\ufffd\ufffdF\ufffd8\ufffd\ufffd\ufffd\ufffd\ufffd\u0006l\\]`eN|q\ufffdg\u003e\ufffd\ufffd5\ufffdĝ\ufffdi\ufffdx\ufffd\ufffd\ufffd\ufffdK\ufffd\ufffdm\\\ufffdtJ\ufffdH-\ufffd\ufffdΤfwy^\u003cb/+\ufffd\u000f\ufffd\ufffdL1\ufffd\u0003I\u0000N|\ufffd\ufffd\ufffdؤ5\ufffd\ufffd\u001e/\ufffd\u0016\ufffdTΘL\ufffdQ\u001b0\ufffd\r\rK\u0011\ufffd\ufffdF\ufffdDqk\ufffdQ\ufffdY/\u0015A:\ufffd\ufffd\r\ufffd\ufffd\ufffd\ufffdm\ufffd\ufffd}\u0026-\ufffd\ufffdR\ufffd\ufffdX\ufffd\ufffd\tU\ufffdY\ufffd4\ufffd\ufffdP6\u0017c\u0006\u0019\ufffdL\ufffd\ufffd\u0015\ufffdȩ\u0016)\ufffd\ufffd\ufffd9a\ufffd\ufffdS\"\ufffd\ufffdǶx\ufffd\u0018(\ufffdtuh\ufffd\ufffd\ufffd\ufffd\ufffd7\n0\ufffd\u0005_.\ufffd\ufffd\u001b1\ufffds\u0003PA\ufffd\ufffd$\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u003e}9bCv\ufffd\ufffd6\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u001c\ufffd\ufffdޓл\ufffdF\ufffdnw\ufffd\ufffd\u000c\ufffd\ufffda$'\ufffd^{\ufffd\ufffdwY{\ufffd\ufffdד\ufffd\ufffd\ufffd\ufffdL\ufffdf\ufffd\ufffd\ufffd;3\ufffdw\ufffd\ufffd\ufffd\ufffdG\ufffd\ufffd\u0007*\ufffd\ufffd\ufffd×\"=S*\ufffd\u000f\ufffd\u0007\ufffd\ufffd\ufffd*\ufffdIf\ufffdA8\ufffdbw\ufffd\ufffd]k;\ufffd\ufffdv\ufffd\ufffd\ufffd4\u001a\ufffd\ufffd\u001c\ufffd\u0001k\ufffd\ufffd\ufffd9\ufffd\\\u0026\ufffd\ufffd\ufffd\u0000\ufffd\ufffd\ufffd\rp\ufffd\ufffd\ufffd\u0002\ufffd\ufffdX\u003c\u0008\ufffd}\ufffd':\ufffd\ufffd\ufffd\ufffd\u001dHɤp\t\ufffd\u001c\ufffd`\ufffd\u000e\ufffd\rl6\ufffd\ufffd\ufffdp\u0010\r\ufffd)ڷ\ufffd\ufffd\ufffd\ufffd\ufffd+V\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdh\ufffde\ufffd%E\ufffd\u0016\ufffd\u0006\ufffd\ufffdzL\ufffd\ufffd\u0003K`\ufffd\ufffd(e\ufffd\ufffd:\ufffdm8\ufffd\ufffdX*\ufffd\ufffd\ufffd\u0013\ufffd\ufffd\ufffd\ufffd\ufffd9\u0018\ufffd\ufffd\ufffdQ\u000cdr\ufffd\u0013\ufffdQ\ufffd\ufffdJ\ufffdݺ)+\ufffd\ufffd.\u0013\ufffdt\ufffd\ufffd\ufffd8\ufffd.\ufffd\u001c{\u0019ɴ\ufffd\u0008\ufffd-\ufffd\ufffdcS\ufffdh\ufffd\ufffd\u000e\ufffd3e\ufffd\ufffd\ufffd\u001bĕ\ufffdf,\ufffd0\u001a\ufffd\ufffd2\ufffdx\ufffd\ufffdJ\ufffd\ufffdLZ\ufffd\ufffd\ufffd\u001dn\ufffdΦ\ufffd\u0001\u000cڢ\ufffdʭ\u0002\ufffdS\ufffd\ufffd\ufffd\u0005}\u001f\ufffdX\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdm\ufffdO\ufffd\ufffdm\ufffd\ufffd\u001bፖ}}\ufffdkph/\ufffd\u0015\ufffd\u0000\ufffd;K\ufffd\ufffdvB\ufffd\ufffd\ufffd\ufffd\ufffdf\ufffd\ufffd-\ufffd\ufffd\u001f\ufffd\ufffd\ufffd}\u0005`\u0013^\ufffd\ufffd\ufffd\ufffd\ufffd1\ufffd\u0010^\ufffd\u0005\u001e5\ufffd\ufffd#zi\ufffd\ufffd\ufffd\u0015\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd[\u0007\ufffd\ufffd\ufffdt\ufffd\u0004f\ufffd+\ufffd\ufffd\ufffdN)T\u000c\ufffdY.f\ufffd\u000b\ufffd\ufffdV\ufffd4\ufffd\ufffd:\ufffd-.xC\ufffd\ufffd\ufffdb\ufffdʻfD,\ufffd\ufffd\u0004\ufffd\ufffd3\u001c\ufffdᵗ\ufffd{S$|\ufffd\ufffd\ufffd%\u001dB\ufffd^\u0001\ufffdn1\ufffd\ufffd`f\ufffd\u001bn\ufffd\ufffd4\ufffdpc\ufffd\ufffd\r\ufffdC\ufffd6\ufffdG\ufffd\ufffd\ufffdÖ\ufffd\ufffd*\ufffd9X\ufffdORQ\ufffd\ufffd\ufffd\ufffdL\u000eZ\ufffdɎ\u0001V\ufffd2\ufffd`\ufffd\ufffd\ufffd\ufffdQ\ufffd\ufffd^\ufffd\ufffd0z\u0007\u0018\ufffd\u000e\ufffd0$4d\ufffd\ufffdw̐Kf\u0026\u001d\ufffd=\ufffd\u0007fR\u0017U\ufffd\ufffdQj\ufffd\n\ufffd\u0013\ufffd\u0019\ufffd\ufffd\u001b\u001e\\\ufffd\ufffd}\ufffdJl\ufffd\ufffd\ufffdAHP\ufffdEj\ufffd\ufffdd\ufffd\n\u001d\ufffd\ufffd\u003c\ufffdd3\ufffd*ф\u0015\ufffd\u001e\ufffd8hb\u0012\ufffd\ufffdV\ufffd\\\ufffdf\u0017B\ufffd(\ufffd4\ufffd\ufffd\ufffd\u001d'\ufffdve\u001b46F\ufffd\ufffd\ufffd5X\ufffd\ufffdp\ufffd\ufffd퐽\rmO_\ufffd\ufffd\ufffd\ufffd\u001dl\ufffdD\ufffd+\ufffd9O\ufffd'\ufffd$2\ufffd6\ufffd\ufffd\ufffd|q\ufffd\ufffd\ufffdhm\ufffd\ufffd\ufffd\ufffd\ufffdF\ufffd\ufffd\ufffd ;\u001e=f/\ufffd,k\ufffd\ufffd#^\ufffd\ufffdv\ufffdb\ufffdѰ\ufffdB\ufffdy\ufffd=\ufffd\ufffd2\ufffde\ufffd\u0014\ufffdOqN\ufffd\ufffd\ufffdv\u003e\ufffd\u0011JQ^\ufffd|@\ufffd\ufffd\u0019w,C\ufffd*(5E\"Np\ufffd\u0000M\ufffd'\ufffd?%Ky\ufffdg\ufffd\ufffd\u003e\ufffd|,\ufffd\n\ufffd\ufffdW\u000bvr\ufffd9F9%\ufffd\ufffd\ufffd1\ufffdT\ufffdr\ufffd\ufffd\ufffd;e\ufffd\ufffd:\ufffd\ufffdX\ufffdI\ufffdLX\u0004\ufffd}va\ufffd\u000fx\ufffd\u0018\u0019t\ufffd\u0019-X\u0002B\ufffd\ufffdOk۾\u001a\ufffd\ufffd\ufffd\ufffd\u001c\u0003\ufffd]\ufffd\ufffd\ufffd\u0014sF\ufffd\ufffdw{{\ufffd㻿\u001fBN;!\ufffd\ufffd#B\ufffdCIOM\ufffd\ufffd/)\u000eك\u0011\ufffd,d\ufffd\ufffdG\ufffdw\ufffdxK\ufffdA\n2\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd^\ufffd:2b\ufffdA\ufffd9\u0014d\u0026\u0013\u0001\u003c\ufffd\ufffd%\ufffd\ufffd\ufffd\u0002O\ufffd\u0014\ufffd\u001a\r];v\ufffd\ufffd\u001cp2\ufffdr\ufffd\ufffd\ufffd\ufffdx\ufffd\ufffd\ufffd\ufffd\ufffd1\u0001i!\ufffd\u001ch\u0012%/E\ufffd=\ufffd\ufffd\ufffd\ufffd \ufffd\u000bp\u0001\ufffd\u003eW\u0016\u000f\ufffd\ufffdL\u0012_\ufffd'\u0001D\u000f\u0017\ufffd\u0012\ufffd\u001a\u0012\ufffd\ufffd@\u0002\u0014\ufffd\u0002tN\u003c\ufffd\u003c\ufffd\u0004\ufffdӮ\ufffd)\u0001\u0005:\ufffd]\ufffd\u000bpVӎ3m\u003cz\ufffd\ufffd\ufffdٹUPg\ufffd:\n\u003c\ufffd\ufffd\u0000\t\ufffd\ufffd2\u0018\u001a\ufffd\ufffdR`\ufffd\u0001C\ufffd5\ufffd\u000emx\ufffdA\ufffdWt\ufffdV@a\ufffdnn\ufffdK@\u0007\u0000jA%\ufffd\u0001\u001e\ufffd\ufffd\ufffdPe\ufffd\ufffdp\ufffd\ufffd\u000b4\ufffd\t\ufffd\u0018L\rz@\ufffd\ufffd\u0000\ufffd[\ufffd\ufffd\ufffd\u001f\u000f#ǝ0\ufffd\ufffd\u0006\ufffd\ufffd}\u0026˔}ȄP]\ufffdPfrI^Ȼ\u001c\ufffd\u001b\ufffd\ufffd\u001bs\u0026\ufffd\ufffd\ufffdZ\ufffdƲt\u0019\ufffd\u0018,\u001b\ufffd\u0016\ufffd\ufffd߸\ufffd\u0014\ufffd\ufffd\ufffdI\ufffd\"N\ufffd\ufffdF\ufffd\ufffd\ufffds\ufffdi\ufffdI\ufffdD\u003c/\ufffd\ufffd\ufffdz*\ufffd.\u0019\u00121\ufffd;\u00184Gh\ufffd\u0014\u000b\ufffd1[\ufffdD\ufffd\ufffdǬ7N\ufffd\ufffd\ufffd,դ\ufffdyI\u0019\ufffd\ufffdM$WD^\ufffd\u0016\u0000s\ufffd\ufffd\u0001\ufffdA'\ufffd\u001cu\u0004L\u0013{\ufffdF\ufffd`\ufffd\ufffd\ufffd]\ufffd3{\ufffds\u003e\"\ufffd8\ufffd\u0017\ufffd\u0005\ufffd\u000e-u@ת\ufffd\"S\ufffd\ufffd2P\ufffd۸\ufffd\ufffd\ufffd䀠\u0013\ufffd\ufffd\u001d\u0018\u000cC\ufffdm\ufffd\ufffd\ufffdk\ufffd ,*\ufffd\ufffd2\ufffd\u0010c\ufffd\ufffd\ufffd\ufffd\ufffdG4\ufffd~\ufffd$\u0013!\\!\u0007FȂ\ufffd\u0003~\u0010d\u0001P~\ufffd\ufffd\ufffd\u000c\ufffdQ4\u0003\ufffd\ufffd\\3\ufffd\ufffd\ufffd\ufffd[\u0000σ\u001f\u000f\u003cG\ufffd\ufffds\ufffd\u0011\u003c\ufffd\ufffd\ufffdq\ufffd7\u0012\ufffd\ufffd\u0012T\ufffd\ufffd\ufffd[d\ufffdЌN\u0004\ufffd\ufffd\ufffd\ufffd\ufffd'\ufffd\tp\u003c\ufffd\ufffd\u0010\ufffd@se\ufffd\ufffd\"\ufffd\ufffd\ufffdP\ufffd\rT\ufffd+\u003c\ufffd\ufffd58_\u0018\ufffd\u0015\ufffd\u0014\ufffd\ufffdM\ufffdRf+\ufffd\ufffd_\ufffd\u0008=xx\ufffdc\ufffd\ufffdνo\ufffd\u0015h\"^\u0002\ufffd8L\u0011\ufffd\ufffd\u003c\ufffd\u0003A\ufffd[@\ufffd\ufffdw@̎|\ufffd[Y\ufffd7\ufffd 71\u0006\ufffd\ufffd7/)\ufffd\ufffdXiXK\ufffdm\ufffd\ufffd뜕\ufffdPyjǒ\ufffd\ufffdI\ufffd\ufffdٮC\u00004\ufffd\u0011\ufffd\ufffd\ufffd\u0008~\ufffd\ufffd_\ufffd#\ufffd\u0001c\u0001 \ufffd\ufffdb\ufffd%`\ufffd\ufffdR\t\ufffd\ufffdJ\ufffd\u0000,\ufffd\ufffd畖\ufffd\u0026\u000b5E7\ufffd\ufffd\ufffd\u001e\ufffd\u0013\ufffd\u0001\ufffd\u0004q\u000c\ufffd8\ufffd%Q\ufffd\ufffd@\ufffd\u0016soۈ\ufffd\ufffdt!\ufffd\ufffd\u0001\u001dz\ufffd\ufffdZp+\ufffd\ufffd\u0018\ufffd\ufffdvK_p\ufffd;q\ufffd=8\ufffdQ\nY,\ufffd\ufffd\ufffdw(\ufffd,\ufffd\ufffd\ufffd\ufffd.\ufffdFW[_\ufffd\u0011\ufffd\u0000\ufffdk*\u001e\ufffd\ufffdD\ufffd\ufffd)\ufffd\\U\u001d\ufffd\u0018t\ufffd\ufffd\ufffd\ufffd\u001f\ufffd,)\u0006\ufffdj\ufffd@ޣBY#\u003c\ufffdK%\ufffds\ufffd\ufffd\ufffd\u0014\ufffd\ufffdW\ufffd\ufffd\ufffd\u003e\nu\ufffd\ufffd\ufffd\u0002 \ufffd\ufffd$Z\ufffdN.N\ufffd,\ufffdt~\ufffd\ufffd\ufffd\ufffd_\u0026\u0017g\ufffd\ufffd\ufffd\ufffd?\ufffd\u003e\ufffd\ufffd\ufffd7\ufffd/\ufffd\u0007\u001f_\ufffd\u000f\u001d\ufffd*k\u0005\ufffdV\ufffdet\ufffdؙ.\ufffd\ufffd}\ufffd\ufffd\ufffd\ufffd+\ufffd\u0002j\ufffd{\ufffde\ufffd\ufffd+\ufffdA?n\ufffd\ufffd\ufffd\u0004\u0001\ufffd\ufffd-\ufffdit\ufffddr\ufffd4?\ufffd\ufffd\ufffdy\ufffd\ufffd\ufffd4jw\ufffdN\ufffd\ufffdU\ufffd\u0010S\ufffd\ufffd\ufffd \ufffd\u001f\ufffd\u001d\ufffd\ufffd\ufffd#\ufffd鄑%\ufffd)o\ufffdQ\ufffd\ufffd4{Q\ufffdr\ufffd\ufffdE8itS\ufffd\ufffd\ufffdA/\ufffd\ufffdFac\ufffd3\ufffd\ufffdJ\ufffd\ufffd\ufffd\ufffd\u0006l\u0017\u001e\ufffdaݰ]*a)4\ufffd\ufffd+\u0006\ufffda\ufffd\ufffd\ufffd\ufffd\ufffdP\u0007\ufffdR\ufffd=X\ufffd\ufffdhm\ufffdZ]\ufffd9v\ufffd\ufffd\ufffd\ufffd\ufffdn@Z\ufffd\u001e\u0017\ufffd\ufffdC\ufffd*LOў\ufffd,\ufffd\ufffdR)\ufffdw#\ufffdu\u0008\u001e'\u00142\ufffdU\ufffd6OaJ\ufffdji\ufffd\ufffd\ufffd\ufffdP\ufffdNn\u001c\u000ej\ufffd\ufffdo\ufffd\ufffd\ufffd:\u001f\ufffd\ufffd\ufffdxӗMv\ufffdoM\ufffdg\u0003\ufffd6\ufffd\u0018\ufffd\ufffd\ufffd\u001fv\ufffd\ufffd\ufffd\t{\u0007\u000e\u0017\ufffd\u0003{\ufffd\ufffd~\ufffd\ufffd\ufffd\ufffd\ufffdd\ufffdj\ufffd\ufffdn\ufffdc\ufffd\u001e\ufffdl\u000cH\ufffd\ufffd\ufffd\r7\ufffd\ufffd玕hk(U}\ufffd\ufffdFz\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdw\ufffd\ufffd\ufffdo-\ufffd\ufffd\ufffd\ufffd\ufffd\\a\ufffd\u001as\ufffduKt\u001a\u000e\ufffd\u000fR\ufffdך\ufffd\ufffdSx%\ufffd֣\ufffd\ufffd\u001b\ufffd7\ufffd\ufffd\u0007ts\ufffdѫ*\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2651\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:10 GMT\r\nSet-Cookie: AWSALB=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+; Expires=Thu, 14 Sep 2023 15:34:10 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+; Expires=Thu, 14 Sep 2023 15:34:10 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:13+05:30","url":"https://ginandjuice.shop/blog/post?postId=3","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+; AWSALBCORS=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+","Referer":"https://ginandjuice.shop/blog/","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/blog/post","scheme":"https"},"raw":"GET /blog/post?postId=3 HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+; AWSALBCORS=mMf3rdKgea2WMm1zlXRLuVlGnzwzbnCekLUEJC1ovH7rG4GvyvUURlqixQ3pFQSyaGvl4sxhMoY/ptxpaAO2y0WTm/iV8QTUpZ7boE6tcrN3sR+Ibwx2OvFmWPN+\r\nReferer: https://ginandjuice.shop/blog/\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"3942","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:13 GMT","Set-Cookie":"AWSALB=85BJo1Zpdk9Zp+yPBrFftDnRpkda2GE1/JD01eSP9Ex//O3wSyqO/AF6ykA8rziJvN/Q7QNg9UV1oNa53YrhOnHvoGPe6yk0hzUoN1V5Rcp/SYNljF/y+T7fkl7C; Expires=Thu, 14 Sep 2023 15:34:13 GMT; Path=/, AWSALBCORS=85BJo1Zpdk9Zp+yPBrFftDnRpkda2GE1/JD01eSP9Ex//O3wSyqO/AF6ykA8rziJvN/Q7QNg9UV1oNa53YrhOnHvoGPe6yk0hzUoN1V5Rcp/SYNljF/y+T7fkl7C; Expires=Thu, 14 Sep 2023 15:34:13 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffd[\ufffdn\u001c7\ufffd}\ufffd\ufffd\ufffd;\u0018\ufffd\u0006\ufffd\u0012I\ufffd\u003cHj×\ufffd\ufffd\u001c[\u0016\ufffd\u001e\u0004\ufffd\ufffd\ufffd]\ufffd\ufffd\ufffdUU\ufffd!Yݮ\u0003?\ufffd3f\ufffd9\u001fp~\ufffd|J\ufffd䬽\ufffd*UK}\ufffd\u0012\u0007\u0018`\ufffd\u0008\ufffd.\u0016\ufffd\ufffd/k\ufffdX\ufffd\ufffd\ufffd\u0017o\ufffd\ufffd\ufffd\ufffd\ufffd;\ufffd\ufffd\"\ufffd\ufffd\ufffd4\ufffd%\ufffd\ufffd4S2\r?\ufffd1\ufffd\ufffd\ufffdȬ\ufffd\ufffdM\ufffdr\ufffd\ufffd\ufffdr\ufffd\\\ufffdh\ufffd\ufffd\ufffdĹ\ufffdKd\ufffdF\ufffd\ufffd\ufffd1\u0006\ufffdU\ufffd\ufffd\ufffdM\ufffd\\\ufffd\ufffd\ufffdG\ufffdH\ufffd\ufffd{\u00072\ufffd\ufffdM\ufffdP^\ufffdR\u0016\ufffdl\ufffd\ufffdjU\u0019\ufffd\u0007\"1\ufffdW\ufffd?\u001b\ufffdt곳T-u\ufffdF\ufffd0\u0014\ufffdSv\u0004\u000e\ufffdC\ufffd\ufffdJ3\ufffdQs\ufffdՕ\u0017\ufffd\u0026g\ufffd\u001eC\u001f\u001c\u001ed\ufffdǠ\ufffdrS\u0015 \u003e\ufffd\ufffd\u0006\ufffd\ufffdIXqw\u0012\ufffd\ufffd\u0014\ufffd \ufffd\ufffd\n\ufffdy\ufffd\ufffdO\u003eȥ\u000c\ufffd\ufffdM\ufffde\ufffd\ufffdsi:\u001c};\ufffdv\u001bU\ufffd}\ufffd\ufffdO\ufffd+\ufffdm#^\ufffdF\ufffdij\ufffd,\ufffd\ufffdK]\ufffd\ufffd\ufffd\ufffdN\ufffd\ufffd5\ufffd%\ufffde\ufffd:\ufffd\ufffd\u0005\u0001\u0007\ufffdk \ufffd\ufffdLڈr1\ufffdU\ufffd#\ufffd\ufffd\ufffd\ufffd\ufffd٠o\ufffd\ufffdz\ufffd`*\ufffdڔ\"ɥsg\ufffd\ufffd\ufffdQ\ufffd\u0002\ufffdxsc\u0001/\ufffdn\ufffdџ\ufffd\ufffdv\u0002\ufffdI\ufffd\ufffd\\ϔ\ufffd^\ufffd\ufffdX\ufffdy\ufffd\ufffd0\ufffdX\ufffd\ufffd\u0000\ufffd\ufffdN$\ufffd\ufffd}\ufffd\ufffdT\ufffd\ufffd\u001b+\ufffdr^\ufffd\u000b\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd]\ufffds\ufffd\ufffd0D\ufffd`̍72p\ufffd*ىBX\u001e\u0008S\u0016\u0006\u0010\ufffdi\ufffd%\u0000\ufffd\ufffdY\ufffd\ufffd\ufffd\ufffd\ufffd8\u0013\ufffd\ufffdk\ufffd\\{\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd}\ufffdѲ\ufffd\ufffd\ufffd\ufffd\ufffduu6\ufffds\ufffd\ufffd\ufffd\ufffdÇ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdW\ufffdEn\ufffd\ufffd΄\ufffdf\ufffd\ufffd\ufffd\ufffd\ufffd_\u000fg/\ufffdΓ\ufffdOZ\ufffd\ufffd\ufffdJ_\ufffdy\ufffd:;;x\ufffd\ufffd\ufffd+I\u003c\ufffd\u000eʫ\u001e\ufffd\ufffd\u0013qk\ufffdh\ufffd\ufffd\u0006\ufffd\ufffdڋ\u0006 \u0017\ufffd\u000e\ufffd\u001b\ufffd3Ŧ{\u0000\ufffdC\ufffd\u001b\ufffd2\ufffd\ufffd\u0017L\u000c\ufffdۉŃ\u0000\ufffdg\ufffd\ufffd\ufffd\u0006\ufffd\u0004\ufffd0\ufffd\u0002\ufffdԘ\ufffd\u0019\ufffd\ufffd2Ĵ\ufffd\ufffd\u00062\u001b\ufffd9\u000et#8\ufffd\ufffd\ufffdb|\u000bى\ufffd\ufffd\ufffd\ufffd\u0014;\ufffdh\u000f\ufffd\ufffd\ufffd[\ufffd\ufffdf\ufffdy\u000bm\ufffd\ufffd\u000b\ufffd\ufffd(:,\ufffd݉\ufffd\ufffdB\ufffd\u0026\u003cmp\ufffd[$s\ufffd\u0012O\ufffd\ufffdֳ\ufffd{\u0004\ufffd\ufffd\ufffd\ufffd\u0004Ȕ\ufffd\u0013\ufffdaMZ'\ufffdmU\ufffd\u001a\ufffd\ufffd]6\ufffd\ufffd\ufffd\t\ufffd\ufffdUڱ9c\u001e)\ufffd\ufffd+\ufffdױ%g\ufffd\ufffd\ufffd\ufffd[r(ol\ufffd\ufffd\ufffd;\ufffd\ufffd\ufffdo\ufffd\u0012\ufffdє\ufffd\ufffd\ufffd\u0026\ufffd$\ufffd.\ufffdH'=\ufffd\u0014\ufffd(\ufffd#i\ufffd\ufffdbz\ufffd\ufffd־\ufffdN\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdv\ufffd\u0018\ufffd\ufffdX\ufffd\t\ufffd\ufffdbʽD\ufffd.\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd{\ufffd}[\ufffd\u001bp\ufffd\u000b\ufffd\u001aU\ufffd.\ufffd\ufffd1ӽ\u0013j_\ufffd\ufffd4\"\ufffd\ufffd\ufffdXߏ\ufffd\ufffd\ufffd\ufffd\u0015\ufffdM\ufffd\ufffd\ufffd\ufffd\u0018\u0001'\ufffd\ufffd\ufffdJ)\ufffd0\ufffd\ufffd;\ufffd\ufffd\ufffd2t\ufffd\ufffd\ufffd\u001f\ufffdw\u0016\ufffd\ufffd\ufffd#o\u0016\ufffd\\a7\ufffd6j\ufffdbA\ufffdb\ufffd\ufffd\u0013f\ufffd\u0003\ufffd\ufffd\ufffdQ\ufffdt\ufffd5\u0001nI\ufffd\u001b\ufffd7\u0014\u00167fqjF\ufffdB\r\n%\ufffd\u00114\ufffd\u0013R\ufffdβ\ufffd@\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd:\ufffd\u000f\ufffdy(\ufffdG\u0015\ufffd\ufffd%t\ufffd\ufffdp\ufffd)\ufffdx=\ufffduq\ufffd\ufffd\ufffd\u0016N\ufffd\ufffd-o\ufffdC\ufffd\u000c-N\ufffdغ\ufffd\ufffd\n\ufffd\ufffd\u0005m\ufffd4\ufffd\u000c\ufffd\ufffdL\ufffd\ufffd[t}\ufffdz~ݿ\ufffd\ufffd\ufffdl\ufffd\ufffd\u001d0}u\ufffd\u0015+\ufffd\ufffd\ufffd\ufffdy\ufffde\ufffdnIv\ufffd\ufffd+\ufffd\ufffd\ufffd\u0010\t4\ufffd:b4k\ufffd3P?\u0015pS\ufffd\ufffd\ufffd\ufffdsis\ufffd\ufffd\u001b\ufffd\ufffd42\ufffd\ufffd\ufffd$\ufffd'\ufffd 2=\u003c\u0012O\ufffdE\rF\ufffd\ufffd\u003c:\ufffd\\gs\ufffd̜\ufffdb\u0011[K\ufffd\u0016\ufffdP\ufffd\ufffd\ufffd'$\ufffd\ufffd|=\ufffdP-\ufffdJ\ufffd\r!\ufffd\ufffdG#\ufffd\u001a\ufffd\ufffd\u0003\u0011\u0005ȔUB.\ufffd۱8\u0017+Yz.\ufffdU\ufffdS\ufffd/\ufffdP\u0011\ufffdLz\ufffd\ufffdSԲ\ufffdA\ufffdҟ\n\u0017ſ\u000c\ufffdgE*\ufffd\ufffdx#\ufffd!\ufffdqb\ufffd\u003cwu\u000e\ufffd\ufffd\"\ufffd\ufffdz-\ufffd=^C\ufffd5\ufffd\ufffd\ufffd\ufffd\ufffd?R1#\ufffdH\u0001\ufffdL*\ufffdʡ\ufffd\u001b\ufffdw\ufffd\ufffd\ufffd\u0006\u0026\ufffd\ufffd\ufffd2S*\ufffdH\ufffd\u0005VJxY\ufffdFa,\u001eA\ufffd\ufffd\u000e\ufffd\ufffd\ufffd\ufffd̘\ufffdV\u0002=\ufffd*]xQ)S\ufffd\u001b\ufffd`|a\ufffd*#*\ufffd\ufffdX\"\ufffdR;\ufffd\ufffd\"\ufffdTr%\ufffd\n=U\u0010\ufffd\ufffd,\ufffd\ufffd\ufffd\ufffd\ufffd4 y\ufffd8\ufffd\ufffd;\u0016(\ufffd\ufffd\ufffd\u0016\ufffd\u000f\ufffdc\ufffd+E[\ufffd#W\ufffdh\u0004:F\ufffd\u0019\ufffddC\u0026\ufffd\ufffd\ufffd|%\u001bh\ufffdx\ufffdR\ufffd\ufffd6\ufffd\ufffd\u0002\ufffd\ufffd\u0010\ufffdӨ\ufffdB^\ufffd2%6\ufffd`\ufffd\ufffdQ\ufffd\ufffd9\ufffdi\u0002/\u0019\ufffd\ufffd6i5\ufffd\nK\ufffd%:9+~\ufffd0\ufffd\u001d2]X\u001a\ufffd\ufffd\ufffd_\ufffdݭR\ufffd\ufffdK\ufffd\u003c\u0018\ufffd\ufffd\ufffdT^\ufffdF2\ufffd\ufffd49F\ufffd/=\ufffdvЊ*ɔ$5\u0018\ufffdp\ufffdN\ufffd+k\ufffd\ufffd\ufffdV\ufffd\ufffd\u0003a`G\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd-Iۿ\ufffd\ufffdw\ufffd\ufffd\ufffd2U\ufffd`x\ufffd\ufffd\u00131k\ufffd\ufffdrؚa\u0005\ufffd\u000c[\ufffdT)*c\ufffd\ufffd\ufffdJ\ufffd$\ufffd\u00120S\ufffde\u0001\ufffd8\ufffd\u0010\ufffd\u000b\ufffd\ufffd@E\ufffd\ufffdC\ufffd\ufffdN\u0000\ufffd%\u000b\ufffd\ufffdy5\u001dcd\u0018 \ufffd\u0010\u000c\ufffd/,\u000cʁ\u0026\u003e\ufffd\ufffdgƣ\ufffds\ufffdB\u001fjG+\u001d\ufffd8\ufffd\ufffd\ufffd08\ufffdFW\ufffd]\ufffd\u0001\ufffd8v\u0002\ufffd\u000f\ufffd\\F\"95\ufffd\ufffd\ufffd\ufffd!CD\n\ufffd\u0000\u0014\ufffdഠ\ufffd\ufffdg\u0001\ufffd\ufffd\\\ufffdWb.\ufffd\u0016k\ufffdFL\ufffd\t\ufffd\ufffd\ufffdӲ\t\ufffd\ufffd\ufffdt\ufffd*d2ca\ufffd\ufffdf\"Χn\ufffd\ufffd\ufffdY \ufffd\u00042^\ufffdfEk\ufffdbӚε@\ufffd\u0013bH\ufffd\ufffd\ufffdΌ\u001c2\u0008p\ufffd\ufffd]VL{\u001c\ufffd\ufffdA!}\ufffd\ufffd]\u0017\ufffd\ufffd\ufffd\u0005)ׇʒf\ufffd\ufffdj5\u001b\ufffd\ufffd\ufffd\ufffd\u0002~\u0012\ufffdӀ\ufffdaD\ufffd--\ufffd_\u0003(\ufffd\ufffdKl\ufffd\ufffd\u0011\u000c\u0004\ufffd\ufffdmx®\ufffd\ufffd!ۊ\ufffd\u0026\no\ufffd1, \ufffd\ufffdD\u0008{@\"\"\u0003\ufffdy\u0013\ufffd\ufffd\u0002b\ufffdo\ufffd\u0004re-\ufffdsc;\u0006\ufffd38E\ufffd\rǭ\u0010\u000c\ufffd\u001c=\u0007\ufffdT\ufffd\ufffdk\ufffd\ufffd.\ufffd\u0026_\ufffdy\ufffdکI\u0017\ufffdH\ufffd/K\ufffd8\ufffd\ufffd:\ufffd\u000bf\ufffd0 [ J\ufffd\ufffd\u0005m\u0002W\ufffd\ufffd\ufffd\ufffd|\ufffd\ufffd.\ufffdCԕW}\ufffd\ufffd\ufffd}\u00151\ufffd\u003e\ufffd\ufffd\ufffd$\ufffd\ufffdQ\ufffd\ufffdHn,\u0006\ufffd\u00036|aXk\ufffd\ufffd\ufffdj\ufffd\ufffd\ufffd\ufffd$\ufffd\u0018@\ufffd`\u000bC\ufffd\ufffd\u0008\ufffd?*\ufffd`\ufffd\ufffd\ufffdiz=\ufffd\u001b\ufffd֕\ufffd+\ufffd\u0016P\u0005Ŕ\ufffd)\ufffd\ufffd\u0003\ufffd\ufffdw\ufffd|(\ufffd\ufffdx!S\ufffd\ufffd\u0000\u001e\ufffd\u0012\ufffdd\u0008\ufffd\ufffd!HєY\ufffd\ufffd\u000bc:!\ufffd8#\ufffd\ufffd\ufffd\ufffd\u00033J@i)\ufffd\u0010BD]f\u0026o\ufffdz\ufffdb\u001agFb\ufffd\ufffd\u001a\ufffd\ufffd\ufffd4\u0026\u000fFR\u000cC+\ufffdƾ\ufffd\ufffd\ufffdo\ufffdku\ufffdeI\ufffd\ufffd{\n\ufffd\ufffd\\\u0016\ufffd\ufffd\ufffd\u003c\ufffd\u000bVl\ufffd\ufffd\ufffd\n\u001cϮ\u0003\u0019\ufffd\ufffd\ufffdH\ufffd\\\u0026\ufffd\ufffd\u0008\ufffdz\ufffd\ufffdx9\ufffdY\ufffd$D!\u0018Й\ufffdI\ufffd\ufffd6ף\nP\ufffd\u0019\u0016\ufffd\ufffd\ufffd\u0007\u003exf\ufffd \u0008\ufffd\ufffd\ufffd\u0005\ufffd\u0004w)\ufffdϠ̑eC\ufffd\u0007r\ufffd\u001b S\ufffd\u0005Q_\u000bS\ufffd\ufffd\ufffdN\ufffd\u0004\ufffd\ufffd$넅\ufffdb\u0010\ufffd\ufffdf\ufffd\ufffd%\ufffd\ufffd\ufffd\u000bF%\ufffd\u000eXI2\ufffd\ufffd1`\ufffdw\ufffd\ufffdr\ufffd\ufffd\ufffdԔ\ufffd(\ufffd\ufffdW\u0014t\ufffd\ufffd**\ufffd\u0000\ufffd\u00172\ufffdxR!-\"\ufffdk\ufffd2g\ufffd\ufffdT;S\ufffd\ufffd\u001b1\ufffd̞\ufffdJp\u0008\ufffdm\ufffdU1\u003e\u0007\u0001\ufffd)ڍ\u000e\ufffd\ufffd𘠂\u0000\ufffdB\ufffd9\u000f\u0018\ufffd\ufffd\ufffd\u0014\ufffdK\ufffd\ufffd8*\ufffd\u0004\u0006\ufffd\u0013֘\ufffd\ufffdi\ufffd\ufffd\ufffd\"\ufffd\ufffdt\u001c+'\nFe,T\ufffd\ufffd\ufffd\ufffd\u000c\ufffd\ufffd\ufffdg \ufffd\u0014BLp\u0012B\ufffd\ufffdLQ\ufffd\ufffd$4\ufffd~\ufffd\ufffd6\ufffd^\ufffd\ufffd\ufffd\ufffdI;-@\ufffd2(E\ufffd6\ufffd\ufffd\ufffd\ufffd1J\ufffdy\u001a\u00177\ufffdץ\ufffd\ufffd\ufffdy[Ǡ\ufffd\ufffd|\u003e\ufffd(\u0007\ufffdY{\ufffd#\ufffd#\ufffd-j\ufffd\u001f{\ufffd\u0013qަ\ufffdX4 \ufffd\ufffdP\u0008yJ`\"\ufffdЁ\r8\ufffd\u003e\ufffd\ufffd\ufffd\u0026\ufffdIr]͌\ufffd\ufffd\ufffd\u000f\u0011f\u001c\ufffd\u0002I\ufffd\u0019\ufffd|\ufffdp\ufffd\u0017\\\u000f\ufffd\ufffdq)c\ufffdX\ufffd\ufffd\ufffdl\n\ufffd\u0015p\u0010У]\ufffd\ufffd'!ER\u0015\u001a\u0012\u0004D%\ufffd\ufffdB\ufffd\ufffd\ufffd t \ufffd\u0015\ufffd#\ufffd\u001eV\ufffd4\u0008\ufffd\u0014a\u0015\ufffd̦u\ufffduB\ufffd\ufffd'\u0008D\ufffd\ufffd\ufffd%\u0005\ufffd\ufffd\ufffdw+*\ufffd\ufffd\t\ufffd\ufffd\ufffd'\ufffd\ufffd \ufffd1\ufffd\ufffd\ufffdNFe\ufffd\ufffd\ufffdg\u000f\ufffd\ufffd\u0014\u0015I]\u0015\u001c\ufffdh\ufffd\ufffd\u0010\ufffdP\ufffdH\ufffd1fo\ufffd\u00011\u0002r\ufffd7G\ufffd\u000f\ufffd`\ufffd'\ufffd\r[\u003e\u0010/\rj1\ufffd\u0000{\ufffd\ufffd\ufffd\ufffd-\u0004^\u0012\u0004\ufffd$\ufffdD4\ufffdN\ufffd_\\\ufffd\ufffd\ufffd\u0010\ufffdo\ufffdaN\ufffd\ufffd\u001eu\ufffdS\u0011t\u003c\u0026\ufffd^1/m\ufffd\ufffd\ufffdg\n\u0018\ufffd,\ufffdV1w(\ufffd:d\u0005\ufffd\u001a2C}À\ufffd\ufffdĺ\ufffd\ufffd\ufffd΄\u0013\ufffd\u0013\u0012\ufffdy\ufffd\ufffd\u001b\ufffdU\ufffd\ufffd\ufffd\ufffd\u001dT\ufffd\ufffdܤ,8fõU\ufffd~4\u000b.\ufffd6(\ufffd\ufffd\u00083\ufffd\u001b\ufffd\u0008\u0002\ufffd`\ufffd\u0017¾\r\ufffd\ufffdU\u0002\u0017c\ufffd\ufffd\ufffd\ufffdF\ufffd;\ufffd\ufffd\ufffd}\n\u001e\ufffd\ufffd\u000c\ufffd\ufffd2:\ufffd\ufffd+\ufffdC\ufffdL\ufffd8\ufffd\u0005]\ufffd\\8\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd@uȲĂk\ufffd\u0018|\u001fJ\ufffdЪ\ufffdk\ufffdmd\ufffd\ufffd1Ss\ufffd\ufffd\ufffd\ufffdX\ufffd\ufffd\ufffd\ufffd:\ufffd\ufffd/\ufffd\ufffdZU\ufffde\ufffd\n\ufffd\tz\u0002*\u0013\ufffd\ufffd\u001dۈ\ufffd\ufffd\"\ufffd(\ufffd5E?\ufffd\ufffdX\u0016\ufffd\u0013\ufffdR.\ufffdv)e\u000c\ufffd\u000b\ufffd\ufffd^6\ufffd\ufffd\u0005\ufffd\"\ufffd\ufffd@\ufffdK\u000cf\ufffd~2\ufffdJ*\u001a\u0010\ufffd\ufffd2Ĺ\ufffd\ufffd9\ufffd\u003ePQ\ufffd\ufffdH;RJ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd)\ufffd\ufffdݮc\ufffd\ufffd\u0013\ufffd$\ufffd\ufffdu\u000e\ufffd\ufffdG~w}\u0014q\ufffd\u0008S.%\u0002\u0008\ufffd_\u000e\ufffdc}\u001e\u001aL\ufffd\ufffd\ufffd?\u0017\u001a\ufffd\ufffd\ufffdCY\u0019w\ufffd\u003cӕ\u0013\ufffd\ufffd\ufffdq\ufffd\ufffdd\ufffdY\ufffd.V\ufffd\ufffd\ufffdt@qK/Ȳ\ufffd\r\u0010Wl7\ufffd\ufffdO\ufffd\ufffd\ufffdu-\ufffd\u001d\ufffd\ufffd2\ufffd\ufffd\ufffdo?\ufffdn\ufffdo\ufffd\ufffd\u001fFߞQ\u0004e_D\ufffd\t\u0006]r\ufffdD\ufffd/|\ufffd\ufffd\u0019\u003e\u0015z\ufffd_\ufffdpPT捈\ufffd[\ufffd\ufffd\ufffdö Q\ufffd\u0007\ufffdWtK\ufffd\ufffdF\ufffdЈho\ufffd\u0026\ufffdS\u001c\ufffd$\ufffd\u000f?\ufffdg\ufffd\ufffd\ufffd\ufffd1\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd3T\u003c\ufffd%r3\ufffd\u0008\ufffd\ufffd\ufffd\ufffdx\ufffd*\ufffd\ufffd\u00192\ufffdoR\ufffd\ufffd\ufffdJ\u0018\ufffd\ufffd\u001b\ufffd*\ufffdL\ufffdю\ufffdb\u0015\ufffdV\u003c\u0026E\nJ\ufffd\ufffdH!E\ufffd-e\ufffdBQ7\ufffd}(\u000b\ufffd\ufffdn\ufffd靟k\ufffd\u001fx)\ufffd\ufffd\ufffdO{\ufffd\ufffd\ufffd\u0003\u0008\ufffdz:\ufffd:;\ufffd\u003c\ufffd\u001f\ufffd\ufffd\ufffd\ufffd_\ufffd\ufffd\ufffds\ufffd\ufffd\ufffdI\ufffd\ufffdJ\ufffdV\ufffd/~\ufffdNQ\ufffdu)\ufffd,ܣ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd1j\ufffdG\u0003f\ufffd\ufffd\ufffd\ufffdI\ufffd\ufffd\t'\u0007\ufffdg\ufffdڡ\ufffd\ufffd\u001f\ufffd\ufffd硛ژ\u001b\ufffd\ufffdi\ufffd\ufffdtʽ\ufffdK\ufffd\rh\ufffd\u0005ێ\ufffdoS\ufffdzj\ufffd\ufffdV\ufffd\ufffd5\t\ufffd^\ufffde\ufffd\ufffdhz\ufffdek\ufffd]\ufffd%s1\u0012\ufffd\ufffd\ufffd=.\u0014\ufffd\ufffdXP+\u001c\ufffdD\ufffd\ufffdh\u0026\u0004\ufffdc\ufffdf\ufffd\ufffd\ufffd\ufffd#ǭK\ufffd\ufffd\u0016\ufffd\ufffdN\u0006B)N\ufffd\u0002s4\ufffd^'(\ufffd\ufffd}S\u001f\ufffd\ufffdv\ufffdtaq\ufffd\u000eL(\ufffdt1\ufffd\ufffd\ufffd\u003cU|V\ufffd\ufffdĠ\ufffd\ufffd\u0019\ufffdP\ufffd'\ufffdt\ufffd\ufffd'(\ufffd\ufffd\ufffd\u001d\ufffd߸넽0\ufffd\ufffd\u0007w\ufffd\ufffd\ufffd\ufffdF]\ufffd\r\ufffdv\ufffd\ufffdZ\ufffd\ufffd\u0018\ufffdZ\ufffdrDM\ufffd\ufffd$\ufffd\ufffd\u0012\ufffd$c\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd[\ufffd\ufffdo\ufffd\u000b\ufffd\ufffd\ufffd(n\ufffd\ufffdd\ufffd\ufffdǦh\ufffdR\ufffd\ufffd\ufffd\u001d\u000f\ufffd4\ufffd\ufffd\ufffd\ufffdal$?\u0008'\u000b\ufffdx/3qv\u003e\u0010K\ufffd\ufffdx\ufffd[\ufffd\ufffd\ufffd\"\ufffde\u0017\ufffdO\ufffd\\\ufffdy\ufffd\ufffd\ufffd.|u\ufffd\ufffd\ufffd]\ufffd\ufffdw\ufffd/\ufffd߷_\ufffdps\ufffdb\u0000o\u000b\ufffd\u0014\ufffdOߵ\ufffd9\ufffd\ufffd\ufffd\u0001o\ufffd\ufffdh-\ufffd5\u001b,1ue\ufffdQ\u0018\ufffd\ufffd\ufffd\ufffd\ufffdY^\ufffdݿ\ufffdH\ufffd\ufffd1٨\ufffd\ufffd\ufffd\ufffda\ufffd9\ufffd~\ufffd,=\ufffd\ufffd\ufffd\ufffd\u003c}\ufffd\ufffd;\ufffd\ufffd\ufffd\ufffd܁G^\ufffdF\ufffd\ufffd\ufffd?\ufffdy\ufffdus\ufffd\ufffd?\ufffd\ufffd\ufffdU\ufffd+g\ufffdf\ufffd8ڦ\ufffd\u0002n\u0014\ufffd\u000c\ufffdA1\ufffd)5u\ufffd\ufffd\ufffd\ufffd{\ufffd\ufffd\u0016hIG\ufffd\ufffd\u0011:\ufffd\ufffd\ufffd\ufffda0\u001a\ufffd\ufffd\u0015\u0016Y\ufffdM\u000fu \ufffdU:B\ufffd\ufffd\u001a\ufffd\ufffdY\ufffdU\u003c\ufffd\ufffd\u0019\ufffdo\ufffdt\ufffd\ufffd\ufffd\ufffdiU\ufffdBډ\ufffd=\ufffdJ\ufffd\ufffdC\ufffd\ufffd+\ufffd\ufffd\ufffdS\ufffd\u0013\ufffdn\ufffd*4\ufffd3P~\ufffd=}\ufffd=\ufffd\ufffd繓\ufffd\ufffdw\ufffd}\ufffde=\ufffd\ufffd\ufffd]\ufffd\ufffd\ufffdt\ufffdܭ\ufffd\ufffd\n_\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u000b?q\t\n\ufffd\u0002\u0005\ufffdڧ\ufffd;Hv\ufffdk+[\ufffd\ufffd\ufffdn-f\ufffd\ufffds\ufffd\u000b\u0012H\ufffd\ufffdGYr\ufffd]\u0002\ufffdUe\ufffd\ufffd9\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u000cܧ\ufffd\ufffd\ufffdy\ufffdl\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd]\ufffd\ufffdW\ufffdq\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd48\u0019\u0017\ufffd\ufffd\ufffd\ufffd\ufffd.O\ufffd\ufffdL\ufffdL\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0001j\ufffdl#\u00024\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 3942\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:13 GMT\r\nSet-Cookie: AWSALB=85BJo1Zpdk9Zp+yPBrFftDnRpkda2GE1/JD01eSP9Ex//O3wSyqO/AF6ykA8rziJvN/Q7QNg9UV1oNa53YrhOnHvoGPe6yk0hzUoN1V5Rcp/SYNljF/y+T7fkl7C; Expires=Thu, 14 Sep 2023 15:34:13 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=85BJo1Zpdk9Zp+yPBrFftDnRpkda2GE1/JD01eSP9Ex//O3wSyqO/AF6ykA8rziJvN/Q7QNg9UV1oNa53YrhOnHvoGPe6yk0hzUoN1V5Rcp/SYNljF/y+T7fkl7C; Expires=Thu, 14 Sep 2023 15:34:13 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:18+05:30","url":"https://ginandjuice.shop/about","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=FuPzkvEYylog+dQhM7EDdfOxlO4LNNlDYYFUu86LrSuM/kx3kGryxBucqnFtsBKkCp4hyX30SKkFqbN+LcVwM135w3aUgOugwu1lG3qZ1Hig6rAW0C0h0PS0EdtD; AWSALBCORS=FuPzkvEYylog+dQhM7EDdfOxlO4LNNlDYYFUu86LrSuM/kx3kGryxBucqnFtsBKkCp4hyX30SKkFqbN+LcVwM135w3aUgOugwu1lG3qZ1Hig6rAW0C0h0PS0EdtD","Referer":"https://ginandjuice.shop/blog/post?postId=3","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/about","scheme":"https"},"raw":"GET /about HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=FuPzkvEYylog+dQhM7EDdfOxlO4LNNlDYYFUu86LrSuM/kx3kGryxBucqnFtsBKkCp4hyX30SKkFqbN+LcVwM135w3aUgOugwu1lG3qZ1Hig6rAW0C0h0PS0EdtD; AWSALBCORS=FuPzkvEYylog+dQhM7EDdfOxlO4LNNlDYYFUu86LrSuM/kx3kGryxBucqnFtsBKkCp4hyX30SKkFqbN+LcVwM135w3aUgOugwu1lG3qZ1Hig6rAW0C0h0PS0EdtD\r\nReferer: https://ginandjuice.shop/blog/post?postId=3\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2591","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:19 GMT","Set-Cookie":"AWSALB=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB; Expires=Thu, 14 Sep 2023 15:34:19 GMT; Path=/, AWSALBCORS=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB; Expires=Thu, 14 Sep 2023 15:34:19 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdZ\ufffdr۸\u0019\ufffdߧ\ufffd\ufffd\ufffd(\ufffd\tŵ\ufffd6\ufffdF\ufffdL\u000e\ufffd\ufffdns\ufffd؝4\ufffd\ufffd@$$\ufffd\u0006\t\ufffd\u0000%\ufffd\ufffd}\ufffd\ufffd\ufffd5\ufffd(}\ufffd~?@ɔDIT\ufffd̴\ufffdx\u003c6\ufffdÏ\ufffd|\u0002\u0007\ufffd?{\ufffd\ufffd\ufffd\ufffd۟Xj35\ufffdn\ufffd\ufffd1\ufffd\u000cR\ufffd\u0013\ufffd\ufffd^\ufffd̯XZ\ufffd\ufffd0*\ufffd\ufffdU\u0019\u000b\u0013)\u003e\ufffde\ufffd\ufffdbc\"\u0013\ufffd\ufffd\ufffdx\ufffd\u0006\ufffd\u0018`\ufffdPCc\u0017J\ufffdT\u0008{\u0008\u0018\ufffd\u0000@s\u000e0\ufffd\ufffd\u000f \u0013\ufffd\ufffd\ufffdgb\u0018̤\ufffd\u0017\ufffd\ufffd\u0001\ufffdunEn\ufffd\ufffd\\\u00266\u001d\u0026b\u0026c\u0011\ufffd\ufffd\ufffd\ufffd2\ufffd\u000c\ufffd!NPb\ufffd\ufffd\ufffd\u0001\ufffdĥ,,3e\u003c\u000c\u001a\u0008]\u001a\ufffd\ufffd\ufffd\ufffd\u0001I(]d\u00004\ufffdh\u0010\ufffd\u001d\ufffdA\ufffd\ufffdΎ\u0000c\u0017\u0005(\ufffd\ufffd\ufffdF\ufffd|\ufffd\ufffdh\ufffd\u0006\ufffd\ufffd\ufffdJ\ufffd\ufffd\ufffdI\ufffd0|\ufffd\u000b\ufffd\ufffdV\ufffdћ\ufffdd\ufffd\ufffdr\ufffdB\ufffd\\\ufffd\ufffd\u000eϊG\ufffd\ufffd\nLb\ufffd\ufffd.\u0006\ufffd_\ufffd\ufffd\u001f\ufffd\ufffd0\ufffdɂ\ufffdӐ\u0017E\u0003j\"gL\u0026à)\ufffd\u0006W==\"\ufffdR\ufffd,Vܘa\ufffd\ufffd%L\ufffdG\u00113\u001b\u001bܦb{\ufffd~.Ri\u0018~9K\ufffd\ufffdcQr+Ԃ\ufffd*\ufffd\ufffd\u0019Res1f\ufffdQɘ\ufffdSq\ufffd\ufffd\ufffd\"a\u0013]2+\ufffd\ufffd\ufffd\ufffd\u0016\ufffd\ufffdǦx\ufffd\ufffd(\ufffd\ufffd\u000b?D\ufffd`\ufffd\ufffd[\u0011\u0018\ufffd\ufffd\ufffdH!\u0015\u000e\ufffd\ufffd3\r͂DEIz\ufffd'z\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\r\ufffd\ufffdjZ\ufffd\ufffdgO\ufffdf3L7g\ufffd\ufffd\ufffdr\u001a\ufffdys\ufffd\ufffd\ufffd\ufffd\ufffd\u0018\u0006r\ufffd\ufffd6\ufffd\ufffds\ufffd5\ufffdZ{=[}p\ufffd)]skȸ\ufffd㻽\ufffdg=\u0019?\ufffd\ufffd\ufffd\ufffd\ufffd%]$ϕ\ufffd\ufffd\ufffda\ufffd\ufffd\ufffdT%8\ufffd\u000c9\u0008+\u001a\ufffdN\u001e\ufffd\ufffd\ufffdӖ\ufffd\ufffd\ufffd\ufffd\u0007\ufffd\ufffdme\ufffdB\ufffd\ufffdz90\ufffd\ufffdM\ufffd\u0013\ufffd\ufffd\ufffdk\ufffd\ufffdE]\ufffd\r}\ufffdB\ufffdu{u\ufffd\ufffd\ufffd\ufffd\ufffd;\ufffd\ufffd\u0002\ufffd\ufffd\ufffd/%\ufffd\ufffd%\ufffd\ufffd\ufffd\ufffd\ufffd{WZ\ufffd\ufffd\ufffd3ο\ufffdJO5\ufffd\u0015\ufffd;\ufffdF|\ufffd\ufffd\r(g\ufffd\ufffd\u0001\ufffdܞ\ufffd\ufffd8f\ufffd\ufffdRK\ufffd\ufffdZ9u:\u0011\ufffd\u0006K\ufffdnXQʌ\ufffd\u000b\ufffd\ufffdb\ufffd[ \ufffd\u003c\ufffd\ufffd-\ufffdˣǕ\ufffdp\n\ufffd\ufffdA\u0004\ufffd\ufffd\ufffd\u00134\ufffd\ufffdI\u0015[\ufffd\ufffd)k\ufffd\ufffd.\u0007\ufffd\u001e\ufffd\ufffdC\ufffd\t\ufffd\ufffd7\ufffd\ufffd\ufffd,c+\ufffd\u0015~|\ufffd+\u001b\ufffd\ufffd\ufffd/\ufffd\ufffd \ufffdԭu\tƨ\ufffd\ufffd+k\u0013\ufffdc]\ufffd6\ufffdqCj\ufffd\"\ufffd\ufffd\u0011+\ufffdl:\u001a\ufffd\ufffd-'ob+T}J\ufffd\ufffdu\ufffd\ufffd\ufffdտY\ufffd\t\ufffd\ufffdf\n\ufffd\u0004\ufffd\u000b{k\ufffdt[x\u0014\ufffd\ufffd\ufffdo\ufffdk\ufffd\ufffd\ufffdz\ufffdd\ufffd\u0019c\u0007\ufffd\ufffd\ufffd~]\ufffd_-X\ufffd\ufffd\ufffdP?\ufffd\ufffd\ufffd\ufffd}\ufffd\ufffdƼ\ufffd\ufffd\ufffd\ufffd\u0003F4C\ufffdJ!\ufffd\ufffd\u000e\ufffd\u001d\ufffd\ufffd\ufffd:ս\ufffd~\ufffd\ufffdv\u0026\ufffda\ufffd\ufffd\ufffdө\u00128\ufffd\ufffd\ufffd\ufffdr:\ufffdT\ufffdS\ufffd\"f\ufffd\u000b\ufffd\ufffd\ufffdW\u001aD;\u0003\ufffd\ufffd\u0010\ufffd2ܒXl\ufffdr\ufffd\u0019\u0019\u000b\ufffd%\ufffd\ufffdݛ\u000fg\u0008۫\ufffdݖ\n߄\ufffd`\ufffd\u000e9pX@\ufffd;|\ufffd\ufffd\ufffd\ufffd\u0015ǵ\ufffd\ufffd:!\ufffd]𮍑\ufffd\ufffd1\ufffd\ufffd\ufffdK=|\ufffd\ufffd\u0013^k\u001e\ufffd\u0005\ufffdj\u0008\ufffd\ufffd9\ufffd\ufffd=q`Uo8\ufffd^\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdP\ufffdP:\u0010I\u0006\ufffd\ufffd\ufffd߱͟\ufffd\ufffd7\ufffd\u003e\ufffd\ufffd\ufffd}:\ufffd37\ufffd\ufffd\ufffd!\ufffd\ufffdן\u001bX\ufffdU\ufffd!\ufffd\u001a\ufffd\ufffd\ufffdf2\u0011:\ufffd\ufffd(hv\ufffd\ufffd\u0003\ufffd\u000e;\ufffdn\ufffdؕХV\ufffde\u00152\tVh\ufffd\n\ufffdm\ufffd2\ufffd\u0008\ufffdy\u0012^R\ufffd\u0018Z\ufffd\ufffd\ufffde1\ufffdx\ufffdg\ufffd\u0003\ufffdU\ufffd\u0015\u000f\ufffd\ufffd2v\ufffdF4\ufffd\ufffd\ufffd\u000fTX\ufffdK=70\ufffdD\u000b\ufffd`\u001a\ufffdT\u00055\u000f\\\ufffd\ufffdY`\ufffd\ufffd\ufffd\ufffdۢ r\u001b\ufffd\ufffdν\ufffd\ufffdZ\ufffd%@Nj\ufffd\u0002\ufffdٴ\u001b3\u0013\ufffdBX)Q.\ufffd\ufffd\u0018Wv\u0018PC\ufffdf\"\ufffd\ufffd\u0008U]\ufffd\ufffdY\ufffd\ufffdFc`\ufffd\u0015\ufffd[\u0006\ufffd\ufffd^\ufffdk{\ufffd\ufffd+0֕\ufffd\ufffd\ufffd\ufffd\u0002\ufffdQTe\ufffd\u0004\ufffdD\ufffdc\u0001\ufffdq\ufffdq{1z\ufffdK\ufffd\r{\u0005\ufffd\ufffd\u000b\ufffdg\ufffdY\ufffds\ufffd'\ufffdo\ufffd\ufffdX\ufffdGv\ufffdS\ufffd\ufffd#\ufffdy\ufffd\u001f\ufffdߘ\u00163\ufffd\ufffdT\ufffd\ufffd2\u0004\u0003\ufffd\ufffds,d\u0010\ufffd\ufffdu\ufffd\ufffd\u0002\ufffd\ufffd\ufffd\ufffd\ufffd,\ufffdՙ\ufffd]8\ufffdC\ufffd\ufffd\ufffd\ufffd\ufffd\u0017\ufffdY\ufffd\ufffd\u0004\ufffdU\u0002\ufffdw=\ufffdF\u0008\t#;\ufffd\ufffd\ufffd\ufffd\ufffdE\ufffd]\ufffd!\ufffd/*\ufffd\ufffd=\ufffd\u0026\ufffd\ufffd]g\u0026\ufffd\ufffdk\ufffdɸR\u001ee\u003c\ufffd,\ufffd{\ufffdΐ\ufffd\ufffd\ufffd\ufffd0l.m\n\ufffd\ufffdRp%\ufffdF}\u001ank245\ufffd\ufffds*}\u0003k\ufffd\raC\r\ufffd\u00144\ufffd\ufffdV\u0013\ufffdU\u0012\ufffdk\ufffd\ufffd\u001ci\ufffd\ufffdÑ\ufffdY\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdo\ufffd\ufffdQ\u001e൞\ufffd\ufffd/\ufffd\ufffd\u0016\ufffd2\ufffdgc\ufffd\ufffd\ufffd\ufffd}6\ufffd\t=\ufffd\ufffdk◶\ufffd\ufffd\ufffd\ufffdЙ̷\u0016\ufffd\ufffdnQ\ufffd\u003c\ufffd:\u0007\ufffd\u001c\u0015\ufffde̚}d)L]\ufffdx\ufffd5G\u003c\ufffd\ufffdT\u0005\ufffd5I\ufffd\ufffd\ufffd\ufffd \ufffd\ufffd0?F\u0011\u0019\ufffd\ufffd\ufffd\ufffd\ufffd\u000f\ufffdFc8\ufffd\ufffd\t\ufffd(\ufffd\u0011\r\ufffdN\ufffd\u001c\u0015U(f\\U܊\ufffd\ufffdЋp\ufffd\ufffd\u001dֺ\u0019\ufffd\n\ufffdR\n.\ufffd:kK\ufffdz\ufffdTa\ufffd\ufffd\u0013l\ufffd\ufffd\u0007\ufffd\ufffd\u0011\u001b\ufffd~\ufffdh\ufffd\ufffd\u000bͪ\u001d\ufffd;\ufffd\ufffdT\ufffd\u003e\ufffd\ufffd\ufffd)9\u0011\ufffdG(̗w\ufffdk6}v\ufffd\ufffd\u003e\ufffd,\ufffd\ufffdQ\ufffd\ufffds\ufffd3\ufffdV\u0019\ufffd\ufffdX\ufffd\ufffd\ufffd\ufffd\ufffd`D\ufffd\u003c(]\ufffd\u0018ꆪ\ufffd$\ufffd\ufffd{\u0008\ufffd\ufffd~c\ufffdc\u0014_\ufffdk\ufffd\ufffd_\ufffd\ufffd\u0014q\u000e\ufffd\ufffd\ufffd\ufffd\ufffd1\u000e\u0003_\ufffd\u001f\ufffd6uP\ufffd\ufffd\ufffdR\ufffdW\ufffd3\ufffd\ufffd\\\ufffd*\ufffd\ufffdLE\ufffd{\ufffd\ufffd\u0026\ufffd\u0000\ufffd#~\u0016\ufffd\ufffd\ufffd\ufffdޤ\ufffd\ufffd\ufffd?\ufffdA\ufffd7K\ufffd\ufffd*0!ZkL\ufffd[\ufffd\ufffde\ufffdj\ufffd\ufffd)\ufffd\ufffd䦴\u000fÊ\ufffd\ufffd\ufffd\ufffdٟ\ufffd(\ufffdyL,\ufffd\u0026P\ufffdt$\u0017s\ufffd\ufffd\ufffdH\ufffd\ufffd5\u0002\ufffd\ufffd\ufffd\ufffd\u0015\ufffd\ufffd6NE^\ufffd/\ufffd\rYEi\ufffd۶a\\\u001e\ufffdA6\u00033\ufffd\ufffd8\rFo1s\ufffdgػzԫ\ufffd{уmre4\ufffd\"\ufffd\ufffd\ufffd9\ufffd\u0004p\ufffdr\u0016i\ufffdG\u0026\ufffd\u000b\\\u0011\ufffd\ufffd\ufffdY\ufffd\ufffd\ufffd\ufffd\ufffd\u000e\ufffd-\ufffdG\ufffd\ufffd\ufffd8\ufffdH\ufffdIDD\ufffd\ufffd:\ufffd\ufffd\ufffd'\ufffd\ufffde¡\u003e\ufffd\ufffd\ufffdn=\u001c7\ufffd`\ufffdDkx\ufffd=\ufffd\ufffdf+\ufffdo\ufffd\ufffd\u0005ن\ufffdĄzy{\ufffd~\ufffd\ufffd\ufffd.$\ufffdk\ufffd\ufffd\ufffd\ufffd\ufffdP\ufffd\ufffde\ufffd\ufffdKR\ufffdV\ufffd\ufffdlL\ufffd\ufffd\u0018\ufffd\ufffd\ufffdpu\ufffd{@\u0014\ufffd_\ufffd\u0004\u0018\ufffdwΉ̑\ufffd\ufffd\u0018\ufffd\ufffd\ufffd\ufffdCy\ufffd\ufffd\ufffdԩ\u0008\ufffd\ufffd\ufffd\u001c#6\ufffd\ufffd\ufffd\ufffdXUFΜ\ufffd\u001ar\u000c\u0004Hq\ufffd6\u00116XG\u0026]Rl6\u0002o\ufffdV\n*\\\ufffd\ufffd\ufffdw\ufffdL\ufffdg\ufffd\ufffd4\ufffd\ufffd{\ufffd\ufffd\ufffd+b\ufffdo\ufffd/M\ufffd\ufffd2\ufffd\ufffd\ufffd\ufffd\u001a{\ufffd7\ufffda}\ufffd\u0005,ᖇ\ufffd@y\ufffdE\ufffd\ufffd\ufffdC\ufffd\ufffd@\ufffdE{\u0003\ufffd\ufffd\ufffd˼p\ufffdΧJ\ufffd\ufffd\ufffd)\u0013\u0017\u0019GU\ufffd\ufffdh\ufffd\ufffd\ufffdB\ufffd\ufffdRR\ufffd\ufffd\ufffd'7\ufffd\ufffd\u0010\ufffd\u001e\ufffd+i\u0005\u001f\ufffd\u0012Y%\ufffdj\ufffd\ufffdDl\ufffdI\ufffd(\ufffd\ufffdK\u003e\ufffd\ufffdT.\ufffd/\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0017\ufffd\ufffdw\ufffd\ufffd2~\ufffd\ufffd\ufffd\ufffd\ufffd'\ufffdt\ufffdsU_?mt\ufffdݱ`I\u0026\ufffd\ufffd|əA\ufffd\ufffd?\ufffd\ufffd\ufffdH\ufffd\ufffd\u0013\u0018\ufffdD\ufffd\ufffdЏ\u001c\ufffd^\ufffd\ufffd\u001d\ufffdY[\ufffd0F\u003c\u0014\ufffd\ufffdN\ufffd\ufffd\ufffd˯\ufffd\ufffd\ufffd\u000e\ufffd3\ufffd\ufffd]Xcn\u001f\ufffdz\u000f\ufffd2\ufffdt.=ӓ\ufffd\ufffd\u000f\ufffd\ufffd\ufffdN\u0018y\ufffd\ufffdM\u0011\ufffd\ufffd79\u000f\ufffd^l5\ufffd\ufffd\ufffdpV˦XP\ufffd\u0012z8\ufffd\ufffd3\ufffd\ufffd\"\ufffd\ufffd\ufffd=\ufffdr`k\t,A\ufffd`WBX!\ufffd\ufffdm\ufffd`\ufffd\u001f\ufffd\u0019\u0012Y\ufffdMC\ufffd\u0000T\ufffd$\ufffd\ufffd\ufffd\n6x֘b\ufffd\ufffd\ufffds\ufffd['\u001d\ufffd\ufffd\u0018=FY\ufffd@V\ufffd\ufffd\ufffd\u001fO\ufffd\ufffd\ufffd\ufffd\ufffdRt\ufffd\ufffd \ufffd\ufffd\ufffdU'\ufffdґW\ufffd1\ufffdB\ufffd\ufffd\ufffd֗\ufffdM\u000eFqo\ufffd\ufffd\u003e\ufffdXE=\ufffd\ufffd\ufffd\ufffd~\ufffd0\ufffdF.辱\ufffd\ufffd|\u00020\ufffd\ufffd?\ufffd\ufffduƚ9\ufffdK\ufffd\ufffd;Pv\ufffd\ufffd\ufffd\u000ejkJw^H\ufffd\ufffdsZ\u0013\u0012P??\"-y\ufffd\ufffd\ufffd?t\tSo3:\ufffdD_\u001e\ufffd\ufffd?ļo\u001f\ufffd|y\ufffd\ufffd}\ufffd\ufffd:{\ufffd\u0015p{\ufffd\ufffdq\ufffd\ufffd\ufffd\ufffd#;\ufffdF\ufffd\ufffdT\ufffd}\ufffdvz\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd;\ufffdF\ufffd\u0019\ufffd\u0000j\ufffd\ufffd\ufffd\ufffd+\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2591\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:19 GMT\r\nSet-Cookie: AWSALB=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB; Expires=Thu, 14 Sep 2023 15:34:19 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB; Expires=Thu, 14 Sep 2023 15:34:19 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:25+05:30","url":"https://ginandjuice.shop/my-account","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB; AWSALBCORS=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB","Referer":"https://ginandjuice.shop/about","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/my-account","scheme":"https"},"raw":"GET /my-account HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB; AWSALBCORS=Prgzdf44LBH/gIvkpQ7RQidBUe8DBb1sOfSy2cOoObGCZj/Pw+JO24xtHjKhCruF8b6CtxRw/8xqmTUMB3Guew6HtEFfVT+oRIyi5OX8fbUB1fodnvla28WXfiAB\r\nReferer: https://ginandjuice.shop/about\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"0","Date":"Thu, 07 Sep 2023 15:34:26 GMT","Location":"/login","Set-Cookie":"AWSALB=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/, AWSALBCORS=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"raw":"HTTP/1.1 302 Found\r\nConnection: close\r\nContent-Encoding: gzip\r\nDate: Thu, 07 Sep 2023 15:34:26 GMT\r\nLocation: /login\r\nSet-Cookie: AWSALB=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\nContent-Length: 0\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:26+05:30","url":"https://ginandjuice.shop/login","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm; AWSALBCORS=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm","Referer":"https://ginandjuice.shop/about","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/login","scheme":"https"},"raw":"GET /login HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm; AWSALBCORS=YQrYtEDgBJg08T9WcAOq2QBpXgV1lXFcJkxdUrJJT3bwm6199fl2Pa96roWYv8FnW2sr+bIcQUEV+98gRuQOfXRbsr5zMpj/eW72rpGJOfeDtsUozRwI+Qhi1WCm\r\nReferer: https://ginandjuice.shop/about\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"1793","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:26 GMT","Set-Cookie":"AWSALB=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/, AWSALBCORS=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdY\ufffdn\ufffd6\u0014\ufffd\ufffd\ufffd`5\ufffdi\ufffd*\ufffd\ufffd^6\ufffd2\ufffd\ufffdm\ufffd\"M\ufffd\ufffdٚ\ufffd)(\ufffd\ufffd\ufffdR\ufffd\u0026Rv\ufffdH{\ufffd=\ufffd\u000eIY\ufffdmɒ{\u0001\ufffd\ufffdA\u0010\ufffd\ufffd\ufffd\u001f\u000f\u000fϕ\ufffd\ufffd{uq\ufffd\ufffd\ufffd\ufffd5JTʦ?L\ufffd\u0007\ufffd\ufffdIBpd\ufffd\ufffd!\ufffd\ufffd\u0013Jr2\ufffd\ufffd\ufffdHQ\ufffd!\ufffd\u001eÁf#\ufffd\u0017J\ufffd\ufffd\u0010\ufffdw\ufffdWC8\u0004\u0002\ufffd\t\ufffd\ufffd*\u0019\ufffd\t!\ufffd\u000fLC\u0000\ufffd\ufffd\u0002\ufffd\ufffd\ufffd\u0006H\ufffd\ufffd\ufffd\ufffdΜ\ufffdE\u0026r\ufffd\ufffdPpE\ufffd\ufffd\ufffd\u0005\ufffdT\ufffdGdNC\ufffd\ufffd\ufffd#TH\ufffd\ufffd !\ufffd\ufffd\ufffdυ\ufffd@\ufffdaN3\ufffdd\u001e\ufffdNC\ufffd[\t\u0003\u001c\ufffdC@\"Ld)\ufffd\u001f\ufffdJg:\ufffd\ufffd\ufffd\ufffd\u0010n$\ufffd=`T\ufffd\ufffd\ufffd\u0014\ufffdS\ufffd-\ufffdcKu\ufffd\ufffd1\ufffd\u000b\ufffd\ufffd\ufffd#\ufffd\ufffd\ufffd\ufffd\u000bUQ\ufffd\ufffd\ufffdLĔ#\u0017\ufffd\ufffd\ufffd\ufffd8\ufffd^\ufffd\ufffd\u0005(\u0008]%\"\ufffdx\ufffd\ufffd^\ufffd\ufffd\ufffd\ufffdI \ufffd\u0012\ufffd\ufffd\ufffdY\ufffd@\ufffd\ufffd\u001c\ufffd\ufffdw\ufffdW\ufffdШ=\u000b\t\u0015\u0015\u001c\ufffd\u000cK\ufffd;\ufffdP܈X\ufffd`fc\ufffdY\ufffdm\ufffd\ufffd\ufffd\ufffd\ufffdJ\u0004\ufffd\u0018E\ufffdр\ufffdX\u0011V\ufffdy\ufffd8|\ufffd\u001bE\u000b\u0012 \ufffd\ufffd\ufffd\u0010\ufffd]a\u001f\u001as\u0012\ufffd\ufffdȑ\"RQ\u001ek\ufffd\ufffd\u003c\ufffdً\ufffdBʨ*-I\u001f\u0005h\ufffd\ufffdU\ufffd\ufffd\ufffdp}\u0014m\ufffd\u000e\u0012\u003c\u0015`Up\ufffd$\ufffd6\ufffd#\ufffd8\ufffd\ufffd\ufffdn\ufffd|4\ufffd\ufffd\ufffd|}\ufffdhm6\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd.\ufffd\ufffdʛ\ufffdO\ufffd\u0016\u0017\ufffd\ufffd\ufffd\u0019z\ufffd\ufffd\ufffd\ufffd}\ufffd\ufffdkm8^\u001f\u003ey\ufffd\ufffd\ufffd\ufffd\ufffd#\ufffdD\ufffd\ufffd\ufffdl\ufffd\ufffd(8}\ufffd\ufffd\ufffd\r\ufffd\ufffde\ufffd)c\ufffd\ufffd\ufffd\u000f\u001eֻ2\ufffd\ufffd\ufffdp\u000fD\ufffd\u0006\ufffd\ufffd\u0005ڢ\u001d\ufffd\ufffd\ufffd-\ufffd'\ufffd\ufffd\ufffdP\ufffd\u0004\ufffdF\ufffd= %\ufffdJ\ufffd\ufffd\ufffd{`Ӡ\ufffd\u0016s\ufffd6\ufffd\u0005\u0018\ufffd\ufffd\ufffd\ufffd\ufffd\u0003k\ufffd/\ufffdF\u0007-\ufffdڼ-\ufffd\ufffd)\ufffd\u0002[\ufffd]N\ufffd\rc\u0007^\u000bL\u000b\ufffd4\ufffd\ufffde\"\u0016\ufffd\ufffd@\ufffd\ufffd\ufffdp\ufffd\ufffd\n\ufffd8\ufffd\ufffd#\ufffdY\ufffdq\ufffd65G\ufffd\ufffd\ufffd\r\ufffd466\ufffdV\u000e\ufffd\ufffd]\ufffd,\ufffd)\ufffdK;jq\ufffd-HF\ufffd\ufffd\u000c#^n\u001d\u0014JAP\ufffd\nu\u003c\ufffdL\u000cz\u0002\ufffd\ufffdET\ufffdJv*e\r\ufffd\u001b\ufffd\ufffd\ufffdK\u0017\u0018\ufffd^\ufffd\ufffd\ufffd\ufffdX8\u0010\ufffdr\ufffd\u0017ڏ\ufffd\ufffd˯$\ufffd\ufffd+\ufffd\u0017\ufffd\u0010\ufffd\ufffd\ufffd\ufffd76\"\u001c\ufffd\ufffd\ufffdʥ\ufffd\u0017\ufffd\ufffd*T$\ufffdՓ\ufffdn\ufffd\u0000yR\ufffd\ufffd\ufffd\u0004\u0002\ufffdrr\ufffdW\ufffd\ufffdc\ufffd\u0001\u0018K\ufffdC\ufffd\ufffd\ufffd\t\ufffd\u0013-,\ufffd\ufffdV\ufffd\u000c\ufffds\ufffd\ufffda\ufffd{\ufffd[\u000f\u001bv\ufffd\u003c8\ufffd\u0001\ufffd\ufffd\ufffd\u0012\u001b\ufffdA\ufffd\ufffdm\ufffd~W\ufffd\ufffd\ufffd7\u0012\ufffd\ufffdȇ\ufffd}\ufffd\ufffd\ufffd8\ufffd,k#\u0002zzF۫N\ufffd\ufffd*\u0015\u000e\ufffd^\ufffdԘ\ufffd\n}\ufffd\u001d|\ufffdF\u0004p\ufffd\ufffdcF`7\ufffdF\ufffdi\u001c\ufffdRў\ufffd\u003eL\ufffd\u0000\ufffd\ufffd\ufffd\ufffd4\ufffd:\u0013`G\nn!\ufffd\u0014\u0016\u001b\\\u00265CŢ{\u0012\ufffdK\ufffd\ufffdz8\ufffd\ufffd]g\ufffd\ufffdRx\ufffdꝚ\u000fj`7\ufffd\ufffd\ufffd\u0008\ufffd\u0013\u001bpk\ufffd\u000bEgUA\\\ufffd⮅\ufffd\ufffd\ufffd\ufffd\u001d\ufffd\ufffd\u0001\ufffdF\u001d,\ufffdu\ufffd\u001a\u0007\u0014\ufffdi%\ufffdяk\u0008\ufffd\ufffd%\"\ufffd//\ufffdރk\u00080\ufffd6\ufffdm\ufffdQ\ufffdA͘\ufffd\ufffd\u000b\ufffdC\ufffdo{\ufffd\ufffdF\u0011\u0001\u0017\ufffd\ufffda(\ufffd\ufffd\ufffd\ufffd\ufffd\u001508M\ufffd\u000fD\ufffd\ufffd8\u003e\ufffd\ufffd\\\ufffdQ\ufffd\ufffd\ufffd\u0014o.\ufffd\ufffd\ufffd\ufffd\ufffdϮ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u001ad0\ufffd\ufffdNR\ufffdO\ufffd`\ufffd\ufffd\ufffd\ufffd\ufffd]\ufffdi\ufffd\ufffd\n\ufffd\u000e\u001e\ufffd;\ufffd1\ufffd\u0018\u000eI\"X\ufffd;\ufffd%\ufffd\ufffdq\ufffd\ufffd\ufffdW'*j6\\(1\u0013a!{\ufffd\ufffd!\ufffdR|50Ȳ\u0008R\ufffd\ufffd\ufffd\ufffd\u00030\u0001;\ufffdˑ\ufffd\ufffdu\u0019P\ufffd\u0001\u000c\ufffd\u0026Cn\ufffd\ufffdL\u0008\ufffd\ufffd\ufffdE\u000eM]\ufffdl\ufffd\ufffd]\ufffde\ufffd\ufffdȌ\ufffdtT\ufffdQ\ufffdo\ufffd\tM\ufffd\ufffd\ufffdP\u0026\ufffd\ufffd\ufffd\u001c\ufffd\ufffd\u001c\ufffdT\ufffdv\u00153\ufffd\ufffdA\ufffd\r\ufffd\u001a\ufffd\u0002\ufffd\ufffdh\u0007D6}+\ufffd\u003et/\ufffd\u00109\ufffd\u00164\"(\u0014iZphV\ufffd\ufffd!\ufffd\ufffdc\u001e\ufffd[ӿ\ufffd0\u0007\u000f\u000f\ufffd#\ufffd꒻\ufffd\u0015\ufffd\ufffda'\ufffd\ufffdд\u0019 \ufffdu\u001fe\ufffd\u0001\u003e\ufffd\ufffdO+\u0004K\u0002\ufffdP0\u0006ucn\ufffd\u0004\ufffd5r*rr\ufffd\ufffd]\ufffd\ufffd\ufffd\ufffdq\ufffd\ufffd\u0026Q\u001f\ufffd\u001c\ufffd\ufffd[y\ufffd\ufffd$Ѫk\ufffd\ufffd\ufffd\\\ufffd\ufffdT\ufffd\ufffd\u000e\ufffd \u0017\ufffdU\ufffdp2!UE\ufffdC\ufffd2Y\ufffd\u0000\u003e#|\u0010\u0008\ufffd\ufffdz\ufffd\ufffd\ufffd梯\r\tG\u0011\ufffd\ufffd\ufffd|\ufffd;:\ufffd\ufffd_\u0018~)f\u001f\ufffd\ufffd\ufffd\ufffd\ufffdwrL\ufffd]\ufffda\ufffd6\u003e\u001e/\ufffd\ufffdiܷߚ\ufffd\ufffduT\ufffdѯ\ufffd\ufffd\u0019\ufffd\ufffd\ufffd^Qݖֵ\ufffd0\ufffd\ufffd2\ufffd.\ufffd\ufffd'\ufffdZJ3\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd!\ufffd]\ufffd.\ufffd)x\ufffdh\ufffd\ufffd\"\ufffd\u0018\ufffdWF\ufffd\u0007\ufffd\ufffd\\=Ԟ\ufffdw\ufffd\u001dbR\u003e\u0013\u0003d4\ufffd!E\u001e=\ufffd\t\ufffdt\ufffdt$(UByܝ9\u0007\ufffd\ufffd\ufffd\ufffdnx͛\ufffd\ufffd\ufffd\ufffdJ\ufffd8\ufffdZ\u001cgj\u0015\u00031HA\ufffd(x\u0004R\ufffd\ufffd\ufffd\ufffdn`\t]\ufffd֗P\u000b\rS\ufffd\u0017\u0003T\ufffd\ufffdg\ufffdȚn\u001aV\u0007\ufffd\ufffdD.D\ufffdOΆ\ufffd\u001aS\ufffdr\ufffd]\ufffd~k\ufffd=X\ufffd\ufffdq\ufffd\ufffd\u0012\ufffd?*\ufffd\ufffd^\ufffd^\ufffd\ufffd,\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0013(\ufffdQ@ \ufffd\u0011\u0013U4\ufffdp\ufffd\\?\ufffd{\u0008\ufffd繞u\ufffdA\ufffdUuփ\ufffd\ufffd\ufffd=\ufffd3\ufffd\ufffdR\ufffd\"/\u0017\ufffd\ufffd7\ufffd]\ufffd\ufffd\ufffd\u0001\ufffd\ufffd\ufffd\ufffd\ufffd\u001e\u001f\ufffd\ufffd% \\Y\u0004t\ufffd\ufffd\ufffd\u0001'ۯ\ufffd\ufffd8mu\ufffd\ufffd֠\ufffd\ufffdi-H\ufffd\ufffd\ufffd=ʒ\ufffd\ufffd\ufffddW\ufffd\ufffdX\u0026E\u00087z\ufffd\ufffd\ufffdҧ\ufffd\ufffdO\ufffd__\ufffd\ufffdO\ufffd\ufffd\ufffd\ufffd{\ufffd\ufffd\u0016a\ufffd\ufffd\ufffd\u0018v\u0014\ufffdַLmj\ufffd\ufffd\ufffd]\ufffdB2\u0012Q9\ufffd\u0001R\ufffd\ufffd\u001f\ufffd}9\ufffdo\u001b\u001d\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 1793\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:26 GMT\r\nSet-Cookie: AWSALB=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx; Expires=Thu, 14 Sep 2023 15:34:26 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:30+05:30","url":"https://ginandjuice.shop/login","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Cache-Control":"max-age=0","Connection":"close","Content-Length":"53","Content-Type":"application/x-www-form-urlencoded","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx; AWSALBCORS=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx","Origin":"https://ginandjuice.shop","Referer":"https://ginandjuice.shop/login","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"POST","path":"/login","scheme":"https"},"body":"csrf=GhyXet8wACfYUo1chNYuFPbOCI36SVSj\u0026username=carlos","raw":"POST /login HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nCache-Control: max-age=0\r\nConnection: close\r\nContent-Length: 53\r\nContent-Type: application/x-www-form-urlencoded\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx; AWSALBCORS=bqZoSugibrUn2bfJXYlvAufNHb6V5/dDhGQEYNEgWk9i8ARnQb/nXdgJ2kUC/ruOt3kfOm5GioxnCSPhWXHQq7eqXcg+qfYT1aWoQTJiY/4PmV/OUGHZlL2oJDKx\r\nOrigin: https://ginandjuice.shop\r\nReferer: https://ginandjuice.shop/login\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"1877","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:30 GMT","Set-Cookie":"AWSALB=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI; Expires=Thu, 14 Sep 2023 15:34:30 GMT; Path=/, AWSALBCORS=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI; Expires=Thu, 14 Sep 2023 15:34:30 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdY\ufffdn\ufffd6\u0014\ufffdߧ\ufffd4\ufffdN\ufffdʪ\ufffdl\ufffd\u0010\ufffd\ufffdzK/i\u00134-\ufffd\ufffdOA\ufffd\ufffdŔ\"U\ufffd\ufffd\ufffdG\ufffdk\ufffd\ufffdvHʊlK\ufffd\ufffd\u000b\ufffd\u001f5\ufffd\ufffd\u003c\u003c\ufffdxxx\ufffd\ufffd\ufffd\ufffd'\ufffd\ufffd\ufffd\ufffd}\ufffd\u0014E:\ufffd\ufffd{#\ufffd\u0007\ufffdg\u0014QL\ufffdW;\ufffdL|FQJg\ufffd \ufffdJfiHU\ufffd\ufffd\ufffd4\u0008\ufffd\nT\ufffd\ufffdk\ufffd\ufffd\u0012\ufffd@@)\ufffdc\ufffdsNUD\ufffdn\u00033\u0010\u0000\ufffd\ufffd\u0001\u0026\ufffd\ufffd\u0001b\ufffd1\u00128\ufffdco\ufffd\ufffd2\ufffd\ufffd\ufffdP(\ufffd\ufffdB\ufffd\ufffd%#:\u001a\u0013\ufffd`!\ufffd\ufffd\ufffd\u0001\ufffd\u0014M}\ufffd\u0010v\ufffdt,\ufffdWASa\ufffd\u0012\ufffdT\u001a\ufffd\ufffd\ufffd@7\n\u00068\ufffd}@\ufffd\\\u00261\ufffd\ufffdo\ufffd7\u0019\u0005nEw\u0008\ufffd\ufffdx\u000f\u0018\ufffd'p2Moup\ufffd\u0017\ufffdQ\ufffd:t,\ufffd\u0019\ufffd駁\ufffd\ufffd4\ufffdj\ufffd9\ufffd\\\ufffd9\u0013\ufffdG\ufffd\ufffd\ufffd\u003e\ufffd\ufffd3\ufffd2\u0003\u0005\ufffd\ufffdH\u0026\ufffd\ufffd\ufffd\ufffd\ufffd\u000f\ufffd\ufffd~4\ufffd$Gb\ufffd\ufffd$\ufffd \u0012\ufffd@\ufffd\ufffd\ufffd\ufffd\ufffdW4\ufffd\ufffdBCͤ@!\ufffdJ\ufffd=g(\u003e\ufffdN\u003c\ufffd\ufffdX`\u0017%\ufffd4\ufffdy\u00171\ufffd\ufffd\u0007#B9\ufffd\ufffd\u0014k\ufffds\ufffdȸ\ufffd\ufffdp\ufffdhI\ufffd\u0008d\ufffd,\ufffdvW؇\ufffd\u0005%h\u0026S\ufffd\ufffd\ufffdL\ufffd\r\ufffd}1U\ufffd\ufffdj!\ufffdL\ufffd\ufffdd\ufffd\u00024կ\u0015`\ufffd\u0012\\\u001eŘ\ufffd\ufffd\ufffd\ufffd%X\u0015\ufffd\u0026M\ufffd\ufffd\t\"\ufffd\ufffdO\ufffdn\u0007h\ufffd\u0006\ufffd\ufffd\\\ufffd\ufffd\u000e\ufffdfc\ufffd\ufffd\ufffd\u001e\ufffd\ufffd\ufffd4PEu\ufffdxmq\ufffd\ufffd=6C\u0007խ\ufffd\ufffdGսֆG\ufffd\ufffd\ufffdC\ufffde\ufffd\ufffd1\ufffdZN\u000fz\u0017G\u001f\u0007\ufffd\ufffd\ufffdy\u0018?c\ufffd\ufffdmB\ufffd9\u000f\ufffd\ufffdq\ufffd\ufffdܕSld\ufffd{\ufffd\ufffdV\ufffd\u0006gh\ufffd6\ufffd\ufffd\u001d\ufffdЎ\ufffd\ufffdU\ufffdQ\u000ev\ufffd\ufffd{@Z\"\u001dQ{u\ufffd\ufffdM\ufffd\ufffdk\ufffd%ذ\u0017`tV\ufffd\ufffd\u0016{\ufffdl\u001fٍz5\ufffdƼ\u001d\ufffd\ufffd)\ufffd\u0001[\ufffd]\ufffd\ufffd\u000bc\ufffd\ufffd\u0006\ufffd\u0006N\ufffd\ufffd\ufffds9\ufffd\ufffd\ufffd@o\ufffd\rp\ufffd\ufffd\u001d\ufffduX\ufffdE\u003e\ufffdF\ufffd\ufffdmJ\ufffd\ufffd\ufffdL\u001bx\ufffd\ufffdڄ_8\ufffd1v\ufffd\ufffd\ufffd\ufffd8\ufffdݨ\ufffdq\ufffd 9kg\ufffd\ufffdx\ufffd\ufffd4\ufffd\u001a\ufffd\ufffdS\ufffd\u0017\ufffdeb\ufffd\u0013XF*I\u0016jը\ufffd5\ufffd\ufffd\ufffd\ufffd\ufffd.\ufffdԊ\ufffd\u0008~\ufffd\ufffd\ufffd\ufffdS\ufffdiori\ufffdH\ufffd4\ufffdN\ufffd\ufffd\ufffd\t\ufffd\u000fJA~\ufffd\u0011\ufffd0\ufffd\ufffd\ufffd\u003e\ufffd\ufffd\ufffd\tV\ufffd\ufffd\ufffdTO\ufffd\ufffd\u0005\u0003\ufffdI\ufffd\ufffdOF\u0010\ufffdV\ufffdwy\u0015L}n\ufffd\u0000Ɗ\ufffd\u000fܿV\ufffdM\ufffd\ufffd\ufffd\u0026\ufffd\u001a\ufffd.z.\ufffdԍq\ufffd\ufffdo\ufffda\ufffd.\ufffd\u0007\ufffd:\u00001\ufffdYb\ufffd\ufffd\ufffd|\ufffdدsT|\ufffdA\ufffd\ufffd\u001byw\ufffd\ufffd\ufffd\ufffd\u0010\ufffd\ufffdemD\ufffd\ufffd\ufffd\u0018{5)pP\ufffd\ufffdk\ufffdZӽC\ufffd\ufffdn;\u001f\ufffd\u0012\u0001|-\ufffdsNa7\ufffdFM\ufffd|nJEw\ufffd\ufffd0\ufffd\u0003\ufffd\ufffd[\ufffd\ufffd(hL\ufffd\r)\ufffd\ufffd\\SXlp\ufffd\ufffd\u000c\u0015\ufffd\ufffdI\ufffd)\ufffd[\ufffd\ufffd\u0018\ufffdv\ufffd\ufffd\ufffdJ\ufffd\ufffdT\ufffd\ufffd|P\u0003\ufffd\t\\oC\ufffd\u001c\ufffd\ufffd[j\\j6+\n\ufffd\"\u00167-\u000c\ufffdt\u0013\ufffd\ufffdu\u000f\ufffd6h`\ufffd\ufffd\ufffd\ufffd8\ufffd\u0010\ufffd\u000bɬ~|K\ufffdN.\ufffdd|uy\ufffd\u000e\ufffd\ufffd@\ufffd1\ufffd\ufffdo\u000b\ufffd\ufffd\u0004jƔ~\ufffdX\nu\ufffd\ufffd\ufffd\"F\u0008\u0005\u0017r\ufffda\ufffdҙ\ufffd\u0016\ufffdg0\ufffd8%ǯ\u0014;_\u003c[\ufffd\ufffd\ufffd\ufffd,\u000c\ufffd/\ufffd\ufffd\ufffd\ufffd\ufffd/NO\ufffd̻\ufffd\ufffd\ufffdi\u0010\ufffdގ\u001f\ufffd\ufffd\ufffd\ufffdF\ufffd\u0013Sῇ\ufffd\ufffdl\ufffdmH\ufffd\u0004\ufffd\ufffdRV\ufffd\ufffd0@+\u0011WĶ\ufffd7\ufffd\ufffd\ufffd\ufffd\u0002\ufffdh\ufffd\te}\u000f\u001c\ufffdK\ufffd;k]Hd\ufffd\ufffd\ufffdtN\ufffdSN\ufffd\ufffdG\ufffd\u000br\ufffd[\u0013\ufffdwط\ufffd\u0004\ufffd\u0015}7\ufffdv;Z\u003c\ufffd\ufffd\ufffd\ufffd\u0015\ufffd\ufffdR\ufffdd\u0014L'(\ufffdLo5l\ufffd\ufffd\ufffd\u0000v\ufffd\ufffd\nv\ufffdv\ufffd\ufffd^\\FR\ufffd\ufffdL\ufffd\u0019hD\ufffdl\ufffd\u0012Va\ufffd\ufffd\ufffd\"\ufffdl\u001a3=A.ۂ\u001a\ufffd\ufffd\ufffd0e\ufffd\ufffd\ufffd=\u001bݫ[\ufffd\ufffd\ufffdJ@\ufffdI\t\ufffd\ufffd\ufffd)\ufffd\ufffd\ufffd\ufffdg#Z\ufffd\u0005M\ufffdc\u001b\ufffdә\ufffdY;Z\ufffd\ufffd5\ufffdm\ufffdw8\ufffd(\u001aN\ufffdPh\ufffdQ̔{\u000c\ufffd\u001c\ufffd\u0008tm\ufffdlJ\ufffd\ufffdK\ufffdQ\ufffd\u001d\u0010\ufffd䥄\ufffd0\ufffd\u0026\ufffd4'KF(\ne\u001cg\ufffd\ufffd\u001c\ufffd\u00192\ufffd$X\u0010tc_GfX@\ufffd\u000c\ufffd\u0003\ufffd\ufffd@oC\ufffd)\ufffd\ufffd\ufffd\ufffdRAKl\ufffd86]\ufffd\ufffd\u0006\ufffd`\ufffd\u003c\\Q\ufffd(\ufffdB\ufffd9T\ufffd\ufffd\r\ufffd06ȱLi\ufffdw]W\ufffd\ufffd{Ro\ufffdŧ\u003c\ufffd\u001b\ufffd\ufffdoT\ufffd\ufffd\ufffd\ufffdV\ufffd\ufffd\ufffdf\ufffdֻS}\u001a{\ufffd@\ufffd\ufffd\u0017\ufffd\ufffdK\ufffd\ufffd\u0005\ufffd\u000cȫR\ufffd\u000e\ufffd+\ufffd3\ufffd\ufffdǝ\ufffd\ufffd\ufffdk.\ufffdԒ0!pڶ\ufffd`\ufffd\ufffd|\ufffds\ufffd\ufffd\ufffd\u0017\ufffd$y{\ufffd\ufffd\ufffd\u0026\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd'o\ufffd\ufffd[s\ufffd\ufffdJ\ufffd:\ufffd\ufffdJ3]\u003c\ufffd\ufffd+\ufffd\ufffd2\ufffd\ufffd\u0017\u0006\ufffdn\u0002\ufffd\ufffdQڄ\\+\u0018\ufffd\ufffdf\ufffdn9a\u00089\ufffd\ufffd\ufffdsJ\u0011r\u0016~.ȏ-\ufffd\u0013+\ufffd\u0001x\ufffdЇ\ufffd\ufffd\ufffdN\ufffdCL\u0026f\ufffd\ufffd\ufffdv5\u0014 Ç\ufffd\ufffd\ufffdΐ\ufffd\u0004\ufffd\ufffd\ufffd\ufffd7\ufffd%\ufffdv7\ufffdx\ufffd\ufffd\":*\ufffd\u0026\ufffd\ufffdӣ\ufffdp\ufffd\ufffdS\u000c\ufffd \r\ufffd\"\u0013\ufffdâ\ufffd=`\ufffd\u001bXA\u0017\ufffd\ufffd%\ufffdB\ufffd\ufffd\ufffd\ufffd\u0000\ufffdm\ufffd\u00157\ufffd\ufffd\ufffd\ufffd\ufffd\u0001(\ufffdć\ufffd\ufffd\ufffd\ufffd\ufffdYe\n\u0015n\ufffd+\ufffdo\ufffd\ufffd\u0007k2\ufffd+Ix\u000e\ufffd5S\ufffdmo\ufffd\u0006\ufffd[\ufffdy\ufffdN\ufffd\ufffd\ufffdchoДB4\ufffd6\ufffd\u0018\ufffd\ufffd\ufffddN\ufffdݱv\u000f\ufffd\ufffd\u003c7p\ufffd\ufffd\ufffd)\ufffd\ufffdzpu\ufffd\u0015Em\u0026X]j\ufffdߡ\ufffd\ufffd\ufffd\ufffdo\ufffd\ufffd\ufffdo\u0000\u0026\ufffd\ufffd\ufffd\ufffd\u000f\ufffdG\ufffd\n\u0010\ufffd\u001d\u0002\ufffdФ\ufffd\ufffdd\ufffd\ufffdP\r\ufffd-N\ufffd\ufffdx5\ufffd9\ufffd\u0005\t\ufffd~\ufffdGY\ufffd\ufffd|\ufffd\ufffdUeT\ufffd)\u0019^\ufffd\ufffdW\ufffd)\ufffd\ufffd\u0003\ufffd\ufffd\ufffd\ufffd\ufffd\u0003luv\ufffd\u0017\ufffd\ufffd\u0016a\ufffdIcc\ufffdP\ufffd:߲\ufffd\ufffd\ufffd\ufffd\ufffdvU\n\ufffdH\ufffd|r\u000fR\ufffd\ufffd\u000f\ufffdZ\ufffd\ufffday\u001e\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 1877\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:30 GMT\r\nSet-Cookie: AWSALB=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI; Expires=Thu, 14 Sep 2023 15:34:30 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI; Expires=Thu, 14 Sep 2023 15:34:30 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:33+05:30","url":"https://ginandjuice.shop/login","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Cache-Control":"max-age=0","Connection":"close","Content-Length":"70","Content-Type":"application/x-www-form-urlencoded","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI; AWSALBCORS=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI","Origin":"https://ginandjuice.shop","Referer":"https://ginandjuice.shop/login","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"POST","path":"/login","scheme":"https"},"body":"csrf=gW8d4KsiGvFwrnUHucc4OumZ28lv879y\u0026username=carlos\u0026password=hunter2","raw":"POST /login HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nCache-Control: max-age=0\r\nConnection: close\r\nContent-Length: 70\r\nContent-Type: application/x-www-form-urlencoded\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=rXVoplR77zJ2sMgzZWa5Cp5X2y0YMzSK; AWSALB=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI; AWSALBCORS=f3uSeSLqZLjyLkgMubDnyLSLN4l5RHxJl2qNJIirhEpxbJNK9Q153T7UIWBXqoLUqADaTkYpLyY+e0ZITkQH2RbSlO2SL8pWPSA9bmVjvoTc37kvVwsUU6sGvbkI\r\nOrigin: https://ginandjuice.shop\r\nReferer: https://ginandjuice.shop/login\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"0","Date":"Thu, 07 Sep 2023 15:34:33 GMT","Location":"/my-account","Set-Cookie":"AWSALB=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; Expires=Thu, 14 Sep 2023 15:34:33 GMT; Path=/, AWSALBCORS=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; Expires=Thu, 14 Sep 2023 15:34:33 GMT; Path=/; SameSite=None; Secure, session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; Secure; HttpOnly; SameSite=None","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"raw":"HTTP/1.1 302 Found\r\nConnection: close\r\nContent-Length: 0\r\nContent-Encoding: gzip\r\nDate: Thu, 07 Sep 2023 15:34:33 GMT\r\nLocation: /my-account\r\nSet-Cookie: AWSALB=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; Expires=Thu, 14 Sep 2023 15:34:33 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; Expires=Thu, 14 Sep 2023 15:34:33 GMT; Path=/; SameSite=None; Secure\r\nSet-Cookie: session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; Secure; HttpOnly; SameSite=None\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:33+05:30","url":"https://ginandjuice.shop/my-account","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Cache-Control":"max-age=0","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; AWSALB=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; AWSALBCORS=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2","Referer":"https://ginandjuice.shop/login","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/my-account","scheme":"https"},"raw":"GET /my-account HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nCache-Control: max-age=0\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; AWSALB=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; AWSALBCORS=A8FP7QaUyTZcc1eqKIrwbXu1bU7eejb169j6dtYkZIoq+xNxSgeFjvTG3fo5IxkRKmFnCjcicOqFaNkotzDAeVhz7bj4YTjbFF9pI+euPCOy8scUu1Pu53wub9sf; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2\r\nReferer: https://ginandjuice.shop/login\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Cache-Control":"no-cache","Content-Encoding":"gzip","Content-Length":"2092","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:34 GMT","Set-Cookie":"AWSALB=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta; Expires=Thu, 14 Sep 2023 15:34:34 GMT; Path=/, AWSALBCORS=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta; Expires=Thu, 14 Sep 2023 15:34:34 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffd[\ufffdr\ufffd6\u0012\ufffdާ@ywq2\u0013\ufffd\ufffdc[\ufffdD\ufffdL\ufffd\ufffdɤn\ufffd\u0019g\ufffdi\ufffdd \u0010\u0012a\ufffd\u0000\ufffd\u0000%\ufffd\u003e\ufffdk\ufffd#\ufffd5\ufffdQ\ufffdIn\u0001P2%\ufffd\u0012\u0019\ufffdN?ȓ\ufffdE`\ufffd\ufffdb\ufffd\ufffd\ufffdB\\\ufffd\ufffd\ufffd\ufffdëO\ufffd}|\ufffd\"\u001d\ufffd\ufffd7#\ufffd\u000b\ufffd\ufffd(\ufffd8t\u001f\ufffd#g\ufffd\u0006E)\ufffd\ufffd\ufffd\ufffd*\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0011\ufffdi@\ufffd\n\u0014\ufffd\ufffdg\ufffd\ufffd6t\ufffd\u0001\ufffd\ufffd\ufffd\ufffd\ufffd9U\u0011\ufffd\ufffd\u0010\ufffd\ufffd\u0000@u\u000501\ufffd\u000f\u0010S\ufffd\ufffd\ufffd1\u001d{\u000bF\ufffd\ufffdL\ufffd\ufffd\ufffd\u0014\ufffd\n=\ufffd\ufffd,\ufffd\ufffd8\ufffd\u000bF\ufffdo\u001f\ufffd\ufffdL\ufffd\ufffd\u0007\ra\u0006N\ufffdBz%4ER\ufffdh\ufffdR2\ufffdJ\n]+x\ufffdDw\u0000\ufffdr\ufffd\ufffd\u0000V\ufffdd\u0014\ufffd\u0011\ufffd!\ufffdP\ufffd-`t\ufffd\ufffd\ufffd4\ufffd\ufffd\ufffd5^`\ufffd\ufffdU\ufffdc1\ufffd8N?\ufffd\ufffd\ufffd?\ufffdC\ufffdLs:\ufffd9G\ufffd\u0010\ufffd\t\ufffd|\ufffd\ufffd\t\ufffd\u0004\ufffd\ufffdK\ufffd.\u0003+\ufffd\ufffdH\u0026\ufffd\ufffd\t\ufffd\ufffd\u000f\ufffd\u001c`4\ufffda\ufffd\ufffd\ufffd\ufffdIR\ufffd\r\ufffd\u0002\ufffdp\ufffd\ufffd\ufffd\ufffddV\ufffd J4\ufffd\u0002\u0011\ufffd\ufffd\u001a{\ufffd[\ufffd\ufffd:\u001d\ufffdgk\ufffd\u001d\ufffd춙\ufffdO\u0011S\u0008\ufffda\u0014RΦ4Ś\ufffd\u001c-2.\ufffd3l+Z\ufffd)\u0002\u001d9#\ufffd\ufffd\n!\ufffd\ufffd\u0014i\ufffd4\u0013s#\ufffdDLU\ufffdr5\ufffdq\ufffds\ufffdd\ufffd\u0002m\ufffdS\ufffd\ufffdH%x\ufffd\u0014\ufffd\ufffd\u001e\ufffd\"\ufffd\ufffdZ\ufffd\ufffd45\ufffd'B\ufffd\ufffd|\ufffd|\ufffdCc\ufffd[w\ufffd\ufffdfo\ufffd7\ufffd\ufffdr\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdU\ufffd\ufffdO7\u0006g\ufffd\ufffdc3\ufffd\ufffd\u003c\ufffd\ufffd'\ufffd\u003c\ufffd\ufffd\ufffd`\ufffd\ufffd\ufffd\u0019Ⲱ\ufffd\u0018a-\ufffdOO.\u0007\ufffd\ufffd\ufffdo\ufffd8\ufffdd\ufffd\ufffd\ufffd$|\ufffd9Y\ufffd\ufffd'\ufffdֳr\ufffd\ufffdΰ\u000fT\ufffd\u0012\\\ufffd%\ufffdi\ufffdW\ufffd\r*\ufffdN\ufffd\ufffd\ufffdL\ufffd\u001c\ufffd\u001b\u0015\ufffd\ufffd\ufffdD:\ufffdv\ufffd\ufffd\u0005\ufffd\u0006\ufffdW\ufffdK\ufffd\ufffd/ \ufffd\ufffdn\ufffd/\ufffd8\ufffd\ufffd\ufffdNtR\u0001k\ufffdۉ\u001ab\ufffd\u000cĪ\ufffdr\ufffd\u001d\ufffd\ufffd\u0004\u00150\u0015p\ufffd\u0012\ufffd\ufffd\ufffd\\B\ufffdB{\rl\ufffdk:\ufffd\ufffdl\ufffd\ufffd\u0007\ufffd\ufffdc\u0004\ufffd\ufffdf-\ufffd\ufffd\ufffdk\ufffd,\ufffd[\ufffd\ufffd\ufffd\ufffd5ήP\ufffd\ufffd\u0018\ufffd\ufffd{\ufffd\u0008\ufffd\u001dH\ufffd\u000e\u000bYA\ufffd\ufffdz\ufffdi\r\ufffd\ufffd\u000c\ufffd\u0005\ufffd\ufffd\u0018\ufffd\u0004\ufffd\ufffd\ufffd0#Z\ufffd\u001ae\u0003.h2\ufffd\ufffd\ufffd\ufffdZվ\ufffd\ufffd\ufffdRj\ufffd\ufffd̴7\ufffd`\ufffdH\ufffd4 \ufffdFA\ufffd\ufffd\ufffdB\u0010\ufffdR\ufffd\ufffd\u0013\u0015ǜ\ufffd`.80L\ufffd\ufffdi\ufffdÑg\ufffd\ufffdh\u001a\ufffdm\u0015\ufffd~!\r'\ufffdZ\ufffd'#`\ufffdU\ufffd\ufffdI\u000b~?7\ufffd\u0000p%\ufffd\u0001鿕g2G/\u000c6\u0007\ufffd\ufffd9\u0008F\"Jn|\ufffdR©\u0005+7l\ufffd5\ufffd\ufffdb\u0007\ufffd\t\ufffd\ufffd쮅\ufffd\u003c\ufffdP\ufffdq\ufffdK9G𡱺\u0016\ufffdQT\u003c\ufffd\ufffd坿K\ufffd\ufffd$\ufffd\u000f\ufffdNs\ufffd/\u0008\u0008\ufffd\ufffd\ufffdG\ufffd\ufffd50=\ufffd\ufffd\ufffd\ufffd\ufffd+N؆q`\ufffd:\ufffd]\ufffd\ufffdw\ufffd\ufffdK.\u0011\ufffd\ufffd!\ufffdm\ufffd\ufffd\ufffd֔A\ufffd\ufffd\ufffdլ\u0017S\ufffd\u0000\ufffdݗ\ufffdFA\ufffd\ufffdZs\ufffdW4W\ufffd+[R\ufffdćD\ufffd\ufffdw\ufffd~\ufffd7!%Xg\u0006Ui\ufffd]\u001a\ufffd\ufffd\ufffd\u000c]\u0026\ufffd\ufffd5\ufffd\u003crd\ufffd6\ufffd\ufffdlV$\ufffd\u0005\ufffd\ufffd\r\u000c\\w\u001dl\ufffd\ufffd\ufffdw\ufffd\u0018\ufffd\ufffd\ufffd\ufffd\u0007\ufffd\u001c+\ufffd-n|{\ufffdg\ufffd\u002625G\u0011\ufffd#̹x\ufffd\ufffd)\ufffdǍc\ufffd\ufffdMN,\u0016Ϸ\u0006\ufffd\ufffdY\ufffd\ufffd\ufffdC\ufffd\ufffd\ufffd qy\ufffd*\u001c\ufffdG\u0015$Y\ufffdp\ufffd9º\ufffd\ufffdy\ufffdIw\ufffd\u00153\ufffd`\ufffd\u001d\u001c\r \ufffd63\ufffd\ufffdX\ufffd\ufffd!\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd洐$\u0012p\ufffd\ufffd\ufffd\ufffd\ufffdN\ufffd;\n\ufffd\rav\ufffd\u000f\ufffd\ufffd\ufffdx\ufffd\u0014a\ufffda\ufffd\ufffd\ufffd\u0019\ufffd\ufffd\ufffd\ufffdn\ufffd\ufffdt8\ufffd\ufffd]\u001c\ufffd\ufffd\ufffdp\ufffdD\u0017Ao\u0018\ufffd\ufffd\ufffd\ufffd\u0017!\ufffd\ufffdQ\ufffdM\ufffd\ufffdnqJc\ufffd\ufffdY\ufffd\ufffd3\ufffd\ufffd\ufffd%@A\ufffd\ufffdJ\u000c\ufffdLHs\ufffd\u003c\ufffd\ufffdۘ\ufffd\ufffd\ufffd\ufffd\ufffdY\ufffdDlg\ufffd[٦\ufffdM\u001a\u001a\ufffd\ufffd\ufffdMD\ufffd\u0026o\ufffd=\u0016]\ufffd\ufffd\ufffd^\ufffd\ufffd\u0014\u0013 \ufffd\ufffd\ufffd\ufffdE\ufffdsz\ufffd\ufffd\ufffd\ufffd?|\u0000\ufffd\ufffd^\u001c\ufffd\ufffd${\ufffd\ufffdV\u000bzD\ufffd\ufffdu\u001f\ufffd/~L3\ufffd\ufffd\u0007\ufffd/ǹ\ufffd?]\ufffd\ufffdw\ufffd/\ufffd:]\ufffd\u001b\u001d\ufffdI\u0017\ufffdZ\ufffd\u001f\ufffd\ufffd${\ufffd\ufffdV\u000bzD\ufffd\ufffdx4\ufffd\ufffd8f\ufffd\ufffd\ufffd\u000fz%ɍ\ufffdT\ufffd\ufffd\ufffd\ufffd\u0007`\ufffd\ufffd\u0017\ufffd\ufffd\ufffd\ufffdg\ufffd\ufffd\ufffd\u00030G\ufffd\ufffd\ufffd\u001c%\ufffd#s\ufffdZ\ufffd\ufffd^R\u001e\ufffd\ufffd\ufffd\ufffd\ufffd\u000fN\u001f\ufffd.\ufffd/\ufffdtQ\ufffd=\ufffdEmw\ufffd\u001b\ufffd\u0003\ufffd\ufffd}\ufffdm\ufffdKƚI\ufffd\ufffdZ\ufffd\u0014'I\ufffd\ufffd\ufffd[\ufffd\ufffd\ufffd\u0001u\ufffd3\ufffd\"s:3\ufffd8\ufffd\ufffdh\ufffd\u001dClA\ufffd\u001e[\ufffd\ufffd\ufffd\ufffd=\ufffd]A1S\ufffd$\u0005s\ufffd#\ufffdMMi˔B\ufffd.\ufffd|\ufffd{ \ufffd\ufffd;\ufffd\u00042\ufffd\u000eK\ufffd\ufffdp\ufffdB\ufffd\ufffd\ufffd\ufffdL0\ufffd#9Cs\ufffd\ufffd\"Dז\ufffdfX`͈zn\ufffdY\ufffd-\ufffd\ufffd\u0002\ufffd@\ufffd.\u0015\ufffd\u000e\ufffdcS+a\ufffd\u00019\ufffd15T\u0014C\ufffd\ufffd\u001c\ufffd9\ufffdS\ufffdگ\ufffd\ufffd\ufffd \ufffd2\ufffd\ufffd\ufffd\n\ufffdM\ufffdߕ6\ufffdl\u0016\u001f\ufffd\u0017\ufffd^.;\ufffdꤢ\ufffd\ufffd\ufffdֶhh5ֻ3}\u001a{\ufffd\ufffd\ufffd\u001fS\u001dI\u0010J\ufffd\ufffdE\u0013\ufffd\u003ePzsu\u0007p\ufffdՙH2\rf\ufffdg\ufffd \ufffd\\m\u0015\ufffdMJi\u000b\ufffd\ufffdDŽcB#\ufffdCS\ufffd\ufffd\ufffd6\ufffd0\ufffd\ufffd\u001e\n\ufffdJx/baH\ufffdW\ufffd\ufffd\u0011\ufffd\ufffd\u003c\ufffd\ufffd\u003c\ufffd\u0007\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdw\ufffd\ufffdkF\ufffdO˫\ufffdf\ufffd\ufffd\ufffd\ufffdL\ufffd\ufffd\ufffdp\ufffd\ufffd\ufffd\ufffd|\ufffd5\ufffd\ufffdKM;-\ufffd$fzr\ufffd\ufffd\u000c\ufffdZ\ufffd{_\ufffd\ufffd灐\u0019[\ufffd\r#2K\ufffd\ufffd]K\ufffdW'Ÿ\ufffd\ufffd\u003e\ufffdB¥\ufffd\ufffdj\ufffdR\u0010\ufffd\ufffdM\ufffd\ufffd\ufffdb\ufffd`Uz\n\ufffd(\ufffd3\u0013\ufffd\ufffdV\ufffdG\ufffdV\ufffdFo\ufffd\ufffd\ufffd\u0003\ufffdt\ufffd\u000c\u0013\ufffd:bb^\ufffd\ufffd\ufffd\ufffd\ufffdI\ufffd\ufffdZo\ufffd\n\ufffdbo\ufffd\ufffd\u0014\ufffd\ufffd\u000eǛ8\ufffd\u0000\u0007i\ufffd\ufffdL\ufffd\ufffd\ufffd \u000b[\ufffd\ufffd\n\ufffd\ufffd]o\ufffdZi\ufffd\ufffd\ufffd\u0018hu\ufffd\ufffd\ufffdlئ\ufffdu\u0000\n\ufffd\ufffd\u0003\ufffd\ufffdx[6+u\ufffd\"\ufffd\ufffd\ufffd\ufffd\ufffdL-D\ufffd\ufffdwI\ufffds\ufffdM!\ufffd\ufffd\ufffdT\ufffdي5S@\ufffd\ufffd\ufffd\ufffdW8\ufffdhJ\ufffdͨe\u0015\ufffdf%lV\ufffd\ufffdk[(u\ufffd\u0004w\ufffdz\ufffd\ufffd\ufffdN=غ\ufffdͣC.X\u001ejJo\ufffdҾy\ufffd\u0015m\ufffd\ufffdo\u0000\u0026\ufffd\ufffd\u0003\ufffdd\u0014}\u0004\ufffd+\ufffd\ufffd.u\ufffdi\ufffd\ufffdv\ufffd\ufffdkV[\ufffd\ufffd6\ufffd\ufffdM\ufffd\ufffd\u0013\u0012X\ufffd\ufffdEZ\ufffd~] \ufffd/\ufffd(\rS\ufffd\ufffd\ufffd^\u001e\ufffd\ufffd:d\ufffdc\u0019\ufffd\ufffdkw,\u0003,\ufffd\ufffd/\ufffd\ufffd\ufffd\"lU\ufffdl=\ufffd$\ufffd.\ufffdln\ufffd\ufffd\ufffd`7+\ufffd\ufffdH\ufffd\ufffd\ufffd\u001b8\u0012\ufffd\u001f;\ufffd\u001fq\u0007%\ufffd\u00041\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2092\r\nCache-Control: no-cache\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:34 GMT\r\nSet-Cookie: AWSALB=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta; Expires=Thu, 14 Sep 2023 15:34:34 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta; Expires=Thu, 14 Sep 2023 15:34:34 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:39+05:30","url":"https://ginandjuice.shop/catalog/cart","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; AWSALB=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta; AWSALBCORS=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta","Referer":"https://ginandjuice.shop/my-account","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/catalog/cart","scheme":"https"},"raw":"GET /catalog/cart HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; AWSALB=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta; AWSALBCORS=Yj6jGTtNRQBhM6lgLDvgcMeE6a2Q8QoLKIpMK31LCyuD8hBeyNGoGebt0J65jEdsn6MA10IU78o/xHz/IblQi5lC4NmL51AiQOxVjyyqyBHIkfTffkZOuAaB8jta\r\nReferer: https://ginandjuice.shop/my-account\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"1806","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:39 GMT","Set-Cookie":"AWSALB=+OTzt/cHdN9mzp1pbOgaURPkES7i2qq1lhilq3fOQUe1jfh6+KYbRfxvolgT0DjiZvlhhdhoctO4ecMahMhz5hagBN8ye+HbQJnxFvNdj2yozEGUDHaWbKKErer+; Expires=Thu, 14 Sep 2023 15:34:39 GMT; Path=/, AWSALBCORS=+OTzt/cHdN9mzp1pbOgaURPkES7i2qq1lhilq3fOQUe1jfh6+KYbRfxvolgT0DjiZvlhhdhoctO4ecMahMhz5hagBN8ye+HbQJnxFvNdj2yozEGUDHaWbKKErer+; Expires=Thu, 14 Sep 2023 15:34:39 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffdZ\ufffdS\ufffd6\u0018\ufffdB\ufffdvM{7ǘ@\ufffd%\ufffd\u000e\u0018e\ufffdx[\ufffd֮_8\ufffdVbQ\ufffdrm9\ufffd\ufffd\ufffd{$9\ufffd\t6\u0011`v\ufffd\ufffd\u001cG\ufffd\ufffd\ufffd\u001e=\ufffd\u000f\ufffd\ufffd\ufffd\ufffd\ufffd}v\ufffd\"\u00113\ufffd\ufffdP!\ufffd\u000c#\ufffdC\ufffd\ufffd\ufffd\ufffd\u0026_Q\ufffd\ufffd\ufffd\ufffdd$\ufffdE\u0016\ufffd\ufffdax$\ufffd\ufffd\ufffd\t\ufffd\ufffd\ufffd\u0003\ufffd\u001c\ufffd\ufffdTG\u001f:PF\ufffd\ufffd\ufffd\u0019#yD\ufffdX\u0005\u0026!\u00000\ufffd\u000801\ufffd\u001b \u0026\u0002\ufffd\u0004\ufffdij\ufffd\ufffd\\\ufffd\u003c\u0013\u0016\nx\"H\"\u003c늆\"\ufffdB2\ufffd\u0001\ufffdU\ufffdgT\ufffd$\ufffd\ufffdB\u0011/\ufffdV\r-\u000f2\ufffd\n\ufffdg\ufffdg\ufffd\u0008\ufffd̡\ufffd\u0003\ufffd\u0007$\ufffdx\u001a\u0003x\ufffd2\ufffd\ufffd\ufffd\ufffdW\ufffdC\ufffd!\ufffd\ufffd\u0001#f)\ufffdL\ufffdk\ufffd\\\ufffd)ֽV\u0013:N\u0026\u0005\ufffdمko\ufffd[m\ufffd\ufffd\nF\ufffd}\ufffd\td\ufffdC\ufffd\ufffd\ufffd8Nw\ufffd\ufffd\u0002\ufffd\ufffd\u003eF\u003c\u001d:z\ufffd\ufffd\ufffds#\ufffdሇ3\ufffdLl\ufffd\ufffd5\ufffd\ufffdN\u0011\r=\ufffd.\ufffd\u001aC\ufffdQH (OP\ufffdp\ufffd{\ufffd\ufffd\u0013;$\ufffd:\u0018YZ\ufffd\u0016\ufffd\ufffd\ufffd\ufffd\ufffd\u003c\ufffd9\ufffd?\ufffdB\ufffd\ufffd\ufffddX\u00106Cӂ%\ufffd\u000c\u0002EWd\ufffd\ufffdFF\u0003\ufffdv\ufffd}\ufffd$!!\u001a\ufffd\u000c\t\ufffd\u000b\ufffdL\ufffd\ufffd\ufffd\ufffd(Ow\ufffd\u000b)\ufffdb\ufffd\ufffd\ufffdQ\ufffd/\ufffd7\u00120\ufffdS\\\u001dEj\ufffd\ufffdx\u0012sP*\u0010\u0026ɤ\ufffd%!\ufffd\ufffd_\\\\\ufffd\ufffdCn5̧\ufffd\ufffd\ufffd\u000b\ufffd1\u000c\ufffdG\u0007zt\u003e\u000c\ufffdI}xcaq\ufffdz\u0016\u001d\ufffd\u0017\ufffd\ufffd\ufffd?G\ufffd\ufffd\u0016\ufffd\ufffd\ufffd\ufffd\ufffdK\ufffdx\ufffd-\u000fa\ufffdG/zG\ufffd/\ufffd\ufffdp\ufffd\u0005\ufffd[\ufffd?]\ufffd\ufffd!c\ufffd\ufffd\ufffd\ufffd^V\ufffd2\ufffd%\ufffd \u0007\"H\r\ufffd\ufffdA\ufffd\ufffd\ufffd\u001b\ufffd\u0006\r}\u001b\ufffdV\u00084\u0003\ufffdF\ufffd\u001c\ufffd\ufffdHDD\ufffd\ufffd\u0007Pi`\ufffd\ufffd8K\ufffd\u0002\u0013\ufffd\ufffdݩ\ufffd=\ufffd\ufffd{j\ufffd^\u0003\ufffdTo=U\ufffd\u0014LaZ\ufffd^\u000e\ufffd\ufffdb=\ufffd\u0001\ufffd\u0001.W\ufffd\ufffdf|\ufffd\ufffdN\ufffd\ufffd\u0005\ufffd\ufffd-\u00037P\ufffd`\ufffd\u0015\ufffd\ufffd5\tn٦\ufffdQ\ufffd\ufffdj\ufffd\\:Q:a\ufffd\u0006+\ufffd=GiFc\ufffd\ufffdt\ufffd\ufffdpoA2\ufffdz\ufffd\ufffd\ufffd\ufffd[\ufffd\n!\ufffd)h\ufffdZ\u000eh\u0026\u0006\u003e\ufffdfd\u003c,\u0002\ufffd\ufffd2e\u0001\ufffd1\ufffd\ufffd\ufffdԍ\u0014i{\ufffd\ufffdE\u0016\u001e\ufffdBX\ufffd\ufffd\ufffd#\ufffd\ufffdYG\ufffd\r\ufffd\ufffd=Z\ufffd\ufffd\u0006y\u0012\u003e\ufffd\u0012\ufffd \ufffdE\"l\n{A\ufffd\ufffd\ufffd6!\ufffdMoX\u0014\ufffd\ufffdr\u0012\ufffd\ufffd|:\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd7\ufffd\u0015\ufffd}\"\ufffd\u0000g\u003e\ufffd\u000f\ufffd\ufffdo c-,\ufffd\u0011W\ufffd\ufffd\u0004\u000b\"\u0012|\ufffd\u0003\ufffd\u0005\ufffd(\ufffdz\ufffd\u0012\ufffd\ufffd\ufffdJƛM\ufffd\u0017Co3vIѤ\u0007\ufffd\ufffdv\ufffd'\u0008\u001e\ufffd\ufffdU\ufffdF\ufffd\ufffd=\ufffdu\ufffd\u001f\ufffdP\ufffd\ufffdD\ufffd\ufffd6\u0019s\ufffd\u0007\ufffdA\u0000\ufffd\ufffd6\u0002\u0019\ufffd\u0003A\ufffde\ufffd\ufffd\ufffd)\ufffd\u0004ddu\ufffd\u0008kh\u0010r\ufffdV\ufffd\ufffd6\u000f\ufffd^\ufffd\ufffd\ufffd\u001c\ufffd-\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdތ\ufffd\ufffdg\ufffd\ufffdT\ufffdim\u0000}\ufffd\ufffdzC\ufffd5\ufffd\ufffdD\ufffd\ufffd\ufffd\ufffd|ei\ufffd\ufffd\ufffd\ufffd\u0008\ufffdJGK\ufffd\ufffd,;\ufffdd\ufffd\ufffd\t\ufffd\u0012\ufffd\ufffd\u0004ª\ufffdIG\ufffd\ufffdt[\\\ufffdP\ufffd\ufffd\ufffd\ufffd\\\ufffdq\ufffdf\ufffd\u001e\ufffdm\ufffd\ufffd\ufffd[FS\u0010\ufffd\ufffdx2Q\ufffd\t\ufffdB7n%u\ufffd\ufffdKŻ\ufffd \ufffdo\ufffd\ufffd\ufffd%6#\ufffdeV\ufffd\\K\u0005\ufffdM\ufffdV\ufffdT\ufffdkle:\u0006+\ufffdj\u001aO\ufffd:O-st\ufffd\ufffd\ufffd:\u000b\ufffd\u001bo\ufffd̝\u0014\u0004(\ufffd\u001erAB*E\ufffdO\ufffd\ufffd\t\ufffd-)\ufffd\ufffdӄ@ؠ2VS6\ufffd\ufffd\ufffd\ufffdt\ufffd_\ufffd\ufffdw\ufffd\ufffd\ufffdg\ufffd\ufffd\ufffd\u0003}v\ufffdσ\ufffd\ufffd\ufffd\ufffd\ufffd\u0001=\ufffd\u0005\ufffd\r\u0007p\ufffd\ufffd\u0006k\ufffd\ufffd5S\ufffdf\ufffdo\u0005N\ufffd1\ufffd\ufffd\ufffd\ufffdC\ufffd\ufffd\u0018SV\ufffdB\ufffd\u001bC@\ufffd\u003c\ufffd\u0016\u001c\u003c\ufffd\ufffd\ufffdx蝝~\u003cG\ufffd\u0026\u0005J7\ufffd\ufffd\u000c\ufffd64\ufffdL\ufffdT\"\ufffd^4I\ufffdV\ufffdȷ\ufffdfP_\ufffd\ufffd\ufffd\ufffd\ufffd!I\ufffd\ufffdL%!4Ŭ \ufffd\ufffd\ufffd\ufffd\ufffd5/\ufffdJ\ufffd\ufffdO\ufffd\ufffd\ufffd\ufffdn\ufffd~(O\ufffd\u0008'\u0013ym\u0012Ѽ/9\ufffdϋQLŋ\ufffd;\ufffd\u003c\ufffd\ufffd\ufffd\ufffdK\ufffd\ufffd\u0010֚UER\u0019-\ufffd\ufffd\ufffdQ]\ufffd_\ufffd\u000cl\ufffd\ufffd\u0007\ufffd\ufffd\r,\ufffd30\ufffd\ufffd7;\u0003۴\ufffdW\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd,\ufffd3\ufffdm\ufffd\ufffd\u0019\ufffdk\ufffdw\ufffd\ufffd5\ufffd\ufffd\ufffd\u0008\ufffd\n\ufffd\ufffd\ufffd\ufffd\u0005;p\ufffd3\u0004\u0017,\ufffd\ufffd\ufffd\u0014\\\ufffd\u0005\ufffd\ufffd\ufffd \ufffdE\ufffd\ufffd:v\ufffd\ufffdI\ufffd\ufffd\ufffd\ufffd\ufffd\u000f\ufffd\ufffd)\ufffd\ufffd\ufffd5-\ufffd\u000c\ufffd\ufffdC\ufffdr\ufffdnR\ufffdJČ\ufffd\ufffd(d\u003ee\ufffd\\\ufffd]\u0005G\rmw\ufffd\ufffd\u0008\ufffd\ufffdu\ufffd\ufffd\ufffd!\ufffd\ufffds/\ufffd\ufffd~_\ufffd\u0006\ufffdB\ufffd\ufffd\ufffdA\tv\ufffd\ufffd%\ufffd\ufffdf\ufffd\ufffd\u0026\ufffdv\ufffd%\ufffd\ufffdp[\ufffd\u0001\ufffdjt\ufffd\ufffd\ufffdg\ufffd2\ufffd,\ufffdL2\ufffdh\ufffd\ufffdsP\ufffd7P\ufffd\rL,J\u0017`UZ\ufffd\ufffd\ufffd\ufffd)SҔ\ufffd\u0011\ufffd\u0008U\u0007\r\ufffd\ufffd\u0017)/\ufffdM\ufffd\ufffd\ufffd\t\u000b\u0016g(c\ufffdG\ufffd\ufffd\ufffdj=\ufffdO7\r+\ufffd\u0006Ͷ\ufffdj[\ufffd;\ufffd \ufffd\ufffd\ufffd\ufffdev\ufffd^\ufffd\ufffd\ufffd\ufffd]0\ufffd\ufffd߲\ufffd\ufffd\ufffd\ufffd\ufffdߏ\ufffd9\ufffd\ufffd\ufffd =\ufffdd\\\ufffd-\ufffd\u000b\u000e% \u0011g\ufffd|A\ufffd\u001b\ufffdH3\ufffd\ufffd\u0004\ufffdw\ufffd\u0018\ufffdm\ufffdGiZZ\u0018\ufffd\ufffd\ufffd߅rifnNƦԬ\u0002\ufffd2\ufffd\ufffd\ufffd\ufffdX\ufffd\ufffdO$\ufffd\ufffd\ufffd\ufffd\ufffdɫ\ufffd\ufffd\ufffd\ufffd\ufffdG\ufffd\ufffd?\ufffd\u001b\ufffd\ufffd\ufffdͽ\u003c99\u003e\u0008x\ufffd\ufffd5\ufffd\ufffd*\ufffd\ufffdIQ\"e\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdQwP\ufffd\ufffd\ufffd~Ɯ\u000bp=\ufffd\ufffd-\ufffd\ufffdP\ufffd\u0002Ư\ufffd/\ufffdn\ufffd\ufffdT/\u000e\u000cotr\u001eP̎V\ufffdMX\ufffd\ufffd\ufffd\ufffdǺ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd/\ufffd\ufffd-r\ufffdfx\ufffdY\ufffd\u0005J\ufffdvo\ufffdmK\ufffdTD\ufffd$\ufffd/\ufffd\ufffd\ufffdoD\ufffdg\ufffdp\ufffd?\ufffd4A\ufffd\ufffd\ufffd_\ufffd\u0017\ufffd\ufffd\u0016$\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 1806\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:39 GMT\r\nSet-Cookie: AWSALB=+OTzt/cHdN9mzp1pbOgaURPkES7i2qq1lhilq3fOQUe1jfh6+KYbRfxvolgT0DjiZvlhhdhoctO4ecMahMhz5hagBN8ye+HbQJnxFvNdj2yozEGUDHaWbKKErer+; Expires=Thu, 14 Sep 2023 15:34:39 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=+OTzt/cHdN9mzp1pbOgaURPkES7i2qq1lhilq3fOQUe1jfh6+KYbRfxvolgT0DjiZvlhhdhoctO4ecMahMhz5hagBN8ye+HbQJnxFvNdj2yozEGUDHaWbKKErer+; Expires=Thu, 14 Sep 2023 15:34:39 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:41+05:30","url":"https://ginandjuice.shop/my-account","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; AWSALB=+n84438yZsDA5AHP8fkJy0HrFaX/8Yq0pknF0+7HT5H3HB2hEd3G3yvICmv5HTZkzoDUZB/b7S77KFxPM4mi7pHuQYLCafFCtH2zJrM/l9i9JIn+2wcdTRh/fxDy; AWSALBCORS=+n84438yZsDA5AHP8fkJy0HrFaX/8Yq0pknF0+7HT5H3HB2hEd3G3yvICmv5HTZkzoDUZB/b7S77KFxPM4mi7pHuQYLCafFCtH2zJrM/l9i9JIn+2wcdTRh/fxDy","Referer":"https://ginandjuice.shop/catalog/cart","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/my-account","scheme":"https"},"raw":"GET /my-account HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; AWSALB=+n84438yZsDA5AHP8fkJy0HrFaX/8Yq0pknF0+7HT5H3HB2hEd3G3yvICmv5HTZkzoDUZB/b7S77KFxPM4mi7pHuQYLCafFCtH2zJrM/l9i9JIn+2wcdTRh/fxDy; AWSALBCORS=+n84438yZsDA5AHP8fkJy0HrFaX/8Yq0pknF0+7HT5H3HB2hEd3G3yvICmv5HTZkzoDUZB/b7S77KFxPM4mi7pHuQYLCafFCtH2zJrM/l9i9JIn+2wcdTRh/fxDy\r\nReferer: https://ginandjuice.shop/catalog/cart\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Cache-Control":"no-cache","Content-Encoding":"gzip","Content-Length":"2094","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:41 GMT","Set-Cookie":"AWSALB=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq; Expires=Thu, 14 Sep 2023 15:34:41 GMT; Path=/, AWSALBCORS=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq; Expires=Thu, 14 Sep 2023 15:34:41 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffd[\ufffdr۸\u0011\ufffd~O\ufffdc\ufffd8\ufffd\tEQr\ufffdg\"i\u0026\ufffd\ufffd|s\ufffd\ufffd\ufffd\ufffd\ufffdn\ufffd/\u0019\u0008\ufffd$\ufffd \ufffd\u0012\ufffddާ\ufffdF\u001f\ufffd\ufffd\ufffdG\ufffd\ufffdt\u0001P2%\ufffd\"\u0015\ufffd\ufffd\ufffd O\u0026\u0016\ufffd\ufffd\u000f\ufffd\ufffd\ufffd\u000f\u000bq=\ufffd\ufffd\ufffd닟\ufffd\ufffd\ufffd\u0003\ufffd阏\ufffd\u0019\ufffd_\u0008~\u00063\ufffd#\ufffd\ufffd\u003er\u0026\ufffd\ufffd,\ufffd\ufffda\ufffdR%\ufffd\ufffdP\u0015p\u003c6b4\r\ufffdR\ufffd\"X\ufffdD\ufffd\r\u001dh@)\ufffdC\ufffdsNՌR\ufffd\u0004f \u0000P\ufffd\u0000LLw\u0003\ufffdTc$pL\ufffdޜ\ufffdE\"S\ufffd!\"\ufffd\ufffdB\u000f\ufffd\u0005\ufffd\ufffdl\u0018\ufffd9#Է\u000f\ufffdQ\ufffdhꃆ0\u0003\ufffdC!\ufffd\u0012\ufffd\")K4R)\u0019z%\ufffdn\u0015\u003c`\ufffd;\ufffdD\ufffdLb\u0000\ufffd\ufffd*o4\u0008܈\ufffd\u0010~$\ufffd=`t\ufffd\ufffd\ufffd4\ufffd\ufffd\ufffd-\ufffdc\ufffd\ufffdU\ufffdc1\ufffd8N?\ufffd\ufffd\ufffdZ\ufffd\ufffd\ufffd\ufffdt\ufffdS\ufffd0!2\u0013\u001a\ufffd\ufffd\ufffd\t\ufffd\u0002\ufffd\ufffd[\ufffdc\u0006VB73\ufffd\u000c\u0002'\ufffd\ufffd?xp\ufffd\ufffdXF9\u0012S\u001f'I\t6bsĢ\ufffdW\ufffd\ufffd\ufffdY݂(\ufffdL\nD8Vj\ufffd9o\ufffd#\ufffdt\ufffd\ufffd\ufffd\u0001vP\ufffd\ufffdf~~\ufffd1\ufffd\ufffd\u001fF\u0011\ufffdlLS\ufffd)\ufffd\ufffd\u003c\ufffd\u0002\u003eö\ufffd\u0005\u001d#Б3\ufffd\ufffd\ufffd0\u000f\ufffd\n\u001a\ufffd\ufffdL\ufffd\ufffdJ315B/\ufffdX%o\ufffd\u0003\u0019g:wMf)Ц:\ufffd\n\u000cT\ufffdWK1\u003e\ufffd!)b\t\ufffd\u0005[JS\ufffdx\"\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd!\u001a\ufffdp\ufffd-\ufffd뽽\ufffd\ufffd\u0018\ufffd˽}\ufffd\ufffdVQ\ufffd\u003e^\u001b\ufffd%C\ufffdM\ufffd\ufffd\ufffd\ufffd/^\ufffd\ufffd\\k\ufffd\ufffd\ufffd\ufffd\ufffdW\ufffd\ufffd\ufffdZC\ufffd\ufffd\u001c\ufffd\u003c\ufffd\ufffd\ufffdG8\ufffd|\ufffdI\ufffd=ÿ\ufffd'\ufffd%\ufffdd1\u001c\u001e\ufffdZ\ufffd\ufffd)6:\ufffd\u003ePMKp\ufffd[\ufffd\ufffd֫h\ufffdW\ufffd\u001d{\ufffdO\ufffdF987*\ufffd\u0001i\ufffd\ufffd\ufffdڭ\ufffd\u0016\u001c\u001b\ufffd_\ufffd.\ufffd\ufffd\ufffd\ufffd\ufffdx\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u0002ָ\ufffd\u00135Ă\u0019\ufffdU\ufffd\ufffd\u0000;.;\n*`*\ufffd\ufffd%8\ufffd˩\ufffdh\ufffd\ufffd\u001a\ufffd\u0000\ufffdt\u003c@ـ\ufffd\u001b\ufffd\ufffdc\u0004\ufffd\ufffdf%\ufffd\ufffd\ufffdk\ufffd,\ufffdZ\ufffd\ufffd\ufffd\ufffd5ήP\ufffd\ufffd\u0018\ufffd\ufffd{\ufffd\u0008\ufffd-HΚ\ufffd\ufffd ^N=δ\u0006Rp\u0006\ufffd\u0002\ufffdL\u000cv\u0002\ufffdHe\ufffd\u0011\ufffdj\ufffd\ufffd\u0006\u0017\ufffd\ufffd\ufffd\ufffdڍ\ufffdj\ufffd\ufffd\ufffd?\ufffdZx,3퍮M\u001ci\ufffd\ufffdO\ufffd\ufffd \ufffd\ufffd\ufffd]\u0008bP\ufffd\ufffdwv\ufffd\ufffd\ufffd\ufffd\u0019\ufffd\u0005\u0007\ufffd\ufffd\ufffd)\ufffd|8\ufffd\u000cs\u0011M\ufffd\ufffd\ufffd\ufffd\ufffd/\ufffd\ufffd\ufffdT\ufffd\ufffdh\u0000\ufffd\ufffd\ufffd|8i\ufffd\ufffd\ufffd\ufffd\u0017\u0000.\ufffd; \ufffd\ufffd\ufffdL\ufffd\ufffd\ufffd\ufffd\ufffd\u000068\ufffd`dFɝOXJ8\ufffd`\ufffd\ufffd\r\ufffd6;X\ufffd@;\ufffd\ufffd,\ufffdm\ufffd\r\ufffd3Tf\\\"\ufffd\ufffdZ]\u000b\ufffd**\ufffd^\ufffd\ufffd\ufffd?\ufffdF\ufffd\ufffd\ufffdͱ\ufffd\u001e\ufffd\u000b\u0002\ufffd\ufffd\ufffd\ufffd\ufffd\rb\rL\ufffd\ufffd|s\ufffd\ufffd\ufffd\t\ufffd2\u000e\ufffdP\ufffd\ufffd+\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdK\ufffd\ufffdk\ufffdg\u001b\"x\ufffd5e\u0010\ufffd\ufffdr5\ufffd\ufffd\ufffd\u003e\ufffd~\ufffde\ufffdAP{\ufffd֜\ufffd\u0015\ufffd\u0015\ufffdʆ\ufffd=\ufffd!\u00112\ufffd\ufffd\ufffd\ufffd\ufffd̵cH\tV\ufffdAU\ufffd\ufffd\ufffdFx+9C\ufffd\t\ufffdq\r1\u000f\u001c\ufffd\ufffd\ufffd.5\ufffd\u0014\ufffdv\ufffd\ufffdu\u0003\u0003\ufffd]\u0007\u001b\ufffd\u0018|\ufffd\ufffdAx\ufffd\ufffd|\ufffdʱ\ufffd\ufffd\ufffdƷc6l\"Ss\u0014\ufffd=\ufffd\r\ufffdO\ufffd\u003en\u001c\ufffd4nsb\ufffdx\ufffd1Є\ufffd\ufffd\ufffdf\u001f\u0002\ufffd\u0004\u0006\ufffd\ufffdk\ufffd\ufffdX\u003c\ufffd \ufffd҄\ufffd\ufffd3\ufffd;\ufffd\ufffd\ufffd\ufffdt[[1\ufffd-\u0006\ufffd\ufffd\ufffd\u003e\ufffd\ufffdfF\ufffd\u0003\ufffd\ufffdr\u0008{\ufffdo9v\ufffd\u003e-$\ufffd\u0004\ufffd\ufffd\ufffda\ufffd\ufffd\ufffdv\u0007\ufffd\ufffd%̖\ufffd\u0011\ufffd\ufffd\u0019o\ufffd\"\ufffd0l\\_\ufffd\ufffdH\ufffd\u000e\ufffd\ufffd\ufffd\u001c\ufffd\ufffd\ufffdu\u0017\ufffd60\u0011\ufffd1\ufffdY\u0010\ufffd\u0006\ufffdn\ufffd\ufffdEH\ufffdx\ufffdpӤ\ufffd[\ufffd\ufffdXg\ufffd\ufffd\ufffd\ufffd\u0019\ufffd\ufffd\ufffd\u0012\ufffd\ufffdds%\ufffd[\u0026\ufffd9n\u001e\ufffd\ufffd\ufffd\ufffdn\ufffd\ufffd\ufffd\ufffd\ufffd|\ufffd\ufffd\ufffd\ufffd\ufffde\ufffdV6ii\ufffd\u0016\u001a\ufffd\u0011\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd}m\ufffd\ufffd^\ufffd\ufffd\u0000\ufffd\u003e\ufffd/\ufffd\ufffd\ufffd\ufffd\ufffdק\ufffd\ufffd\ufffd\u0013\ufffdE\ufffd\ufffd@\u0017%\ufffd\u0003]쵠g\ufffd\ufffd\ufffd\ufffd\\|\ufffd}\ufffd1\ufffd\ufffd\ufffd\ufffd\u001c\ufffd\ufffd\ufffdtq\ufffd뜞u\ufffd81:\u003c\ufffd. \ufffd89\ufffdEI\ufffd@\u0017{-\ufffd\u0019\ufffd\ufffd\ufffd\ufffd㘉\ufffd\ufffd\ufffd\ufffd\ufffdB\ufffd;\u0013\ufffd\ufffd\ufffd\ufffd\ufffd'`\ufffd\ufffd\ufffd\ufffdY\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\t\ufffd#\u003c\u003e0GI\ufffd\ufffd\u001c{-\ufffdp/)\u000f\ufffdC\ufffdKN\ufffd\ufffdO@\u0017\ufffd\ufffd\u0003]\ufffdd\u000ftQ\ufffd]\ufffd\u0006\ufffdat\ufffd\ufffd\ufffdms\ufffdX\u0013)5Xk\ufffd\ufffd$\ufffd\ufffd\ufffdz\ufffd;\\7\ufffd\ufffd{\ufffdmdN'\ufffd\u0015ǎ\u0017\ufffd\ufffdc\ufffd-\ufffd\ufffda\ufffd\ufffd\ufffd7\ufffd\ufffd\ufffd+(fʕ\ufffd`\ufffd|\ufffd\ufffd\ufffd)m\u0019S\ufffd\ufffd\u0005\ufffdOo\u0007D2\ufffdQ2\ufffdL\ufffd\ufffdB\ufffd\u003cZ\ufffd\ufffd\"\"\ufffd8\u0013L\ufffdHN\ufffd\u0014\ufffd\ufffd\ufffdЭ%\ufffd\t\u0016X3\ufffd^\ufffdr\u0016zOx\ufffd\ufffd1\ufffd\ufffd\u000b\ufffd\ufffd\u0003\ufffd\ufffd\ufffdJXm@\u000ezL\r\u0015Ő8\ufffd\u0006h\ufffd\ufffdX\ufffd\ufffd\ufffdzx6ȱLig\ufffd\ufffdb\ufffd\ufffd\u000f\ufffdMG\ufffd\ufffdG\ufffd\ufffd^\ufffdE\ufffdV\u001dU\ufffd\u001eU\ufffd\ufffd\u0016\r-\ufffdz\u000f\ufffdOc\ufffd0\u0015\ufffdc\ufffdg\u0012\ufffd\u0012\ufffdtф\ufffd\u000f\ufffd\ufffd\\=\u00004\ufffd:\u0013I\ufffd\ufffd\u000c\ufffd\ufffd\u0018Đ\ufffd\ufffd\ufffd\ufffdI)m\u0001\ufffd\ufffd\ufffdpL\ufffdL\ufffd\ufffd\u0014\ufffd|\ufffdM8\ufffd`\ufffdM\u0001\\\t\ufffd\ufffdX\u0014Q\ufffd\u0015%jD\ufffd\u0013\u000f\ufffd1\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdn\u003c\u0017\ufffd/\ufffd\ufffd]\ufffdO~\ufffd=\ufffd\ufffd}\ufffdk\ufffd\ufffd\ufffd\ufffd~k:\ufffd\u0006\ufffd5\ufffd\ufffdKM;-\ufffd$fzt\ufffd\ufffd\u000c\ufffdZ\ufffd{W\ufffd\ufffd恈\u0019[\ufffd\r#2K\ufffd\ufffd]\ufffd\u001e\ufffdN\ufffdq\ufffd\ufffdݰB¥\ufffd\ufffdr\ufffdR\u0010\ufffd\ufffd]\ufffd|a\ufffd\ufffd\ufffd*\ufffd\ufffdh\u0014\ufffd\ufffd\ufffd\ufffd\ufffdU\ufffdPs\ufffdl#\u001c\ufffd\ufffd\ufffd8\ufffd \ufffd\u0004\ufffd\ufffd11\ufffdy\ufffdj\ufffd$\ufffd|\ufffd\ufffd[\ufffd~\ufffd7In\n\ufffd|\ufffd㍜a\ufffd\ufffd4pE\u0026\ufffd\ufffdi\ufffd\ufffd-v`\t]\ufffd\ufffd6a\ufffd4tmo\u000c\ufffd\ufffd\ufffd\ufffd`G\ufffdlS\ufffd:\u0000e\ufffd\u0013\u0000\ufffd\ufffdy\u001b6+u\ufffd\"\ufffdv\ufffd\ufffd\ufffdL{\ufffd\u0026\ufffdwI\ufffds\ufffdM!\ufffd\ufffd\ufffdT\ufffdي5S@\ufffd\ufffd\ufffd\ufffd\u000b\ufffdj4\ufffd\ufffdfԲ\ufffdi\ufffd\u00126+\ufffd͵{(\ufffdx\ufffd\ufffd@m`\ufffd\ufffdS\u000f\ufffd.e\ufffdY\ufffd\u000b\ufffd\ufffd\ufffd\ufffd[\ufffd\ufffdo\ufffdmE[+\ufffd\u001b\ufffd\ufffd\ufffd\ufffdL2\ufffd\u003e\u0001C@\u001fu\ufffdi\ufffd\ufffd\ufffd^\ufffd\ufffdXim2S\ufffd\u0002U'$\ufffd\ufffd\ufffd\u001ei\ufffdժ@jW\ufffdQ\u001a\ufffd$\ufffd\u001d\ufffd\ufffdP5\ufffdd\ufffdC\u0019\ufffd\ufffdkw(\u0003,\ufffd\ufffd_\u0010S}Eب\ufffd\ufffdx\ufffdIJ]l\ufffd\ufffd\ufffd\ufffd\u0015\ufffdvV\n\ufffd\ufffd\ufffd\ufffd\ufffd7p$\ufffd?v\ufffd?\ufffd\ufffd;\ufffd\u00041\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2094\r\nCache-Control: no-cache\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:41 GMT\r\nSet-Cookie: AWSALB=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq; Expires=Thu, 14 Sep 2023 15:34:41 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq; Expires=Thu, 14 Sep 2023 15:34:41 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:46+05:30","url":"https://ginandjuice.shop/logout","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; AWSALB=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq; AWSALBCORS=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq","Referer":"https://ginandjuice.shop/my-account","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/logout","scheme":"https"},"raw":"GET /logout HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=wrNhEoOD0CeeH8cagJk19XHRP32b6YM2; AWSALB=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq; AWSALBCORS=W++/+JQbTxiN/OHBUJnq0z7nTriL7qXmdSqtD8FuMwXVMB+DdSW4k3k6e2NDavgrFaNmXo7qvphCRsGZUXDaguARWYOYLs5NMs+ZFvg0Q1fcK87mjQYc3/zgcDdq\r\nReferer: https://ginandjuice.shop/my-account\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"0","Date":"Thu, 07 Sep 2023 15:34:47 GMT","Location":"/","Set-Cookie":"AWSALB=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/, AWSALBCORS=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/; SameSite=None; Secure, session=UeLc4S4hyi19aLba4fvsmba8ZhjwmwH2; Secure; HttpOnly; SameSite=None","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"raw":"HTTP/1.1 302 Found\r\nConnection: close\r\nContent-Encoding: gzip\r\nDate: Thu, 07 Sep 2023 15:34:47 GMT\r\nLocation: /\r\nSet-Cookie: AWSALB=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/; SameSite=None; Secure\r\nSet-Cookie: session=UeLc4S4hyi19aLba4fvsmba8ZhjwmwH2; Secure; HttpOnly; SameSite=None\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\nContent-Length: 0\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:47+05:30","url":"https://ginandjuice.shop/","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; AWSALB=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; AWSALBCORS=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; session=UeLc4S4hyi19aLba4fvsmba8ZhjwmwH2","Referer":"https://ginandjuice.shop/my-account","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/","scheme":"https"},"raw":"GET / HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; AWSALB=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; AWSALBCORS=L9mzxS2E7L48F2f8vDl+MO39oxE9+M9tFcy+STvbOJYFf3nTXFODardtaxqjkhm4leDa2G+3/sDz4EMXNmu/mSP4LIZBJANKWnr2cfqgpLpusUPISK8wkBli4N0D; session=UeLc4S4hyi19aLba4fvsmba8ZhjwmwH2\r\nReferer: https://ginandjuice.shop/my-account\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2128","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:47 GMT","Set-Cookie":"AWSALB=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/, AWSALBCORS=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffd\u001a\ufffdr\ufffd6\ufffd\ufffdb˻\ufffd\ufffd\ufffdP\ufffd$\ufffd\ufffdL$u\u0012;\u001f\ufffd\ufffd\ufffd[{\ufffd\ufffd\ufffdd \u0012\ufffd\ufffd\ufffd\u0000K\ufffd\ufffd\ufffdH}\ufffd{\ufffd[\u0000\ufffdLI\ufffdH\ufffd\ufffdLn\u0026\u001e\ufffd-\u0000\ufffd\ufffd\ufffd~/\ufffd\ufffd\ufffdg\ufffdO\ufffd\u003e\\\ufffd\ufffd\ufffdN\ufffd仑\ufffd\u0007\ufffd3\ufffdS\u0012\ufffd\ufffdvș\ufffd\u0004\ufffd\ufffd\ufffd\ufffdAF\ufffd̳\ufffd\ufffd\ufffd\ufffd\ufffd\u0001\ufffdY\u0010*\u0015\ufffd\ufffd\ufffd_\ufffd[;\ufffd\ufffd\t\ufffd(\u001f+]p\ufffd\ufffd\ufffd\ufffd6b\ufffd\u0004\u0012T\ufffdH\u0026\ufffd\ufffd\t$T\u0013\u0010$\ufffdco\ufffd\ufffd2\ufffd\ufffd\ufffd \ufffdBS\ufffd\ufffdޒEz\u003e\ufffd肅Է\ufffdǐ+\ufffd\ufffd\ufffd!\ufffd\ufffd\ufffdXH\ufffdBM\ufffd\u0019K5\ufffd,\u001c{\u0015\ufffd\ufffd\u0015\u000eH\ufffd{H\ufffdr\ufffd\u0026H\ufffdw\ufffd\ufffd\ufffd(p\u0018\ufffdI\ufffd\ufffdL\u000e \ufffd\ufffd\u0014O\ufffd\ufffd\ufffd\u000e\ufffdɂ\ufffdY\ufffd\ufffd:\u0011q\ufffdI\ufffd\ufffd\ufffd?\ufffd\ufffd6Q\ufffdLs:y+\u0013\n\u003e\ufffda\u0002\u001e\ufffd$}\u000e?\ufffd(\u001f\ufffd\ufffd\ufffdt\u00148\u0010\ufffd\ufffd\ufffdV\ufffd\ufffd\ufffd\ufffd\n\u0010\ufffdOҴB0b\u000b`\ufffdثj\ufffd\"Pw\u0014\u001aj\u0026\u0005\ufffd\ufffd(5\ufffd\ufffd\ufffd\ufffd\u0011u\ufffd\ufffd\ufffd\u0016\ufffdEJw\ufffd\ufffd\ufffd՜)\ufffd_\u0002\u0011\ufffdlJ3\ufffd)/`\ufffds\ufffd\ufffdQ\ufffd\ufffd\ufffdS@\u001e9\u000b\ufffd\ufffd\u0015\ufffda\ufffd\ufffd\u0011\ufffdd\u0006\ufffd*\ufffdDl\ufffd\u001e\ufffd\ufffdJ\ufffd\ufffd\u0010\u0019g\ufffdpS\ufffd(8\ufffdz\ufffd\u000c\ufffdTJ\ufffdG1\ufffd\ufffd\ufffd\u0014\ufffdD\ufffdBe\ufffd̘\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdM\u001f\ufffd\ufffd_/\ufffd\ufffd\ufffd\ufffd`c5\ufffd\ufffd\ufffd\ufffdЭ\ufffd\ufffdqVT\ufffdO6\ufffd\ufffdt\ufffd\ufffd\u0019\u003c\ufffdn\ufffd\ufffd\u0001T\ufffd\ufffd\u0018\u000e7\ufffd'\ufffd\ufffd\ufffdRZc ZN\u001f\u001e\ufffd\u000f\ufffdӟ\ufffdy\ufffd\ufffd\ufffd5#ܤ\ufffd\u001b\ufffd\ufffd\ufffdx|\ufffdh\ufffd+\ufffd\ufffd\ufffd\ufffdz\ufffd\ufffdV\ufffd\ufffd\ufffd\ufffd\ufffdܠfnX3w\ufffdM.r\r\u0005\ufffd5\ufffdz\u0000-AϩU\ufffd\ufffdh\ufffd(\ufffd\u001as\t\ufffd\ufffd\u0005\u0001\ufffd\ufffd\ufffd\ufffd\ufffd#g\ufffd/\ufffdFG5d\ufffdy;P\u0013R\u0008C\ufffdz\ufffd\u001c\u0011\u0017Ŏ\ufffd\u001a25\ufffd\ufffd\rm\u003e\ufffd\ufffdD?\ufffd\ufffd\u0006\ufffd\u0001iX\ufffd%e\u001d\ufffdo\ufffd\ufffd\ufffd\u0008Ұ\ufffd\u001a\"\ufffd+\ufffdFX\u0016[\ufffd\ufffdK\ufffd5Ʈ \ufffdXB\ufffdj\u001cw\ufffd$g\ufffd@\u0016\ufffd\ufffd\ufffd\ufffd\ufffdZcPp\u0002\ufffd\u0002\ufffdL\ufffdrB\ufffd\ufffdd\ufffd\ufffdZ5\ne\ufffd\\\ufffde\ufffd\ufffds7\ufffd\ufffd\ufffdĿ_\u0015[d*s\ufffdM\ufffd\u001b?\ufffd2+\ufffd\u0010s\ufffd \ufffdw6!\ufffdA)\ufffd{6\"\u0012\ufffd2\u0017\ufffdgaE*I\ufffd\ufffd\ufffd\ufffd\u001d\ufffd\"\ufffd\ufffd0\ufffd\ufffd\u0016o\ufffd)Zxl\ufffd!\ufffd\n\ufffd\ufffd\ufffd\ufffdؠ\ufffdn\ufffd\ufffd\u0026\ufffd\u001a:]\ufffd[\ufffd\ufffd\u001b\ufffdA\ufffd\ufffd=\ufffd\ufffd9T\u000f~.c`\ufffd3ǖn'\ufffd\ufffd_\ufffd)\ufffd\ufffd|O\ufffd\ufffd\ufffdvwz\ufffda\ufffd!ɶ\ufffd\ufffd\u000c|\ufffdY1\ufffdj2_\ufffd̀\u001d\ufffdנZӽ\ufffd~\ufffd\ufffdv\u003er\ufffd\ufffd}-\ufffd\ufffdS܍l\ufffdf,\ufffdM\ufffd\ufffdN\ufffd\u003eL\ufffd\u0000\ufffd\ufffdkT\u001a\u0005\ufffdy\ufffd!\ufffd\ufffdL\ufffd\ufffd\u0013[P6#c\ufffdb:\ufffd9\u0016\ufffd-Up\ufffd\ufffdz\ufffd\ufffd\ufffd\n\ufffd\ufffd\u0004\ufffd탳\ufffd.\ufffd\ufffd\u0005-5\ufffd\ufffd\ufffdo\u0019y\ufffd\u0010\u0003\ufffdܰ\ufffdŲ-4\\\ufffd\ufffd'f\ufffd*\ufffd\ufffdc\ufffd\ufffd\ufffd\ufffd!\ufffd\ufffd\ufffd0@8Ǻ\ufffd%\ufffd7Tt;̚ndE\ufffd\"\ufffd\ufffd\ufffd}\ufffdVļ\ufffd:\ufffdۙl`\ufffd\ufffdS\ufffd\ufffd4v\u0017\ufffdK\r\ufffd\u0007\u0003\ufffd\u0016\ufffdZM\ufffdI8c\ufffdlp\ufffd\ufffd\ufffd\ufffd?d\ufffd#\ufffd\u0013\u0005\ufffdxr\ufffd\ufffd\u000c\u0014r\ufffd!\ufffd\ufffd\ufffd\n\ufffd\u000cb\u0026\ufffdǮ-\ufffd\ufffdd\ufffdݑ)E\ufffd'\ufffdSS\r+Ԭ\ufffd\u0015Vl\ufffde\ufffd\ufffdom\ufffd=\ufffd%\u001d:F7\ufffd\u000b\ufffds\ufffdu\u0019\ufffd@P\u001a\ufffd\ufffdN\ufffd\ufffdi܍-@\ufffd\ufffd\ufffd\ufffd}\ufffdF\ufffdf\ufffd[~\ufffd\u000e'X)\ufffd\ufffd\ufffd\ufffdNE\u0018\ufffdNL%+?\ufffd\ufffd\ufffd\ufffd\ufffd\u000et,-\ufffd\ufffd\ufffd%\ufffdMW\ufffd\ufffd\ufffdV\u0014\ufffd6PA\ufffd욦\ufffd~\ufffd\u00113g\ufffd\ufffd\"\ufffd\ufffd\ufffd|8\ufffdX\ufffd\ufffd+\ufffd\u000f\ufffd2\ufffd\ufffdR\ufffd\u0018\u0002\ufffd\u0007\ufffd\ufffd\ufffdl3b\ufffd\u0015\ufffd\ufffdpUuXl\ufffdBL\u0018\ufffd\u001c\u001e\ufffd\ufffd\u001c7\ufffd\ufffd\ufffdT\ufffd\ufffd\ufffd\ufffdԈ\ufffdө\ufffdĺ\u0015\u0002\u001d,`pO\u0016\ufffd\ufffd\u001f\ufffdr\u0017\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd'wU\ufffd\ufffdOz\ufffd~\ufffd\ufffdV\ufffd\ufffd\ufffd\u0014~|\ufffd\ufffd_g9\ufffd\ufffd\u001e\ufffd\u0019'\ufffd\ufffd\ufffd\ufffd\ufffd٠\ufffd\ufffd\ufffdש斲ʁ\ufffdON\ufffdFr_U\ufffd\ufffdj9\ufffd\ufffd\ufffd\u0018R\ufffd.Ir\u000b\ufffdOe;\u000e\ufffd\ufffd\u0002\u0005\u0006\ufffdG\ufffd\ufffdyE\ufffd\ufffd\ufffdaU\ufffd\ufffdw\ufffd\ufffd^{\u00176\ufffd\u000f\u0026/\ufffd-aY\u0001g\ufffd@\ufffd\u001e\ufffdr\ufffda\u003cXC\ufffd*A\ufffdx\ufffd8\ufffdj3\ufffd\u000eV\ufffd\ufffd$,ȗ\u0015\ufffdI'\ufffd\u000e\u000f\u0010\ufffd\u0015\u0016\ufffd\ufffd2I9\ufffdB\ufffd^Dz\ufffd\u0005E\ufffd\ufffd\t\ufffd\ufffd\u001eh\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdn\ufffd\ufffd\ufffd\ufffd\ufffd{\u0026%\ufffd\u001c\ufffd2Ò\ufffd\ufffd\ufffdݪH\u001dBS\ufffd\ufffdK\ufffdә\ufffd\u0011\ufffdso\ufffd\ufffd\u0013\ufffdFh_\ufffd@\u000bxG1}@{a\"\u001c|P\ufffd\ufffd\ufffd\ufffdS\nB.\ufffd\ufffd\t\ufffd\ufffd?Kl\ufffdLͱ4\u001dߒE\u0014B\ufffd$\ufffd\ufffdn\ufffd\ufffd\ufffd\ufffd\ufffd\u0008\ufffdm7#\u00023L\ufffd\u001e\ufffd\ufffd)z\u0013\ufffd\\\ufffd\u0005\ufffdD\ufffd\ufffd\ufffd9B\ufffd\ufffd\ufffd\u000f\ufffd\r\ufffd\ufffd\ufffdy\u000c\ufffdDQ\u001c\ufffd\ufffds2\ufffd\ufffd\ufffd7pl('2\ufffd-\ufffdF\ufffd\ufffd\ufffdh\ufffd\u0015q}\ufffdw\ufffd\ufffd\\\ufffd\ufffd\ufffdG\ufffdZY\ufffd7\ufffd\u0015\ufffdw+\ufffd,\ufffd ´\ufffd'Tϥi\ufffdM\u0014pS\ufffd\ufffd@\ufffd\ufffd\ufffd%\ufffd\ufffd*L\ufffd\ufffdF1\ufffd\ufffd\ufffd\u000c{i\ufffdHJ\u0013̋\ufffd%\ufffd}D\ufffd\u000e\ufffd\\\ufffd\ufffd4\ufffd\ufffd\ufffd\u0014\ufffd\"\u003cm[\ufffdSKޛ\ufffd(\ufffd\ufffd+ߚC\ufffd\ufffd\u003c0\ufffd\u001e\u000e\ufffd͟\ufffdIt\u001a\ufffd.^\u003cS\ufffd\ufffd)5\ufffd\ufffd\ufffd\ufffd\u001f\ufffd_/\ufffd^\ufffd\ufffd\ufffdж_\u0019P\ufffd\ufffd@\ufffd\ufffd(\ufffd\ufffd\ufffd\ufffd\ufffdJ2\ufffd\ufffd-ߥ\ufffd4\ufffd\ufffd\n\u000be\ufffdJộ\u0003\ufffdc\ufffd\ufffd\ufffd\ufffd-'\u000c\ufffdT\ufffd_\ufffdS\ufffd\ufffd\ufffd\ufffdS9}ji\ufffdY\ufffd\u001e\ufffd7\n\ufffd\ufffdxz۩\ufffd\ufffd\ufffd\ufffdLv.#\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdOg`\"A\ufffd\ufffdX\ufffd\ufffd\ufffd\ufffd;\ufffd\ufffd\ufffd\ufffd\ufffdmio\ufffd\ufffda\ufffd\ufffd\ufffd0\ufffdپ\ufffd\ufffdM\ufffd`0\u0006i\ufffd\u0015\ufffd\ufffd\ufffd\u0017\ufffd\ufffd\ufffd*i\ufffd\ufffdK\ufffdk%\ufffd\ufffdƥ]\ufffd\ufffd\ufffd\ufffd\ufffd34\ufffd!\ufffd\ufffd\ufffd!QF#\u001f\ufffd\ufffd'oKf\ufffd%(\ufffdn_\ufffd\ufffd\ufffd\ufffd\u0000\ufffdt\ufffd\"M\ufffd\ufffd\ufffdc\n\ufffd\ufffd\ufffd\ufffd\ufffdީ\ufffd˷\ufffd|[\ufffd\ufffdd\u001a\ufffd\u0014\ufffd\u0019\ufffdQ\ufffd\ufffdY\u0008\ufffd\ufffd/\ufffd썵\u00070ա\u00020^ѭ\ufffd]e=T]\ufffd\ufffd\ufffd!\ufffd\ufffd\ufffd\u000e\ufffdZڋz\ufffd@\ufffdI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdK\ufffd!\\ \ufffdKG\u0001\ufffdu\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\u001c_\ufffd\ufffd\ufffdZ\ufffd\ufffdΩ-H\ufffd\ufffd\ufffd\u0003ʒw\ufffd\ufffdΎ퉒!j\ufffd\ufffd\ufffd\u0011\ufffdMx\ufffd^\ufffd\ufffd\u003cw\ufffd^\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdշ\u0008[\u000ff[Æ\ufffd\ufffd\ufffd\ufffd\ufffdM\ufffd\ufffd\u0001w\ufffdRLF2*\u0026\ufffdaJ\ufffd\ufffdZ\ufffd\u001f\u000blT\ufffd(\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2128\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:47 GMT\r\nSet-Cookie: AWSALB=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom; Expires=Thu, 14 Sep 2023 15:34:47 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
+{"timestamp":"2023-09-07T21:04:52+05:30","url":"https://ginandjuice.shop/catalog","request":{"header":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","Accept-Encoding":"gzip, deflate, br","Accept-Language":"en-US,en;q=0.9,hi;q=0.8","Connection":"close","Cookie":"TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=UeLc4S4hyi19aLba4fvsmba8ZhjwmwH2; AWSALB=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom; AWSALBCORS=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom","Referer":"https://ginandjuice.shop/","Sec-Ch-Ua":"\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"same-origin","Sec-Fetch-User":"?1","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36","host":"ginandjuice.shop","method":"GET","path":"/catalog","scheme":"https"},"raw":"GET /catalog HTTP/1.1\r\nHost: ginandjuice.shop\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9,hi;q=0.8\r\nConnection: close\r\nCookie: TrackingId=eyJ0eXBlIjoiY2xhc3MiLCJ2YWx1ZSI6InkyRTQ5UzdBNFdiWUVDZEYifQ==; session=UeLc4S4hyi19aLba4fvsmba8ZhjwmwH2; AWSALB=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom; AWSALBCORS=EeUP0iKoblECp3EJrR7G3VkVXCB824uzYMUKxXSQm3dzHWM8O+zBi9JJ1ycx4rw89sTDpO5ron/v2igr7ki2rVUBc9cHkO/BE+HpmdhpXzFd01fKZVWnAa9/Muom\r\nReferer: https://ginandjuice.shop/\r\nSec-Ch-Ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"\r\nSec-Ch-Ua-Mobile: ?0\r\nSec-Ch-Ua-Platform: \"macOS\"\r\nSec-Fetch-Dest: document\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-User: ?1\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\r\n\r\n"},"response":{"header":{"Content-Encoding":"gzip","Content-Length":"2876","Content-Type":"text/html; charset=utf-8","Date":"Thu, 07 Sep 2023 15:34:52 GMT","Set-Cookie":"AWSALB=AymL6NoUb7IQ+yLeqn8Nx2AnsAEQE7J/dECy9Mv2IjZxSjlYL3ClOPOJQywrvrB2uDIqCLT8bh+PpOR56TWHYLLnsfn2bXbh+12VUozjFNV+c3PYsBusyKnEB1Ut; Expires=Thu, 14 Sep 2023 15:34:52 GMT; Path=/, AWSALBCORS=AymL6NoUb7IQ+yLeqn8Nx2AnsAEQE7J/dECy9Mv2IjZxSjlYL3ClOPOJQywrvrB2uDIqCLT8bh+PpOR56TWHYLLnsfn2bXbh+12VUozjFNV+c3PYsBusyKnEB1Ut; Expires=Thu, 14 Sep 2023 15:34:52 GMT; Path=/; SameSite=None; Secure","X-Backend":"ecfca00b-5a9e-4a89-91bd-de41ecbc4611","X-Frame-Options":"SAMEORIGIN"},"body":"\u001f\ufffd\u0008\u0000\u0000\u0000\u0000\u0000\u0000\ufffd\ufffd\\}r\ufffd6\u0016\ufffd\ufffd\ufffd@\ufffd\ufffd\ufffd=#Q\ufffd\ufffd\ufffdĒ:\ufffd\ufffd\ufffdi\ufffd8\ufffd\ufffd\ufffdvwv\u003c\u0010\tI\ufffdA\ufffd\u0005@)\ufffdLf\ufffd\u001a{\ufffd\ufffd\ufffd\u001eeO\ufffd\u000f\u0000EQ\u0012)\ufffd.;^\ufffd֓\ufffdE\u0000\ufffd\ufffd\ufffd\ufffd\ufffd\u0017(\ufffd\ufffdg\ufffdn.\ufffd\ufffd\ufffd\ufffd\u0012\ufffdU\ufffd\ufffd_t\ufffd/\u0004?\ufffd1\ufffd\ufffd\ufffdh\u001e\u0019\r\ufffd\ufffdX\ufffda\ufffd)\ufffd\ufffd\ufffd\ufffd\ufffdl2\u003c\ufffdÈhzR6\ufffd\ufffd\ufffd\ufffd\ufffdצ\ufffd\ufffd\u0006$\u0008\ufffdI5cD\ufffd\tQۘi\u0016\ufffdP^z\u003c\u0008\u00084\ufffd\n\u001e\ufffd J\ufffd\ufffdA@\u0014F!\u000eHϙP2\ufffd\ufffdP\u000e\ufffdx\ufffdH\ufffdzΔ\ufffdj\ufffd\ufffdɄz\ufffda\u001e\ufffd(\ufffdD4`\ufffd0\u0003#\ufffd\ufffd;\u0019n\ufffd\u00134RH\n\ufffd\ufffdd\u0004\ufffd \ufffd\u0001{\ufffd\u0005N\ufffd\ufffd(\u0000\ufffd\ufffd\u0007\ufffd\ufffd\ufffdMKQ\ufffdE\ufffd\ufffd\ufffd\u0003بY\u0004+S\ufffd\ufffdj~\ufffd\u0013l[\ufffd\u003c\ufffd8\u001c\ufffd\u000c\ufffd\ufffdV\ufffd\ufffdqR\ufffdUQ\ufffdH\ufffd\ufffd\ufffd~\ufffd)\ufffd\u001a芆\ufffd9\u000e\ufffd3\ufffdM\u000c:B\ufffdc\u001eu\ufffdv\ufffd\ufffd\ufffd\ufffd\ufffd\u0003\ufffd\ufffdP8j\ufffd(\ufffd0\ufffd\ufffd\u0004Q\ufffd\ufffdd-'\ufffdT\ufffd\u001c\ufffd)\ufffdC\ufffd1,eϱ\ufffd\ufffd\ufffd\ufffd\ufffd\u0010zV\u0008\u000cQ\ufffdަޏ\ufffdD\ufffd\u000f#\ufffd0: \u0002+\ufffdfh\u0012\ufffd\u0010\u003e\u0003\ufffdhJ\u0006\u0008dd\ufffd\ufffdfV\ufffd\ufffd\ufffdB\ufffd\ufffd!\u0017H\u0011\ufffdh8҃\ufffd\ufffd\u0003\u0019\ufffd\ufffd\t)\ufffdjf\ufffd\ufffdR\ufffdM\ufffd\ufffd\u0002te\ufffdӥh\u000bv\u0010\u000f\u0003\u000e\ufffd\u0005\ufffd\u0012\ufffd\ufffd.\ufffd\ufffdԽ\ufffd\ufffd\ufffdB=\ufffdJ\ufffd\ufffdd\ufffd\ufffd\ufffd\ufffd\u001b@w\ufffd\ufffdc{\ufffd\ufffd\ufffd\u001af\ufffd\u000f\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd!\ufffd\ufffdN\ufffd\ufffd9\ufffdε\ufffd\ufffdY~\u003c\ufffdG\ufffd'\ufffd\ufffd!\ufffd\ufffd`\ufffdv\ufffd\ufffdkkpuļ\ufffd5\ufffd\ufffd\u0018\ufffdW\ufffdy\ufffd^\ufffd\ufffd\ufffd\ufffd\ufffd\u0008\ufffd2\u0003\u000eD\ufffd\u000c\ufffd\ufffd\u0019Zkk\ufffd\ufffdur\ufffd\u000e\ufffd\ufffd\ufffdX\ufffd\u0019\ufffd6Jp@\ufffd#5\u0026\u0006\ufffdg`֠\ufffd\u001csi\ufffd\ufffd\u000b\u000c\ufffdV\ufffd\ufffd\u0016k\ufffdl\ufffd\ufffdD\ufffd\u001c\ufffdڼ\ufffdP\u001dV0\ufffda\ufffdv\ufffd\ufffd6\ufffd՚9lr\ufffdI\u0013\ufffd\u001a\ufffd\ufffd8\ufffd*\ufffd\u0017\ufffdm₎\u0005+㰍-\ufffd\u0019\ufffd\u0010\u0017L\ufffd\ufffd\ufffd\ufffdܴa,\u001d\u0019\ufffdh$\u000e\ufffd\ufffd]\ufffdH\ufffd\u0000\ufffd\ufffd}\ufffdq\ufffd5\ufffd\ufffdn\u001fd\u0006\ufffd\ufffdԃX)\ufffdH[\ufffd\ufffd\ufffd\ufffdX\ufffd:M0Q\u000c\ns\ufffd\u0018V\ufffd\ufffd%\ufffd\ufffd2\u0012\u003cZ\ufffdT\ufffd\ufffd\u0011\ufffd\u001c\ufffd\ufffd\ufffd\u0012\u000b\u000fx\ufffd\ufffd\ufffd\ufffdv(\ufffdŬ\"\ufffd\ufffd͘\ufffdj[\u0002g\ufffd\ufffd\ufffd\u001b[\u0013\ufffd\u003c\u001e\ufffd\ufffdA\ufffd\ufffdV\ufffdY#i\ufffdT)'\ufffd~\u0017\u0002ڼs\ufffdZ\ufffd\ufffdG\ufffd\u0017\ufffd\ufffdǻ0\ufffd\u000fK\u003c\ufffd\ufffdXg\\ͧ\ufffdz\u0013\ufffd\ufffd\u001b\ufffd\ufffde\ufffd/\ufffd\u001c\ufffd\u000b\ufffd\ufffd#D\ufffd\ufffd\u0012\u001b\ufffd\ufffd\ufffd\ufffd\ufffd\u0015\ufffd\ufffd\u0019J\u003e\ufffdF\ufffdo\ufffd\ufffd\ufffd\ufffd\u001ea\ufffd\u001e\u0016+֚\u0004\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdS`+I\ufffd%\ufffdW\ufffd\u001a\ufffd]p\ufffdݖ^r\ufffd\ufffd\u001b\ufffd\ufffdF\ufffd\ufffdlx\ufffdU\ufffd\ufffdH\ufffd\ufffdv5\ufffdb\n\u001f@\ufffd_\u001b\ufffd\ufffd\ufffd\ufffd\u0004X\ufffd\ufffds\ufffds\n\ufffd\ufffdQ\u00265CŢ\ufffd%d\ufffd\u0013\ufffdR\u0013\u0007\ufffd\ufffd\ufffd\u000c\ufffdW\u000e/ҽ\ufffd\ufffd\ufffd:\ufffd\u0011\u0001\ufffd\u0005q\ufffdkcm\ufffdu\ufffd\ufffd0)\ufffd\ufffd0\\Dش\ufffdEl[\ufffd\u0004\u000c\u000f\u0005e\ufffd\ufffd\u0002%\ufffd\ufffd\u001bo\ufffd\u0006\ufffd\ufffd\u0000\ufffdZ\ufffdd2=\ufffd\u001dޘ\ufffd\ufffd\ufffd\ufffd\ufffd[\ufffd\ufffda\u0014';\u0026\ufffda\ufffd{\u00123\ufffd9\u0016\u000e\ufffd\u0018\ufffdȘ3_\ufffd෦\u001d*\u0019\ufffd\u0008'\ufffdB\ufffd\ufffd\ufffd\ufffd\u0008\ufffd$\ufffd\ufffd\ufffd֪\ufffdg\ufffd!\ufffd\u0026\\A\ufffd\u001e\ufffd\ufffdζ\u0012\ufffd܋\ufffd\ufffdpD\ufffd%#\ufffd\ufffd\ufffd썿WK\ufffdS\ufffdw'\ufffd\ufffd\u0004\u0018.\ufffdof\ufffd\ufffd\u001d\ufffd\u001d\ufffdT^F\ufffd2\u001e\u0004T%\ufffdَ\ufffd\ufffd\\\ufffd\ufffd\u003cn\ufffd4\ufffdg\ufffdu\ufffdV\ufffdi\ufffd\ufffdp4\ufffdvp\ufffd\ufffd-\ufffde7\ufffd\ufffd\ufffd\ufffdkS\ufffdЅ\ufffd\u003ea\ufffd\u001f\ufffd\u0010\ufffd\ufffdm\ufffd\ufffd}\ufffdmڮb\ufffdͻpK\u0008\ufffdI\ufffd\ufffd\ufffd\t\ufffd\ufffd\ufffd\ufffd)\ufffd@nE\u0012\ufffd\ufffd2\u0003\ufffd\ufffdɈ\u000bJ$\ufffd\ufffd\ufffd|Ř\ufffdra\ufffdu\ufffd+\u000f\ufffd\ufffd4\u00032\u001d_\u0026d\ufffd^\ufffdߌ\ufffd\u0001\u0004G\ufffd\ufffd)$\ufffd\u000e\ufffd;\ufffd\ufffd\ufffd\ufffd\u000f\ufffd=u犆\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd7\u0005\ufffd\ufffd\ufffd\ufffdsv\ufffd\ufffd\n\ufffd\"\u0019\u0003\ufffd\u000ecƲC\u0004\ufffd\ufffd\ufffd^\ufffd|\ufffd\ufffd\ufffd\u0007h\ufffd+t\ufffd\u0015\ufffd\ufffd\ufffd\ufffd\ufffd}\ufffd\ufffd\ufffd\ufffdm2;\ufffd\ufffd\ufffd\u001e^O\ufffd\ufffdG\ufffd\u003ez\ufffdl\ufffd\ufffd\ufffd4\u0011\u0000\ufffdz\ufffdt\u0008z\ufffdh38\ufffdNqM\ufffd\ufffd\ufffdf\ufffd\u0001\ufffd\\\u0010P#\ufffd\ufffd@y\ufffd\rp\ufffd7o\ufffd\ufffd\u00115SJ\ufffdβ\ufffd3\ufffd\\\ufffdv\ufffd\ufffd\ufffd\ufffd\u0011:\ufffdgG\ufffd\ufffdF\ufffd\ufffdjW\u0015\ufffd\ufffd\ufffd9\u001a\ufffd\ufffd,\ufffds\ufffd\ufffd\ufffddtS\ufffdn֘\ufffdM\ufffdj\ufffd\ufffd\ufffd\ufffdL\ufffd\u0013D\ufffd\"\ufffd;\ufffd^\r\ufffd\ufffd\ufffd\u0013\ufffd'\ufffd\ufffd\ufffd\ufffd\u0017\ufffd\ufffd\ufffd\ufffd\u003e\u001a\u0012\ufffd\u003e/Cj'\ufffd\ufffd\u0007\ufffd\ufffd\ufffd %\u0002GmP\ufffd%@\u0012\u0016ڲ\\AB\u0008\ufffd{)\ufffdf\ufffd9\u0016\ufffd\rO\ufffd\ufffd\u0018\ufffd0R5\u0014edc\u003c«5]\ufffd\ufffd\ufffdL~\ufffd\ufffd{\ufffdm\ufffd\ufffd\u0006\ufffd\ufffd%\ufffd\ufffd\ufffd\ufffd\ufffd]\ufffd\ncٌ@\u003c\ufffdB\ufffd\ufffd\u0011\ufffdj\ufffd\ufffd(\u001cm\ufffdc\ufffd鿛ӡKK\ufffd.\ufffdw\u000f\ufffde\ufffd\ufffd;\ufffde\\\ufffdG\u0005֯\ufffd:e\ufffdȾk\ufffd\ufffd\ufffd/\ufffd?v\u000eܣ\ufffd\ufffd\ufffd@\ufffd\ufffd\ufffd~\ufffd\ufffd#%S\ufffd\u0013\ufffd\n\ufffd\ufffd\ufffdƚ\ufffd\u000c\ufffd튑l\ufffdJBwa\ufffd(\ufffdY绛i\ufffd\ufffd\u001d=\u0016\ufffd\ufffdC\ufffd\ufffd\ufffdn\u0000ש\u001a\ufffd\ufffd\ufffd\ufffd\ufffd\u00161\ufffd\\7\u0013\"\u0018\ufffd\ufffd'\ufffd\ufffd\u0017m\ufffd\ufffd\ufffdn\ufffduX1\\\ufffdL\u001c\ufffd\ufffd_\ufffd\\~T\u0002\n\u0012.\ufffdֻZ\ufffd\ufffd\ufffdx\ufffdQ\ufffdp\ufffd\ufffdu.\ufffd\u0003\u001a\ufffd\ufffd\u001f\ufffdL\ufffd!\ufffd\ufffdj \ufffd8Z\ufffd\ufffd\ufffd\ufffd\u000b\ufffd\ufffd\ufffd\u001b\ufffd\u001dW\ufffd\ufffd\u0000+o|\ufffd\ufffdtNJBx\ufffd\t\ufffd\u0026\ufffd4\ufffd\u001d\ufffd\u001f\u0014#'\u0015cW*\ufffd\ufffd)햁\ufffd\u0004ڻ\ufffd\u0001\ufffdۊ\ufffd\ufffd\ufffdR\ufffd\ufffd-\ufffd\ufffd#1\ufffd\ufffd\ufffd\ufffd\ufffd\u0001)\ufffd\ufffd\ufffdq\ufffd\ufffd\u0019:\u0007\ufffd\ufffd?mQr춏v\u0003\ufffd\u0017\u0015#V6D\ufffdx\ufffd\"\ufffdݎ\ufffd=\ufffd\ufffdHi?\u0016\u003e\ufffd\ufffd\ufffdڻ\u0001_\ufffd\ufffdb\ufffdJ)\r\ufffd\ufffde\ufffd\ufffd\ufffd9\ufffdi\u0000\u0011\ufffd[\ufffd\ufffd\ufffd\ufffdN\ufffdܓ\ufffd\u001d\ufffd\ufffd\ufffd7'\ufffd\ufffd\ufffd]\ufffdR\ufffd\ufffdJp\ufffd\ufffd\ufffd\ufffdx\ufffdI}\ufffd\ufffd\ufffd\u001e\ufffd\ufffd\u0008pU\ufffd(y\ufffd\ufffd\ufffd\ufffd\"\u0016\ufffdN\ufffdՄ\ufffdG\ufffd\u0004\ufffd\u0007\ufffd\ufffd\ufffd\ufffd#\ufffd\ufffd_\ufffd\u001c\ufffd\ufffd\ufffdF\ufffdpd\u0003\ufffdk\u001a\u0012YIt|\ufffd\ufffd\u001d\ufffdLJ;\ufffdX\ufffdoI\ufffd\ufffdR\ufffd\ufffdIE\u0019+\t\ufffd\u0004\ufffdj\ufffd\ufffd@\ufffd\ufffdgP\ufffd\ufffd\ufffd\ufffdс{\ufffd#{\ufffdVկN\ufffd\ufffd#\u001abv\ufffd\ufffdٝ\ufffd\ufffd\ufffd\ufffd^h\ufffd\ufffd+1C\ufffd\ufffd_\ufffd߷\ufffd\ufffd\ufffd2PV\ufffd.%\ufffd\ufffd\ufffd\ufffdg\ufffdU\ufffd\ufffdw\u000c\u0001\ufffd\u001a\ufffd'w\ufffd\ufffd\ufffd\u000e\ufffd`\ufffd/R\u0018\ufffdꎆw\ufffdnLfD\ufffd\ufffd\ufffd\u0001\u0015\ufffd$\ufffd\ufffdך\ufffd\ufffd!ܥ(Z\ufffd˔R\ufffd\n\ufffd1E\u000b\ufffd\u0013P\ufffd\ufffd\ufffdpE\ufffd\n\ufffd\ufffd\ufffdO\ufffd\ufffd;\u003euO\ufffd\u0018\ufffd\r_\ufffd\ufffd;\ufffdg\ufffd3'䆜\ufffd3\tS\ufffd\ufffd(\ufffd8\ufffdʷ\ufffd\ufffd\ufffd\ufffd8\ufffd:gF\ufffd\ufffd \ufffd\ufffds\ufffd\ufffd4\ufffd\ufffd\u001f\ufffd\ufffdl\ufffd\ufffd\ufffdK\u0026\ufffd燝\ufffd\ufffd\ufffd\u0002\t\ufffd\ufffdd\u003c\ufffd\u0007\u0016\u0006\u0004\ufffd|\n\ufffd\ufffd\ufffd\ufffd\"\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdS.\ufffd?\ufffd\u003eA\ufffd\u000cb\u001cR5C|\ufffdF:f\ufffd\u003e\ufffd`\ufffd\ufffd\u001a\ufffd\u0010\ufffdǓus;\ufffd|\ufffdX,\ufffd\u0004f\"S\ufffd\ufffdeİ\ufffdza\ufffd\ufffdqУ/d\u0011,\t\u003cy\ufffd1\u003c\ufffd*\ufffdg\ufffd9\ufffd\ufffd\ufffdk\u00172\ufffdտ\ufffd'U[\ufffdɔ.\ufffd-\ufffd\ufffd\u001fd-\ufffd\"S\ufffd\ufffd\ufffdy\ufffd9\ufffd\ufffdP\ufffd\u0008\u001c䃿6\ufffd\ufffd\ufffdN\u0004q3iZ=n\ufffd\ufffd|k|0\ufffd\r\u0005\ufffd%\ufffd\u0002\ufffd\ufffd\ufffd\ufffd\u0018\t\ufffd\ufffd\ufffd\u001c%\ufffd\u001f\ufffd\ufffd\u001c^\ufffd\u0026\ufffd\ufffd\ufffd\ufffdm\u0007\ufffds\ufffd;c\ufffd\ufffd$\ufffd\u001fV\ufffd\ufffd\u0018:\ufffd\u001c\u0003\ufffd9\ufffdG\ufffdO\ufffd㛟n\ufffd\ufffd\ufffd{\ufffd\ufffdtz|=\ufffd.\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdk\ufffdӟ\ufffd͗\u001c\ufffd[9z\ufffd9\u0005ؿ\ufffdk\ufffd\ufffdٿB\ufffdH\ufffdҺ6\ufffdy\u003c\ufffdxذ-ۄ\\:\u0001k\ufffd\ufffd\ufffd{\ufffd\n=H\ufffd\ufffd1_'\u000f=F\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd~eD\ufffd\u0003o\u000cվ\ufffd\ufffdm\ufffd\ufffd \u0026\r\ufffd\ufffd\ufffd\ufffd\ufffdz\ufffd\ufffd\ufffd\u000f\ufffd\u0004~:D:\u0012\ufffd\ufffd\u0018b{\ufffd)\ufffdR\ufffdG\ufffd\ufffdG)r+B'\ufffd\u0026\ufffd\ufffd\ufffdt\r\ufffd\ufffd\ufffd[\ufffd@\u000cR\u0010+\ufffd\ufffdߞ\ufffd\ufffd\ufffd\u0026\u0008\ufffdY'lS\u0010R\ufffd\ufffdk\u001d\u0018h\ufffd\ufffd?\u0002\ufffd%\ufffdd\ufffd\u000e\ufffdR\ufffd7 \ufffd\ufffd;+:\ufffdt\ufffd\ufffd\ufffd6\u0005\ufffd\ufffd\ufffd\u001e04\ufffd\u0015El\ufffd\ufffd\ufffd\ufffdh\ufffd\ufffd\u0017\ufffd\ufffdIU}\u001f3҅\ufffd\u0005\u0016\n\r\u0008D3b\ufffd\ufffdn3#\ufffd\ufffd\u0017u7\ufffd\ufffd\u0007\u0008\ufffd\ufffds\ufffd\ufffdQ\ufffdD╬\u0007\ufffd\ufffd^q\ufffd\ufffd\u0004\ufffd\ufffd\ufffd\u001e\ufffd\ufffd\ufffd\ufffd\u0001\ufffd\ufffd\\)\ufffdk\u0006\ufffd\ufffd\u000b\ufffd\u000f\ufffd\u001d\ufffd\u000e8\ufffdZ\u000e\ufffdZ\ufffdn\ufffd\ufffd=\ufffdb@\ufffdj\ufffd\ufffd\u0016\ufffd\u0026(\ufffdsr\u000b\u0012X\ufffd\ufffd\u0001e\ufffd\ufffd\ufffd\ufffdզ*#C\u0026\ufffd\u0007\ufffd^o\ufffd{\ufffdMy\ufffd\ufffd*\ufffd^\ufffd\ufffdo\u0015\ufffd\ufffd\u003e\ufffd\ufffdN\ufffd^a\ufffd\ufffd\ufffd\ufffdcAuj\ufffd\ufffd\u0014\ufffd\ufffdo\u0013\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd?\ufffd\u0001\ufffd\ufffd\ufffd\u0019\ufffd\ufffd\u0002\ufffdYQ\ufffd\ufffdA\u0000\u0000","raw":"HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 2876\r\nContent-Encoding: gzip\r\nContent-Type: text/html; charset=utf-8\r\nDate: Thu, 07 Sep 2023 15:34:52 GMT\r\nSet-Cookie: AWSALB=AymL6NoUb7IQ+yLeqn8Nx2AnsAEQE7J/dECy9Mv2IjZxSjlYL3ClOPOJQywrvrB2uDIqCLT8bh+PpOR56TWHYLLnsfn2bXbh+12VUozjFNV+c3PYsBusyKnEB1Ut; Expires=Thu, 14 Sep 2023 15:34:52 GMT; Path=/\r\nSet-Cookie: AWSALBCORS=AymL6NoUb7IQ+yLeqn8Nx2AnsAEQE7J/dECy9Mv2IjZxSjlYL3ClOPOJQywrvrB2uDIqCLT8bh+PpOR56TWHYLLnsfn2bXbh+12VUozjFNV+c3PYsBusyKnEB1Ut; Expires=Thu, 14 Sep 2023 15:34:52 GMT; Path=/; SameSite=None; Secure\r\nX-Backend: ecfca00b-5a9e-4a89-91bd-de41ecbc4611\r\nX-Frame-Options: SAMEORIGIN\r\n\r\n"}}
diff --git a/pkg/input/formats/testdata/ginandjuice.proxify.yaml b/pkg/input/formats/testdata/ginandjuice.proxify.yaml
new file mode 100644
index 00000000..4ebbb308
--- /dev/null
+++ b/pkg/input/formats/testdata/ginandjuice.proxify.yaml
@@ -0,0 +1,269 @@
+timestamp: 2024-02-20T19:24:13+05:30
+url: https://ginandjuice.shop/blog/post?postId=3&source=proxify
+request:
+ header:
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: ginandjuice.shop
+ method: GET
+ path: /blog/post
+ scheme: https
+ raw: |+
+ GET /blog/post?postId=3&source=proxify HTTP/1.1
+ Host: ginandjuice.shop
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+response:
+ header:
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/, AWSALBCORS=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure, session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; Secure; HttpOnly; SameSite=None
+ X-Backend: ea6c1d8c-a8e5-4bef-b8db-879bbb13cf62
+ X-Frame-Options: SAMEORIGIN
+ raw: |+
+ HTTP/1.1 200 OK
+ Connection: close
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/
+ Set-Cookie: AWSALBCORS=9l3X2bRs5JVQp5cO8o7xLckrdo3FZIQzbS0ga0n4ctfDApb/nn0K6AiSLLAMbG7CCDHqKOj9kQdyj6T2RzBDULszJ+2Oy8KcyuOKhFsCGVTVabnJTkVwhyXLciFt; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure
+ Set-Cookie: session=ymwLa8dKmWjLl43BBpQnrp5LkFZraYkp; Secure; HttpOnly; SameSite=None
+ X-Backend: ea6c1d8c-a8e5-4bef-b8db-879bbb13cf62
+ X-Frame-Options: SAMEORIGIN
+
+---
+timestamp: 2024-02-20T19:24:13+05:32
+url: https://ginandjuice.shop/users/3
+request:
+ header:
+ Accept-Encoding: gzip
+ Authorization: Bearer 3x4mpl3t0k3n
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+ host: ginandjuice.shop
+ method: POST
+ path: /catalog/product
+ scheme: https
+ raw: |+
+ POST /catalog/product?productId=3 HTTP/1.1
+ Host: ginandjuice.shop
+ Authorization: Bearer 3x4mpl3t0k3n
+ Accept-Encoding: gzip
+ Connection: close
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
+
+response:
+ header:
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/, AWSALBCORS=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure, session=fFcCUjmQguQy820Y8xrnRypp3KBWSPk6; Secure; HttpOnly; SameSite=None
+ X-Backend: 2235790d-f089-4324-8ac0-f64cc96f2460
+ X-Frame-Options: SAMEORIGIN
+ body: |
+
+
+
+
+
+
+
+
+
+ Fruit Overlays - Product - Gin & Juice Shop
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Fruit Overlays
+
+
+
+ $92.79
+
+
+
+
+ Description:
+ When it comes to hospitality presentation is key, and nothing looks better than a well-dressed drink. We know gin fans like plenty of fruit in their glasses, some a bit more than they really need, but hey ho, each to their own. But what about fruit not inside your glass, but classily arranged over your glass? In comes Fruitus overlayus, the best way to jazz up any party. The possible colour combinations are endless, just picture that! All you need is a nice selection of small fruits, or maybe even use our Fruit Curliwurlier to add a dash of even more drama, and we will do the rest. This one is a real winner at our Christmas and New year’s outings, give it a go and turn some heads.
+ CONTENTS: 12 cocktail sticks.
+ HOW TO USE: Let your creative juices flow (Pun intended), and spend some time working on your colour coordination, try not to think too much about it, just do it! Pick up one of the Fruitus overlayus sticks and carefully slide the fruit along until there is a small space on either end of the stick. Balance the stick across the rim of the glass. Ta-Da! Your first fruit overlay. Keep going until you have as many overlays as you need. You can always purchase more at any time with a discount on bulk buys.
+
+
+
+
+
+
+
+
+
+
+
+ View cart
+
+
+
+
+
+
+
+
+
+
+ raw: |+
+ HTTP/1.1 200 OK
+ Connection: close
+ Content-Encoding: gzip
+ Content-Type: text/html; charset=utf-8
+ Date: Tue, 20 Feb 2024 13:54:13 GMT
+ Set-Cookie: AWSALB=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/
+ Set-Cookie: AWSALBCORS=Rzm8ZSSL/yQq1mG1SdGmWAahqexWvOcjIhlNKm0wBnk4jvY3Hdy3mRc+NKoMRNJ2RW+FNbtRk7DX+itnfzjMvKNpwtLWWAafxeKybc+v351g0MsLycRNQF5fG78y; Expires=Tue, 27 Feb 2024 13:54:13 GMT; Path=/; SameSite=None; Secure
+ Set-Cookie: session=fFcCUjmQguQy820Y8xrnRypp3KBWSPk6; Secure; HttpOnly; SameSite=None
+ X-Backend: 2235790d-f089-4324-8ac0-f64cc96f2460
+ X-Frame-Options: SAMEORIGIN
\ No newline at end of file
diff --git a/pkg/input/formats/testdata/openapi.yaml b/pkg/input/formats/testdata/openapi.yaml
new file mode 100644
index 00000000..93a37df7
--- /dev/null
+++ b/pkg/input/formats/testdata/openapi.yaml
@@ -0,0 +1,582 @@
+openapi: 3.1.0
+info:
+ title: VAmPI
+ description: OpenAPI v3 specs for VAmPI
+ version: '0.1'
+servers:
+ - url: http://hackthebox:5000
+components: {}
+paths:
+ /createdb:
+ get:
+ tags:
+ - db-init
+ summary: Creates and populates the database with dummy data
+ description: Creates and populates the database with dummy data
+ operationId: api_views.main.populate_db
+ responses:
+ '200':
+ description: Creates and populates the database with dummy data
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ example: 'Database populated.'
+ /:
+ get:
+ tags:
+ - home
+ summary: VAmPI home
+ description: >-
+ VAmPI is a vulnerable on purpose API. It was created in order to
+ evaluate the efficiency of third party tools in identifying
+ vulnerabilities in APIs but it can also be used in learning/teaching
+ purposes.
+ operationId: api_views.main.basic
+ responses:
+ '200':
+ description: Home - Help
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ example: 'VAmPI the Vulnerable API'
+ help:
+ type: string
+ example: 'VAmPI is a vulnerable on purpose API. It was created in order to evaluate the efficiency of third party tools in identifying vulnerabilities in APIs but it can also be used in learning/teaching purposes.'
+ vulnerable:
+ type: number
+ example: 1
+ /users/v1:
+ get:
+ tags:
+ - users
+ summary: Retrieves all users
+ description: Displays all users with basic information
+ operationId: api_views.users.get_all_users
+ responses:
+ '200':
+ description: See basic info about all users
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ email:
+ type: string
+ example: 'mail1@mail.com'
+ username:
+ type: string
+ example: 'name1'
+ /users/v1/_debug:
+ get:
+ tags:
+ - users
+ summary: Retrieves all details for all users
+ description: Displays all details for all users
+ operationId: api_views.users.debug
+ responses:
+ '200':
+ description: See all details of the users
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ admin:
+ type: boolean
+ example: false
+ email:
+ type: string
+ example: 'mail1@mail.com'
+ password:
+ type: string
+ example: 'pass1'
+ username:
+ type: string
+ example: 'name1'
+ /users/v1/register:
+ post:
+ tags:
+ - users
+ summary: Register new user
+ description: Register new user
+ operationId: api_views.users.register_user
+ requestBody:
+ description: Username of the user
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ username:
+ type: string
+ example: 'John.Doe'
+ password:
+ type: string
+ example: 'password123'
+ email:
+ type: string
+ example: 'user@tempmail.com'
+ required: true
+ responses:
+ '200':
+ description: Sucessfully created user
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ example: 'Successfully registered. Login to receive an auth token.'
+ status:
+ type: string
+ enum: ['success', 'fail']
+ example: 'success'
+ '400':
+ description: Invalid request
+ content: {}
+ /users/v1/login:
+ post:
+ tags:
+ - users
+ summary: Login to VAmPI
+ description: Login to VAmPI
+ operationId: api_views.users.login_user
+ requestBody:
+ description: Username of the user
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ username:
+ type: string
+ example: 'John.Doe'
+ password:
+ type: string
+ example: 'password123'
+ required: true
+ responses:
+ '200':
+ description: Sucessfully logged in user
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ auth_token:
+ type: string
+ example: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NzAxNjA2MTcsImlhdCI6MTY3MDE2MDU1Nywic3ViIjoiSm9obi5Eb2UifQ.n17N4AxTbL4_z65-NR46meoytauPDjImUxrLiUMSTQw'
+ message:
+ type: string
+ example: 'Successfully logged in.'
+ status:
+ type: string
+ enum: ['success', 'fail']
+ example: 'success'
+ '400':
+ description: Invalid request
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Password is not correct for the given username.'
+ /users/v1/{username}:
+ get:
+ tags:
+ - users
+ summary: Retrieves user by username
+ description: Displays user by username
+ operationId: api_views.users.get_by_username
+ parameters:
+ - name: username
+ in: path
+ description: retrieve username data
+ required: true
+ schema:
+ type: string
+ example: 'John.Doe'
+ responses:
+ '200':
+ description: Successfully display user info
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ username:
+ type: string
+ example: 'John.Doe'
+ email:
+ type: string
+ example: 'user@tempmail.com'
+ '404':
+ description: User not found
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'User not found'
+
+ delete:
+ tags:
+ - users
+ summary: Deletes user by username (Only Admins)
+ description: Deletes user by username (Only Admins)
+ operationId: api_views.users.delete_user
+ parameters:
+ - name: username
+ in: path
+ description: Delete username
+ required: true
+ schema:
+ type: string
+ example: 'name1'
+ responses:
+ '200':
+ description: Sucessfully deleted user
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ example: 'User deleted.'
+ status:
+ type: string
+ enum: ['success', 'fail']
+ example: 'success'
+ '401':
+ description: User not authorized
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ example: 'fail'
+ enum: ['fail']
+ message:
+ type: string
+ example: 'Only Admins may delete users!'
+ '404':
+ description: User not found
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ example: 'fail'
+ enum: ['fail']
+ message:
+ type: string
+ example: 'User not found!'
+ /users/v1/{username}/email:
+ put:
+ tags:
+ - users
+ summary: Update users email
+ description: Update a single users email
+ operationId: api_views.users.update_email
+ parameters:
+ - name: username
+ in: path
+ description: username to update email
+ required: true
+ schema:
+ type: string
+ example: 'name1'
+ requestBody:
+ description: field to update
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ email:
+ type: string
+ example: 'mail3@mail.com'
+ required: true
+ responses:
+ '204':
+ description: Sucessfully updated user email
+ content: {}
+ '400':
+ description: Invalid request
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Please Provide a valid email address.'
+ '401':
+ description: User not authorized
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Invalid Token'
+ /users/v1/{username}/password:
+ put:
+ tags:
+ - users
+ summary: Update users password
+ description: Update users password
+ operationId: api_views.users.update_password
+ parameters:
+ - name: username
+ in: path
+ description: username to update password
+ required: true
+ schema:
+ type: string
+ example: 'name1'
+ requestBody:
+ description: field to update
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ password:
+ type: string
+ example: 'pass4'
+ required: true
+ responses:
+ '204':
+ description: Sucessfully updated users password
+ content: {}
+ '400':
+ description: Invalid request
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Malformed Data'
+ '401':
+ description: User not authorized
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Invalid Token'
+ /books/v1:
+ get:
+ tags:
+ - books
+ summary: Retrieves all books
+ description: Retrieves all books
+ operationId: api_views.books.get_all_books
+ responses:
+ '200':
+ description: See all books
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ Books:
+ type: array
+ items:
+ type: object
+ properties:
+ book_title:
+ type: string
+ user:
+ type: string
+ example:
+ Books:
+ - book_title: 'bookTitle77'
+ user: 'name1'
+ - book_title: 'bookTitle85'
+ user: 'name2'
+ - book_title: 'bookTitle47'
+ user: 'admin'
+ post:
+ tags:
+ - books
+ summary: Add new book
+ description: Add new book
+ operationId: api_views.books.add_new_book
+ requestBody:
+ description: >-
+ Add new book with title and secret content only available to the user
+ who added it.
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ book_title:
+ type: string
+ example: 'book99'
+ secret:
+ type: string
+ example: 'pass1secret'
+ required: true
+ responses:
+ '200':
+ description: Sucessfully added a book
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
+ example: 'Book has been added.'
+ status:
+ type: string
+ enum: ['success', 'fail']
+ example: 'success'
+ '400':
+ description: Invalid request
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Book Already exists!'
+ '401':
+ description: User not authorized
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Invalid Token'
+ /books/v1/{book_title}:
+ get:
+ tags:
+ - books
+ summary: Retrieves book by title along with secret
+ description: >-
+ Retrieves book by title along with secret. Only the owner may retrieve
+ it
+ operationId: api_views.books.get_by_title
+ parameters:
+ - name: book_title
+ in: path
+ description: retrieve book data
+ required: true
+ schema:
+ type: string
+ example: 'bookTitle77'
+ responses:
+ '200':
+ description: Successfully retrieve book info
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ book_title:
+ type: string
+ example: 'bookTitle77'
+ owner:
+ type: string
+ example: 'name1'
+ secret:
+ type: string
+ example: 'secret for bookTitle77'
+ '401':
+ description: User not authorized
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Invalid Token'
+ '404':
+ description: Book not found
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: string
+ enum: ['fail']
+ example: 'fail'
+ message:
+ type: string
+ example: 'Book not found!'
\ No newline at end of file
diff --git a/pkg/input/formats/testdata/postman.json b/pkg/input/formats/testdata/postman.json
new file mode 100644
index 00000000..50044e4e
--- /dev/null
+++ b/pkg/input/formats/testdata/postman.json
@@ -0,0 +1,159 @@
+{
+ "info": {
+ "_postman_id": "20a3fd41-6a86-4e49-8860-f796559d0223",
+ "name": "advancedsearch",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+ },
+ "item": [
+ {
+ "name": "List Projects, Assets and Hosts",
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "value": "application/json",
+ "type": "text"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://127.0.0.1:8000/api/v1/search/",
+ "protocol": "http",
+ "host": ["127", "0", "0", "1"],
+ "port": "8000",
+ "path": ["api", "v1", "search", ""]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "List Assets and Hosts",
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "type": "text",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://127.0.0.1:8000/api/v1/search/?projectId=1,2",
+ "protocol": "http",
+ "host": ["127", "0", "0", "1"],
+ "port": "8000",
+ "path": ["api", "v1", "search", ""],
+ "query": [
+ {
+ "key": "projectId",
+ "value": "1,2"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "List Hosts",
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "type": "text",
+ "value": "application/json"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://127.0.0.1:8000/api/v1/search/?projectId=1,2&assetId=1,2",
+ "protocol": "http",
+ "host": ["127", "0", "0", "1"],
+ "port": "8000",
+ "path": ["api", "v1", "search", ""],
+ "query": [
+ {
+ "key": "projectId",
+ "value": "1,2"
+ },
+ {
+ "key": "assetId",
+ "value": "1,2"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Search Request",
+ "request": {
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "name": "Content-Type",
+ "value": "application/json",
+ "type": "text"
+ }
+ ],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n\t\"query\": \"query\",\n\t\"projectId\": [4,3,4],\n\t\"assetId\": [2,3,4],\n\t\"hostId\": [1,2,3],\n \"limit\": 10,\n \"offset\": 10\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://127.0.0.1:8000/api/v1/search/",
+ "protocol": "http",
+ "host": ["127", "0", "0", "1"],
+ "port": "8000",
+ "path": ["api", "v1", "search", ""]
+ }
+ },
+ "response": []
+ }
+ ],
+ "protocolProfileBehavior": {}
+}
diff --git a/pkg/input/formats/testdata/swagger.yaml b/pkg/input/formats/testdata/swagger.yaml
new file mode 100644
index 00000000..cd20b184
--- /dev/null
+++ b/pkg/input/formats/testdata/swagger.yaml
@@ -0,0 +1,37 @@
+swagger: "2.0"
+info:
+ title: Sample API
+ description: API description in Markdown.
+ version: 1.0.0
+host: localhost
+basePath: /v1
+schemes:
+ - https
+paths:
+ /users:
+ get:
+ summary: Returns a list of users.
+ description: Optional extended description in Markdown.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: OK
+ /users/{userId}:
+ get:
+ summary: Returns a user by ID.
+ parameters:
+ - in: path
+ name: userId
+ required: true
+ type: integer
+ default: 1
+ description: Parameter description in Markdown.
+ - in: query
+ name: test
+ type: string
+ enum: [asc, desc]
+ description: Type of query
+ responses:
+ 200:
+ description: OK
\ No newline at end of file
diff --git a/pkg/input/formats/yaml/multidoc.go b/pkg/input/formats/yaml/multidoc.go
new file mode 100644
index 00000000..dc258408
--- /dev/null
+++ b/pkg/input/formats/yaml/multidoc.go
@@ -0,0 +1,78 @@
+package yaml
+
+import (
+ "io"
+ "os"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ YamlUtil "gopkg.in/yaml.v3"
+)
+
+// YamlMultiDocFormat is a Yaml format parser for nuclei
+// input HTTP requests with multiple documents separated by ---
+type YamlMultiDocFormat struct {
+ opts formats.InputFormatOptions
+}
+
+// New creates a new JSON format parser
+func New() *YamlMultiDocFormat {
+ return &YamlMultiDocFormat{}
+}
+
+var _ formats.Format = &YamlMultiDocFormat{}
+
+// proxifyRequest is a request for proxify
+type proxifyRequest struct {
+ URL string `json:"url"`
+ Request struct {
+ Header map[string]string `json:"header"`
+ Body string `json:"body"`
+ Raw string `json:"raw"`
+ } `json:"request"`
+}
+
+// Name returns the name of the format
+func (j *YamlMultiDocFormat) Name() string {
+ return "yaml"
+}
+
+func (j *YamlMultiDocFormat) SetOptions(options formats.InputFormatOptions) {
+ j.opts = options
+}
+
+// Parse parses the input and calls the provided callback
+// function for each RawRequest it discovers.
+func (j *YamlMultiDocFormat) Parse(input string, resultsCb formats.ParseReqRespCallback) error {
+ file, err := os.Open(input)
+ if err != nil {
+ return errors.Wrap(err, "could not open json file")
+ }
+ defer file.Close()
+
+ decoder := YamlUtil.NewDecoder(file)
+ for {
+ var request proxifyRequest
+ err := decoder.Decode(&request)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return errors.Wrap(err, "could not decode json file")
+ }
+ if strings.TrimSpace(request.Request.Raw) == "" {
+ continue
+ }
+
+ rawRequest, err := types.ParseRawRequestWithURL(request.Request.Raw, request.URL)
+ if err != nil {
+ gologger.Warning().Msgf("multidoc-yaml: Could not parse raw request %s: %s\n", request.URL, err)
+ continue
+ }
+ resultsCb(rawRequest)
+ }
+ return nil
+}
diff --git a/pkg/input/formats/yaml/multidoc_test.go b/pkg/input/formats/yaml/multidoc_test.go
new file mode 100644
index 00000000..6275eae5
--- /dev/null
+++ b/pkg/input/formats/yaml/multidoc_test.go
@@ -0,0 +1,28 @@
+package yaml
+
+import (
+ "testing"
+
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/stretchr/testify/require"
+)
+
+func TestYamlFormatterParse(t *testing.T) {
+ format := New()
+
+ proxifyInputFile := "../testdata/ginandjuice.proxify.yaml"
+
+ expectedUrls := []string{
+ "https://ginandjuice.shop/blog/post?postId=3&source=proxify",
+ "https://ginandjuice.shop/users/3",
+ }
+
+ var urls []string
+ err := format.Parse(proxifyInputFile, func(request *types.RequestResponse) bool {
+ urls = append(urls, request.URL.String())
+ return false
+ })
+ require.Nilf(t, err, "error parsing yaml file: %v", err)
+ require.Len(t, urls, len(expectedUrls), "invalid number of urls")
+ require.ElementsMatch(t, urls, expectedUrls, "invalid urls")
+}
diff --git a/pkg/input/provider/chunked.go b/pkg/input/provider/chunked.go
new file mode 100644
index 00000000..904acd5b
--- /dev/null
+++ b/pkg/input/provider/chunked.go
@@ -0,0 +1,29 @@
+package provider
+
+import (
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
+)
+
+// TODO: Implement ChunkedInputProvider
+// 1. Lazy loading of input targets
+// 2. Load and execute in chunks that fit in memory
+// 3. Eliminate use of HybridMap since it performs worst due to marshal/unmarshal overhead
+
+// ChunkedInputProvider is an input providing chunked targets instead of loading all at once
+type ChunkedInputProvider interface {
+ // Count returns total targets for input provider
+ Count() int64
+ // Iterate over all inputs in order
+ Iterate(callback func(value *contextargs.MetaInput) bool)
+ // Set adds item to input provider
+ Set(value string)
+ // SetWithProbe adds item to input provider with http probing
+ SetWithProbe(value string, probe types.InputLivenessProbe) error
+ // SetWithExclusions adds item to input provider if it doesn't match any of the exclusions
+ SetWithExclusions(value string) error
+ // InputType returns the type of input provider
+ InputType() string
+ // Switches to the next chunk/batch of input
+ NextChunk() bool
+}
diff --git a/pkg/input/provider/http/multiformat.go b/pkg/input/provider/http/multiformat.go
new file mode 100644
index 00000000..ee95079e
--- /dev/null
+++ b/pkg/input/provider/http/multiformat.go
@@ -0,0 +1,120 @@
+package http
+
+import (
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats/burp"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats/json"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats/openapi"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats/swagger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats/yaml"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
+)
+
+// HttpMultiFormatOptions contains options for the http input provider
+type HttpMultiFormatOptions struct {
+ // Options for the http input provider
+ Options formats.InputFormatOptions
+ // InputFile is the file containing the input
+ InputFile string
+ // InputMode is the mode of input
+ InputMode string
+}
+
+// HttpInputProvider implements an input provider for nuclei that loads
+// inputs from multiple formats like burp, openapi, postman,proxify, etc.
+type HttpInputProvider struct {
+ format formats.Format
+ inputFile string
+ count int64
+}
+
+// NewHttpInputProvider creates a new input provider for nuclei from a file
+func NewHttpInputProvider(opts *HttpMultiFormatOptions) (*HttpInputProvider, error) {
+ var format formats.Format
+ for _, provider := range providersList {
+ if provider.Name() == opts.InputMode {
+ format = provider
+ }
+ }
+ if format == nil {
+ return nil, errors.Errorf("invalid input mode %s", opts.InputMode)
+ }
+ format.SetOptions(opts.Options)
+ // Do a first pass over the input to identify any errors
+ // and get the count of the input file as well
+ count := int64(0)
+ parseErr := format.Parse(opts.InputFile, func(request *types.RequestResponse) bool {
+ count++
+ return false
+ })
+ if parseErr != nil {
+ return nil, errors.Wrap(parseErr, "could not parse input file")
+ }
+ return &HttpInputProvider{format: format, inputFile: opts.InputFile, count: count}, nil
+}
+
+// Count returns the number of items for input provider
+func (i *HttpInputProvider) Count() int64 {
+ return i.count
+}
+
+// Iterate over all inputs in order
+func (i *HttpInputProvider) Iterate(callback func(value *contextargs.MetaInput) bool) {
+ err := i.format.Parse(i.inputFile, func(request *types.RequestResponse) bool {
+ return callback(&contextargs.MetaInput{
+ ReqResp: request,
+ })
+ })
+ if err != nil {
+ gologger.Warning().Msgf("Could not parse input file while iterating: %s\n", err)
+ }
+}
+
+// Set adds item to input provider
+// No-op for this provider
+func (i *HttpInputProvider) Set(value string) {}
+
+// SetWithProbe adds item to input provider with http probing
+// No-op for this provider
+func (i *HttpInputProvider) SetWithProbe(value string, probe types.InputLivenessProbe) error {
+ return nil
+}
+
+// SetWithExclusions adds item to input provider if it doesn't match any of the exclusions
+// No-op for this provider
+func (i *HttpInputProvider) SetWithExclusions(value string) error {
+ return nil
+}
+
+// InputType returns the type of input provider
+func (i *HttpInputProvider) InputType() string {
+ return "MultiFormatInputProvider"
+}
+
+// Close closes the input provider and cleans up any resources
+// No-op for this provider
+func (i *HttpInputProvider) Close() {}
+
+// Supported Providers
+var providersList = []formats.Format{
+ burp.New(),
+ json.New(),
+ yaml.New(),
+ openapi.New(),
+ swagger.New(),
+}
+
+// SupportedFormats returns the list of supported formats in comma-separated
+// manner
+func SupportedFormats() string {
+ var formats []string
+ for _, provider := range providersList {
+ formats = append(formats, provider.Name())
+ }
+ return strings.Join(formats, ", ")
+}
diff --git a/pkg/input/provider/interface.go b/pkg/input/provider/interface.go
new file mode 100644
index 00000000..cb48fc76
--- /dev/null
+++ b/pkg/input/provider/interface.go
@@ -0,0 +1,126 @@
+package provider
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider/http"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider/list"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
+ configTypes "github.com/projectdiscovery/nuclei/v3/pkg/types"
+ errorutil "github.com/projectdiscovery/utils/errors"
+)
+
+var (
+ ErrNotImplemented = errorutil.NewWithFmt("provider %s does not implement %s")
+ ErrInactiveInput = fmt.Errorf("input is inactive")
+)
+
+const (
+ MultiFormatInputProvider = "MultiFormatInputProvider"
+ ListInputProvider = "ListInputProvider"
+ SimpleListInputProvider = "SimpleInputProvider"
+)
+
+// IsErrNotImplemented checks if an error is a not implemented error
+func IsErrNotImplemented(err error) bool {
+ if err == nil {
+ return false
+ }
+ if strings.Contains(err.Error(), "provider") && strings.Contains(err.Error(), "does not implement") {
+ return true
+ }
+ return false
+}
+
+// Validate all Implementations
+var (
+ // SimpleInputProvider is more like a No-Op and returns given list of urls as input
+ _ InputProvider = &SimpleInputProvider{}
+ // HttpInputProvider provides support for formats that contain complete request/response
+ // like burp, openapi, postman,proxify, etc.
+ _ InputProvider = &http.HttpInputProvider{}
+ // ListInputProvider provides support for simple list of urls or files etc
+ _ InputProvider = &list.ListInputProvider{}
+)
+
+// InputProvider is unified input provider interface that provides
+// processed inputs to nuclei by parsing and providing different
+// formats such as list,openapi,postman,proxify,burp etc.
+type InputProvider interface {
+ // Count returns total targets for input provider
+ Count() int64
+ // Iterate over all inputs in order
+ Iterate(callback func(value *contextargs.MetaInput) bool)
+ // Set adds item to input provider
+ Set(value string)
+ // SetWithProbe adds item to input provider with http probing
+ SetWithProbe(value string, probe types.InputLivenessProbe) error
+ // SetWithExclusions adds item to input provider if it doesn't match any of the exclusions
+ SetWithExclusions(value string) error
+ // InputType returns the type of input provider
+ InputType() string
+ // Close the input provider and cleanup any resources
+ Close()
+}
+
+// InputOptions contains options for input provider
+type InputOptions struct {
+ // Options for global config
+ Options *configTypes.Options
+ // NotFoundCallback is the callback to call when input is not found
+ // only supported in list input provider
+ NotFoundCallback func(template string) bool
+}
+
+// NewInputProvider creates a new input provider based on the options
+// and returns it
+func NewInputProvider(opts InputOptions) (InputProvider, error) {
+ // optionally load generated vars values if available
+ val, err := formats.ReadOpenAPIVarDumpFile()
+ if err != nil && !errors.Is(err, formats.ErrNoVarsDumpFile) {
+ // log error and continue
+ gologger.Error().Msgf("Could not read vars dump file: %s\n", err)
+ }
+ extraVars := make(map[string]interface{})
+ if val != nil {
+ for _, v := range val.Var {
+ v = strings.TrimSpace(v)
+ // split into key value
+ parts := strings.SplitN(v, "=", 2)
+ if len(parts) == 2 {
+ extraVars[parts[0]] = parts[1]
+ }
+ }
+ }
+
+ // check if input provider is supported
+ if strings.EqualFold(opts.Options.InputFileMode, "list") {
+ // create a new list input provider
+ return list.New(&list.Options{
+ Options: opts.Options,
+ NotFoundCallback: opts.NotFoundCallback,
+ })
+ } else {
+ // use HttpInputProvider
+ return http.NewHttpInputProvider(&http.HttpMultiFormatOptions{
+ InputFile: opts.Options.TargetsFilePath,
+ InputMode: opts.Options.InputFileMode,
+ Options: formats.InputFormatOptions{
+ Variables: generators.MergeMaps(extraVars, opts.Options.Vars.AsMap()),
+ SkipFormatValidation: opts.Options.SkipFormatValidation,
+ RequiredOnly: opts.Options.FormatUseRequiredOnly,
+ },
+ })
+ }
+}
+
+// SupportedFormats returns all supported input formats of nuclei
+func SupportedInputFormats() string {
+ return "list, " + http.SupportedFormats()
+}
diff --git a/pkg/core/inputs/hybrid/hmap.go b/pkg/input/provider/list/hmap.go
similarity index 87%
rename from pkg/core/inputs/hybrid/hmap.go
rename to pkg/input/provider/list/hmap.go
index bbc675dc..f7e3bd14 100644
--- a/pkg/core/inputs/hybrid/hmap.go
+++ b/pkg/input/provider/list/hmap.go
@@ -1,6 +1,6 @@
-// Package hybrid implements a hybrid hmap/filekv backed input provider
+// package list implements a hybrid hmap/filekv backed input provider
// for nuclei that can either stream or store results using different kv stores.
-package hybrid
+package list
import (
"bufio"
@@ -19,6 +19,7 @@ import (
"github.com/projectdiscovery/hmap/filekv"
"github.com/projectdiscovery/hmap/store/hybrid"
"github.com/projectdiscovery/mapcidr/asn"
+ providerTypes "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/uncover"
@@ -34,8 +35,9 @@ import (
const DefaultMaxDedupeItemsCount = 10000
-// Input is a hmap/filekv backed nuclei Input provider
-type Input struct {
+// ListInputProvider is a hmap/filekv backed nuclei ListInputProvider provider
+// it supports list type of input ex: urls,file,stdin,uncover,etc. (i.e just url not complete request/response)
+type ListInputProvider struct {
ipOptions *ipOptions
inputCount int64
excludedCount int64
@@ -59,7 +61,7 @@ type Options struct {
// New creates a new hmap backed nuclei Input Provider
// and initializes it based on the passed options Model.
-func New(opts *Options) (*Input, error) {
+func New(opts *Options) (*ListInputProvider, error) {
options := opts.Options
hm, err := hybrid.New(hybrid.DefaultDiskOptions)
@@ -67,7 +69,7 @@ func New(opts *Options) (*Input, error) {
return nil, errors.Wrap(err, "could not create temporary input file")
}
- input := &Input{
+ input := &ListInputProvider{
hostMap: hm,
ipOptions: &ipOptions{
ScanAllIPs: options.ScanAllIPs,
@@ -105,109 +107,39 @@ func New(opts *Options) (*Input, error) {
return input, nil
}
-// Close closes the input provider
-func (i *Input) Close() {
- i.hostMap.Close()
- if i.hostMapStream != nil {
- i.hostMapStream.Close()
- }
+// Count returns the input count
+func (i *ListInputProvider) Count() int64 {
+ return i.inputCount
}
-// initializeInputSources initializes the input sources for hmap input
-func (i *Input) initializeInputSources(opts *Options) error {
- options := opts.Options
-
- // Handle targets flags
- for _, target := range options.Targets {
- switch {
- case iputil.IsCIDR(target):
- ips := expand.CIDR(target)
- i.addTargets(ips)
- case asn.IsASN(target):
- ips := expand.ASN(target)
- i.addTargets(ips)
- default:
- i.Set(target)
- }
- }
-
- // Handle stdin
- if options.Stdin {
- i.scanInputFromReader(readerutil.TimeoutReader{Reader: os.Stdin, Timeout: time.Duration(options.InputReadTimeout)})
- }
-
- // Handle target file
- if options.TargetsFilePath != "" {
- input, inputErr := os.Open(options.TargetsFilePath)
- if inputErr != nil {
- // Handle cloud based input here.
- if opts.NotFoundCallback == nil || !opts.NotFoundCallback(options.TargetsFilePath) {
- return errors.Wrap(inputErr, "could not open targets file")
+// Iterate over all inputs in order
+func (i *ListInputProvider) Iterate(callback func(value *contextargs.MetaInput) bool) {
+ if i.hostMapStream != nil {
+ i.hostMapStreamOnce.Do(func() {
+ if err := i.hostMapStream.Process(); err != nil {
+ gologger.Warning().Msgf("error in stream mode processing: %s\n", err)
}
- }
- if input != nil {
- i.scanInputFromReader(input)
- input.Close()
- }
+ })
}
- if options.Uncover && options.UncoverQuery != nil {
- gologger.Info().Msgf("Running uncover query against: %s", strings.Join(options.UncoverEngine, ","))
- uncoverOpts := &uncoverlib.Options{
- Agents: options.UncoverEngine,
- Queries: options.UncoverQuery,
- Limit: options.UncoverLimit,
- MaxRetry: options.Retries,
- Timeout: options.Timeout,
- RateLimit: uint(options.UncoverRateLimit),
- RateLimitUnit: time.Minute, // default unit is minute
- }
- ch, err := uncover.GetTargetsFromUncover(context.TODO(), options.UncoverField, uncoverOpts)
- if err != nil {
+ callbackFunc := func(k, _ []byte) error {
+ metaInput := &contextargs.MetaInput{}
+ if err := metaInput.Unmarshal(string(k)); err != nil {
return err
}
- for c := range ch {
- i.Set(c)
+ if !callback(metaInput) {
+ return io.EOF
}
+ return nil
}
-
- if len(options.ExcludeTargets) > 0 {
- for _, target := range options.ExcludeTargets {
- switch {
- case iputil.IsCIDR(target):
- ips := expand.CIDR(target)
- i.removeTargets(ips)
- case asn.IsASN(target):
- ips := expand.ASN(target)
- i.removeTargets(ips)
- default:
- i.Del(target)
- }
- }
- }
-
- return nil
-}
-
-// scanInputFromReader scans a line of input from reader and passes it for storage
-func (i *Input) scanInputFromReader(reader io.Reader) {
- scanner := bufio.NewScanner(reader)
- for scanner.Scan() {
- item := scanner.Text()
- switch {
- case iputil.IsCIDR(item):
- ips := expand.CIDR(item)
- i.addTargets(ips)
- case asn.IsASN(item):
- ips := expand.ASN(item)
- i.addTargets(ips)
- default:
- i.Set(item)
- }
+ if i.hostMapStream != nil {
+ _ = i.hostMapStream.Scan(callbackFunc)
+ } else {
+ i.hostMap.Scan(callbackFunc)
}
}
// Set normalizes and stores passed input values
-func (i *Input) Set(value string) {
+func (i *ListInputProvider) Set(value string) {
URL := strings.TrimSpace(value)
if URL == "" {
return
@@ -289,21 +221,138 @@ func (i *Input) Set(value string) {
}
}
+// SetWithProbe only sets the input if it is live
+func (i *ListInputProvider) SetWithProbe(value string, probe providerTypes.InputLivenessProbe) error {
+ probedValue, err := probe.ProbeURL(value)
+ if err != nil {
+ return err
+ }
+ i.Set(probedValue)
+ return nil
+}
+
// SetWithExclusions normalizes and stores passed input values if not excluded
-func (i *Input) SetWithExclusions(value string) {
+func (i *ListInputProvider) SetWithExclusions(value string) error {
URL := strings.TrimSpace(value)
if URL == "" {
- return
+ return nil
}
if i.isExcluded(URL) {
i.skippedCount++
- return
+ return nil
}
i.Set(URL)
+ return nil
+}
+
+// ListInputProvider is a hmap/filekv backed nuclei ListInputProvider provider
+func (i *ListInputProvider) InputType() string {
+ return "ListInputProvider"
+}
+
+// Close closes the input provider
+func (i *ListInputProvider) Close() {
+ i.hostMap.Close()
+ if i.hostMapStream != nil {
+ i.hostMapStream.Close()
+ }
+}
+
+// initializeInputSources initializes the input sources for hmap input
+func (i *ListInputProvider) initializeInputSources(opts *Options) error {
+ options := opts.Options
+
+ // Handle targets flags
+ for _, target := range options.Targets {
+ switch {
+ case iputil.IsCIDR(target):
+ ips := expand.CIDR(target)
+ i.addTargets(ips)
+ case asn.IsASN(target):
+ ips := expand.ASN(target)
+ i.addTargets(ips)
+ default:
+ i.Set(target)
+ }
+ }
+
+ // Handle stdin
+ if options.Stdin {
+ i.scanInputFromReader(readerutil.TimeoutReader{Reader: os.Stdin, Timeout: time.Duration(options.InputReadTimeout)})
+ }
+
+ // Handle target file
+ if options.TargetsFilePath != "" {
+ input, inputErr := os.Open(options.TargetsFilePath)
+ if inputErr != nil {
+ // Handle cloud based input here.
+ if opts.NotFoundCallback == nil || !opts.NotFoundCallback(options.TargetsFilePath) {
+ return errors.Wrap(inputErr, "could not open targets file")
+ }
+ }
+ if input != nil {
+ i.scanInputFromReader(input)
+ input.Close()
+ }
+ }
+ if options.Uncover && options.UncoverQuery != nil {
+ gologger.Info().Msgf("Running uncover query against: %s", strings.Join(options.UncoverEngine, ","))
+ uncoverOpts := &uncoverlib.Options{
+ Agents: options.UncoverEngine,
+ Queries: options.UncoverQuery,
+ Limit: options.UncoverLimit,
+ MaxRetry: options.Retries,
+ Timeout: options.Timeout,
+ RateLimit: uint(options.UncoverRateLimit),
+ RateLimitUnit: time.Minute, // default unit is minute
+ }
+ ch, err := uncover.GetTargetsFromUncover(context.TODO(), options.UncoverField, uncoverOpts)
+ if err != nil {
+ return err
+ }
+ for c := range ch {
+ i.Set(c)
+ }
+ }
+
+ if len(options.ExcludeTargets) > 0 {
+ for _, target := range options.ExcludeTargets {
+ switch {
+ case iputil.IsCIDR(target):
+ ips := expand.CIDR(target)
+ i.removeTargets(ips)
+ case asn.IsASN(target):
+ ips := expand.ASN(target)
+ i.removeTargets(ips)
+ default:
+ i.Del(target)
+ }
+ }
+ }
+
+ return nil
+}
+
+// scanInputFromReader scans a line of input from reader and passes it for storage
+func (i *ListInputProvider) scanInputFromReader(reader io.Reader) {
+ scanner := bufio.NewScanner(reader)
+ for scanner.Scan() {
+ item := scanner.Text()
+ switch {
+ case iputil.IsCIDR(item):
+ ips := expand.CIDR(item)
+ i.addTargets(ips)
+ case asn.IsASN(item):
+ ips := expand.ASN(item)
+ i.addTargets(ips)
+ default:
+ i.Set(item)
+ }
+ }
}
// isExcluded checks if a URL is in the exclusion list
-func (i *Input) isExcluded(URL string) bool {
+func (i *ListInputProvider) isExcluded(URL string) bool {
metaInput := &contextargs.MetaInput{Input: URL}
key, err := metaInput.MarshalString()
if err != nil {
@@ -315,7 +364,7 @@ func (i *Input) isExcluded(URL string) bool {
return exists
}
-func (i *Input) Del(value string) {
+func (i *ListInputProvider) Del(value string) {
URL := strings.TrimSpace(value)
if URL == "" {
return
@@ -398,7 +447,7 @@ func (i *Input) Del(value string) {
}
// setItem in the kv store
-func (i *Input) setItem(metaInput *contextargs.MetaInput) {
+func (i *ListInputProvider) setItem(metaInput *contextargs.MetaInput) {
key, err := metaInput.MarshalString()
if err != nil {
gologger.Warning().Msgf("%s\n", err)
@@ -417,7 +466,7 @@ func (i *Input) setItem(metaInput *contextargs.MetaInput) {
}
// setItem in the kv store
-func (i *Input) delItem(metaInput *contextargs.MetaInput) {
+func (i *ListInputProvider) delItem(metaInput *contextargs.MetaInput) {
targetUrl, err := urlutil.ParseURL(metaInput.Input, true)
if err != nil {
gologger.Warning().Msgf("%s\n", err)
@@ -450,52 +499,20 @@ func (i *Input) delItem(metaInput *contextargs.MetaInput) {
}
// setHostMapStream sets item in stream mode
-func (i *Input) setHostMapStream(data string) {
+func (i *ListInputProvider) setHostMapStream(data string) {
if _, err := i.hostMapStream.Merge([][]byte{[]byte(data)}); err != nil {
gologger.Warning().Msgf("%s\n", err)
return
}
}
-// Count returns the input count
-func (i *Input) Count() int64 {
- return i.inputCount
-}
-
-// Scan iterates the input and each found item is passed to the
-// callback consumer.
-func (i *Input) Scan(callback func(value *contextargs.MetaInput) bool) {
- if i.hostMapStream != nil {
- i.hostMapStreamOnce.Do(func() {
- if err := i.hostMapStream.Process(); err != nil {
- gologger.Warning().Msgf("error in stream mode processing: %s\n", err)
- }
- })
- }
- callbackFunc := func(k, _ []byte) error {
- metaInput := &contextargs.MetaInput{}
- if err := metaInput.Unmarshal(string(k)); err != nil {
- return err
- }
- if !callback(metaInput) {
- return io.EOF
- }
- return nil
- }
- if i.hostMapStream != nil {
- _ = i.hostMapStream.Scan(callbackFunc)
- } else {
- i.hostMap.Scan(callbackFunc)
- }
-}
-
-func (i *Input) addTargets(targets []string) {
+func (i *ListInputProvider) addTargets(targets []string) {
for _, target := range targets {
i.Set(target)
}
}
-func (i *Input) removeTargets(targets []string) {
+func (i *ListInputProvider) removeTargets(targets []string) {
for _, target := range targets {
metaInput := &contextargs.MetaInput{Input: target}
i.delItem(metaInput)
diff --git a/pkg/core/inputs/hybrid/hmap_test.go b/pkg/input/provider/list/hmap_test.go
similarity index 97%
rename from pkg/core/inputs/hybrid/hmap_test.go
rename to pkg/input/provider/list/hmap_test.go
index c11c6efd..c3fb4a66 100644
--- a/pkg/core/inputs/hybrid/hmap_test.go
+++ b/pkg/input/provider/list/hmap_test.go
@@ -1,4 +1,4 @@
-package hybrid
+package list
import (
"net"
@@ -32,7 +32,7 @@ func Test_expandCIDR(t *testing.T) {
for _, tt := range tests {
hm, err := hybrid.New(hybrid.DefaultDiskOptions)
require.Nil(t, err, "could not create temporary input file")
- input := &Input{hostMap: hm}
+ input := &ListInputProvider{hostMap: hm}
ips := expand.CIDR(tt.cidr)
input.addTargets(ips)
@@ -127,7 +127,7 @@ func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
for _, tt := range tests {
hm, err := hybrid.New(hybrid.DefaultDiskOptions)
require.Nil(t, err, "could not create temporary input file")
- input := &Input{
+ input := &ListInputProvider{
hostMap: hm,
ipOptions: &ipOptions{
ScanAllIPs: true,
@@ -169,7 +169,7 @@ func Test_expandASNInputValue(t *testing.T) {
for _, tt := range tests {
hm, err := hybrid.New(hybrid.DefaultDiskOptions)
require.Nil(t, err, "could not create temporary input file")
- input := &Input{hostMap: hm}
+ input := &ListInputProvider{hostMap: hm}
// get the IP addresses for ASN number
ips := expand.ASN(tt.asn)
input.addTargets(ips)
diff --git a/pkg/core/inputs/hybrid/tests/AS134029.txt b/pkg/input/provider/list/tests/AS134029.txt
similarity index 100%
rename from pkg/core/inputs/hybrid/tests/AS134029.txt
rename to pkg/input/provider/list/tests/AS134029.txt
diff --git a/pkg/core/inputs/hybrid/tests/AS14421.txt b/pkg/input/provider/list/tests/AS14421.txt
similarity index 100%
rename from pkg/core/inputs/hybrid/tests/AS14421.txt
rename to pkg/input/provider/list/tests/AS14421.txt
diff --git a/pkg/core/inputs/hybrid/options.go b/pkg/input/provider/list/utils.go
similarity index 83%
rename from pkg/core/inputs/hybrid/options.go
rename to pkg/input/provider/list/utils.go
index 8c7f13af..221b40a8 100644
--- a/pkg/core/inputs/hybrid/options.go
+++ b/pkg/input/provider/list/utils.go
@@ -1,4 +1,4 @@
-package hybrid
+package list
type ipOptions struct {
ScanAllIPs bool
diff --git a/pkg/input/provider/simple.go b/pkg/input/provider/simple.go
new file mode 100644
index 00000000..71b280c2
--- /dev/null
+++ b/pkg/input/provider/simple.go
@@ -0,0 +1,73 @@
+package provider
+
+import (
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
+)
+
+// SimpleInputProvider is a simple input provider for nuclei
+// that acts like a No-Op and returns given list of urls as input
+type SimpleInputProvider struct {
+ Inputs []*contextargs.MetaInput
+}
+
+// NewSimpleInputProvider creates a new simple input provider
+func NewSimpleInputProvider() *SimpleInputProvider {
+ return &SimpleInputProvider{
+ Inputs: make([]*contextargs.MetaInput, 0),
+ }
+}
+
+// NewSimpleInputProviderWithUrls creates a new simple input provider with the given urls
+func NewSimpleInputProviderWithUrls(urls ...string) *SimpleInputProvider {
+ provider := NewSimpleInputProvider()
+ for _, url := range urls {
+ provider.Set(url)
+ }
+ return provider
+}
+
+// Count returns the total number of targets for the input provider
+func (s *SimpleInputProvider) Count() int64 {
+ return int64(len(s.Inputs))
+}
+
+// Iterate over all inputs in order
+func (s *SimpleInputProvider) Iterate(callback func(value *contextargs.MetaInput) bool) {
+ for _, input := range s.Inputs {
+ if !callback(input) {
+ break
+ }
+ }
+}
+
+// Set adds an item to the input provider
+func (s *SimpleInputProvider) Set(value string) {
+ s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: value})
+}
+
+// SetWithProbe adds an item to the input provider with HTTP probing
+func (s *SimpleInputProvider) SetWithProbe(value string, probe types.InputLivenessProbe) error {
+ probedValue, err := probe.ProbeURL(value)
+ if err != nil {
+ return err
+ }
+ s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: probedValue})
+ return nil
+}
+
+// SetWithExclusions adds an item to the input provider if it doesn't match any of the exclusions
+func (s *SimpleInputProvider) SetWithExclusions(value string) error {
+ s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: value})
+ return nil
+}
+
+// InputType returns the type of input provider
+func (s *SimpleInputProvider) InputType() string {
+ return "SimpleInputProvider"
+}
+
+// Close the input provider and cleanup any resources
+func (s *SimpleInputProvider) Close() {
+ // no-op
+}
diff --git a/pkg/input/input.go b/pkg/input/transform.go
similarity index 100%
rename from pkg/input/input.go
rename to pkg/input/transform.go
diff --git a/pkg/input/input_test.go b/pkg/input/transform_test.go
similarity index 100%
rename from pkg/input/input_test.go
rename to pkg/input/transform_test.go
diff --git a/pkg/input/types/http.go b/pkg/input/types/http.go
new file mode 100644
index 00000000..62b25249
--- /dev/null
+++ b/pkg/input/types/http.go
@@ -0,0 +1,305 @@
+package types
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/sha256"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/textproto"
+ "strings"
+ "sync"
+
+ "github.com/projectdiscovery/retryablehttp-go"
+ "github.com/projectdiscovery/utils/conversion"
+ mapsutil "github.com/projectdiscovery/utils/maps"
+ urlutil "github.com/projectdiscovery/utils/url"
+)
+
+var (
+ _ json.Marshaler = &RequestResponse{}
+ _ json.Unmarshaler = &RequestResponse{}
+)
+
+// RequestResponse is a struct containing request and response
+// obtained from one of the input formats.
+// this struct can be considered as pd standard for request and response
+type RequestResponse struct {
+ // Timestamp is the timestamp of the request
+ // Timestamp string `json:"timestamp"`
+ // URL is the URL of the request
+ URL urlutil.URL `json:"url"`
+ // Request is the request of the request
+ Request *HttpRequest `json:"request"`
+ // Response is the response of the request
+ Response *HttpResponse `json:"response"`
+
+ // unexported / internal fields
+ // lazy build request
+ req *retryablehttp.Request `json:"-"`
+ reqErr error `json:"-"`
+ once sync.Once `json:"-"`
+}
+
+// Clone clones the request response
+func (rr *RequestResponse) Clone() *RequestResponse {
+ cloned := &RequestResponse{
+ URL: *rr.URL.Clone(),
+ }
+ if rr.Request != nil {
+ cloned.Request = rr.Request.Clone()
+ }
+ if rr.Response != nil {
+ cloned.Response = rr.Response.Clone()
+ }
+ return cloned
+}
+
+// BuildRequest builds a retryablehttp request from the request response
+func (rr *RequestResponse) BuildRequest() (*retryablehttp.Request, error) {
+ rr.once.Do(func() {
+ urlx := rr.URL.Clone()
+ var body io.Reader = nil
+ if rr.Request.Body != "" {
+ body = strings.NewReader(rr.Request.Body)
+ }
+ req, err := retryablehttp.NewRequestFromURL(rr.Request.Method, urlx, body)
+ if err != nil {
+ rr.reqErr = fmt.Errorf("could not create request: %s", err)
+ return
+ }
+ rr.Request.Headers.Iterate(func(k, v string) bool {
+ req.Header.Add(k, v)
+ return true
+ })
+ rr.req = req
+ })
+ return rr.req, rr.reqErr
+}
+
+// To be implemented in the future
+// func (rr *RequestResponse) BuildUnsafeRequest()
+
+// ID returns a unique id/hash for request response
+func (rr *RequestResponse) ID() string {
+ var buff bytes.Buffer
+ buff.WriteString(rr.URL.String())
+ if rr.Request != nil {
+ buff.WriteString(rr.Request.ID())
+ }
+ if rr.Response != nil {
+ buff.WriteString(rr.Response.ID())
+ }
+ val := sha256.Sum256(buff.Bytes())
+ return string(val[:])
+}
+
+// MarshalJSON marshals the request response to json
+func (rr *RequestResponse) MarshalJSON() ([]byte, error) {
+ m := make(map[string]interface{})
+ m["url"] = rr.URL.String()
+ reqBin, err := json.Marshal(rr.Request)
+ if err != nil {
+ return nil, err
+ }
+ m["request"] = reqBin
+ respBin, err := json.Marshal(rr.Response)
+ if err != nil {
+ return nil, err
+ }
+ m["response"] = respBin
+ return json.Marshal(m)
+}
+
+// UnmarshalJSON unmarshals the request response from json
+func (rr *RequestResponse) UnmarshalJSON(data []byte) error {
+ var m map[string]json.RawMessage
+ if err := json.Unmarshal(data, &m); err != nil {
+ return err
+ }
+ urlStr, ok := m["url"]
+ if !ok {
+ return fmt.Errorf("missing url in request response")
+ }
+ parsed, err := urlutil.ParseAbsoluteURL(string(urlStr), false)
+ if err != nil {
+ return err
+ }
+ rr.URL = *parsed
+
+ reqBin, ok := m["request"]
+ if ok {
+ var req HttpRequest
+ if err := json.Unmarshal(reqBin, &req); err != nil {
+ return err
+ }
+ rr.Request = &req
+ }
+
+ respBin, ok := m["response"]
+ if ok {
+ var resp HttpResponse
+ if err := json.Unmarshal(respBin, &resp); err != nil {
+ return err
+ }
+ rr.Response = &resp
+ }
+ return nil
+}
+
+// HttpRequest is a struct containing the http request
+type HttpRequest struct {
+ // method of the request
+ Method string `json:"method"`
+ // headers of the request
+ Headers mapsutil.OrderedMap[string, string] `json:"headers"`
+ // body of the request
+ Body string `json:"body"`
+ // raw request (includes everything including method, headers, body, etc)
+ Raw string `json:"raw"`
+}
+
+// ID returns a unique id/hash for raw request
+func (hr *HttpRequest) ID() string {
+ val := sha256.Sum256([]byte(hr.Raw))
+ return string(val[:])
+}
+
+// Clone clones the request
+func (hr *HttpRequest) Clone() *HttpRequest {
+ return &HttpRequest{
+ Method: hr.Method,
+ Headers: hr.Headers.Clone(),
+ Body: hr.Body,
+ Raw: hr.Raw,
+ }
+}
+
+type HttpResponse struct {
+ // status code of the response
+ StatusCode int `json:"status_code"`
+ // headers of the response
+ Headers mapsutil.OrderedMap[string, string] `json:"headers"`
+ // body of the response
+ Body string `json:"body"`
+ // raw response (includes everything including status code, headers, body, etc)
+ Raw string `json:"raw"`
+}
+
+// Id returns a unique id/hash for raw response
+func (hr *HttpResponse) ID() string {
+ val := sha256.Sum256([]byte(hr.Raw))
+ return string(val[:])
+}
+
+// Clone clones the response
+func (hr *HttpResponse) Clone() *HttpResponse {
+ return &HttpResponse{
+ StatusCode: hr.StatusCode,
+ Headers: hr.Headers.Clone(),
+ Body: hr.Body,
+ Raw: hr.Raw,
+ }
+}
+
+// ParseRawRequest parses a raw request from a string
+// and returns the request and response object
+// Note: it currently does not parse response and is meant to be added manually since its a optional field
+func ParseRawRequest(raw string) (rr *RequestResponse, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("panic: %v", r)
+ }
+ }()
+ protoReader := textproto.NewReader(bufio.NewReader(strings.NewReader(raw)))
+ methodLine, err := protoReader.ReadLine()
+ if err != nil {
+ return nil, fmt.Errorf("failed to read method line: %s", err)
+ }
+ rr = &RequestResponse{
+ Request: &HttpRequest{},
+ }
+ /// must contain at least 3 parts
+ parts := strings.Split(methodLine, " ")
+ if len(parts) < 3 {
+ return nil, fmt.Errorf("invalid method line: %s", methodLine)
+ }
+ method := parts[0]
+ rr.Request.Method = method
+
+ // parse relative url
+ urlx, err := urlutil.ParseRawRelativePath(parts[1], true)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse url: %s", err)
+ }
+ rr.URL = *urlx
+
+ // parse host line
+ hostLine, err := protoReader.ReadLine()
+ if err != nil {
+ return nil, fmt.Errorf("failed to read host line: %s", err)
+ }
+ sep := strings.Index(hostLine, ":")
+ if sep <= 0 || sep >= len(hostLine)-1 {
+ return nil, fmt.Errorf("invalid host line: %s", hostLine)
+ }
+ hostLine = hostLine[sep+2:]
+ rr.URL.Host = hostLine
+
+ // parse headers
+ rr.Request.Headers = mapsutil.NewOrderedMap[string, string]()
+ for {
+ line, err := protoReader.ReadLine()
+ if err != nil {
+ return nil, fmt.Errorf("failed to read header line: %s", err)
+ }
+ if line == "" {
+ // end of headers next is body
+ break
+ }
+ parts := strings.SplitN(line, ":", 2)
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("invalid header line: %s", line)
+ }
+ rr.Request.Headers.Set(parts[0], parts[1][1:])
+ }
+
+ // parse body
+ rr.Request.Body = ""
+ var buff bytes.Buffer
+ _, err = buff.ReadFrom(protoReader.R)
+ if err != nil && err != io.EOF {
+ return nil, fmt.Errorf("failed to read body: %s", err)
+ }
+ if buff.Len() > 0 {
+ // yaml may include trailing newlines
+ // remove them if present
+ bin := buff.Bytes()
+ if bin[len(bin)-1] == '\n' {
+ bin = bin[:len(bin)-1]
+ }
+ if bin[len(bin)-1] == '\r' || bin[len(bin)-1] == '\n' {
+ bin = bin[:len(bin)-1]
+ }
+ rr.Request.Body = conversion.String(bin)
+ }
+
+ // set raw request
+ rr.Request.Raw = raw
+ return rr, nil
+}
+
+// ParseRawRequestWithURL parses a raw request from a string with given url
+func ParseRawRequestWithURL(raw, url string) (rr *RequestResponse, err error) {
+ rr, err = ParseRawRequest(raw)
+ if err != nil {
+ return nil, err
+ }
+ urlx, err := urlutil.ParseAbsoluteURL(url, false)
+ if err != nil {
+ return nil, err
+ }
+ rr.URL = *urlx
+ return rr, nil
+}
diff --git a/pkg/input/types/http_test.go b/pkg/input/types/http_test.go
new file mode 100644
index 00000000..d674c563
--- /dev/null
+++ b/pkg/input/types/http_test.go
@@ -0,0 +1,67 @@
+package types
+
+import (
+ "io"
+ "net/http"
+ "net/http/httputil"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+// Possibly add more tests here.
+func TestParseHttpRequest(t *testing.T) {
+ tests := []struct {
+ name string
+ method string
+ url string
+ headerKey string
+ headerValue string
+ body string
+ contentLength string
+ }{
+ {"GET Request", "GET", "example.com/", "X-Test", "test", "", "0"},
+ {"POST Request with body", "POST", "example.com/resource", "Content-Type", "application/json", `{"key":"value"}`, "15"},
+ {"PUT Request with body", "PUT", "example.com/update", "Content-Type", "text/plain", "update data", "11"},
+ {"DELETE Request", "DELETE", "example.com/delete", "X-User", "user1", "", "0"},
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ var bodyReader io.Reader
+ if tc.body != "" {
+ bodyReader = strings.NewReader(tc.body)
+ }
+ req, err := http.NewRequest(tc.method, "http://"+tc.url, bodyReader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Add(tc.headerKey, tc.headerValue)
+ if tc.contentLength != "" {
+ req.Header.Add("Content-Length", tc.contentLength)
+ }
+ binx, err := httputil.DumpRequestOut(req, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rr, err := ParseRawRequest(string(binx))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if rr.Request.Method != tc.method {
+ t.Fatalf("invalid method: got %v want %v", rr.Request.Method, tc.method)
+ }
+ require.Equal(t, tc.url, rr.URL.String())
+ val, _ := rr.Request.Headers.Get(tc.headerKey)
+ require.Equal(t, tc.headerValue, val)
+ if tc.body != "" {
+ require.Equal(t, tc.body, rr.Request.Body)
+ contentLengthVal, _ := rr.Request.Headers.Get("Content-Length")
+ require.Equal(t, tc.contentLength, contentLengthVal)
+ }
+
+ t.Log(*rr.Request)
+ })
+ }
+}
diff --git a/pkg/input/types/probe.go b/pkg/input/types/probe.go
new file mode 100644
index 00000000..006faada
--- /dev/null
+++ b/pkg/input/types/probe.go
@@ -0,0 +1,7 @@
+package types
+
+// InputLivenessProbe is an interface for probing the liveness of an input
+type InputLivenessProbe interface {
+ // ProbeURL probes the scheme for a URL. first HTTPS is tried
+ ProbeURL(input string) (string, error)
+}
diff --git a/pkg/operators/operators.go b/pkg/operators/operators.go
index 1d6103fe..41fafc83 100644
--- a/pkg/operators/operators.go
+++ b/pkg/operators/operators.go
@@ -287,7 +287,7 @@ func (operators *Operators) Execute(data map[string]interface{}, match MatchFunc
}
if isMatch, matched := match(data, matcher); isMatch {
if isDebug { // matchers without an explicit name or with AND condition should only be made visible if debug is enabled
- matcherName := getMatcherName(matcher, matcherIndex)
+ matcherName := GetMatcherName(matcher, matcherIndex)
result.Matches[matcherName] = matched
} else { // if it's a "named" matcher with OR condition, then display it
if matcherCondition == matchers.ORCondition && matcher.Name != "" {
@@ -331,7 +331,8 @@ func (operators *Operators) Execute(data map[string]interface{}, match MatchFunc
return nil, false
}
-func getMatcherName(matcher *matchers.Matcher, matcherIndex int) string {
+// GetMatcherName returns matchername of given matcher
+func GetMatcherName(matcher *matchers.Matcher, matcherIndex int) string {
if matcher.Name != "" {
return matcher.Name
} else {
@@ -376,3 +377,20 @@ func getExtractedValue(values []string) any {
return values
}
}
+
+// EvalBoolSlice evaluates a slice of bools using a logical AND
+func EvalBoolSlice(slice []bool, isAnd bool) bool {
+ if len(slice) == 0 {
+ return false
+ }
+
+ result := slice[0]
+ for _, b := range slice[1:] {
+ if isAnd {
+ result = result && b
+ } else {
+ result = result || b
+ }
+ }
+ return result
+}
diff --git a/pkg/parsers/parser.go b/pkg/parsers/parser.go
index 16ebb379..25e01b63 100644
--- a/pkg/parsers/parser.go
+++ b/pkg/parsers/parser.go
@@ -146,6 +146,7 @@ const (
HeadlessFlagWarningStats = "headless-flag-missing-warnings"
TemplatesExecutedStats = "templates-executed"
CodeFlagWarningStats = "code-flag-missing-warnings"
+ FuzzFlagWarningStats = "fuzz-flag-missing-warnings"
// Note: this is redefined in workflows.go to avoid circular dependency, so make sure to keep it in sync
SkippedUnsignedStats = "skipped-unsigned-stats" // tracks loading of unsigned templates
)
@@ -161,6 +162,7 @@ func init() {
stats.NewEntry(HeadlessFlagWarningStats, "Excluded %d headless template[s] (disabled as default), use -headless option to run headless templates.")
stats.NewEntry(CodeFlagWarningStats, "Excluded %d code template[s] (disabled as default), use -code option to run code templates.")
stats.NewEntry(TemplatesExecutedStats, "Excluded %d template[s] with known weak matchers / tags excluded from default run using .nuclei-ignore")
+ stats.NewEntry(FuzzFlagWarningStats, "Excluded %d fuzz template[s] (disabled as default), use -fuzz option to run fuzz templates.")
stats.NewEntry(SkippedUnsignedStats, "Skipping %d unsigned template[s]")
}
diff --git a/pkg/protocols/common/automaticscan/automaticscan.go b/pkg/protocols/common/automaticscan/automaticscan.go
index 4a6f0491..81939471 100644
--- a/pkg/protocols/common/automaticscan/automaticscan.go
+++ b/pkg/protocols/common/automaticscan/automaticscan.go
@@ -15,7 +15,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
- "github.com/projectdiscovery/nuclei/v3/pkg/core/inputs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
@@ -45,7 +45,7 @@ type Options struct {
ExecuterOpts protocols.ExecutorOptions
Store *loader.Store
Engine *core.Engine
- Target core.InputProvider
+ Target provider.InputProvider
}
// Service is a service for automatic scan execution
@@ -53,7 +53,7 @@ type Service struct {
opts protocols.ExecutorOptions
store *loader.Store
engine *core.Engine
- target core.InputProvider
+ target provider.InputProvider
wappalyzer *wappalyzer.Wappalyze
childExecuter *core.ChildExecuter
httpclient *retryablehttp.Client
@@ -129,7 +129,7 @@ func (s *Service) Execute() error {
gologger.Info().Msgf("Executing Automatic scan on %d target[s]", s.target.Count())
// setup host concurrency
sg := sizedwaitgroup.New(s.opts.Options.BulkSize)
- s.target.Scan(func(value *contextargs.MetaInput) bool {
+ s.target.Iterate(func(value *contextargs.MetaInput) bool {
sg.Add()
go func(input *contextargs.MetaInput) {
defer sg.Done()
@@ -185,7 +185,8 @@ func (s *Service) executeAutomaticScanOnTarget(input *contextargs.MetaInput) {
execOptions := s.opts.Copy()
execOptions.Progress = &testutils.MockProgressClient{} // stats are not supported yet due to centralized logic and cannot be reinitialized
eng.SetExecuterOptions(execOptions)
- tmp := eng.ExecuteScanWithOpts(finalTemplates, &inputs.SimpleInputProvider{Inputs: []*contextargs.MetaInput{input}}, true)
+
+ tmp := eng.ExecuteScanWithOpts(finalTemplates, provider.NewSimpleInputProviderWithUrls(input.Input), true)
s.hasResults.Store(tmp.Load())
}
diff --git a/pkg/protocols/common/contextargs/metainput.go b/pkg/protocols/common/contextargs/metainput.go
index 4027bd7d..afda2fda 100644
--- a/pkg/protocols/common/contextargs/metainput.go
+++ b/pkg/protocols/common/contextargs/metainput.go
@@ -7,6 +7,8 @@ import (
"strings"
jsoniter "github.com/json-iterator/go"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
+ urlutil "github.com/projectdiscovery/utils/url"
)
// MetaInput represents a target with metadata (TODO: replace with https://github.com/projectdiscovery/metainput)
@@ -17,6 +19,9 @@ type MetaInput struct {
CustomIP string `json:"customIP,omitempty"`
// hash of the input
hash string `json:"-"`
+
+ // ReqResp is the raw request for the input
+ ReqResp *types.RequestResponse `json:"raw-request,omitempty"`
}
func (metaInput *MetaInput) marshalToBuffer() (bytes.Buffer, error) {
@@ -25,11 +30,31 @@ func (metaInput *MetaInput) marshalToBuffer() (bytes.Buffer, error) {
return b, err
}
+// Target returns the target of the metainput
+func (metaInput *MetaInput) Target() string {
+ if metaInput.ReqResp != nil && metaInput.ReqResp.URL.URL != nil {
+ return metaInput.ReqResp.URL.String()
+ }
+ return metaInput.Input
+}
+
+// URL returns request url
+func (metaInput *MetaInput) URL() (*urlutil.URL, error) {
+ instance, err := urlutil.ParseAbsoluteURL(metaInput.Target(), false)
+ if err != nil {
+ return nil, err
+ }
+ return instance, nil
+}
+
// ID returns a unique id/hash for metainput
func (metaInput *MetaInput) ID() string {
if metaInput.CustomIP != "" {
return fmt.Sprintf("%s-%s", metaInput.Input, metaInput.CustomIP)
}
+ if metaInput.ReqResp != nil {
+ return metaInput.ReqResp.ID()
+ }
return metaInput.Input
}
@@ -58,16 +83,23 @@ func (metaInput *MetaInput) Unmarshal(data string) error {
}
func (metaInput *MetaInput) Clone() *MetaInput {
- return &MetaInput{
+ input := &MetaInput{
Input: metaInput.Input,
CustomIP: metaInput.CustomIP,
}
+ if metaInput.ReqResp != nil {
+ input.ReqResp = metaInput.ReqResp.Clone()
+ }
+ return input
}
func (metaInput *MetaInput) PrettyPrint() string {
if metaInput.CustomIP != "" {
return fmt.Sprintf("%s [%s]", metaInput.Input, metaInput.CustomIP)
}
+ if metaInput.ReqResp != nil {
+ return fmt.Sprintf("%s [%s]", metaInput.ReqResp.URL.String(), metaInput.ReqResp.Request.Method)
+ }
return metaInput.Input
}
@@ -77,7 +109,11 @@ func (metaInput *MetaInput) GetScanHash(templateId string) string {
// but that totally changes the scanID/hash so to avoid that we compute hash only once
// and reuse it for all subsequent calls
if metaInput.hash == "" {
- metaInput.hash = getMd5Hash(templateId + ":" + metaInput.Input + ":" + metaInput.CustomIP)
+ var rawRequest string
+ if metaInput.ReqResp != nil {
+ rawRequest = metaInput.ReqResp.ID()
+ }
+ metaInput.hash = getMd5Hash(templateId + ":" + metaInput.Input + ":" + metaInput.CustomIP + rawRequest)
}
return metaInput.hash
}
diff --git a/pkg/protocols/common/fuzz/execute.go b/pkg/protocols/common/fuzz/execute.go
deleted file mode 100644
index 1a4700b0..00000000
--- a/pkg/protocols/common/fuzz/execute.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package fuzz
-
-import (
- "regexp"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
- "github.com/projectdiscovery/retryablehttp-go"
- errorutil "github.com/projectdiscovery/utils/errors"
-)
-
-// ExecuteRuleInput is the input for rule Execute function
-type ExecuteRuleInput struct {
- // Input is the context args input
- Input *contextargs.Context
- // Callback is the callback for generated rule requests
- Callback func(GeneratedRequest) bool
- // InteractURLs contains interact urls for execute call
- InteractURLs []string
- // Values contains dynamic values for the rule
- Values map[string]interface{}
- // BaseRequest is the base http request for fuzzing rule
- BaseRequest *retryablehttp.Request
-}
-
-// GeneratedRequest is a single generated request for rule
-type GeneratedRequest struct {
- // Request is the http request for rule
- Request *retryablehttp.Request
- // InteractURLs is the list of interactsh urls
- InteractURLs []string
- // DynamicValues contains dynamic values map
- DynamicValues map[string]interface{}
-}
-
-// Execute executes a fuzzing rule accepting a callback on which
-// generated requests are returned.
-//
-// Input is not thread safe and should not be shared between concurrent
-// goroutines.
-func (rule *Rule) Execute(input *ExecuteRuleInput) error {
- if input.BaseRequest == nil {
- return errorutil.NewWithTag("fuzz", "base request is nil for rule %v", rule)
- }
- if !rule.isExecutable(input.BaseRequest) {
- return errorutil.NewWithTag("fuzz", "rule is not executable on %v", input.BaseRequest.URL.String())
- }
- baseValues := input.Values
- if rule.generator == nil {
- evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(baseValues, rule.options.Interactsh)
- input.Values = generators.MergeMaps(evaluatedValues, baseValues, rule.options.Constants)
- input.InteractURLs = interactURLs
- err := rule.executeRuleValues(input)
- return err
- }
- iterator := rule.generator.NewIterator()
- for {
- values, next := iterator.Value()
- if !next {
- return nil
- }
- evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(generators.MergeMaps(values, baseValues), rule.options.Interactsh)
- input.InteractURLs = interactURLs
- input.Values = generators.MergeMaps(values, evaluatedValues, baseValues, rule.options.Constants)
-
- if err := rule.executeRuleValues(input); err != nil {
- return err
- }
- }
-}
-
-// isExecutable returns true if the rule can be executed based on provided input
-func (rule *Rule) isExecutable(req *retryablehttp.Request) bool {
- if !req.Query().IsEmpty() && rule.partType == queryPartType {
- return true
- }
- if len(req.Header) > 0 && rule.partType == headersPartType {
- return true
- }
- return false
-}
-
-// executeRuleValues executes a rule with a set of values
-func (rule *Rule) executeRuleValues(input *ExecuteRuleInput) error {
- for _, payload := range rule.Fuzz {
- if err := rule.executePartRule(input, payload); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Compile compiles a fuzzing rule and initializes it for operation
-func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *protocols.ExecutorOptions) error {
- // If a payload generator is specified from base request, use it
- // for payload values.
- if generator != nil {
- rule.generator = generator
- }
- rule.options = options
-
- // Resolve the default enums
- if rule.Mode != "" {
- if valueType, ok := stringToModeType[rule.Mode]; !ok {
- return errors.Errorf("invalid mode value specified: %s", rule.Mode)
- } else {
- rule.modeType = valueType
- }
- } else {
- rule.modeType = multipleModeType
- }
- if rule.Part != "" {
- if valueType, ok := stringToPartType[rule.Part]; !ok {
- return errors.Errorf("invalid part value specified: %s", rule.Part)
- } else {
- rule.partType = valueType
- }
- } else {
- rule.partType = queryPartType
- }
-
- if rule.Type != "" {
- if valueType, ok := stringToRuleType[rule.Type]; !ok {
- return errors.Errorf("invalid type value specified: %s", rule.Type)
- } else {
- rule.ruleType = valueType
- }
- } else {
- rule.ruleType = replaceRuleType
- }
-
- // Initialize other required regexes and maps
- if len(rule.Keys) > 0 {
- rule.keysMap = make(map[string]struct{})
- }
- for _, key := range rule.Keys {
- rule.keysMap[strings.ToLower(key)] = struct{}{}
- }
- for _, value := range rule.ValuesRegex {
- compiled, err := regexp.Compile(value)
- if err != nil {
- return errors.Wrap(err, "could not compile value regex")
- }
- rule.valuesRegex = append(rule.valuesRegex, compiled)
- }
- for _, value := range rule.KeysRegex {
- compiled, err := regexp.Compile(value)
- if err != nil {
- return errors.Wrap(err, "could not compile key regex")
- }
- rule.keysRegex = append(rule.keysRegex, compiled)
- }
- return nil
-}
diff --git a/pkg/protocols/common/fuzz/execute_test.go b/pkg/protocols/common/fuzz/execute_test.go
deleted file mode 100644
index a922fbb7..00000000
--- a/pkg/protocols/common/fuzz/execute_test.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package fuzz
-
-import (
- "github.com/projectdiscovery/retryablehttp-go"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestRuleIsExecutable(t *testing.T) {
- rule := &Rule{Part: "query"}
- err := rule.Compile(nil, nil)
- require.NoError(t, err, "could not compile rule")
-
- req, err := retryablehttp.NewRequest("GET", "https://example.com/?url=localhost", nil)
- require.NoError(t, err, "could not build request")
-
- result := rule.isExecutable(req)
- require.True(t, result, "could not get correct result")
-
- req, err = retryablehttp.NewRequest("GET", "https://example.com/", nil)
- require.NoError(t, err, "could not build request")
-
- result = rule.isExecutable(req)
- require.False(t, result, "could not get correct result")
-}
diff --git a/pkg/protocols/common/fuzz/parts.go b/pkg/protocols/common/fuzz/parts.go
deleted file mode 100644
index 533de60a..00000000
--- a/pkg/protocols/common/fuzz/parts.go
+++ /dev/null
@@ -1,211 +0,0 @@
-package fuzz
-
-import (
- "context"
- "io"
- "net/http"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/projectdiscovery/gologger"
- "github.com/projectdiscovery/useragent"
-
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
- "github.com/projectdiscovery/nuclei/v3/pkg/types"
- "github.com/projectdiscovery/retryablehttp-go"
- sliceutil "github.com/projectdiscovery/utils/slice"
- urlutil "github.com/projectdiscovery/utils/url"
-)
-
-// executePartRule executes part rules based on type
-func (rule *Rule) executePartRule(input *ExecuteRuleInput, payload string) error {
- switch rule.partType {
- case queryPartType:
- return rule.executeQueryPartRule(input, payload)
- case headersPartType:
- return rule.executeHeadersPartRule(input, payload)
- }
- return nil
-}
-
-// executeHeadersPartRule executes headers part rules
-func (rule *Rule) executeHeadersPartRule(input *ExecuteRuleInput, payload string) error {
- // clone the request to avoid modifying the original
- originalRequest := input.BaseRequest
- req := originalRequest.Clone(context.TODO())
- // Also clone headers
- headers := req.Header.Clone()
-
- for key, values := range originalRequest.Header {
- cloned := sliceutil.Clone(values)
- for i, value := range values {
- if !rule.matchKeyOrValue(key, value) {
- continue
- }
- var evaluated string
- evaluated, input.InteractURLs = rule.executeEvaluate(input, key, value, payload, input.InteractURLs)
- cloned[i] = evaluated
-
- if rule.modeType == singleModeType {
- headers[key] = cloned
- if err := rule.buildHeadersInput(input, headers, input.InteractURLs); err != nil && err != io.EOF {
- gologger.Error().Msgf("Could not build request for headers part rule %v: %s\n", rule, err)
- return err
- }
- cloned[i] = value // change back to previous value for headers
- }
- }
- headers[key] = cloned
- }
-
- if rule.modeType == multipleModeType {
- if err := rule.buildHeadersInput(input, headers, input.InteractURLs); err != nil {
- return err
- }
- }
- return nil
-}
-
-// executeQueryPartRule executes query part rules
-func (rule *Rule) executeQueryPartRule(input *ExecuteRuleInput, payload string) error {
- requestURL, err := urlutil.Parse(input.Input.MetaInput.Input)
- if err != nil {
- return err
- }
- origRequestURL := requestURL.Clone()
- // clone the params to avoid modifying the original
- temp := origRequestURL.Params.Clone()
-
- origRequestURL.Query().Iterate(func(key string, values []string) bool {
- cloned := sliceutil.Clone(values)
- for i, value := range values {
- if !rule.matchKeyOrValue(key, value) {
- continue
- }
- var evaluated string
- evaluated, input.InteractURLs = rule.executeEvaluate(input, key, value, payload, input.InteractURLs)
- cloned[i] = evaluated
-
- if rule.modeType == singleModeType {
- temp.Update(key, cloned)
- requestURL.Params = temp
- if qerr := rule.buildQueryInput(input, requestURL, input.InteractURLs); qerr != nil {
- err = qerr
- return false
- }
- cloned[i] = value // change back to previous value for temp
- }
- }
- temp.Update(key, cloned)
- return true
- })
-
- if rule.modeType == multipleModeType {
- requestURL.Params = temp
- if err := rule.buildQueryInput(input, requestURL, input.InteractURLs); err != nil {
- return err
- }
- }
-
- return err
-}
-
-// buildHeadersInput returns created request for a Headers Input
-func (rule *Rule) buildHeadersInput(input *ExecuteRuleInput, headers http.Header, interactURLs []string) error {
- var req *retryablehttp.Request
- if input.BaseRequest == nil {
- return errors.New("Base request cannot be nil when fuzzing headers")
- } else {
- req = input.BaseRequest.Clone(context.TODO())
- req.Header = headers
- // update host of request and not URL
- // URL.Host is used to dial the connection
- req.Request.Host = req.Header.Get("Host")
- }
- request := GeneratedRequest{
- Request: req,
- InteractURLs: interactURLs,
- DynamicValues: input.Values,
- }
- if !input.Callback(request) {
- return io.EOF
- }
- return nil
-}
-
-// buildQueryInput returns created request for a Query Input
-func (rule *Rule) buildQueryInput(input *ExecuteRuleInput, parsed *urlutil.URL, interactURLs []string) error {
- var req *retryablehttp.Request
- var err error
- if input.BaseRequest == nil {
- req, err = retryablehttp.NewRequestFromURL(http.MethodGet, parsed, nil)
- if err != nil {
- return err
- }
- userAgent := useragent.PickRandom()
- req.Header.Set("User-Agent", userAgent.Raw)
- } else {
- req = input.BaseRequest.Clone(context.TODO())
- req.SetURL(parsed)
- }
- request := GeneratedRequest{
- Request: req,
- InteractURLs: interactURLs,
- DynamicValues: input.Values,
- }
- if !input.Callback(request) {
- return types.ErrNoMoreRequests
- }
- return nil
-}
-
-// executeEvaluate executes evaluation of payload on a key and value and
-// returns completed values to be replaced and processed
-// for fuzzing.
-func (rule *Rule) executeEvaluate(input *ExecuteRuleInput, key, value, payload string, interactshURLs []string) (string, []string) {
- // TODO: Handle errors
- values := generators.MergeMaps(input.Values, map[string]interface{}{
- "value": value,
- })
- firstpass, _ := expressions.Evaluate(payload, values)
- interactData, interactshURLs := rule.options.Interactsh.Replace(firstpass, interactshURLs)
- evaluated, _ := expressions.Evaluate(interactData, values)
- replaced := rule.executeReplaceRule(input, value, evaluated)
- return replaced, interactshURLs
-}
-
-// executeReplaceRule executes replacement for a key and value
-func (rule *Rule) executeReplaceRule(input *ExecuteRuleInput, value, replacement string) string {
- var builder strings.Builder
- if rule.ruleType == prefixRuleType || rule.ruleType == postfixRuleType {
- builder.Grow(len(value) + len(replacement))
- }
- var returnValue string
-
- switch rule.ruleType {
- case prefixRuleType:
- builder.WriteString(replacement)
- builder.WriteString(value)
- returnValue = builder.String()
- case postfixRuleType:
- builder.WriteString(value)
- builder.WriteString(replacement)
- returnValue = builder.String()
- case infixRuleType:
- if len(value) <= 1 {
- builder.WriteString(value)
- builder.WriteString(replacement)
- returnValue = builder.String()
- } else {
- middleIndex := len(value) / 2
- builder.WriteString(value[:middleIndex])
- builder.WriteString(replacement)
- builder.WriteString(value[middleIndex:])
- returnValue = builder.String()
- }
- case replaceRuleType:
- returnValue = replacement
- }
- return returnValue
-}
diff --git a/pkg/protocols/common/fuzz/parts_test.go b/pkg/protocols/common/fuzz/parts_test.go
deleted file mode 100644
index 90b1b2ab..00000000
--- a/pkg/protocols/common/fuzz/parts_test.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package fuzz
-
-import (
- "github.com/projectdiscovery/retryablehttp-go"
- "net/http"
- "testing"
-
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
- "github.com/stretchr/testify/require"
-)
-
-func TestExecuteHeadersPartRule(t *testing.T) {
- options := &protocols.ExecutorOptions{
- Interactsh: &interactsh.Client{},
- }
- req, err := retryablehttp.NewRequest("GET", "http://localhost:8080/", nil)
- require.NoError(t, err, "can't build request")
-
- req.Header.Set("X-Custom-Foo", "foo")
- req.Header.Set("X-Custom-Bar", "bar")
-
- t.Run("single", func(t *testing.T) {
- rule := &Rule{
- ruleType: postfixRuleType,
- partType: headersPartType,
- modeType: singleModeType,
- options: options,
- }
- var generatedHeaders []http.Header
- err := rule.executeHeadersPartRule(&ExecuteRuleInput{
- Input: contextargs.New(),
- BaseRequest: req,
- Callback: func(gr GeneratedRequest) bool {
- generatedHeaders = append(generatedHeaders, gr.Request.Header.Clone())
- return true
- },
- }, "1337'")
- require.NoError(t, err, "could not execute part rule")
- require.ElementsMatch(t, []http.Header{
- {
- "X-Custom-Foo": {"foo1337'"},
- "X-Custom-Bar": {"bar"},
- },
- {
- "X-Custom-Foo": {"foo"},
- "X-Custom-Bar": {"bar1337'"},
- },
- }, generatedHeaders, "could not get generated headers")
- })
-
- t.Run("multiple", func(t *testing.T) {
- rule := &Rule{
- ruleType: postfixRuleType,
- partType: headersPartType,
- modeType: multipleModeType,
- options: options,
- }
- var generatedHeaders http.Header
- err := rule.executeHeadersPartRule(&ExecuteRuleInput{
- Input: contextargs.New(),
- BaseRequest: req,
- Callback: func(gr GeneratedRequest) bool {
- generatedHeaders = gr.Request.Header.Clone()
- return true
- },
- }, "1337'")
- require.NoError(t, err, "could not execute part rule")
- require.Equal(t, http.Header{
- "X-Custom-Foo": {"foo1337'"},
- "X-Custom-Bar": {"bar1337'"},
- }, generatedHeaders, "could not get generated headers")
- })
-}
-func TestExecuteQueryPartRule(t *testing.T) {
- URL := "http://localhost:8080/?url=localhost&mode=multiple&file=passwdfile"
- options := &protocols.ExecutorOptions{
- Interactsh: &interactsh.Client{},
- }
- t.Run("single", func(t *testing.T) {
- rule := &Rule{
- ruleType: postfixRuleType,
- partType: queryPartType,
- modeType: singleModeType,
- options: options,
- }
- var generatedURL []string
- input := contextargs.NewWithInput(URL)
- err := rule.executeQueryPartRule(&ExecuteRuleInput{
- Input: input,
- Callback: func(gr GeneratedRequest) bool {
- generatedURL = append(generatedURL, gr.Request.URL.String())
- return true
- },
- }, "1337'")
- require.NoError(t, err, "could not execute part rule")
- require.ElementsMatch(t, []string{
- "http://localhost:8080/?url=localhost1337'&mode=multiple&file=passwdfile",
- "http://localhost:8080/?url=localhost&mode=multiple1337'&file=passwdfile",
- "http://localhost:8080/?url=localhost&mode=multiple&file=passwdfile1337'",
- }, generatedURL, "could not get generated url")
- })
- t.Run("multiple", func(t *testing.T) {
- rule := &Rule{
- ruleType: postfixRuleType,
- partType: queryPartType,
- modeType: multipleModeType,
- options: options,
- }
- var generatedURL string
- input := contextargs.NewWithInput(URL)
- err := rule.executeQueryPartRule(&ExecuteRuleInput{
- Input: input,
- Callback: func(gr GeneratedRequest) bool {
- generatedURL = gr.Request.URL.String()
- return true
- },
- }, "1337'")
- require.NoError(t, err, "could not execute part rule")
- require.Equal(t, "http://localhost:8080/?url=localhost1337'&mode=multiple1337'&file=passwdfile1337'", generatedURL, "could not get generated url")
- })
-}
-
-func TestExecuteReplaceRule(t *testing.T) {
- tests := []struct {
- ruleType ruleType
- value string
- replacement string
- expected string
- }{
- {replaceRuleType, "test", "replacement", "replacement"},
- {prefixRuleType, "test", "prefix", "prefixtest"},
- {postfixRuleType, "test", "postfix", "testpostfix"},
- {infixRuleType, "", "infix", "infix"},
- {infixRuleType, "0", "infix", "0infix"},
- {infixRuleType, "test", "infix", "teinfixst"},
- }
- for _, test := range tests {
- rule := &Rule{ruleType: test.ruleType}
- returned := rule.executeReplaceRule(nil, test.value, test.replacement)
- require.Equal(t, test.expected, returned, "could not get correct value")
- }
-}
diff --git a/pkg/protocols/headless/headless.go b/pkg/protocols/headless/headless.go
index 81cb3ca4..373880f1 100644
--- a/pkg/protocols/headless/headless.go
+++ b/pkg/protocols/headless/headless.go
@@ -3,10 +3,10 @@ package headless
import (
"github.com/pkg/errors"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
useragent "github.com/projectdiscovery/nuclei/v3/pkg/model/types/userAgent"
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"
uagent "github.com/projectdiscovery/useragent"
diff --git a/pkg/protocols/headless/request.go b/pkg/protocols/headless/request.go
index f800c261..f45afdd3 100644
--- a/pkg/protocols/headless/request.go
+++ b/pkg/protocols/headless/request.go
@@ -12,10 +12,10 @@ import (
"golang.org/x/exp/maps"
"github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/responsehighlighter"
diff --git a/pkg/protocols/http/build_request.go b/pkg/protocols/http/build_request.go
index d8ebb397..7408925a 100644
--- a/pkg/protocols/http/build_request.go
+++ b/pkg/protocols/http/build_request.go
@@ -13,6 +13,7 @@ import (
"github.com/projectdiscovery/useragent"
"github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
@@ -49,6 +50,32 @@ type generatedRequest struct {
customCancelFunction context.CancelFunc
}
+// ApplyAuth applies the auth provider to the generated request
+func (g *generatedRequest) ApplyAuth(provider authprovider.AuthProvider) {
+ if provider == nil {
+ return
+ }
+ if g.request != nil {
+ auth := provider.LookupURLX(g.request.URL)
+ if auth != nil {
+ auth.ApplyOnRR(g.request)
+ }
+ }
+ if g.rawRequest != nil {
+ parsed, err := urlutil.ParseAbsoluteURL(g.rawRequest.FullURL, true)
+ if err != nil {
+ gologger.Warning().Msgf("[authprovider] Could not parse URL %s: %s\n", g.rawRequest.FullURL, err)
+ return
+ }
+ auth := provider.LookupURLX(parsed)
+ if auth != nil {
+ // here we need to apply it custom because we don't have a standard/official
+ // rawhttp request format ( which we probably should have )
+ g.rawRequest.ApplyAuthStrategy(auth)
+ }
+ }
+}
+
func (g *generatedRequest) URL() string {
if g.request != nil {
return g.request.URL.String()
diff --git a/pkg/protocols/http/http.go b/pkg/protocols/http/http.go
index 4796f339..ede8291e 100644
--- a/pkg/protocols/http/http.go
+++ b/pkg/protocols/http/http.go
@@ -8,10 +8,11 @@ import (
json "github.com/json-iterator/go"
"github.com/pkg/errors"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
+ "github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
httputil "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils/http"
@@ -208,6 +209,14 @@ type Request struct {
// description: |
// DisablePathAutomerge disables merging target url path with raw request path
DisablePathAutomerge bool `yaml:"disable-path-automerge,omitempty" json:"disable-path-automerge,omitempty" jsonschema:"title=disable auto merging of path,description=Disable merging target url path with raw request path"`
+ // description: |
+ // Filter is matcher-like field to check if fuzzing should be performed on this request or not
+ FuzzingFilter []*matchers.Matcher `yaml:"filters,omitempty" json:"filter,omitempty" jsonschema:"title=filter for fuzzing,description=Filter is matcher-like field to check if fuzzing should be performed on this request or not"`
+ // description: |
+ // Filter condition is the condition to apply on the filter (AND/OR). Default is OR
+ FuzzingFilterCondition string `yaml:"filters-condition,omitempty" json:"filter-condition,omitempty" jsonschema:"title=condition between the filters,description=Conditions between the filters,enum=and,enum=or"`
+ // cached variables that may be used along with request.
+ fuzzingFilterCondition matchers.ConditionType `yaml:"-" json:"-"`
}
// Options returns executer options for http request
@@ -314,6 +323,20 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
request.CompiledOperators = compiled
}
+ // === fuzzing filters ===== //
+
+ if request.FuzzingFilterCondition != "" {
+ request.fuzzingFilterCondition = matchers.ConditionTypes[request.FuzzingFilterCondition]
+ } else {
+ request.fuzzingFilterCondition = matchers.ORCondition
+ }
+
+ for _, filter := range request.FuzzingFilter {
+ if err := filter.CompileMatchers(); err != nil {
+ return errors.Wrap(err, "could not compile matcher")
+ }
+ }
+
// Resolve payload paths from vars if they exists
for name, payload := range request.options.Options.Vars.AsMap() {
payloadStr, ok := payload.(string)
diff --git a/pkg/protocols/http/raw/raw.go b/pkg/protocols/http/raw/raw.go
index d4004683..a1eb544a 100644
--- a/pkg/protocols/http/raw/raw.go
+++ b/pkg/protocols/http/raw/raw.go
@@ -3,11 +3,14 @@ package raw
import (
"bufio"
"bytes"
+ "encoding/base64"
"errors"
"fmt"
"io"
"strings"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
"github.com/projectdiscovery/rawhttp/client"
errorutil "github.com/projectdiscovery/utils/errors"
stringsutil "github.com/projectdiscovery/utils/strings"
@@ -267,3 +270,44 @@ func (r *Request) TryFillCustomHeaders(headers []string) error {
return errors.New("no host header found")
}
+
+// ApplyAuthStrategy applies the auth strategy to the request
+func (r *Request) ApplyAuthStrategy(strategy authx.AuthStrategy) {
+ if strategy == nil {
+ return
+ }
+ switch s := strategy.(type) {
+ case *authx.QueryAuthStrategy:
+ parsed, err := urlutil.Parse(r.FullURL)
+ if err != nil {
+ gologger.Error().Msgf("auth strategy failed to parse url: %s got %v", r.FullURL, err)
+ return
+ }
+ _ = parsed
+ for _, p := range s.Data.Params {
+ parsed.Params.Add(p.Key, p.Value)
+ }
+ case *authx.CookiesAuthStrategy:
+ var buff bytes.Buffer
+ for _, cookie := range s.Data.Cookies {
+ buff.WriteString(fmt.Sprintf("%s=%s; ", cookie.Key, cookie.Value))
+ }
+ if buff.Len() > 0 {
+ if val, ok := r.Headers["Cookie"]; ok {
+ r.Headers["Cookie"] = strings.TrimSuffix(strings.TrimSpace(val), ";") + "; " + buff.String()
+ } else {
+ r.Headers["Cookie"] = buff.String()
+ }
+ }
+ case *authx.HeadersAuthStrategy:
+ for _, header := range s.Data.Headers {
+ r.Headers[header.Key] = header.Value
+ }
+ case *authx.BearerTokenAuthStrategy:
+ r.Headers["Authorization"] = "Bearer " + s.Data.Token
+ case *authx.BasicAuthStrategy:
+ r.Headers["Authorization"] = "Basic " + base64.StdEncoding.EncodeToString([]byte(s.Data.Username+":"+s.Data.Password))
+ default:
+ gologger.Warning().Msgf("[raw-request] unknown auth strategy: %T", s)
+ }
+}
diff --git a/pkg/protocols/http/request.go b/pkg/protocols/http/request.go
index 09b6c43f..81df15b2 100644
--- a/pkg/protocols/http/request.go
+++ b/pkg/protocols/http/request.go
@@ -24,7 +24,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
- "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/responsehighlighter"
@@ -341,98 +340,6 @@ func (request *Request) executeTurboHTTP(input *contextargs.Context, dynamicValu
return multierr.Combine(spmHandler.CombinedResults()...)
}
-// executeFuzzingRule executes fuzzing request for a URL
-func (request *Request) executeFuzzingRule(input *contextargs.Context, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
- // If request is self-contained we don't need to parse any input.
- if !request.SelfContained {
- // If it's not self-contained we parse user provided input
- if _, err := urlutil.Parse(input.MetaInput.Input); err != nil {
- return errors.Wrap(err, "could not parse url")
- }
- }
- fuzzRequestCallback := func(gr fuzz.GeneratedRequest) bool {
- hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
- hasInteractMarkers := len(gr.InteractURLs) > 0
- if request.options.HostErrorsCache != nil && request.options.HostErrorsCache.Check(input.MetaInput.Input) {
- return false
- }
- request.options.RateLimiter.Take()
- req := &generatedRequest{
- request: gr.Request,
- dynamicValues: gr.DynamicValues,
- interactshURLs: gr.InteractURLs,
- original: request,
- }
- var gotMatches bool
- requestErr := request.executeRequest(input, req, gr.DynamicValues, hasInteractMatchers, func(event *output.InternalWrappedEvent) {
- if hasInteractMarkers && hasInteractMatchers && request.options.Interactsh != nil {
- requestData := &interactsh.RequestData{
- MakeResultFunc: request.MakeResultEvent,
- Event: event,
- Operators: request.CompiledOperators,
- MatchFunc: request.Match,
- ExtractFunc: request.Extract,
- }
- request.options.Interactsh.RequestEvent(gr.InteractURLs, requestData)
- gotMatches = request.options.Interactsh.AlreadyMatched(requestData)
- } else {
- callback(event)
- }
- // Add the extracts to the dynamic values if any.
- if event.OperatorsResult != nil {
- gotMatches = event.OperatorsResult.Matched
- }
- }, 0)
- // If a variable is unresolved, skip all further requests
- if errors.Is(requestErr, errStopExecution) {
- return false
- }
- if requestErr != nil {
- if request.options.HostErrorsCache != nil {
- request.options.HostErrorsCache.MarkFailed(input.MetaInput.Input, requestErr)
- }
- gologger.Verbose().Msgf("[%s] Error occurred in request: %s\n", request.options.TemplateID, requestErr)
- }
- request.options.Progress.IncrementRequests()
-
- // If this was a match, and we want to stop at first match, skip all further requests.
- shouldStopAtFirstMatch := request.options.Options.StopAtFirstMatch || request.StopAtFirstMatch
- if shouldStopAtFirstMatch && gotMatches {
- return false
- }
- return true
- }
-
- // Iterate through all requests for template and queue them for fuzzing
- generator := request.newGenerator(true)
- for {
- value, payloads, result := generator.nextValue()
- if !result {
- break
- }
- generated, err := generator.Make(context.Background(), input, value, payloads, nil)
- if err != nil {
- continue
- }
- input.MetaInput = &contextargs.MetaInput{Input: generated.URL()}
- for _, rule := range request.Fuzzing {
- err = rule.Execute(&fuzz.ExecuteRuleInput{
- Input: input,
- Callback: fuzzRequestCallback,
- Values: generated.dynamicValues,
- BaseRequest: generated.request,
- })
- if err == types.ErrNoMoreRequests {
- return nil
- }
- if err != nil {
- return errors.Wrap(err, "could not execute rule")
- }
- }
- }
- return nil
-}
-
// ExecuteWithResults executes the final request on a URL
func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
if request.Pipeline || request.Race && request.RaceNumberRequests > 0 || request.Threads > 0 {
@@ -655,6 +562,12 @@ func (request *Request) executeRequest(input *contextargs.Context, generatedRequ
}
}
}
+
+ // === apply auth strategies ===
+ if generatedRequest.request != nil {
+ generatedRequest.ApplyAuth(request.options.AuthProvider)
+ }
+
var formedURL string
var hostname string
timeStart := time.Now()
diff --git a/pkg/protocols/http/request_fuzz.go b/pkg/protocols/http/request_fuzz.go
new file mode 100644
index 00000000..b9f22131
--- /dev/null
+++ b/pkg/protocols/http/request_fuzz.go
@@ -0,0 +1,305 @@
+package http
+
+// === Fuzzing Documentation (Scoped to this File) =====
+// -> request.executeFuzzingRule [iterates over payloads(+requests) and executes]
+// -> request.executePayloadUsingRules [executes single payload on all rules (if more than 1)]
+// -> request.executeGeneratedFuzzingRequest [execute final generated fuzzing request and get result]
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
+ "github.com/projectdiscovery/nuclei/v3/pkg/operators"
+ "github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"
+ "github.com/projectdiscovery/nuclei/v3/pkg/output"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
+ "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
+ protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
+ "github.com/projectdiscovery/nuclei/v3/pkg/types"
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+// executeFuzzingRule executes fuzzing request for a URL
+// TODO:
+// 1. use SPMHandler and rewrite stop at first match logic here
+// 2. use scanContext instead of contextargs.Context
+func (request *Request) executeFuzzingRule(input *contextargs.Context, _ output.InternalEvent, callback protocols.OutputEventCallback) error {
+ // methdology:
+ // to check applicablity of rule, we first try to execute it with one value
+ // if it is applicable, we execute all requests
+ // if it is not applicable, we log and fail silently
+
+ // check if target should be fuzzed or not
+ if !request.ShouldFuzzTarget(input) {
+ urlx, _ := input.MetaInput.URL()
+ if urlx != nil {
+ gologger.Verbose().Msgf("[%s] fuzz: target(%s) not applicable for fuzzing\n", request.options.TemplateID, urlx.String())
+ } else {
+ gologger.Verbose().Msgf("[%s] fuzz: target(%s) not applicable for fuzzing\n", request.options.TemplateID, input.MetaInput.Input)
+ }
+ return nil
+ }
+
+ // Iterate through all requests for template and queue them for fuzzing
+ generator := request.newGenerator(true)
+
+ // this will generate next value along with request it is meant to be used with
+ currRequest, payloads, result := generator.nextValue()
+ if !result && input.MetaInput.ReqResp == nil {
+ // this case is only true if input is not a full http request
+ return fmt.Errorf("no values to generate requests")
+ }
+
+ // if it is a full http request obtained from target file
+ if input.MetaInput.ReqResp != nil {
+ // Note: in case of full http request, we only need to build it once
+ // and then reuse it for all requests and completely abandon the request
+ // returned by generator
+ _ = currRequest
+ generated, err := input.MetaInput.ReqResp.BuildRequest()
+ if err != nil {
+ return errors.Wrap(err, "fuzz: could not build request obtained from target file")
+ }
+ input.MetaInput.Input = generated.URL.String()
+ // execute with one value first to checks its applicability
+ err = request.executePayloadUsingRules(input, payloads, generated, callback)
+ if err != nil {
+ // in case of any error, return it
+ if fuzz.IsErrRuleNotApplicable(err) {
+ // log and fail silently
+ gologger.Verbose().Msgf("[%s] fuzz: %s\n", request.options.TemplateID, err)
+ return nil
+ }
+ if errors.Is(err, errStopExecution) {
+ return err
+ }
+ gologger.Verbose().Msgf("[%s] fuzz: inital payload request execution failed : %s\n", request.options.TemplateID, err)
+ }
+
+ // if it is applicable, execute all requests
+ for {
+ _, payloads, result := generator.nextValue()
+ if !result {
+ break
+ }
+ err = request.executePayloadUsingRules(input, payloads, generated, callback)
+ if err != nil {
+ // continue to next request since this is payload specific
+ gologger.Verbose().Msgf("[%s] fuzz: payload request execution failed : %s\n", request.options.TemplateID, err)
+ continue
+ }
+ }
+ return nil
+ }
+
+ // ==== fuzzing when only URL is provided =====
+
+ generated, err := generator.Make(context.Background(), input, currRequest, payloads, nil)
+ if err != nil {
+ return errors.Wrap(err, "fuzz: could not build request from url")
+ }
+ // we need to use this url instead of input
+ inputx := input.Clone()
+ inputx.MetaInput.Input = generated.request.URL.String()
+ // execute with one value first to checks its applicability
+ err = request.executePayloadUsingRules(inputx, generated.dynamicValues, generated.request, callback)
+ if err != nil {
+ // in case of any error, return it
+ if fuzz.IsErrRuleNotApplicable(err) {
+ // log and fail silently
+ gologger.Verbose().Msgf("[%s] fuzz: rule not applicable : %s\n", request.options.TemplateID, err)
+ return nil
+ }
+ if errors.Is(err, errStopExecution) {
+ return err
+ }
+ gologger.Verbose().Msgf("[%s] fuzz: inital payload request execution failed : %s\n", request.options.TemplateID, err)
+ }
+
+ // continue to next request since this is payload specific
+ for {
+ currRequest, payloads, result = generator.nextValue()
+ if !result {
+ break
+ }
+ generated, err := generator.Make(context.Background(), input, currRequest, payloads, nil)
+ if err != nil {
+ return errors.Wrap(err, "fuzz: could not build request from url")
+ }
+ // we need to use this url instead of input
+ inputx := input.Clone()
+ inputx.MetaInput.Input = generated.request.URL.String()
+ // execute with one value first to checks its applicability
+ err = request.executePayloadUsingRules(inputx, generated.dynamicValues, generated.request, callback)
+ if err != nil {
+ gologger.Verbose().Msgf("[%s] fuzz: payload request execution failed : %s\n", request.options.TemplateID, err)
+ continue
+ }
+ }
+ return nil
+}
+
+// executePayloadUsingRules executes a payload using rules with given payload i.e values
+func (request *Request) executePayloadUsingRules(input *contextargs.Context, values map[string]interface{}, baseRequest *retryablehttp.Request, callback protocols.OutputEventCallback) error {
+ applicable := false
+ for _, rule := range request.Fuzzing {
+ err := rule.Execute(&fuzz.ExecuteRuleInput{
+ Input: input,
+ Callback: func(gr fuzz.GeneratedRequest) bool {
+ // TODO: replace this after scanContext Refactor
+ return request.executeGeneratedFuzzingRequest(gr, input, callback)
+ },
+ Values: values,
+ BaseRequest: baseRequest,
+ })
+ if err == nil {
+ applicable = true
+ continue
+ }
+ if fuzz.IsErrRuleNotApplicable(err) {
+ continue
+ }
+ if err == types.ErrNoMoreRequests {
+ return nil
+ }
+ return errors.Wrap(err, "could not execute rule")
+ }
+
+ if !applicable {
+ return fuzz.ErrRuleNotApplicable.Msgf(fmt.Sprintf("no rule was applicable for this request: %v", input.MetaInput.Input))
+ }
+ return nil
+}
+
+// executeGeneratedFuzzingRequest executes a generated fuzzing request after building it using rules and payloads
+func (request *Request) executeGeneratedFuzzingRequest(gr fuzz.GeneratedRequest, input *contextargs.Context, callback protocols.OutputEventCallback) bool {
+ hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
+ hasInteractMarkers := len(gr.InteractURLs) > 0
+ if request.options.HostErrorsCache != nil && request.options.HostErrorsCache.Check(input.MetaInput.Input) {
+ return false
+ }
+ request.options.RateLimiter.Take()
+ req := &generatedRequest{
+ request: gr.Request,
+ dynamicValues: gr.DynamicValues,
+ interactshURLs: gr.InteractURLs,
+ original: request,
+ }
+ var gotMatches bool
+ requestErr := request.executeRequest(input, req, gr.DynamicValues, hasInteractMatchers, func(event *output.InternalWrappedEvent) {
+ if hasInteractMarkers && hasInteractMatchers && request.options.Interactsh != nil {
+ requestData := &interactsh.RequestData{
+ MakeResultFunc: request.MakeResultEvent,
+ Event: event,
+ Operators: request.CompiledOperators,
+ MatchFunc: request.Match,
+ ExtractFunc: request.Extract,
+ }
+ request.options.Interactsh.RequestEvent(gr.InteractURLs, requestData)
+ gotMatches = request.options.Interactsh.AlreadyMatched(requestData)
+ } else {
+ callback(event)
+ }
+ // Add the extracts to the dynamic values if any.
+ if event.OperatorsResult != nil {
+ gotMatches = event.OperatorsResult.Matched
+ }
+ }, 0)
+ // If a variable is unresolved, skip all further requests
+ if errors.Is(requestErr, errStopExecution) {
+ return false
+ }
+ if requestErr != nil {
+ if request.options.HostErrorsCache != nil {
+ request.options.HostErrorsCache.MarkFailed(input.MetaInput.Input, requestErr)
+ }
+ gologger.Verbose().Msgf("[%s] Error occurred in request: %s\n", request.options.TemplateID, requestErr)
+ }
+ request.options.Progress.IncrementRequests()
+
+ // If this was a match, and we want to stop at first match, skip all further requests.
+ shouldStopAtFirstMatch := request.options.Options.StopAtFirstMatch || request.StopAtFirstMatch
+ if shouldStopAtFirstMatch && gotMatches {
+ return false
+ }
+ return true
+}
+
+// ShouldFuzzTarget checks if given target should be fuzzed or not using `filter` field in template
+func (request *Request) ShouldFuzzTarget(input *contextargs.Context) bool {
+ if len(request.FuzzingFilter) == 0 {
+ return true
+ }
+ status := []bool{}
+ for index, filter := range request.FuzzingFilter {
+ isMatch, _ := request.Match(request.filterDataMap(input), filter)
+ status = append(status, isMatch)
+ if request.options.Options.MatcherStatus {
+ gologger.Debug().Msgf("[%s] [%s] Filter => %s : %v", input.MetaInput.Target(), request.options.TemplateID, operators.GetMatcherName(filter, index), isMatch)
+ }
+ }
+ if len(status) == 0 {
+ return true
+ }
+ var matched bool
+ if request.fuzzingFilterCondition == matchers.ANDCondition {
+ matched = operators.EvalBoolSlice(status, true)
+ } else {
+ matched = operators.EvalBoolSlice(status, false)
+ }
+ if request.options.Options.MatcherStatus {
+ gologger.Debug().Msgf("[%s] [%s] Final Filter Status => %v", input.MetaInput.Target(), request.options.TemplateID, matched)
+ }
+ return matched
+}
+
+// input data map returns map[string]interface{} from input
+func (request *Request) filterDataMap(input *contextargs.Context) map[string]interface{} {
+ m := make(map[string]interface{})
+ parsed, err := input.MetaInput.URL()
+ if err != nil {
+ m["host"] = input.MetaInput.Input
+ return m
+ }
+ m = protocolutils.GenerateVariables(parsed, true, m)
+ for k, v := range m {
+ m[strings.ToLower(k)] = v
+ }
+ m["path"] = parsed.Path // override existing
+ m["query"] = parsed.RawQuery
+ // add request data like headers, body etc
+ if input.MetaInput.ReqResp != nil && input.MetaInput.ReqResp.Request != nil {
+ req := input.MetaInput.ReqResp.Request
+ m["method"] = req.Method
+ m["body"] = req.Body
+
+ sb := &strings.Builder{}
+ req.Headers.Iterate(func(k, v string) bool {
+ k = strings.ToLower(strings.ReplaceAll(strings.TrimSpace(k), "-", "_"))
+ if strings.EqualFold(k, "Cookie") {
+ m["cookie"] = v
+ }
+ if strings.EqualFold(k, "User_Agent") {
+ m["user_agent"] = v
+ }
+ if strings.EqualFold(k, "content_type") {
+ m["content_type"] = v
+ }
+ sb.WriteString(fmt.Sprintf("%s: %s\n", k, v))
+ return true
+ })
+ m["header"] = sb.String()
+ }
+
+ // dump if svd is enabled
+ if request.options.Options.ShowVarDump {
+ gologger.Debug().Msgf("Fuzz Filter Variables: \n%s\n", vardump.DumpVariables(m))
+ }
+ return m
+}
diff --git a/pkg/protocols/protocols.go b/pkg/protocols/protocols.go
index c8323dcb..4faa9610 100644
--- a/pkg/protocols/protocols.go
+++ b/pkg/protocols/protocols.go
@@ -10,6 +10,7 @@ import (
"github.com/logrusorgru/aurora"
+ "github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
"github.com/projectdiscovery/nuclei/v3/pkg/input"
"github.com/projectdiscovery/nuclei/v3/pkg/js/compiler"
@@ -116,6 +117,8 @@ type ExecutorOptions struct {
// based on given logic. by default nuclei reverts to using value of `-c` when threads count
// is not specified or is 0 in template
OverrideThreadsCount PayloadThreadSetterCallback
+ // AuthProvider is a provider for auth strategies
+ AuthProvider authprovider.AuthProvider
//TemporaryDirectory is the directory to store temporary files
TemporaryDirectory string
}
diff --git a/pkg/templates/templates.go b/pkg/templates/templates.go
index 1bd5a683..bd81d145 100644
--- a/pkg/templates/templates.go
+++ b/pkg/templates/templates.go
@@ -191,6 +191,29 @@ func (template *Template) Type() types.ProtocolType {
}
}
+// IsFuzzing returns true if the template is a fuzzing template
+func (template *Template) IsFuzzing() bool {
+ if len(template.RequestsHTTP) == 0 && len(template.RequestsHeadless) == 0 {
+ // fuzzing is only supported for http and headless protocols
+ return false
+ }
+ if len(template.RequestsHTTP) > 0 {
+ for _, request := range template.RequestsHTTP {
+ if len(request.Fuzzing) > 0 {
+ return true
+ }
+ }
+ }
+ if len(template.RequestsHeadless) > 0 {
+ for _, request := range template.RequestsHeadless {
+ if len(request.Fuzzing) > 0 {
+ return true
+ }
+ }
+ }
+ return false
+}
+
// HasCodeProtocol returns true if the template has a code protocol section
func (template *Template) HasCodeProtocol() bool {
return len(template.RequestsCode) > 0
diff --git a/pkg/testutils/fuzzplayground/db.go b/pkg/testutils/fuzzplayground/db.go
new file mode 100644
index 00000000..8344f5dc
--- /dev/null
+++ b/pkg/testutils/fuzzplayground/db.go
@@ -0,0 +1,150 @@
+package fuzzplayground
+
+import (
+ "database/sql"
+ "encoding/xml"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+
+ _ "github.com/mattn/go-sqlite3"
+)
+
+var (
+ db *sql.DB
+ tempDBDir string
+)
+
+func init() {
+ dir, err := os.MkdirTemp("", "fuzzplayground-*")
+ if err != nil {
+ panic(err)
+ }
+ tempDBDir = dir
+
+ db, err = sql.Open("sqlite3", fmt.Sprintf("file:%v/test.db?cache=shared&mode=memory", tempDBDir))
+ if err != nil {
+ panic(err)
+ }
+ addDummyUsers(db)
+ addDummyPosts(db)
+}
+
+// Cleanup cleans up the temporary database directory
+func Cleanup() {
+ if db != nil {
+ _ = db.Close()
+ }
+ if tempDBDir != "" {
+ _ = os.RemoveAll(tempDBDir)
+ }
+}
+
+type User struct {
+ XMLName xml.Name `xml:"user"`
+ ID int `xml:"id"`
+ Name string `xml:"name"`
+ Age int `xml:"age"`
+ Role string `xml:"role"`
+}
+
+func addDummyUsers(db *sql.DB) {
+ _, err := db.Exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER, role TEXT)")
+ if err != nil {
+ panic(err)
+ }
+ _, err = db.Exec("INSERT INTO users (id , name, age, role) VALUES (1,'admin', 30, 'admin')")
+ if err != nil {
+ panic(err)
+ }
+ _, err = db.Exec("INSERT INTO users (id , name, age, role) VALUES (75,'user', 30, 'user')")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func patchUnsanitizedUser(db *sql.DB, user User) error {
+ setClauses := ""
+
+ if user.Name != "" {
+ setClauses += "name = '" + user.Name + "', "
+ }
+ if user.Age > 0 {
+ setClauses += "age = " + strconv.Itoa(user.Age) + ", "
+ }
+ if user.Role != "" {
+ setClauses += "role = '" + user.Role + "', "
+ }
+ if setClauses == "" {
+ // No fields to update
+ return nil
+ }
+ setClauses = strings.TrimSuffix(setClauses, ", ")
+
+ query := "UPDATE users SET " + setClauses + " WHERE id = ?"
+ _, err := db.Exec(query, user.ID)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func getUnsanitizedUser(db *sql.DB, id string) (User, error) {
+ var user User
+ err := db.QueryRow("SELECT id, name, age, role FROM users WHERE id = "+id).Scan(&user.ID, &user.Name, &user.Age, &user.Role)
+ if err != nil {
+ return user, err
+ }
+ return user, nil
+}
+
+type Posts struct {
+ ID int
+ Title string
+ Content string
+ Lang string
+}
+
+func addDummyPosts(db *sql.DB) {
+ _, err := db.Exec("CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY, title TEXT, content TEXT, lang TEXT)")
+ if err != nil {
+ panic(err)
+ }
+ // Inserting English dummy posts
+ _, err = db.Exec("INSERT INTO posts (id, title, content, lang) VALUES (1, 'The Joy of Programming', 'Programming is like painting a canvas with logic.', 'en')")
+ if err != nil {
+ panic(err)
+ }
+ _, err = db.Exec("INSERT INTO posts (id, title, content, lang) VALUES (2, 'A Journey Through Code', 'Every line of code tells a story.', 'en')")
+ if err != nil {
+ panic(err)
+ }
+ // Inserting a Spanish dummy post
+ _, err = db.Exec("INSERT INTO posts (id, title, content, lang) VALUES (3, 'La belleza del código', 'Cada función es un poema en un mar de algoritmos.', 'es')")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func getUnsanitizedPostsByLang(db *sql.DB, lang string) ([]Posts, error) {
+ var posts []Posts
+ query := "SELECT id, title, content, lang FROM posts WHERE lang = '" + lang + "'"
+ rows, err := db.Query(query)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var post Posts
+ if err := rows.Scan(&post.ID, &post.Title, &post.Content, &post.Lang); err != nil {
+ return nil, err
+ }
+ posts = append(posts, post)
+ }
+ if err = rows.Err(); err != nil {
+ return nil, err
+ }
+ return posts, nil
+}
diff --git a/pkg/testutils/fuzzplayground/server.go b/pkg/testutils/fuzzplayground/server.go
new file mode 100644
index 00000000..04f00a99
--- /dev/null
+++ b/pkg/testutils/fuzzplayground/server.go
@@ -0,0 +1,212 @@
+// This package provides a mock server for testing fuzzing templates
+package fuzzplayground
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os/exec"
+ "strconv"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/echo/v4/middleware"
+ "github.com/projectdiscovery/retryablehttp-go"
+)
+
+func GetPlaygroundServer() *echo.Echo {
+ e := echo.New()
+ e.Use(middleware.Recover())
+ e.Use(middleware.Logger())
+
+ e.GET("/", indexHandler)
+ e.GET("/info", infoHandler)
+ e.GET("/redirect", redirectHandler)
+ e.GET("/request", requestHandler)
+ e.GET("/email", emailHandler)
+ e.GET("/permissions", permissionsHandler)
+ e.GET("/blog/post", numIdorHandler) // for num based idors like ?id=44
+ e.POST("/reset-password", resetPasswordHandler)
+ e.GET("/host-header-lab", hostHeaderLabHandler)
+ e.GET("/user/:id/profile", userProfileHandler)
+ e.POST("/user", patchUnsanitizedUserHandler)
+ e.GET("/blog/posts", getPostsHandler)
+ return e
+}
+
+var bodyTemplate = `
+
+Fuzz Playground
+
+
+%s
+
+`
+
+func indexHandler(ctx echo.Context) error {
+ return ctx.HTML(200, fmt.Sprintf(bodyTemplate, `Fuzzing Playground
+
+`))
+}
+
+func infoHandler(ctx echo.Context) error {
+ return ctx.HTML(200, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Name of user: %s%s%s", ctx.QueryParam("name"), ctx.QueryParam("another"), ctx.QueryParam("random"))))
+}
+
+func redirectHandler(ctx echo.Context) error {
+ url := ctx.QueryParam("redirect_url")
+ return ctx.Redirect(302, url)
+}
+
+func requestHandler(ctx echo.Context) error {
+ url := ctx.QueryParam("url")
+ data, err := retryablehttp.DefaultClient().Get(url)
+ if err != nil {
+ return ctx.HTML(500, err.Error())
+ }
+ defer data.Body.Close()
+
+ body, _ := io.ReadAll(data.Body)
+ return ctx.HTML(200, fmt.Sprintf(bodyTemplate, string(body)))
+}
+
+func emailHandler(ctx echo.Context) error {
+ text := ctx.QueryParam("text")
+ if strings.Contains(text, "{{") {
+ trimmed := strings.SplitN(strings.Trim(text[strings.Index(text, "{"):], "{}"), "*", 2)
+ if len(trimmed) < 2 {
+ return ctx.HTML(500, "invalid template")
+ }
+ first, _ := strconv.Atoi(trimmed[0])
+ second, _ := strconv.Atoi(trimmed[1])
+ text = strconv.Itoa(first * second)
+ }
+ return ctx.HTML(200, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Text: %s", text)))
+}
+
+func permissionsHandler(ctx echo.Context) error {
+ command := ctx.QueryParam("cmd")
+ fields := strings.Fields(command)
+ cmd := exec.Command(fields[0], fields[1:]...)
+ data, _ := cmd.CombinedOutput()
+
+ return ctx.HTML(200, fmt.Sprintf(bodyTemplate, string(data)))
+}
+
+func numIdorHandler(ctx echo.Context) error {
+ // validate if any numerical query param is present
+ // if not, return 400 if so, return 200
+ for k := range ctx.QueryParams() {
+ if _, err := strconv.Atoi(ctx.QueryParam(k)); err == nil {
+ return ctx.JSON(200, "Profile Info for user with id "+ctx.QueryParam(k))
+ }
+ }
+ return ctx.JSON(400, "No numerical query param found")
+}
+
+func patchUnsanitizedUserHandler(ctx echo.Context) error {
+ var user User
+
+ contentType := ctx.Request().Header.Get("Content-Type")
+ // manually handle unmarshalling data
+ if strings.Contains(contentType, "application/json") {
+ err := ctx.Bind(&user)
+ if err != nil {
+ return ctx.JSON(500, "Invalid JSON data")
+ }
+ } else if strings.Contains(contentType, "application/x-www-form-urlencoded") {
+ user.Name = ctx.FormValue("name")
+ user.Age, _ = strconv.Atoi(ctx.FormValue("age"))
+ user.Role = ctx.FormValue("role")
+ user.ID, _ = strconv.Atoi(ctx.FormValue("id"))
+ } else if strings.Contains(contentType, "application/xml") {
+ bin, _ := io.ReadAll(ctx.Request().Body)
+ err := xml.Unmarshal(bin, &user)
+ if err != nil {
+ return ctx.JSON(500, "Invalid XML data")
+ }
+ } else if strings.Contains(contentType, "multipart/form-data") {
+ user.Name = ctx.FormValue("name")
+ user.Age, _ = strconv.Atoi(ctx.FormValue("age"))
+ user.Role = ctx.FormValue("role")
+ user.ID, _ = strconv.Atoi(ctx.FormValue("id"))
+ } else {
+ return ctx.JSON(500, "Invalid Content-Type")
+ }
+
+ err := patchUnsanitizedUser(db, user)
+ if err != nil {
+ return ctx.JSON(500, err.Error())
+ }
+ return ctx.JSON(200, "User updated successfully")
+}
+
+// resetPassword mock
+func resetPasswordHandler(c echo.Context) error {
+ var m map[string]interface{}
+ if err := c.Bind(&m); err != nil {
+ return c.JSON(500, "Something went wrong")
+ }
+
+ host := c.Request().Header.Get("X-Forwarded-For")
+ if host == "" {
+ return c.JSON(500, "Something went wrong")
+ }
+ resp, err := http.Get("http://internal." + host + "/update?user=1337&pass=" + m["password"].(string))
+ if err != nil {
+ return c.JSON(500, "Something went wrong")
+ }
+ defer resp.Body.Close()
+ return c.JSON(200, "Password reset successfully")
+}
+
+func hostHeaderLabHandler(c echo.Context) error {
+ // vulnerable app has custom routing and trusts x-forwarded-host
+ // to route to internal services
+ if c.Request().Header.Get("X-Forwarded-Host") != "" {
+ resp, err := http.Get("http://" + c.Request().Header.Get("X-Forwarded-Host"))
+ if err != nil {
+ return c.JSON(500, "Something went wrong")
+ }
+ defer resp.Body.Close()
+ c.Response().Header().Set("Content-Type", resp.Header.Get("Content-Type"))
+ c.Response().WriteHeader(resp.StatusCode)
+ _, err = io.Copy(c.Response().Writer, resp.Body)
+ if err != nil {
+ return c.JSON(500, "Something went wrong")
+ }
+ }
+ return c.JSON(200, "Not a Teapot")
+}
+
+func userProfileHandler(ctx echo.Context) error {
+ val, _ := url.PathUnescape(ctx.Param("id"))
+ fmt.Printf("Unescaped: %s\n", val)
+ user, err := getUnsanitizedUser(db, val)
+ if err != nil {
+ return ctx.JSON(500, err.Error())
+ }
+ return ctx.JSON(200, user)
+}
+
+func getPostsHandler(c echo.Context) error {
+ lang, err := c.Cookie("lang")
+ if err != nil {
+ // If the language cookie is missing, default to English
+ lang = new(http.Cookie)
+ lang.Value = "en"
+ }
+ posts, err := getUnsanitizedPostsByLang(db, lang.Value)
+ if err != nil {
+ return c.JSON(http.StatusInternalServerError, err.Error())
+ }
+ return c.JSON(http.StatusOK, posts)
+}
diff --git a/pkg/types/types.go b/pkg/types/types.go
index fb42ea6f..45a8788a 100644
--- a/pkg/types/types.go
+++ b/pkg/types/types.go
@@ -270,6 +270,8 @@ type Options struct {
DisableRedirects bool
// SNI custom hostname
SNI string
+ // InputFileMode specifies the mode of input file (jsonl, burp, openapi, swagger, etc)
+ InputFileMode string
// DialerTimeout sets the timeout for network requests.
DialerTimeout time.Duration
// DialerKeepAlive sets the keep alive duration for network requests.
@@ -370,6 +372,17 @@ type Options struct {
ScanID string
// JsConcurrency is the number of concurrent js routines to run
JsConcurrency int
+ // Fuzz enabled execution of fuzzing templates
+ // Note: when Fuzz is enabled other templates will not be executed
+ FuzzTemplates bool
+ // SecretsFile is file containing secrets for nuclei
+ SecretsFile goflags.StringSlice
+ // PreFetchSecrets pre-fetches the secrets from the auth provider
+ PreFetchSecrets bool
+ // FormatUseRequiredOnly only uses required fields when generating requests
+ FormatUseRequiredOnly bool
+ // SkipFormatValidation is used to skip format validation
+ SkipFormatValidation bool
// PayloadConcurrency is the number of concurrent payloads to run per template
PayloadConcurrency int
}
diff --git a/pkg/utils/http_probe.go b/pkg/utils/http_probe.go
index 1e3db9ab..19059b2a 100644
--- a/pkg/utils/http_probe.go
+++ b/pkg/utils/http_probe.go
@@ -5,6 +5,7 @@ import (
"net/http"
"github.com/projectdiscovery/httpx/common/httpx"
+ "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
"github.com/projectdiscovery/useragent"
)
@@ -32,3 +33,18 @@ func ProbeURL(input string, httpxclient *httpx.HTTPX) string {
}
return ""
}
+
+type inputLivenessChecker struct {
+ client *httpx.HTTPX
+}
+
+// ProbeURL probes the scheme for a URL. first HTTPS is tried
+func (i *inputLivenessChecker) ProbeURL(input string) (string, error) {
+ return ProbeURL(input, i.client), nil
+}
+
+// GetInputLivenessChecker returns a new input liveness checker using provided httpx client
+func GetInputLivenessChecker(client *httpx.HTTPX) types.InputLivenessProbe {
+ x := &inputLivenessChecker{client: client}
+ return x
+}