diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 7d33dd1..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: Feature request -about: Request feature to implement in this project -labels: 'Type: Enhancement' ---- - - - -### Please describe your feature request: - - -### Describe the use case of this feature: - diff --git a/.github/ISSUE_TEMPLATE/issue-report.md b/.github/ISSUE_TEMPLATE/issue-report.md deleted file mode 100644 index d689b0f..0000000 --- a/.github/ISSUE_TEMPLATE/issue-report.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: Issue report -about: Create a report to help us to improve the project -labels: 'Type: Bug' - ---- - - - - - -### simplehttpserver version: - - - - -### Current Behavior: - - -### Expected Behavior: - - -### Steps To Reproduce: - - - -### Anything else: - \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/reference-templates/bug-report-reference.yml b/.github/ISSUE_TEMPLATE/reference-templates/bug-report-reference.yml new file mode 100644 index 0000000..901a1fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/reference-templates/bug-report-reference.yml @@ -0,0 +1,79 @@ +name: Bug Report +description: Create a report to help us to improve the simplehttpserver. +title: "[BUG] ..." +labels: ["Type: Bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + For support requests, FAQs or "How to" questions, please use the [GitHub Discussions](https://github.com/projectdiscovery/simplehttpserver/discussions) section instead or join our [Discord server](https://discord.gg/projectdiscovery) to discuss the idea on the **#simplehttpserver** channel. + + :warning: **Issues missing important information may be closed without further investigation.** + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues. + required: true + - type: textarea + attributes: + label: Current Behavior + description: A concise description of what you're experiencing. + validations: + required: true + - type: textarea + attributes: + label: Expected Behavior + description: A concise description of what you expected to happen. + validations: + required: true + - type: textarea + attributes: + label: Steps To Reproduce + description: | + Steps to reproduce the behavior, for example, commands to run simplehttpserver. + + πŸ“ For a more detailed output that could help in troubleshooting, you may want to run simplehttpserver with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood. + + :warning: **Please redact any literal target hosts/URLs or other sensitive information.** + placeholder: | + 1. Run `simplehttpserver -t ...` + validations: + required: true + - type: textarea + attributes: + label: Relevant log output + description: | + Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + + πŸ“ For a more detailed output that could help in troubleshooting, you may want to run simplehttpserver with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood. + + :warning: **Please redact any literal target hosts/URLs or other sensitive information.** + render: shell + - type: textarea + attributes: + label: Environment + description: | + Examples: + - **OS**: Ubuntu 20.04 + - **simplehttpserver** (`simplehttpserver -version`): v3.3.1 + - **Go** (`go version`): go1.22.0 _(only if you've installed it via the `go install` command)_ + value: | + - OS: + - simplehttpserver: + - Go: + render: markdown + validations: + required: true + - type: textarea + attributes: + label: Anything else? + description: | + Links? References? Templates? Anything that will give us more context about the issue you are encountering! + + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/reference-templates/feature-request-reference.yml b/.github/ISSUE_TEMPLATE/reference-templates/feature-request-reference.yml new file mode 100644 index 0000000..18fc17a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/reference-templates/feature-request-reference.yml @@ -0,0 +1,37 @@ +name: Feature Request +description: Request feature to implement in the simplehttpserver. +title: "[FEATURE] ..." +labels: ["Type: Enhancement"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this feature request! + + Please make sure to provide a detailed description with all the relevant information that might be required to start working on this feature. In case you are not sure about your request or whether the particular feature is already supported or not, please [start a discussion](https://github.com/projectdiscovery/simplehttpserver/discussions/categories/ideas) instead. + + Join our [Discord server](https://discord.gg/projectdiscovery) to discuss the idea on the **#simplehttpserver** channel. + - type: textarea + attributes: + label: Describe your feature request + description: A clear and concise description of feature to implement. + validations: + required: true + - type: textarea + attributes: + label: Describe the use case of the feature + description: A clear and concise description of the feature request's motivation and the use-cases in which it could be useful. + validations: + required: true + - type: textarea + attributes: + label: Describe alternatives you've considered + description: A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + - type: textarea + attributes: + label: Additional context + description: Add any other context about the feature request here. + validations: + required: false diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml new file mode 100644 index 0000000..273b6ac --- /dev/null +++ b/.github/auto_assign.yml @@ -0,0 +1,9 @@ +addReviewers: true +reviewers: + - dogancanbakir + - dwisiswant0 + - mzack9999 + +numberOfReviewers: 1 +skipKeywords: + - '@dependabot' \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 69d9543..e5e1f5f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,13 +1,6 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 updates: - - # Maintain dependencies for GitHub Actions - - package-ecosystem: "github-actions" + - package-ecosystem: "gomod" directory: "/" schedule: interval: "weekly" @@ -15,9 +8,19 @@ updates: commit-message: prefix: "chore" include: "scope" + allow: + - dependency-name: "github.com/projectdiscovery/*" + groups: + modules: + patterns: ["github.com/projectdiscovery/*"] + security: + applies-to: "security-updates" + patterns: ["*"] + exclude-patterns: ["github.com/projectdiscovery/*"] + labels: + - "Type: Maintenance" - # Maintain dependencies for go modules - - package-ecosystem: "gomod" + - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" @@ -25,13 +28,21 @@ updates: commit-message: prefix: "chore" include: "scope" + groups: + workflows: + patterns: ["*"] + exclude-patterns: ["projectdiscovery/actions/*"] + labels: + - "Type: Maintenance" - # Maintain dependencies for docker - - package-ecosystem: "docker" - directory: "/" - schedule: - interval: "weekly" - target-branch: "dev" - commit-message: - prefix: "chore" - include: "scope" \ No newline at end of file +# # Maintain dependencies for docker +# - package-ecosystem: "docker" +# directory: "/" +# schedule: +# interval: "weekly" +# target-branch: "dev" +# commit-message: +# prefix: "chore" +# include: "scope" +# labels: +# - "Type: Maintenance" diff --git a/.github/workflows/auto-merge.yaml b/.github/workflows/auto-merge.yaml new file mode 100644 index 0000000..302b94a --- /dev/null +++ b/.github/workflows/auto-merge.yaml @@ -0,0 +1,28 @@ +name: πŸ€– Auto Merge + +on: + pull_request_review: + types: [submitted] + workflow_run: + workflows: ["♾️ Compatibility Check"] + types: + - completed + +permissions: + pull-requests: write + issues: write + repository-projects: write + +jobs: + auto-merge: + runs-on: ubuntu-latest + if: github.actor == 'dependabot[bot]' + steps: + - uses: actions/checkout@v7 + with: + token: ${{ secrets.DEPENDABOT_PAT }} + + - uses: ahmadnassri/action-dependabot-auto-merge@v2 + with: + github-token: ${{ secrets.DEPENDABOT_PAT }} + target: all \ No newline at end of file diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index c9baa4e..5173e5d 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -13,13 +13,8 @@ jobs: name: Test Builds runs-on: ubuntu-latest steps: - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: 1.19 - - - name: Check out code - uses: actions/checkout@v3 + - uses: actions/checkout@v7 + - uses: projectdiscovery/actions/setup/go@v1 - name: Test run: go test . diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2863865..7f20180 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -26,16 +26,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v7 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 \ No newline at end of file + uses: github/codeql-action/analyze@v4 \ No newline at end of file diff --git a/.github/workflows/dockerhub-push.yml b/.github/workflows/dockerhub-push.yml index d141bff..a0e6411 100644 --- a/.github/workflows/dockerhub-push.yml +++ b/.github/workflows/dockerhub-push.yml @@ -13,22 +13,22 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v7 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v4 - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} - name: Build and push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v7 with: context: . platforms: linux/amd64,linux/arm64,linux/arm diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml index 7f4c078..fe56a0d 100644 --- a/.github/workflows/lint-test.yml +++ b/.github/workflows/lint-test.yml @@ -12,15 +12,6 @@ jobs: name: Lint Test runs-on: ubuntu-latest steps: - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: 1.19 - - name: Checkout code - uses: actions/checkout@v3 - - name: Run golangci-lint - uses: golangci/golangci-lint-action@v3.4.0 - with: - version: latest - args: --timeout 5m - working-directory: . \ No newline at end of file + - uses: actions/checkout@v7 + - uses: projectdiscovery/actions/setup/go@v1 + - uses: projectdiscovery/actions/golangci-lint/v2@v1 \ No newline at end of file diff --git a/.github/workflows/release-binary.yml b/.github/workflows/release-binary.yml index 8581b0b..82a1d48 100644 --- a/.github/workflows/release-binary.yml +++ b/.github/workflows/release-binary.yml @@ -10,16 +10,10 @@ jobs: release: runs-on: ubuntu-latest steps: - - name: "Set up Go" - uses: actions/setup-go@v4 - with: - go-version: 1.19 - - name: "Check out code" - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - uses: actions/checkout@v7 + - uses: projectdiscovery/actions/setup/go@v1 - name: "Create release on GitHub" - uses: goreleaser/goreleaser-action@v4 + uses: goreleaser/goreleaser-action@v7 env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" SLACK_WEBHOOK: "${{ secrets.RELEASE_SLACK_WEBHOOK }}" diff --git a/.gitignore b/.gitignore index 4f9c0f3..0a0b7ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.exe cmd/simplehttpserver/simplehttpserver +simplehttpserver diff --git a/Dockerfile b/Dockerfile index cbcb4d2..113729d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20.2-alpine as build-env +FROM golang:1.27.0-alpine as build-env RUN go install -v github.com/projectdiscovery/simplehttpserver/cmd/simplehttpserver@latest FROM alpine:latest diff --git a/README.md b/README.md index 8d087ae..7452d6a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ SimpleHTTPserver is a go enhanced version of the well known python simplehttpser - HTTP/S Web Server - File Server with arbitrary directory support - HTTP request/response dump +- JSON request logging to file - Configurable ip address and listening port - Configurable HTTP/TCP server with customizable response via YAML template @@ -72,6 +73,7 @@ This will display help for the tool. Here are all the switches it supports. | `-silent` | Show only results | `simplehttpserver -silent` | | `-py` | Emulate Python Style | `simplehttpserver -py` | | `-header` | HTTP response header (can be used multiple times) | `simplehttpserver -header 'X-Powered-By: Go'` | +| `-json-log` | JSON log file path for request logging | `simplehttpserver -json-log /tmp/requests.json` | ### Running simplehttpserver in the current folder @@ -121,6 +123,39 @@ To upload files use the following curl request with basic auth header: curl -v --user 'root:root' --upload-file file.txt http://localhost:8000/file.txt ``` +### Running simplehttpserver with JSON request logging + +This will run the tool and log all HTTP requests to a JSON file: + +```sh +simplehttpserver -json-log /tmp/requests.json + +2021/01/11 21:40:48 Serving . on http://0.0.0.0:8000/... +``` + +The JSON log file will contain structured request data including: +- Timestamp, remote address, HTTP method, URL, protocol +- Status code, response size, user agent +- Request headers, request body, response body + +Example JSON log entry: +```json +{ + "timestamp": "2021-01-11T21:41:15Z", + "remote_addr": "127.0.0.1:50181", + "method": "GET", + "url": "/", + "proto": "HTTP/1.1", + "status_code": 200, + "size": 383, + "user_agent": "curl/7.68.0", + "headers": { + "Accept": "*/*", + "User-Agent": "curl/7.68.0" + } +} +``` + ### Running TCP server with custom responses This will run the tool as TLS TCP server and enable custom responses based on YAML templates: diff --git a/go.mod b/go.mod index 01a2ea1..f596ba1 100644 --- a/go.mod +++ b/go.mod @@ -1,27 +1,53 @@ module github.com/projectdiscovery/simplehttpserver -go 1.19 +go 1.25.0 require ( - github.com/fsnotify/fsnotify v1.6.0 + github.com/fsnotify/fsnotify v1.10.1 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 - github.com/projectdiscovery/gologger v1.1.8 + github.com/projectdiscovery/goflags v0.1.76 + github.com/projectdiscovery/gologger v1.1.72 github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e gopkg.in/yaml.v2 v2.4.0 ) require ( - github.com/dsnet/compress v0.0.1 // indirect - github.com/golang/snappy v0.0.1 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a // indirect + github.com/djherbis/times v1.6.0 // indirect + github.com/ebitengine/purego v0.10.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gorilla/css v1.0.1 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/mholt/archiver v3.1.1+incompatible // indirect + github.com/kr/pretty v0.1.0 // indirect + github.com/logrusorgru/aurora/v4 v4.0.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/microcosm-cc/bluemonday v1.0.27 // indirect + github.com/miekg/dns v1.1.72 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/nwaples/rardecode v1.1.0 // indirect - github.com/pierrec/lz4 v2.6.0+incompatible // indirect - github.com/ulikunitz/xz v0.5.7 // indirect - github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect - golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect - gopkg.in/djherbis/times.v1 v1.3.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/projectdiscovery/blackrock v0.0.1 // indirect + github.com/projectdiscovery/utils v0.11.1 // indirect + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect + github.com/shirou/gopsutil/v4 v4.26.3 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/mod v0.35.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/tools v0.44.0 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 866d4e0..3a5afca 100644 --- a/go.sum +++ b/go.sum @@ -1,70 +1,117 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a h1:Ohw57yVY2dBTt+gsC6aZdteyxwlxfbtgkFEMTEkwgSw= +github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= -github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= -github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= -github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= +github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= +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/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= -github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= -github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= +github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUpJYn9JA= +github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +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/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= -github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= -github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/projectdiscovery/gologger v1.1.8 h1:CFlCzGlqAhPqWIrAXBt1OVh5jkMs1qgoR/z4xhdzLNE= -github.com/projectdiscovery/gologger v1.1.8/go.mod h1:bNyVaC1U/NpJtFkJltcesn01NR3K8Hg6RsLVce6yvrw= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= +github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= +github.com/projectdiscovery/goflags v0.1.76 h1:4OnNU4hvzVdOc+7wcIYBnPOHzo0BcTJ5lC6hS/TeUkA= +github.com/projectdiscovery/goflags v0.1.76/go.mod h1:7nAP1r2Dqgn/rwmOE3EWbZWUCEJKNIhVSBGpuzJAIns= +github.com/projectdiscovery/gologger v1.1.72 h1:PKk+aSx3jYOCBPi+FD+nTnhe+Vxx9u3K7Ega0GVlMCI= +github.com/projectdiscovery/gologger v1.1.72/go.mod h1:mJwODZcFDg70ihINpOvZevmBtgvpP8H9/l8Y+OPhZPY= github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e h1:IZa08TUGbU7I0HUb9QQt/8wuu2fPZqfnMXwWhtMxei8= github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e/go.mod h1:jSp8W5zIkNPxAqVdcoFlfv0K5cqogTe65fMinR0Fvuk= +github.com/projectdiscovery/utils v0.11.1 h1:PWj1KjIASxt8icxommH72C0TQqNOvGkcSODRkiq0SQw= +github.com/projectdiscovery/utils v0.11.1/go.mod h1:yktGrHGk2CTjNiccXovnvGrLHX9sV2bqz9nSnbA3V8M= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= +github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc= +github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4= -github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= -golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= -gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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 h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= diff --git a/internal/runner/options.go b/internal/runner/options.go index 2890a04..8c45098 100644 --- a/internal/runner/options.go +++ b/internal/runner/options.go @@ -7,6 +7,7 @@ import ( "path/filepath" "strings" + "github.com/projectdiscovery/goflags" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger/levels" "github.com/projectdiscovery/simplehttpserver/pkg/httpserver" @@ -27,6 +28,7 @@ type Options struct { Verbose bool EnableUpload bool EnableTCP bool + LogUA bool RulesFile string TCPWithTLS bool Version bool @@ -38,38 +40,56 @@ type Options struct { Python bool CORS bool HTTPHeaders HTTPHeaders + JSONLogFile string } // ParseOptions parses the command line options for application func ParseOptions() *Options { options := &Options{} - flag.StringVar(&options.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port") - flag.BoolVar(&options.EnableTCP, "tcp", false, "TCP Server") - flag.BoolVar(&options.TCPWithTLS, "tls", false, "Enable TCP TLS") - flag.StringVar(&options.RulesFile, "rules", "", "Rules yaml file") + flagSet := goflags.NewFlagSet() + flagSet.SetDescription(`SimpleHTTPserver is a go enhanced version of the well known python simplehttpserver with in addition a fully customizable TCP server, both supporting TLS`) + currentPath := "." if p, err := os.Getwd(); err == nil { currentPath = p } - flag.StringVar(&options.Folder, "path", currentPath, "Folder") - flag.BoolVar(&options.EnableUpload, "upload", false, "Enable upload via PUT") - flag.BoolVar(&options.HTTPS, "https", false, "HTTPS") - flag.StringVar(&options.TLSCertificate, "cert", "", "HTTPS Certificate") - flag.StringVar(&options.TLSKey, "key", "", "HTTPS Certificate Key") - flag.StringVar(&options.TLSDomain, "domain", "local.host", "Domain") - flag.BoolVar(&options.Verbose, "verbose", false, "Verbose") - flag.StringVar(&options.BasicAuth, "basic-auth", "", "Basic auth (username:password)") - flag.StringVar(&options.Realm, "realm", "Please enter username and password", "Realm") - flag.BoolVar(&options.Version, "version", false, "Show version of the software") - flag.BoolVar(&options.Silent, "silent", false, "Show only results in the output") - flag.BoolVar(&options.Sandbox, "sandbox", false, "Enable sandbox mode") - flag.BoolVar(&options.HTTP1Only, "http1", false, "Enable only HTTP1") - flag.IntVar(&options.MaxFileSize, "max-file-size", 50, "Max Upload File Size") - flag.IntVar(&options.MaxDumpBodySize, "max-dump-body-size", -1, "Max Dump Body Size") - flag.BoolVar(&options.Python, "py", false, "Emulate Python Style") - flag.BoolVar(&options.CORS, "cors", false, "Enable Cross-Origin Resource Sharing (CORS)") - flag.Var(&options.HTTPHeaders, "header", "Add HTTP Response Header (name: value), can be used multiple times") - flag.Parse() + + flagSet.CreateGroup("input", "Input", + flagSet.StringVar(&options.ListenAddress, "listen", "0.0.0.0:8000", "Address:Port"), + ) + + flagSet.CreateGroup("config", "Config", + flagSet.BoolVar(&options.EnableTCP, "tcp", false, "TCP Server"), + flagSet.BoolVar(&options.TCPWithTLS, "tls", false, "Enable TCP TLS"), + flagSet.StringVar(&options.RulesFile, "rules", "", "Rules yaml file"), + flagSet.StringVar(&options.Folder, "path", currentPath, "Folder"), + flagSet.BoolVar(&options.EnableUpload, "upload", false, "Enable upload via PUT"), + flagSet.BoolVar(&options.HTTPS, "https", false, "HTTPS"), + flagSet.StringVar(&options.TLSCertificate, "cert", "", "HTTPS Certificate"), + flagSet.StringVar(&options.TLSKey, "key", "", "HTTPS Certificate Key"), + flagSet.StringVar(&options.TLSDomain, "domain", "local.host", "Domain"), + flagSet.StringVar(&options.BasicAuth, "basic-auth", "", "Basic auth (username:password),"), + flagSet.StringVar(&options.Realm, "realm", "Please enter username and password", "Realm"), + flagSet.BoolVar(&options.Silent, "silent", false, "Show only results in the output"), + flagSet.BoolVar(&options.Sandbox, "sandbox", false, "Enable sandbox mode"), + flagSet.BoolVar(&options.HTTP1Only, "http1", false, "Enable only HTTP1"), + flagSet.IntVar(&options.MaxFileSize, "max-file-size", 50, "Max Upload File Size"), + flagSet.IntVar(&options.MaxDumpBodySize, "max-dump-body-size", -1, "Max Dump Body Size"), + flagSet.BoolVar(&options.Python, "py", false, "Emulate Python Style"), + flagSet.BoolVar(&options.CORS, "cors", false, "Enable Cross-Origin Resource Sharing (CORS)"), + flagSet.Var(&options.HTTPHeaders, "header", "Add HTTP Response Header (name: value), can be used multiple times"), + flagSet.StringVar(&options.JSONLogFile, "json-log", "", "JSON log file path for request logging"), + ) + + flagSet.CreateGroup("debug", "Debug", + flagSet.BoolVar(&options.Version, "version", false, "Show version of the software"), + flagSet.BoolVar(&options.Verbose, "verbose", false, "Verbose"), + flagSet.BoolVar(&options.LogUA, "log-ua", false, "Log User Agent"), + ) + + if err := flagSet.Parse(); err != nil { + gologger.Fatal().Msgf("%v: parse error", err.Error()) + } // Read the inputs and configure the logging options.configureOutput() diff --git a/internal/runner/runner.go b/internal/runner/runner.go index dc63940..eecf8b8 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -46,7 +46,11 @@ func New(options *Options) (*Runner, error) { if err != nil { return nil, err } - defer watcher.Close() + defer func() { + if watcher != nil { + _ = watcher.Close() + } + }() r.serverTCP = serverTCP return &r, nil @@ -55,6 +59,7 @@ func New(options *Options) (*Runner, error) { httpServer, err := httpserver.New(&httpserver.Options{ Folder: r.options.Folder, EnableUpload: r.options.EnableUpload, + LogUA: r.options.LogUA, ListenAddress: r.options.ListenAddress, TLS: r.options.HTTPS, Certificate: r.options.TLSCertificate, @@ -71,6 +76,7 @@ func New(options *Options) (*Runner, error) { Python: r.options.Python, CORS: r.options.CORS, HTTPHeaders: r.options.HTTPHeaders, + JSONLogFile: r.options.JSONLogFile, }) if err != nil { return nil, err diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go index 5dd65a6..53e3f73 100644 --- a/pkg/httpserver/httpserver.go +++ b/pkg/httpserver/httpserver.go @@ -14,6 +14,7 @@ import ( type Options struct { Folder string EnableUpload bool + LogUA bool // enable logging user agent ListenAddress string TLS bool Certificate string @@ -30,12 +31,14 @@ type Options struct { Python bool CORS bool HTTPHeaders []HTTPHeader + JSONLogFile string } // HTTPServer instance type HTTPServer struct { - options *Options - layers http.Handler + options *Options + layers http.Handler + jsonLogger *JSONLogger } // LayerHandler is the interface of all layer funcs @@ -46,6 +49,16 @@ func New(options *Options) (*HTTPServer, error) { var h HTTPServer EnableUpload = options.EnableUpload EnableVerbose = options.Verbose + EnableLogUA = options.LogUA + + // Initialize JSON logger if specified + if options.JSONLogFile != "" { + jsonLogger, err := NewJSONLogger(options.JSONLogFile) + if err != nil { + return nil, err + } + h.jsonLogger = jsonLogger + } folder, err := filepath.Abs(options.Folder) if err != nil { return nil, err @@ -127,5 +140,8 @@ func (t *HTTPServer) ListenAndServeTLS() error { // Close the service func (t *HTTPServer) Close() error { + if t.jsonLogger != nil { + return t.jsonLogger.Close() + } return nil } diff --git a/pkg/httpserver/jsonlogger.go b/pkg/httpserver/jsonlogger.go new file mode 100644 index 0000000..960ad83 --- /dev/null +++ b/pkg/httpserver/jsonlogger.go @@ -0,0 +1,93 @@ +package httpserver + +import ( + "encoding/json" + "fmt" + "net/http" + "os" + "sync" + "time" +) + +// JSONLogEntry represents a single HTTP request log entry in JSON format +type JSONLogEntry struct { + Timestamp string `json:"timestamp"` + RemoteAddr string `json:"remote_addr"` + Method string `json:"method"` + URL string `json:"url"` + Proto string `json:"proto"` + StatusCode int `json:"status_code"` + Size int `json:"size"` + UserAgent string `json:"user_agent,omitempty"` + Headers map[string]string `json:"headers,omitempty"` + RequestBody string `json:"request_body,omitempty"` + ResponseBody string `json:"response_body,omitempty"` +} + +// JSONLogger handles writing JSON log entries to a file +type JSONLogger struct { + file *os.File + mutex sync.Mutex + enable bool +} + +// NewJSONLogger creates a new JSON logger instance +func NewJSONLogger(filePath string) (*JSONLogger, error) { + if filePath == "" { + return &JSONLogger{enable: false}, nil + } + + file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return nil, fmt.Errorf("failed to open JSON log file: %w", err) + } + + return &JSONLogger{ + file: file, + enable: true, + }, nil +} + +// LogRequest logs an HTTP request to the JSON file +func (jl *JSONLogger) LogRequest(r *http.Request, statusCode, size int, userAgent string, headers map[string]string, requestBody, responseBody string) error { + if !jl.enable { + return nil + } + + entry := JSONLogEntry{ + Timestamp: time.Now().Format(time.RFC3339), + RemoteAddr: r.RemoteAddr, + Method: r.Method, + URL: r.URL.String(), + Proto: r.Proto, + StatusCode: statusCode, + Size: size, + UserAgent: userAgent, + Headers: headers, + RequestBody: requestBody, + ResponseBody: responseBody, + } + + jl.mutex.Lock() + defer jl.mutex.Unlock() + + jsonData, err := json.Marshal(entry) + if err != nil { + return fmt.Errorf("failed to marshal JSON log entry: %w", err) + } + + _, err = jl.file.Write(append(jsonData, '\n')) + if err != nil { + return fmt.Errorf("failed to write JSON log entry: %w", err) + } + + return nil +} + +// Close closes the JSON log file +func (jl *JSONLogger) Close() error { + if jl.file != nil { + return jl.file.Close() + } + return nil +} diff --git a/pkg/httpserver/loglayer.go b/pkg/httpserver/loglayer.go index f3fb4f7..c4fb78d 100644 --- a/pkg/httpserver/loglayer.go +++ b/pkg/httpserver/loglayer.go @@ -5,6 +5,7 @@ import ( "net/http" "net/http/httputil" "time" + "github.com/projectdiscovery/gologger" ) @@ -12,6 +13,7 @@ import ( var ( EnableUpload bool EnableVerbose bool + EnableLogUA bool ) func (t *HTTPServer) shouldDumpBody(bodysize int64) bool { @@ -29,12 +31,41 @@ func (t *HTTPServer) loglayer(handler http.Handler) http.Handler { lrw := newLoggingResponseWriter(w, t.options.MaxDumpBodySize) handler.ServeHTTP(lrw, r) + // Log to JSON file if JSON logger is enabled + if t.jsonLogger != nil { + // Extract headers + headers := make(map[string]string) + for name, values := range r.Header { + if len(values) > 0 { + headers[name] = values[0] + } + } + + // Extract request body from fullRequest + requestBody := "" + if len(fullRequest) > 0 { + // Find the double CRLF that separates headers from body + bodyStart := bytes.Index(fullRequest, []byte("\r\n\r\n")) + if bodyStart != -1 && bodyStart+4 < len(fullRequest) { + requestBody = string(fullRequest[bodyStart+4:]) + } + } + + // Log to JSON file + _ = t.jsonLogger.LogRequest(r, lrw.statusCode, lrw.Size, r.UserAgent(), headers, requestBody, string(lrw.Data)) + } + + // Continue with existing console logging if EnableVerbose { headers := new(bytes.Buffer) lrw.Header().Write(headers) //nolint gologger.Print().Msgf("\n[%s]\nRemote Address: %s\n%s\n%s %d %s\n%s\n%s\n", time.Now().Format("2006-01-02 15:04:05"), r.RemoteAddr, string(fullRequest), r.Proto, lrw.statusCode, http.StatusText(lrw.statusCode), headers.String(), string(lrw.Data)) } else { - gologger.Print().Msgf("[%s] %s \"%s %s %s\" %d %d", time.Now().Format("2006-01-02 15:04:05"), r.RemoteAddr, r.Method, r.URL, r.Proto, lrw.statusCode, lrw.Size) + if EnableLogUA { + gologger.Print().Msgf("[%s] %s \"%s %s %s\" %d %d - %s", time.Now().Format("2006-01-02 15:04:05"), r.RemoteAddr, r.Method, r.URL, r.Proto, lrw.statusCode, lrw.Size, r.UserAgent()) + } else { + gologger.Print().Msgf("[%s] %s \"%s %s %s\" %d %d", time.Now().Format("2006-01-02 15:04:05"), r.RemoteAddr, r.Method, r.URL, r.Proto, lrw.statusCode, lrw.Size) + } } }) }