Compare commits

...

20 Commits

Author SHA1 Message Date
allcontributors[bot]
378d75964c docs: add aldamd as a contributor for code (#1309)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2026-04-15 08:31:37 -04:00
Daniel Aldam
ffdf871abe fix: support LF-only line endings in --request-file parsing (#1306)
* fix: support LF-only line endings in --request-file parsing
* preserve raw body when parsing request file
* Added CRLFCRLF/LFLF request-file parsing tests
* better invalid UTF-8 in request file header error message
* strengthened request-file mixed CRLF LF headers test
* added request-file explicit binary body test
* cargo fmt
* updated request-file header-body separation logic to choose first occurrence & added testing
2026-04-15 08:30:39 -04:00
epi
bedf4d3f8e visual update for readme 2026-04-12 08:02:37 -04:00
epi
7787c83e1e updated readme with pro domain 2026-04-12 07:47:56 -04:00
allcontributors[bot]
242b134a3d docs: add ghsdpolley as a contributor for bug (#1300)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2026-02-08 09:37:34 -05:00
epi
b4ceaef08d removed is_file check from path extraction (#1299) 2026-02-08 09:36:53 -05:00
allcontributors[bot]
143d5710fc docs: add redacean as a contributor for bug (#1296)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2026-02-06 09:25:18 -05:00
epi
0efb0684b5 1293 fix parser unwrap (#1295)
* removed help unwraps

* clippy

* refixed clippy fix
2026-02-06 09:23:37 -05:00
allcontributors[bot]
c7ed9c9899 docs: add Antonio-R1 as a contributor for code, and bug (#1291)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2026-01-21 20:55:27 -05:00
Antonio
510bad0473 Improve the robots.txt regex (#1290)
Co-authored-by: sbiotto <54334833+sbiotto@users.noreply.github.com>
2026-01-21 20:54:36 -05:00
allcontributors[bot]
23661d17c9 docs: add OpenSourceKyle as a contributor for doc, and bug (#1288)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2026-01-17 06:52:48 -05:00
epi
097d54f384 Add security notice for domain impersonation
Added a security notice regarding domain impersonation and official download sources.
2026-01-17 06:47:48 -05:00
epi
970ce73ac4 Merge branch 'main' of github.com:epi052/feroxbuster 2025-12-24 05:46:10 -05:00
epi
5bb42c4004 updated integration tests to use cargo_bin! macro 2025-12-24 05:45:10 -05:00
allcontributors[bot]
0732ee11ef docs: add sebastiaanspeck as a contributor for bug, and doc (#1286)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

---------

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2025-12-24 05:04:04 -05:00
epi
47b4efdd1b updated links to new docs 2025-12-24 05:01:48 -05:00
epi
e50e150fb9 Update links in README for example usage and documentation 2025-12-24 04:47:31 -05:00
epi
84aef80cea Update copyright year in LICENSE file 2025-12-15 19:35:28 -05:00
epi
9fe5bfd622 re-added dockerhub verification 2025-12-13 09:18:43 -05:00
epi
ddd04dac7f Revert workflow changes 2025-12-13 09:17:21 -05:00
31 changed files with 540 additions and 755 deletions

View File

@@ -990,6 +990,63 @@
"contributions": [ "contributions": [
"doc" "doc"
] ]
},
{
"login": "sebastiaanspeck",
"name": "Sebastiaan Speck",
"avatar_url": "https://avatars.githubusercontent.com/u/12570668?v=4",
"profile": "https://github.com/sebastiaanspeck",
"contributions": [
"bug",
"doc"
]
},
{
"login": "OpenSourceKyle",
"name": "OpenSourceKyle",
"avatar_url": "https://avatars.githubusercontent.com/u/173112933?v=4",
"profile": "https://github.com/OpenSourceKyle",
"contributions": [
"doc",
"bug"
]
},
{
"login": "Antonio-R1",
"name": "Antonio",
"avatar_url": "https://avatars.githubusercontent.com/u/54741970?v=4",
"profile": "https://github.com/Antonio-R1",
"contributions": [
"code",
"bug"
]
},
{
"login": "redacean",
"name": "Redacean",
"avatar_url": "https://avatars.githubusercontent.com/u/125687454?v=4",
"profile": "https://github.com/redacean",
"contributions": [
"bug"
]
},
{
"login": "ghsdpolley",
"name": "ghsdpolley",
"avatar_url": "https://avatars.githubusercontent.com/u/19826831?v=4",
"profile": "https://github.com/ghsdpolley",
"contributions": [
"bug"
]
},
{
"login": "aldamd",
"name": "Daniel Aldam",
"avatar_url": "https://avatars.githubusercontent.com/u/178115486?v=4",
"profile": "https://github.com/aldamd",
"contributions": [
"code"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

View File

@@ -16,10 +16,10 @@ Long form explanations of most of the items below can be found in the [CONTRIBUT
## Documentation ## Documentation
- [ ] New code is documented using [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html) - [ ] New code is documented using [doc comments](https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html)
- [ ] Documentation about your PR is included in the `docs`, as needed. The docs live in a [separate repository](https://epi052.github.io/feroxbuster-docs/docs/). Update the appropriate pages at the links below. - [ ] Documentation about your PR is included in the `docs`, as needed. The docs live in a [separate repository](https://epi052.github.io/feroxbuster-docs/). Update the appropriate pages at the links below.
- [ ] update [example config file section](https://epi052.github.io/feroxbuster-docs/docs/configuration/ferox-config-toml/) - [ ] update [example config file section](https://epi052.github.io/feroxbuster-docs/configuration/ferox-config-toml/)
- [ ] update [help output section](https://epi052.github.io/feroxbuster-docs/docs/configuration/command-line/) - [ ] update [help output section](https://epi052.github.io/feroxbuster-docs/configuration/command-line/)
- [ ] add an [example](https://epi052.github.io/feroxbuster-docs/docs/examples/) - [ ] add an [example](https://epi052.github.io/feroxbuster-docs/examples/auto-tune/)
## Additional Tests ## Additional Tests
- [ ] New code is unit tested - [ ] New code is unit tested

View File

@@ -1,310 +0,0 @@
name: Release
on:
push:
tags:
- 'v*.*.*'
permissions:
contents: write
jobs:
create-release:
name: Create GitHub Release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
version: ${{ steps.get_version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get version from tag
id: get_version
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Generate changelog
id: changelog
run: |
# Get previous tag
PREV_TAG=$(git describe --abbrev=0 --tags HEAD^ 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
# First release, get all commits
CHANGELOG=$(git log --pretty=format:"- %s (%h)" --no-merges)
else
# Get commits since previous tag
CHANGELOG=$(git log ${PREV_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges)
fi
# Create changelog file
{
echo "## What's Changed"
echo ""
echo "$CHANGELOG"
echo ""
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${GITHUB_REF_NAME}"
} > CHANGELOG.md
cat CHANGELOG.md
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v2
with:
body_path: CHANGELOG.md
draft: false
prerelease: false
download-and-upload-artifacts:
name: Download & Upload Release Assets
needs: create-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get latest CD Pipeline run
id: get_run
run: |
# Get the latest successful CD Pipeline run for main branch
RUN_ID=$(gh run list --workflow="CD Pipeline" --branch=main --status=success --limit=1 --json databaseId --jq='.[0].databaseId')
echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
run-id: ${{ steps.get_run.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Display structure of downloaded files
run: ls -R artifacts/
- name: Prepare release assets
id: prepare
run: |
mkdir -p release-assets
cd artifacts
# Process Linux x86_64 binary - create tar.gz
if [ -d "x86_64-linux-feroxbuster" ]; then
tar czf ../release-assets/x86_64-linux-feroxbuster.tar.gz -C x86_64-linux-feroxbuster feroxbuster
fi
# Process Linux x86 binary - create tar.gz
if [ -d "x86-linux-feroxbuster" ]; then
tar czf ../release-assets/x86-linux-feroxbuster.tar.gz -C x86-linux-feroxbuster feroxbuster
fi
# Process ARM binaries - create tar.gz
if [ -d "armv7-linux-feroxbuster" ]; then
tar czf ../release-assets/armv7-linux-feroxbuster.tar.gz -C armv7-linux-feroxbuster feroxbuster
fi
if [ -d "aarch64-linux-feroxbuster" ]; then
tar czf ../release-assets/aarch64-linux-feroxbuster.tar.gz -C aarch64-linux-feroxbuster feroxbuster
fi
# Copy macOS tar.gz files (already compressed)
if [ -f "x86_64-macos-feroxbuster.tar.gz/x86_64-macos-feroxbuster.tar.gz" ]; then
cp x86_64-macos-feroxbuster.tar.gz/x86_64-macos-feroxbuster.tar.gz ../release-assets/
fi
if [ -f "aarch64-macos-feroxbuster.tar.gz/aarch64-macos-feroxbuster.tar.gz" ]; then
cp aarch64-macos-feroxbuster.tar.gz/aarch64-macos-feroxbuster.tar.gz ../release-assets/
fi
# Copy Windows executables - create zip files
if [ -d "x86_64-windows-feroxbuster.exe" ]; then
cd x86_64-windows-feroxbuster.exe
zip ../../release-assets/x86_64-windows-feroxbuster.zip feroxbuster.exe
cd ..
fi
if [ -d "x86-windows-feroxbuster.exe" ]; then
cd x86-windows-feroxbuster.exe
zip ../../release-assets/x86-windows-feroxbuster.zip feroxbuster.exe
cd ..
fi
# Copy .deb file
if [ -d "feroxbuster_amd64.deb" ]; then
cp feroxbuster_amd64.deb/*.deb ../release-assets/ || true
fi
cd ..
# Generate SHA256 checksums
cd release-assets
sha256sum * > SHA256SUMS
cat SHA256SUMS
# Extract specific hashes for homebrew
LINUX_HASH=$(grep "x86_64-linux-feroxbuster.tar.gz" SHA256SUMS | awk '{print $1}')
MACOS_X64_HASH=$(grep "x86_64-macos-feroxbuster.tar.gz" SHA256SUMS | awk '{print $1}')
MACOS_ARM_HASH=$(grep "aarch64-macos-feroxbuster.tar.gz" SHA256SUMS | awk '{print $1}')
echo "linux_hash=$LINUX_HASH" >> $GITHUB_OUTPUT
echo "macos_x64_hash=$MACOS_X64_HASH" >> $GITHUB_OUTPUT
echo "macos_arm_hash=$MACOS_ARM_HASH" >> $GITHUB_OUTPUT
- name: Upload Release Assets
uses: softprops/action-gh-release@v2
with:
files: release-assets/*
publish-crates-io:
name: Publish to crates.io
needs: create-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish
update-homebrew:
name: Update Homebrew Taps
needs: [create-release, download-and-upload-artifacts]
runs-on: ubuntu-latest
steps:
- name: Checkout TGotwig's homebrew-linux-feroxbuster
uses: actions/checkout@v4
with:
repository: TGotwig/homebrew-linux-feroxbuster
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: homebrew-linux
- name: Update Linux formula
run: |
cd homebrew-linux
VERSION="${{ needs.create-release.outputs.version }}"
HASH="${{ needs.download-and-upload-artifacts.outputs.linux_hash }}"
# Update version and hash in formula
sed -i "s|url \"https://github.com/epi052/feroxbuster/releases/download/v[^/]*/x86_64-linux-feroxbuster.tar.gz\"|url \"https://github.com/epi052/feroxbuster/releases/download/v${VERSION}/x86_64-linux-feroxbuster.tar.gz\"|g" feroxbuster.rb
sed -i "s/sha256 \"[^\"]*\"/sha256 \"${HASH}\"/g" feroxbuster.rb
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add feroxbuster.rb
git commit -m "Update feroxbuster to v${VERSION}" || echo "No changes to commit"
git push
- name: Checkout feroxbuster main repo to get config
uses: actions/checkout@v4
with:
path: feroxbuster-src
- name: Check if config changed
id: config_check
run: |
cd feroxbuster-src
CONFIG_HASH=$(sha256sum ferox-config.toml.example | awk '{print $1}')
echo "config_hash=$CONFIG_HASH" >> $GITHUB_OUTPUT
# Check if config changed since last tag
PREV_TAG=$(git describe --abbrev=0 --tags HEAD^ 2>/dev/null || echo "")
if [ -n "$PREV_TAG" ]; then
if git diff ${PREV_TAG}..HEAD --quiet -- ferox-config.toml.example; then
echo "config_changed=false" >> $GITHUB_OUTPUT
else
echo "config_changed=true" >> $GITHUB_OUTPUT
fi
else
echo "config_changed=true" >> $GITHUB_OUTPUT
fi
- name: Update config hash in homebrew if changed
if: steps.config_check.outputs.config_changed == 'true'
run: |
cd homebrew-linux
CONFIG_HASH="${{ steps.config_check.outputs.config_hash }}"
# Update config hash if it exists in formula
if grep -q "ferox-config.toml.example" feroxbuster.rb; then
sed -i "s/sha256 \"[^\"]*\" # ferox-config.toml.example/sha256 \"${CONFIG_HASH}\" # ferox-config.toml.example/g" feroxbuster.rb
git add feroxbuster.rb
git commit -m "Update ferox-config.toml.example hash" || echo "No changes to commit"
git push
fi
publish-winget:
name: Publish to Winget
needs: [create-release, download-and-upload-artifacts]
runs-on: ubuntu-latest
steps:
- uses: vedantmgoyal2009/winget-releaser@main
with:
identifier: epi052.feroxbuster
installers-regex: '-windows-feroxbuster\.exe\.zip$'
token: ${{ secrets.WINGET_TOKEN }}
release-tag: v${{ needs.create-release.outputs.version }}
publish-snapcraft:
name: Publish to Snapcraft
needs: [create-release, download-and-upload-artifacts]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Publish to Snapcraft
uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
with:
snap: feroxbuster
release: stable
manual-steps-reminder:
name: Manual Steps Reminder
needs: [create-release, download-and-upload-artifacts]
runs-on: ubuntu-latest
steps:
- name: Create comment with manual steps
uses: actions/github-script@v7
with:
script: |
const version = '${{ needs.create-release.outputs.version }}';
const linuxHash = '${{ needs.download-and-upload-artifacts.outputs.linux_hash }}';
const body = `## 🚀 Release v${version} Published!
### ✅ Automated Steps Completed
- [x] GitHub Release created with changelog
- [x] All artifacts uploaded with SHA256 checksums
- [x] Published to crates.io
- [x] Homebrew tap updated
- [x] Winget package published
- [x] Snapcraft published to stable
### 📋 Manual Steps Required
1. **Kali Linux**
- Go to https://bugs.kali.org/login_page.php?return=%2Fmy_view_page.php
- Request a tool update
3. **Announcement** (optional)
- Tweet about the release if it's significant!
2. **Announcement** (optional)
- Linux x86_64: \`${linuxHash}\`
See full checksums in release assets: SHA256SUMS
`;
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});

21
.github/workflows/winget.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Publish to Winget
on:
release:
types: [released]
workflow_dispatch:
inputs:
tag_name:
description: 'Tag name of release'
required: true
type: string
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: vedantmgoyal2009/winget-releaser@main
with:
identifier: epi052.feroxbuster
installers-regex: '-windows-feroxbuster\.exe\.zip$'
token: ${{ secrets.WINGET_TOKEN }}
release-tag: ${{ inputs.tag_name || github.event.release.tag_name || github.ref_name }}

11
Cargo.lock generated
View File

@@ -116,13 +116,12 @@ dependencies = [
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "2.0.17" version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bd389a4b2970a01282ee455294913c0a43724daedcd1a24c3eb0ec1c1320b66" checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"bstr", "bstr",
"doc-comment",
"libc", "libc",
"predicates", "predicates",
"predicates-core", "predicates-core",
@@ -790,12 +789,6 @@ dependencies = [
"syn 2.0.104", "syn 2.0.104",
] ]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]] [[package]]
name = "dtoa" name = "dtoa"
version = "1.0.10" version = "1.0.10"

View File

@@ -69,7 +69,7 @@ self_update = { version = "0.40", features = [
[dev-dependencies] [dev-dependencies]
tempfile = "3.20" tempfile = "3.20"
httpmock = "0.7" httpmock = "0.7"
assert_cmd = "2.0" assert_cmd = "2.1"
predicates = "3.1" predicates = "3.1"
[profile.release] [profile.release]

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2020-2023 epi Copyright (c) 2020-2026 epi
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -50,12 +50,4 @@ condition = { env_not_set = ["CI"] }
clear = true clear = true
script = """ script = """
cargo nextest run --all-features --all-targets --no-fail-fast --run-ignored all --retries 4 cargo nextest run --all-features --all-targets --no-fail-fast --run-ignored all --retries 4
"""
# coverage
[tasks.coverage]
clear = true
script = """
cargo llvm-cov nextest --all-features --no-fail-fast --retries 4 --html
echo "Coverage report generated at target/llvm-cov/html/index.html"
""" """

View File

@@ -1,3 +1,18 @@
> [!WARNING]
> **Security Notice Domain Impersonation**
>
> The domain **feroxbuster.com** is **NOT affiliated** with this project, its maintainers, or any official feroxbuster releases.
>
> Official feroxbuster downloads are distributed **ONLY** through:
>
> - [https://github.com/epi052/feroxbuster](https://github.com/epi052/feroxbuster/releases) (open source)
> - [https://www.feroxbuster.pro](https://www.feroxbuster.pro) (commercial)
> - package repositories listed in this README
> - package repositories listed in the [installation docs](https://epi052.github.io/feroxbuster-docs/installation/android/)
>
> We do **not** distribute software from feroxbuster.com, and we cannot vouch for the authenticity or safety of files hosted there.
> If you downloaded feroxbuster from any other domain, we strongly recommend deleting it and reinstalling from an official source.
<h1 align="center"> <h1 align="center">
<br> <br>
<a href="https://github.com/epi052/feroxbuster"><img src="img/logo/default-cropped.png" alt="feroxbuster"></a> <a href="https://github.com/epi052/feroxbuster"><img src="img/logo/default-cropped.png" alt="feroxbuster"></a>
@@ -43,29 +58,26 @@
![demo](img/demo.gif) ![demo](img/demo.gif)
<p align="center"> <p align="center">
🦀 <a href="https://github.com/epi052/feroxbuster/releases"><img src="https://img.shields.io/badge/Releases-CF4F4B?style=flat-square&logo=github&logoColor=white" alt="Releases"></a>&nbsp;
<a href="https://github.com/epi052/feroxbuster/releases">Releases</a> ✨ <a href="https://epi052.github.io/feroxbuster-docs/examples/auto-tune/"><img src="https://img.shields.io/badge/Examples-CF4F4B?style=flat-square" alt="Example Usage"></a>&nbsp;
<a href="https://epi052.github.io/feroxbuster-docs/docs/examples/">Example Usage</a> ✨ <a href="https://github.com/epi052/feroxbuster/blob/main/CONTRIBUTING.md"><img src="https://img.shields.io/badge/Contributing-CF4F4B?style=flat-square" alt="Contributing"></a>&nbsp;
<a href="https://github.com/epi052/feroxbuster/blob/main/CONTRIBUTING.md">Contributing</a> ✨ <a href="https://epi052.github.io/feroxbuster-docs/overview"><img src="https://img.shields.io/badge/Documentation-CF4F4B?style=flat-square&logo=bookstack&logoColor=white" alt="Documentation"></a>&nbsp;
<a href="https://epi052.github.io/feroxbuster-docs/docs/">Documentation</a> <a href="https://www.feroxbuster.pro"><img src="https://img.shields.io/badge/Pro-CF4F4B?style=flat-square" alt="Pro"></a>
🦀
</p> </p>
--- ---
<h1><p align="center">✨🎉👉 <a href="https://epi052.github.io/feroxbuster-docs/docs/">NEW DOCUMENTATION SITE</a> 👈🎉✨</p></h1> > [!TIP]
> **Documentation has moved!** &mdash; Instead of having a 1300 line `README.md` (sorry...), feroxbuster's documentation has moved to GitHub Pages. The move to hosting documentation on Pages should make it a LOT easier to find the information you're looking for, whatever that may be. Please check it out for anything you need beyond a quick-start.
>
> **[View the full documentation &#8594;](https://epi052.github.io/feroxbuster-docs/overview)**
## What the heck is a ferox anyway?
## 🚀 Documentation has **moved** 🚀
Instead of having a 1300 line `README.md` (sorry...), feroxbuster's documentation has moved to GitHub Pages. The move to hosting documentation on Pages should make it a LOT easier to find the information you're looking for, whatever that may be. Please check it out for anything you need beyond a quick-start. The new documentation can be found [here](https://epi052.github.io/feroxbuster-docs/docs/).
## 😕 What the heck is a ferox anyway?
Ferox is short for Ferric Oxide. Ferric Oxide, simply put, is rust. The name rustbuster was taken, so I decided on a Ferox is short for Ferric Oxide. Ferric Oxide, simply put, is rust. The name rustbuster was taken, so I decided on a
variation. 🤷 variation.
## 🤔 What's it do tho? ## What's it do tho?
`feroxbuster` is a tool designed to perform [Forced Browsing](https://owasp.org/www-community/attacks/Forced_browsing). `feroxbuster` is a tool designed to perform [Forced Browsing](https://owasp.org/www-community/attacks/Forced_browsing).
@@ -79,17 +91,17 @@ credentials, internal network addressing, etc...
This attack is also known as Predictable Resource Location, File Enumeration, Directory Enumeration, and Resource This attack is also known as Predictable Resource Location, File Enumeration, Directory Enumeration, and Resource
Enumeration. Enumeration.
## Quick Start ## Quick Start
This section will cover the minimum amount of information to get up and running with feroxbuster. Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/docs/), as it's much more comprehensive. This section will cover the minimum amount of information to get up and running with feroxbuster. Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/overview/), as it's much more comprehensive.
### 💿 Installation ### Installation
There are quite a few other [installation methods](https://epi052.github.io/feroxbuster-docs/docs/installation/), but these snippets should cover the majority of users. There are quite a few other [installation methods](https://epi052.github.io/feroxbuster-docs/installation/android/), but these snippets should cover the majority of users.
#### Kali #### Kali
If you're using kali, this is the preferred install method. Installing from the repos adds a [**ferox-config.toml**](https://epi052.github.io/feroxbuster-docs/docs/configuration/ferox-config-toml/) in `/etc/feroxbuster/`, adds command completion for bash, fish, and zsh, includes a man page entry, and installs `feroxbuster` itself. If you're using kali, this is the preferred install method. Installing from the repos adds a [**ferox-config.toml**](https://epi052.github.io/feroxbuster-docs/configuration/ferox-config-toml/) in `/etc/feroxbuster/`, adds command completion for bash, fish, and zsh, includes a man page entry, and installs `feroxbuster` itself.
``` ```
sudo apt update && sudo apt install -y feroxbuster sudo apt update && sudo apt install -y feroxbuster
@@ -135,7 +147,7 @@ choco install feroxbuster
#### All others #### All others
Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/docs/). Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/overview).
### Updating feroxbuster (new in v2.9.1) ### Updating feroxbuster (new in v2.9.1)
@@ -143,9 +155,9 @@ Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/d
./feroxbuster --update ./feroxbuster --update
``` ```
## 🧰 Example Usage ## Example Usage
Here are a few brief examples to get you started. Please note, feroxbuster can do a **lot more** than what's listed below. As a result, there are **many more** examples, with **demonstration gifs** that highlight specific features, in the [documentation](https://epi052.github.io/feroxbuster-docs/docs/). Here are a few brief examples to get you started. Please note, feroxbuster can do a **lot more** than what's listed below. As a result, there are **many more** examples, with **demonstration gifs** that highlight specific features, in the [documentation](https://epi052.github.io/feroxbuster-docs/overview).
### Multiple Values ### Multiple Values
@@ -205,13 +217,12 @@ cat targets | ./feroxbuster --stdin --silent -s 200 301 302 --redirects -x js |
./feroxbuster -u http://127.1 --data-urlencoded @file.payload ./feroxbuster -u http://127.1 --data-urlencoded @file.payload
``` ```
## 🚀 Documentation has **moved** 🚀 > [!TIP]
> For realsies, there used to be over 1300 lines in this README, but it's all been moved to the [new documentation site](https://epi052.github.io/feroxbuster-docs/overview). Go check it out!
>
> **[View the full documentation &#8594;](https://epi052.github.io/feroxbuster-docs/overview)**
For realsies, there used to be over 1300 lines in this README, but it's all been moved to the [new documentation site](https://epi052.github.io/feroxbuster-docs/docs/). Go check it out! ## Contributors
<h1><p align="center">✨🎉👉 <a href="https://epi052.github.io/feroxbuster-docs/docs/">DOCUMENTATION</a> 👈🎉✨</p></h1>
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -357,6 +368,12 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
</tr> </tr>
<tr> <tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pg9051"><img src="https://avatars.githubusercontent.com/u/202219877?v=4?s=100" width="100px;" alt="pg9051"/><br /><sub><b>pg9051</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/commits?author=pg9051" title="Documentation">📖</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/pg9051"><img src="https://avatars.githubusercontent.com/u/202219877?v=4?s=100" width="100px;" alt="pg9051"/><br /><sub><b>pg9051</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/commits?author=pg9051" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sebastiaanspeck"><img src="https://avatars.githubusercontent.com/u/12570668?v=4?s=100" width="100px;" alt="Sebastiaan Speck"/><br /><sub><b>Sebastiaan Speck</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/issues?q=author%3Asebastiaanspeck" title="Bug reports">🐛</a> <a href="https://github.com/epi052/feroxbuster/commits?author=sebastiaanspeck" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/OpenSourceKyle"><img src="https://avatars.githubusercontent.com/u/173112933?v=4?s=100" width="100px;" alt="OpenSourceKyle"/><br /><sub><b>OpenSourceKyle</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/commits?author=OpenSourceKyle" title="Documentation">📖</a> <a href="https://github.com/epi052/feroxbuster/issues?q=author%3AOpenSourceKyle" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Antonio-R1"><img src="https://avatars.githubusercontent.com/u/54741970?v=4?s=100" width="100px;" alt="Antonio"/><br /><sub><b>Antonio</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/commits?author=Antonio-R1" title="Code">💻</a> <a href="https://github.com/epi052/feroxbuster/issues?q=author%3AAntonio-R1" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/redacean"><img src="https://avatars.githubusercontent.com/u/125687454?v=4?s=100" width="100px;" alt="Redacean"/><br /><sub><b>Redacean</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/issues?q=author%3Aredacean" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ghsdpolley"><img src="https://avatars.githubusercontent.com/u/19826831?v=4?s=100" width="100px;" alt="ghsdpolley"/><br /><sub><b>ghsdpolley</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/issues?q=author%3Aghsdpolley" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aldamd"><img src="https://avatars.githubusercontent.com/u/178115486?v=4?s=100" width="100px;" alt="Daniel Aldam"/><br /><sub><b>Daniel Aldam</b></sub></a><br /><a href="https://github.com/epi052/feroxbuster/commits?author=aldamd" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -13,7 +13,7 @@
<licenseUrl>https://github.com/epi052/feroxbuster/blob/main/LICENSE</licenseUrl> <licenseUrl>https://github.com/epi052/feroxbuster/blob/main/LICENSE</licenseUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<projectSourceUrl>https://github.com/epi052/feroxbuster</projectSourceUrl> <projectSourceUrl>https://github.com/epi052/feroxbuster</projectSourceUrl>
<docsUrl>https://epi052.github.io/feroxbuster-docs/docs/</docsUrl> <docsUrl>https://epi052.github.io/feroxbuster-docs/</docsUrl>
<!--<mailingListUrl></mailingListUrl>--> <!--<mailingListUrl></mailingListUrl>-->
<bugTrackerUrl>https://github.com/epi052/feroxbuster/issues</bugTrackerUrl> <bugTrackerUrl>https://github.com/epi052/feroxbuster/issues</bugTrackerUrl>
<tags>content-discovery pentesting-tool url-bruteforcer</tags> <tags>content-discovery pentesting-tool url-bruteforcer</tags>
@@ -43,19 +43,19 @@ Enumeration.
## Quick Start ## Quick Start
This section will cover the minimum amount of information to get up and running with feroxbuster. Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/docs/), as it's much more comprehensive. This section will cover the minimum amount of information to get up and running with feroxbuster. Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/overview), as it's much more comprehensive.
### Installation ### Installation
There are quite a few other [installation methods](https://epi052.github.io/feroxbuster-docs/docs/installation/), but these snippets should cover the majority of users. There are quite a few other [installation methods](https://epi052.github.io/feroxbuster-docs/installation/android/), but these snippets should cover the majority of users.
#### All others Docs #### All others Docs
Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/docs/). Please refer the the [documentation](https://epi052.github.io/feroxbuster-docs/overview).
## Example Usage ## Example Usage
Here are a few brief examples to get you started. Please note, feroxbuster can do a **lot more** than what's listed below. As a result, there are **many more** examples, with **demonstration gifs** that highlight specific features, in the [documentation](https://epi052.github.io/feroxbuster-docs/docs/). Here are a few brief examples to get you started. Please note, feroxbuster can do a **lot more** than what's listed below. As a result, there are **many more** examples, with **demonstration gifs** that highlight specific features, in the [documentation](https://epi052.github.io/feroxbuster-docs/overview).
### Multiple Values ### Multiple Values

View File

@@ -10,9 +10,8 @@ description: |
This attack is also known as Predictable Resource Location, File Enumeration, Directory Enumeration, and Resource Enumeration. This attack is also known as Predictable Resource Location, File Enumeration, Directory Enumeration, and Resource Enumeration.
confinement: strict
grade: stable base: core18
base: core22
plugs: plugs:
etc-feroxbuster: etc-feroxbuster:

View File

@@ -381,32 +381,54 @@ impl ContentType {
/// unless overridden by CLI options. /// unless overridden by CLI options.
/// ///
pub fn parse_request_file(config: &mut Configuration) -> Result<()> { pub fn parse_request_file(config: &mut Configuration) -> Result<()> {
// read in the file located at config.request_file // read in the file (raw bytes) located at config.request_file
// parse the file into a Request struct // parse the file into a Request struct
let contents = std::fs::read_to_string(&config.request_file)?; let contents = std::fs::read(&config.request_file)?;
if contents.is_empty() { if contents.is_empty() {
bail!("Empty --request-file file provided"); bail!("Empty --request-file file provided");
} }
// this should split the body from the request line and headers // find the first header/body separator
let lines = contents.split("\r\n\r\n").collect::<Vec<&str>>(); // locate both \r\n\r\n and \n\n and pick whichever appears earliest,
// so that a \r\n\r\n inside the body doesn't shadow a \n\n separator
// that terminates the headers
let crlf = contents.windows(4).position(|w| w == b"\r\n\r\n");
let lf = contents.windows(2).position(|w| w == b"\n\n");
if lines.len() < 2 { let (sep_idx, sep_len) = match (crlf, lf) {
bail!("Invalid request: Missing head/body CRLF separator"); (Some(c), Some(l)) => {
} if c <= l {
(c, 4)
} else {
(l, 2)
}
}
(Some(c), None) => (c, 4),
(None, Some(l)) => (l, 2),
(None, None) => bail!("Invalid request: Missing head/body separator"),
};
let head = lines[0]; // split the request head and body
let body = lines[1].as_bytes().to_vec(); let head_bytes = &contents[..sep_idx];
let body_bytes = &contents[sep_idx + sep_len..];
// we only want to use the request's body if the user hasn't // decode only the head; HTTP framing is generally ascii/utf-8
// compatible
let head = std::str::from_utf8(head_bytes)
.map_err(|_| anyhow::anyhow!("Request headers contain invalid UTF-8"))?;
// normalize line endings in the decoded head
let normalized = head.replace("\r\n", "\n");
// we only want to use the request's body bytes if the user hasn't
// overridden it on the cli // overridden it on the cli
if config.data.is_empty() { if config.data.is_empty() {
config.data = body; config.data = body_bytes.to_vec();
} }
// begin parsing the request line and headers // begin parsing the request line and normalized headers
let mut head_parts = head.split("\r\n"); let mut head_parts = normalized.split("\n");
let Some(request_line) = head_parts.next() else { let Some(request_line) = head_parts.next() else {
bail!("Invalid request: Missing request line"); bail!("Invalid request: Missing request line");
@@ -441,7 +463,7 @@ pub fn parse_request_file(config: &mut Configuration) -> Result<()> {
} }
for mut line in head_parts { for mut line in head_parts {
line = line.trim(); line = line.trim_matches('\r').trim();
if line.is_empty() { if line.is_empty() {
break; // Empty line signals the end of headers break; // Empty line signals the end of headers
@@ -904,7 +926,7 @@ mod tests {
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.unwrap_err().to_string(), result.unwrap_err().to_string(),
"Invalid request: Missing head/body CRLF separator" "Invalid request: Missing head/body separator"
); );
tmp.cleanup(); tmp.cleanup();
@@ -1345,4 +1367,145 @@ mod tests {
let result = split_query(""); let result = split_query("");
assert!(result.is_err()); assert!(result.is_err());
} }
#[test]
fn test_parse_raw_lf_only_request() -> io::Result<()> {
let mut tmp = TempSetup::new();
tmp.file
.write_all(b"GET / HTTP/1.1\nHost: example.com\n\nbody")?;
let result = parse_request_file(&mut tmp.config);
assert!(result.is_ok());
assert_eq!(tmp.config.data, b"body".to_vec());
tmp.cleanup();
Ok(())
}
#[test]
fn test_parse_raw_crlf_request() -> io::Result<()> {
let mut tmp = TempSetup::new();
tmp.file
.write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\nbody")?;
let result = parse_request_file(&mut tmp.config);
assert!(result.is_ok());
assert_eq!(tmp.config.data, b"body".to_vec());
tmp.cleanup();
Ok(())
}
#[test]
fn test_parse_raw_crlf_body_preserved() -> io::Result<()> {
let mut tmp = TempSetup::new();
let body = b"line1\r\nline2\r\nbinary\x00data";
let mut request = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".to_vec();
request.extend_from_slice(body);
tmp.file.write_all(&request)?;
parse_request_file(&mut tmp.config).unwrap();
assert_eq!(tmp.config.data, body.to_vec());
tmp.cleanup();
Ok(())
}
#[test]
fn test_parse_raw_lf_headers_crlf_body() -> io::Result<()> {
let mut tmp = TempSetup::new();
let body = b"line1\r\nline2\r\n";
let mut request = b"GET / HTTP/1.1\nHost: example.com\n\n".to_vec();
request.extend_from_slice(body);
tmp.file.write_all(&request)?;
parse_request_file(&mut tmp.config).unwrap();
assert_eq!(tmp.config.data, body.to_vec());
tmp.cleanup();
Ok(())
}
#[test]
fn test_parse_raw_mixed_newlines_headers() -> io::Result<()> {
let mut tmp = TempSetup::new();
tmp.file
.write_all(b"GET / HTTP/1.1\r\nHost: example.com\nUser-Agent: test\r\n\nbody")?;
let result = parse_request_file(&mut tmp.config);
assert!(result.is_ok());
assert_eq!(tmp.config.data, b"body".to_vec());
assert!(tmp.config.headers.contains_key("Host"));
assert_eq!(tmp.config.headers.get("Host").unwrap(), "example.com");
assert_eq!(tmp.config.user_agent, "test");
tmp.cleanup();
Ok(())
}
#[test]
fn test_parse_raw_binary_body_preserved() -> io::Result<()> {
let mut tmp = TempSetup::new();
let body = b"\x00\xde\xad\xbe\xef\x80binary";
let mut request = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".to_vec();
request.extend_from_slice(body);
tmp.file.write_all(&request)?;
parse_request_file(&mut tmp.config).unwrap();
assert_eq!(tmp.config.data, body.to_vec());
tmp.cleanup();
Ok(())
}
#[test]
fn test_parse_raw_lf_headers_with_crlf_crlf_in_body() -> io::Result<()> {
// headers are LF-separated; body contains \r\n\r\n
let mut tmp = TempSetup::new();
tmp.file.write_all(
b"POST /upload HTTP/1.1\nHost: example.com\nContent-Type: application/octet-stream\n\nabc\r\n\r\ndef",
)?;
let result = parse_request_file(&mut tmp.config);
assert!(result.is_ok());
assert_eq!(tmp.config.data, b"abc\r\n\r\ndef".to_vec());
assert_eq!(tmp.config.target_url, "https://example.com/upload");
tmp.cleanup();
Ok(())
}
#[test]
fn test_parse_raw_crlf_headers_with_lf_lf_in_body() -> io::Result<()> {
let mut tmp = TempSetup::new();
tmp.file
.write_all(b"POST /upload HTTP/1.1\r\nHost: example.com\r\n\r\nabc\n\ndef")?;
parse_request_file(&mut tmp.config).unwrap();
assert_eq!(tmp.config.data, b"abc\n\ndef".to_vec());
tmp.cleanup();
Ok(())
}
} }

View File

@@ -227,8 +227,10 @@ impl TermOutHandler {
self.handles = Some(handles); self.handles = Some(handles);
} }
Command::Exit => { Command::Exit => {
if self.file_task.is_some() && self.tx_file.send(Command::Exit).is_ok() { if self.tx_file.send(Command::Exit).is_ok() {
self.file_task.as_mut().unwrap().await??; // wait for death if let Some(task) = self.file_task.as_mut() {
task.await??; // wait for death
}
} }
break; break;
} }
@@ -280,26 +282,31 @@ impl TermOutHandler {
} }
log::trace!("report complete: {}", resp.url()); log::trace!("report complete: {}", resp.url());
if self.config.replay_client.is_some() && should_process_response { if should_process_response {
// replay proxy specified/client created and this response's status code is one that if let Some(client) = self.config.replay_client.as_ref() {
// should be replayed; not using logged_request due to replay proxy client // replay proxy specified/client created and this response's status code is one that
let data = if self.config.data.is_empty() { // should be replayed; not using logged_request due to replay proxy client
None let data = if self.config.data.is_empty() {
} else { None
Some(self.config.data.as_slice()) } else {
}; Some(self.config.data.as_slice())
};
make_request( make_request(
self.config.replay_client.as_ref().unwrap(), client,
resp.url(), resp.url(),
resp.method().as_str(), resp.method().as_str(),
data, data,
self.config.output_level, self.config.output_level,
&self.config, &self.config,
tx_stats.clone(), tx_stats.clone(),
) )
.await .await
.with_context(|| "Could not replay request through replay proxy")?; .with_context(|| "Could not replay request through replay proxy")?;
} else {
// replay proxy not configured, skip replay without exiting response processing
log::trace!("replay proxy not configured, skipping replay");
}
} }
if self.config.collect_backups if self.config.collect_backups

View File

@@ -51,7 +51,7 @@ pub(super) const LINKFINDER_REGEX: &str = r#"(?x)
/// ///
/// ref: https://developers.google.com/search/reference/robots_txt /// ref: https://developers.google.com/search/reference/robots_txt
pub(super) const ROBOTS_TXT_REGEX: &str = pub(super) const ROBOTS_TXT_REGEX: &str =
r#"(?m)^ *(Allow|Disallow): *(?P<url_path>[a-zA-Z0-9._/?#@!&'()+,;%=-]+?)$"#; // multi-line (?m) r#"(?m)^[ \t]*(?i)(allow|disallow)[ \t]*:[ \t]*(?P<url_path>[^ \t\r\n#$]*)?[ \t]*\$?(?:#.*)?$"#; // multi-line (?m), case-insensitive (?i)
/// Regular expression to filter bad characters from extracted url paths /// Regular expression to filter bad characters from extracted url paths
/// ///
@@ -136,11 +136,7 @@ impl<'a> ExtractorBuilder<'a> {
links_regex: Regex::new(LINKFINDER_REGEX).unwrap(), links_regex: Regex::new(LINKFINDER_REGEX).unwrap(),
robots_regex: Regex::new(ROBOTS_TXT_REGEX).unwrap(), robots_regex: Regex::new(ROBOTS_TXT_REGEX).unwrap(),
url_regex: Regex::new(URL_CHARS_REGEX).unwrap(), url_regex: Regex::new(URL_CHARS_REGEX).unwrap(),
response: if self.response.is_some() { response: self.response,
Some(self.response.unwrap())
} else {
None
},
url: self.url.to_owned(), url: self.url.to_owned(),
handles: self.handles.as_ref().unwrap().clone(), handles: self.handles.as_ref().unwrap().clone(),
target: self.target, target: self.target,

View File

@@ -233,9 +233,7 @@ impl<'a> Extractor<'a> {
} }
// request and report assumed file // request and report assumed file
if (resp.is_file() || !resp.is_directory()) if !resp.is_directory() && !c_handles.config.force_recursion {
&& !c_handles.config.force_recursion
{
log::debug!("Extracted File: {resp}"); log::debug!("Extracted File: {resp}");
c_scanned_urls.add_file_scan( c_scanned_urls.add_file_scan(

View File

@@ -743,12 +743,18 @@ pub fn initialize() -> Command {
// which is fine, but if you add -h|--help, it still errors out on the bad flag/option, // which is fine, but if you add -h|--help, it still errors out on the bad flag/option,
// never showing the full help message. This code addresses that behavior // never showing the full help message. This code addresses that behavior
if arg == "--help" { if arg == "--help" {
app.print_long_help().unwrap(); if let Err(err) = app.print_long_help() {
eprintln!("couldn't print help message: {}", err);
process::exit(1);
}
println!(); // just a newline to mirror original --help output println!(); // just a newline to mirror original --help output
process::exit(0); process::exit(0);
} else if arg == "-h" { } else if arg == "-h" {
// same for -h, just shorter // same for -h, just shorter
app.print_help().unwrap(); if let Err(err) = app.print_help() {
eprintln!("couldn't print help message: {}", err);
process::exit(1);
}
println!(); println!();
process::exit(0); process::exit(0);
} }
@@ -813,7 +819,7 @@ EXAMPLES:
./feroxbuster -u http://127.1 --auto-tune ./feroxbuster -u http://127.1 --auto-tune
Examples and demonstrations of all features Examples and demonstrations of all features
https://epi052.github.io/feroxbuster-docs/docs/examples/ https://epi052.github.io/feroxbuster-docs/examples/auto-tune/
"#; "#;
#[cfg(test)] #[cfg(test)]

View File

@@ -192,26 +192,6 @@ impl FeroxResponse {
self.text.shrink_to_fit(); // allocated capacity shrinks to reflect the new size self.text.shrink_to_fit(); // allocated capacity shrinks to reflect the new size
} }
/// Make a reasonable guess at whether the response is a file or not
///
/// Examines the last part of a path to determine if it has an obvious extension
/// i.e. http://localhost/some/path/stuff.js where stuff.js indicates a file
///
/// Additionally, inspects query parameters, as they're also often indicative of a file
pub fn is_file(&self) -> bool {
let has_extension = if let Some(mut path) = self.url.path_segments() {
if let Some(last) = path.next_back() {
last.contains('.') // last segment has some sort of extension, probably
} else {
false
}
} else {
false
};
self.url.query_pairs().count() > 0 || has_extension
}
/// Returns line count of the response text. /// Returns line count of the response text.
pub fn line_count(&self) -> usize { pub fn line_count(&self) -> usize {
self.line_count self.line_count

View File

@@ -1,6 +1,8 @@
mod utils; mod utils;
use assert_cmd::Command; use assert_cmd::cargo_bin;
use assert_cmd::prelude::*;
use predicates::prelude::*; use predicates::prelude::*;
use std::process::Command;
use utils::{setup_tmp_directory, teardown_tmp_directory}; use utils::{setup_tmp_directory, teardown_tmp_directory};
#[test] #[test]
@@ -13,15 +15,13 @@ fn banner_prints_proxy() -> Result<(), Box<dyn std::error::Error>> {
]; ];
let (tmp_dir, file) = setup_tmp_directory(&urls, "wordlist")?; let (tmp_dir, file) = setup_tmp_directory(&urls, "wordlist")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--stdin") .arg("--stdin")
.arg("--proxy") .arg("--proxy")
.arg("http://127.0.0.1:8080") .arg("http://127.0.0.1:8080")
.arg("--wordlist") .arg("--wordlist")
.arg("/definitely/doesnt/exist/0cd7fed0-47f4-4b18-a1b0-ac39708c1676") .arg("/definitely/doesnt/exist/0cd7fed0-47f4-4b18-a1b0-ac39708c1676")
.pipe_stdin(file) .stdin(std::fs::File::open(file)?)
.unwrap()
.assert() .assert()
.success() .success()
.stderr( .stderr(
@@ -53,15 +53,13 @@ fn banner_prints_replay_proxy() -> Result<(), Box<dyn std::error::Error>> {
]; ];
let (tmp_dir, file) = setup_tmp_directory(&urls, "wordlist")?; let (tmp_dir, file) = setup_tmp_directory(&urls, "wordlist")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--stdin") .arg("--stdin")
.arg("--wordlist") .arg("--wordlist")
.arg("/definitely/doesnt/exist/0cd7fed0-47f4-4b18-a1b0-ac39708c1676") .arg("/definitely/doesnt/exist/0cd7fed0-47f4-4b18-a1b0-ac39708c1676")
.arg("--replay-proxy") .arg("--replay-proxy")
.arg("http://127.0.0.1:8081") .arg("http://127.0.0.1:8081")
.pipe_stdin(file) .stdin(std::fs::File::open(file)?)
.unwrap()
.assert() .assert()
.success() .success()
.stderr( .stderr(
@@ -87,8 +85,7 @@ fn banner_prints_replay_proxy() -> Result<(), Box<dyn std::error::Error>> {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + multiple headers /// expect to see all mandatory prints + multiple headers
fn banner_prints_headers() { fn banner_prints_headers() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--headers") .arg("--headers")
@@ -119,8 +116,7 @@ fn banner_prints_headers() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + multiple dont scan url & regex entries /// expect to see all mandatory prints + multiple dont scan url & regex entries
fn banner_prints_denied_urls() { fn banner_prints_denied_urls() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--dont-scan") .arg("--dont-scan")
@@ -155,8 +151,7 @@ fn banner_prints_denied_urls() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + multiple scope url entries /// expect to see all mandatory prints + multiple scope url entries
fn banner_prints_scope_urls() { fn banner_prints_scope_urls() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--scope") .arg("--scope")
@@ -188,8 +183,7 @@ fn banner_prints_scope_urls() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + multiple headers /// expect to see all mandatory prints + multiple headers
fn banner_prints_random_agent() { fn banner_prints_random_agent() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--random-agent") .arg("--random-agent")
@@ -215,8 +209,7 @@ fn banner_prints_random_agent() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + multiple size filters /// expect to see all mandatory prints + multiple size filters
fn banner_prints_filter_sizes() { fn banner_prints_filter_sizes() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-S") .arg("-S")
@@ -261,8 +254,7 @@ fn banner_prints_filter_sizes() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + queries /// expect to see all mandatory prints + queries
fn banner_prints_queries() { fn banner_prints_queries() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-Q") .arg("-Q")
@@ -293,8 +285,7 @@ fn banner_prints_queries() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + status codes /// expect to see all mandatory prints + status codes
fn banner_prints_status_codes() { fn banner_prints_status_codes() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-s") .arg("-s")
@@ -321,8 +312,7 @@ fn banner_prints_status_codes() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + replay codes /// expect to see all mandatory prints + replay codes
fn banner_prints_replay_codes() { fn banner_prints_replay_codes() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--replay-codes") .arg("--replay-codes")
@@ -353,8 +343,7 @@ fn banner_prints_replay_codes() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + output file /// expect to see all mandatory prints + output file
fn banner_prints_output_file() { fn banner_prints_output_file() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--output") .arg("--output")
@@ -385,8 +374,7 @@ fn banner_prints_output_file() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + insecure /// expect to see all mandatory prints + insecure
fn banner_prints_insecure() { fn banner_prints_insecure() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-k") .arg("-k")
@@ -413,8 +401,7 @@ fn banner_prints_insecure() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + follow redirects /// expect to see all mandatory prints + follow redirects
fn banner_prints_redirects() { fn banner_prints_redirects() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-r") .arg("-r")
@@ -441,8 +428,7 @@ fn banner_prints_redirects() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + extensions /// expect to see all mandatory prints + extensions
fn banner_prints_extensions() { fn banner_prints_extensions() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-x") .arg("-x")
@@ -472,8 +458,7 @@ fn banner_prints_extensions() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + dont_filter /// expect to see all mandatory prints + dont_filter
fn banner_prints_dont_filter() { fn banner_prints_dont_filter() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--dont-filter") .arg("--dont-filter")
@@ -500,8 +485,7 @@ fn banner_prints_dont_filter() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + verbosity=1 /// expect to see all mandatory prints + verbosity=1
fn banner_prints_verbosity_one() { fn banner_prints_verbosity_one() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-v") .arg("-v")
@@ -528,8 +512,7 @@ fn banner_prints_verbosity_one() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + verbosity=2 /// expect to see all mandatory prints + verbosity=2
fn banner_prints_verbosity_two() { fn banner_prints_verbosity_two() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-vv") .arg("-vv")
@@ -556,8 +539,7 @@ fn banner_prints_verbosity_two() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + verbosity=3 /// expect to see all mandatory prints + verbosity=3
fn banner_prints_verbosity_three() { fn banner_prints_verbosity_three() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-vvv") .arg("-vvv")
@@ -584,8 +566,7 @@ fn banner_prints_verbosity_three() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + verbosity=4 /// expect to see all mandatory prints + verbosity=4
fn banner_prints_verbosity_four() { fn banner_prints_verbosity_four() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-vvvv") .arg("-vvvv")
@@ -612,8 +593,7 @@ fn banner_prints_verbosity_four() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + add slash /// expect to see all mandatory prints + add slash
fn banner_prints_add_slash() { fn banner_prints_add_slash() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-f") .arg("-f")
@@ -640,8 +620,7 @@ fn banner_prints_add_slash() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + INFINITE recursion /// expect to see all mandatory prints + INFINITE recursion
fn banner_prints_infinite_depth() { fn banner_prints_infinite_depth() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--depth") .arg("--depth")
@@ -669,8 +648,7 @@ fn banner_prints_infinite_depth() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + recursion depth /// expect to see all mandatory prints + recursion depth
fn banner_prints_recursion_depth() { fn banner_prints_recursion_depth() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--depth") .arg("--depth")
@@ -698,8 +676,7 @@ fn banner_prints_recursion_depth() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + server certs /// expect to see all mandatory prints + server certs
fn banner_prints_server_certs() { fn banner_prints_server_certs() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--server-certs") .arg("--server-certs")
@@ -729,8 +706,7 @@ fn banner_prints_server_certs() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + server certs /// expect to see all mandatory prints + server certs
fn banner_prints_client_cert_and_key() { fn banner_prints_client_cert_and_key() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--client-cert") .arg("--client-cert")
@@ -762,8 +738,7 @@ fn banner_prints_client_cert_and_key() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + no recursion /// expect to see all mandatory prints + no recursion
fn banner_prints_no_recursion() { fn banner_prints_no_recursion() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-n") .arg("-n")
@@ -790,8 +765,7 @@ fn banner_prints_no_recursion() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see nothing /// expect to see nothing
fn banner_doesnt_print() { fn banner_doesnt_print() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-q") .arg("-q")
@@ -808,8 +782,7 @@ fn banner_doesnt_print() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + extract-links /// expect to see all mandatory prints + extract-links
fn banner_prints_extract_links() { fn banner_prints_extract_links() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-e") .arg("-e")
@@ -836,8 +809,7 @@ fn banner_prints_extract_links() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + scan-limit /// expect to see all mandatory prints + scan-limit
fn banner_prints_scan_limit() { fn banner_prints_scan_limit() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-L") .arg("-L")
@@ -865,8 +837,7 @@ fn banner_prints_scan_limit() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + response-size-limit /// expect to see all mandatory prints + response-size-limit
fn banner_prints_response_size_limit() { fn banner_prints_response_size_limit() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--response-size-limit") .arg("--response-size-limit")
@@ -894,8 +865,7 @@ fn banner_prints_response_size_limit() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + filter-status /// expect to see all mandatory prints + filter-status
fn banner_prints_filter_status() { fn banner_prints_filter_status() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-C") .arg("-C")
@@ -922,8 +892,7 @@ fn banner_prints_filter_status() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + json /// expect to see all mandatory prints + json
fn banner_prints_json() { fn banner_prints_json() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--json") .arg("--json")
@@ -952,8 +921,7 @@ fn banner_prints_json() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + json /// expect to see all mandatory prints + json
fn banner_prints_debug_log() { fn banner_prints_debug_log() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--debug-log") .arg("--debug-log")
@@ -981,8 +949,7 @@ fn banner_prints_debug_log() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + regex filters /// expect to see all mandatory prints + regex filters
fn banner_prints_filter_regex() { fn banner_prints_filter_regex() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--filter-regex") .arg("--filter-regex")
@@ -1010,8 +977,7 @@ fn banner_prints_filter_regex() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + time limit /// expect to see all mandatory prints + time limit
fn banner_prints_time_limit() { fn banner_prints_time_limit() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--time-limit") .arg("--time-limit")
@@ -1039,8 +1005,7 @@ fn banner_prints_time_limit() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + similarity filter /// expect to see all mandatory prints + similarity filter
fn banner_prints_similarity_filter() { fn banner_prints_similarity_filter() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--filter-similar-to") .arg("--filter-similar-to")
@@ -1068,8 +1033,7 @@ fn banner_prints_similarity_filter() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + rate limit /// expect to see all mandatory prints + rate limit
fn banner_prints_rate_limit() { fn banner_prints_rate_limit() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--rate-limit") .arg("--rate-limit")
@@ -1097,8 +1061,7 @@ fn banner_prints_rate_limit() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + auto tune /// expect to see all mandatory prints + auto tune
fn banner_prints_auto_tune() { fn banner_prints_auto_tune() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--auto-tune") .arg("--auto-tune")
@@ -1125,8 +1088,7 @@ fn banner_prints_auto_tune() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + auto bail /// expect to see all mandatory prints + auto bail
fn banner_prints_auto_bail() { fn banner_prints_auto_bail() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--auto-bail") .arg("--auto-bail")
@@ -1153,8 +1115,7 @@ fn banner_prints_auto_bail() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see no banner output /// expect to see no banner output
fn banner_doesnt_print_when_silent() { fn banner_doesnt_print_when_silent() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--silent") .arg("--silent")
@@ -1179,8 +1140,7 @@ fn banner_doesnt_print_when_silent() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see no banner output /// expect to see no banner output
fn banner_doesnt_print_when_quiet() { fn banner_doesnt_print_when_quiet() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--quiet") .arg("--quiet")
@@ -1205,8 +1165,7 @@ fn banner_doesnt_print_when_quiet() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see nothing as --parallel forces --silent to be true /// expect to see nothing as --parallel forces --silent to be true
fn banner_prints_parallel() { fn banner_prints_parallel() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--stdin") .arg("--stdin")
.arg("--quiet") .arg("--quiet")
.arg("--parallel") .arg("--parallel")
@@ -1231,8 +1190,7 @@ fn banner_prints_parallel() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + methods /// expect to see all mandatory prints + methods
fn banner_prints_methods() { fn banner_prints_methods() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-m") .arg("-m")
@@ -1262,8 +1220,7 @@ fn banner_prints_methods() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + data body /// expect to see all mandatory prints + data body
fn banner_prints_data() { fn banner_prints_data() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-m") .arg("-m")
@@ -1295,8 +1252,7 @@ fn banner_prints_data() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + ignored extensions /// expect to see all mandatory prints + ignored extensions
fn banner_prints_collect_extensions_and_dont_collect_default() { fn banner_prints_collect_extensions_and_dont_collect_default() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--collect-extensions") .arg("--collect-extensions")
@@ -1324,8 +1280,7 @@ fn banner_prints_collect_extensions_and_dont_collect_default() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect extensions /// expect to see all mandatory prints + collect extensions
fn banner_prints_collect_extensions_and_dont_collect_with_input() { fn banner_prints_collect_extensions_and_dont_collect_with_input() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--collect-extensions") .arg("--collect-extensions")
@@ -1356,8 +1311,7 @@ fn banner_prints_collect_extensions_and_dont_collect_with_input() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect backups /// expect to see all mandatory prints + collect backups
fn banner_prints_collect_backups() { fn banner_prints_collect_backups() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--collect-backups") .arg("--collect-backups")
@@ -1383,8 +1337,7 @@ fn banner_prints_collect_backups() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect words /// expect to see all mandatory prints + collect words
fn banner_prints_collect_words() { fn banner_prints_collect_words() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--collect-words") .arg("--collect-words")
@@ -1410,8 +1363,7 @@ fn banner_prints_collect_words() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect words /// expect to see all mandatory prints + collect words
fn banner_prints_all_composite_settings_smart() { fn banner_prints_all_composite_settings_smart() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--smart") .arg("--smart")
@@ -1440,8 +1392,7 @@ fn banner_prints_all_composite_settings_smart() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect words /// expect to see all mandatory prints + collect words
fn banner_prints_all_composite_settings_thorough() { fn banner_prints_all_composite_settings_thorough() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--thorough") .arg("--thorough")
@@ -1470,8 +1421,7 @@ fn banner_prints_all_composite_settings_thorough() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect words /// expect to see all mandatory prints + collect words
fn banner_prints_all_composite_settings_burp() { fn banner_prints_all_composite_settings_burp() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--burp") .arg("--burp")
@@ -1498,8 +1448,7 @@ fn banner_prints_all_composite_settings_burp() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect words /// expect to see all mandatory prints + collect words
fn banner_prints_all_composite_settings_data_json_stdin() { fn banner_prints_all_composite_settings_data_json_stdin() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--data-json") .arg("--data-json")
@@ -1525,8 +1474,7 @@ fn banner_prints_all_composite_settings_data_json_stdin() {
#[test] #[test]
fn banner_prints_all_composite_settings_data_json_file() { fn banner_prints_all_composite_settings_data_json_file() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-m") .arg("-m")
@@ -1555,8 +1503,7 @@ fn banner_prints_all_composite_settings_data_json_file() {
#[test] #[test]
fn banner_prints_all_composite_settings_data_urlencoded_stdin() { fn banner_prints_all_composite_settings_data_urlencoded_stdin() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("-m") .arg("-m")
@@ -1590,8 +1537,7 @@ fn banner_prints_all_composite_settings_data_urlencoded_stdin() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect words /// expect to see all mandatory prints + collect words
fn banner_prints_all_composite_settings_data_urlencoded_file() { fn banner_prints_all_composite_settings_data_urlencoded_file() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--data-urlencoded") .arg("--data-urlencoded")
@@ -1622,8 +1568,7 @@ fn banner_prints_all_composite_settings_data_urlencoded_file() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + collect words /// expect to see all mandatory prints + collect words
fn banner_prints_all_composite_settings_burp_replay() { fn banner_prints_all_composite_settings_burp_replay() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--burp-replay") .arg("--burp-replay")
@@ -1650,8 +1595,7 @@ fn banner_prints_all_composite_settings_burp_replay() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + force recursion /// expect to see all mandatory prints + force recursion
fn banner_prints_force_recursion() { fn banner_prints_force_recursion() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--force-recursion") .arg("--force-recursion")
@@ -1677,8 +1621,7 @@ fn banner_prints_force_recursion() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + scan-dir-listings /// expect to see all mandatory prints + scan-dir-listings
fn banner_prints_scan_dir_listings() { fn banner_prints_scan_dir_listings() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--scan-dir-listings") .arg("--scan-dir-listings")
@@ -1704,8 +1647,7 @@ fn banner_prints_scan_dir_listings() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + protocol /// expect to see all mandatory prints + protocol
fn banner_prints_limit_dirs() { fn banner_prints_limit_dirs() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("localhost") .arg("localhost")
.arg("--limit-bars") .arg("--limit-bars")
@@ -1732,8 +1674,7 @@ fn banner_prints_limit_dirs() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + force recursion /// expect to see all mandatory prints + force recursion
fn banner_prints_update_app() { fn banner_prints_update_app() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--update") .arg("--update")
.assert() .assert()
.success() .success()
@@ -1744,8 +1685,7 @@ fn banner_prints_update_app() {
/// test allows non-existent wordlist to trigger the banner printing to stderr /// test allows non-existent wordlist to trigger the banner printing to stderr
/// expect to see all mandatory prints + unique /// expect to see all mandatory prints + unique
fn banner_prints_unique() { fn banner_prints_unique() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://localhost") .arg("http://localhost")
.arg("--unique") .arg("--unique")

View File

@@ -1,4 +1,5 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use httpmock::MockServer; use httpmock::MockServer;
use predicates::prelude::*; use predicates::prelude::*;
@@ -12,8 +13,7 @@ fn read_in_config_file_for_settings() -> Result<(), Box<dyn std::error::Error>>
let (tmp_dir, file) = setup_tmp_directory(&["threads = 37".to_string()], "ferox-config.toml")?; let (tmp_dir, file) = setup_tmp_directory(&["threads = 37".to_string()], "ferox-config.toml")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.current_dir(&tmp_dir) .current_dir(&tmp_dir)
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))

View File

@@ -1,9 +1,10 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use assert_cmd::Command;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
use predicates::prelude::*; use predicates::prelude::*;
use std::process::Command;
use utils::{setup_tmp_directory, teardown_tmp_directory}; use utils::{setup_tmp_directory, teardown_tmp_directory};
#[test] #[test]
@@ -17,8 +18,7 @@ fn deny_list_works_during_with_a_normal_scan() {
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -54,8 +54,7 @@ fn deny_list_works_during_extraction() {
then.status(200); then.status(200);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -109,8 +108,7 @@ fn deny_list_works_during_recursion() {
.body("this is a test and is more bytes than other ones"); .body("this is a test and is more bytes than other ones");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -179,8 +177,7 @@ fn deny_list_works_during_recursion_with_inverted_parents() {
.body("this is a test and is more bytes than other ones"); .body("this is a test and is more bytes than other ones");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/js")) .arg(srv.url("/js"))
.arg("--wordlist") .arg("--wordlist")
@@ -222,8 +219,7 @@ fn deny_list_prevents_regex_that_denies_base_url() {
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -256,8 +252,7 @@ fn deny_list_prevents_url_that_denies_base_url() {
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")

View File

@@ -1,4 +1,5 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
@@ -25,8 +26,7 @@ fn extractor_finds_absolute_url() -> Result<(), Box<dyn std::error::Error>> {
then.status(200); then.status(200);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -61,8 +61,7 @@ fn extractor_finds_absolute_url_to_different_domain() -> Result<(), Box<dyn std:
.body("\"http://localhost/homepage/assets/img/icons/handshake.svg\""); .body("\"http://localhost/homepage/assets/img/icons/handshake.svg\"");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -102,8 +101,7 @@ fn extractor_finds_relative_url() -> Result<(), Box<dyn std::error::Error>> {
then.status(200); then.status(200);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -151,8 +149,7 @@ fn extractor_finds_same_relative_url_twice() {
then.status(200); then.status(200);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -194,8 +191,7 @@ fn extractor_finds_filtered_content() -> Result<(), Box<dyn std::error::Error>>
then.status(200).body("im a little teapot"); then.status(200).body("im a little teapot");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -266,8 +262,7 @@ fn extractor_finds_robots_txt_links_and_displays_files_or_scans_directories() {
then.status(403); then.status(403);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -341,8 +336,7 @@ fn extractor_finds_robots_txt_links_and_displays_files_non_recursive() {
then.status(404); then.status(404);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -448,8 +442,7 @@ fn extractor_finds_directory_listing_links_and_displays_files() {
then.status(200).body("im a little teapot too"); // 22 then.status(200).body("im a little teapot too"); // 22
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -557,8 +550,7 @@ fn extractor_finds_directory_listing_links_and_displays_files_non_recursive() {
then.status(200).body("im a little teapot too"); // 22 then.status(200).body("im a little teapot too"); // 22
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -613,8 +605,7 @@ fn extractor_recurses_into_403_directories() -> Result<(), Box<dyn std::error::E
then.status(403); then.status(403);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -685,8 +676,7 @@ fn robots_text_extraction_doesnt_run_with_dont_extract_links() {
then.status(404); then.status(404);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")

View File

@@ -1,4 +1,5 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
@@ -24,8 +25,7 @@ fn filters_status_code_should_filter_response() {
then.status(200).body("this is also a test of some import"); then.status(200).body("this is also a test of some import");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -71,8 +71,7 @@ fn filters_lines_should_filter_response() {
.body("this is also a test of some import\nwith 2 lines, no less"); .body("this is also a test of some import\nwith 2 lines, no less");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -117,8 +116,7 @@ fn filters_words_should_filter_response() {
.body("this is also a test of some import\nwith 2 lines, no less"); .body("this is also a test of some import\nwith 2 lines, no less");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -163,8 +161,7 @@ fn filters_size_should_filter_response() {
.body("this is also a test of some import\nwith 2 lines, no less"); .body("this is also a test of some import\nwith 2 lines, no less");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -222,8 +219,7 @@ fn filters_similar_should_filter_response() {
then.status(200).body(mutated); then.status(200).body(mutated);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -266,8 +262,7 @@ fn collect_backups_should_be_filtered() {
.body("im a backup file, but filtered out because im not 200"); .body("im a backup file, but filtered out because im not 200");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -316,8 +311,7 @@ fn filters_regex_should_filter_response_based_on_headers() {
.body("this is also a test"); .body("this is also a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")

View File

@@ -1,9 +1,10 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use assert_cmd::Command;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::{MockServer, Regex}; use httpmock::{MockServer, Regex};
use predicates::prelude::*; use predicates::prelude::*;
use std::process::Command;
use utils::{setup_tmp_directory, teardown_tmp_directory}; use utils::{setup_tmp_directory, teardown_tmp_directory};
#[test] #[test]
@@ -12,8 +13,7 @@ use utils::{setup_tmp_directory, teardown_tmp_directory};
fn test_single_target_cannot_connect() -> Result<(), Box<dyn std::error::Error>> { fn test_single_target_cannot_connect() -> Result<(), Box<dyn std::error::Error>> {
let (tmp_dir, file) = setup_tmp_directory(&["LICENSE".to_string()], "wordlist")?; let (tmp_dir, file) = setup_tmp_directory(&["LICENSE".to_string()], "wordlist")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://fjdksafjkdsajfkdsajkfdsajkfsdjkdsfdsafdsafdsajkr3l2ajfdskafdsjk") .arg("http://fjdksafjkdsajfkdsajkfdsajkfsdjkdsfdsafdsafdsajkr3l2ajfdskafdsjk")
.arg("--wordlist") .arg("--wordlist")
@@ -37,12 +37,11 @@ fn test_two_targets_cannot_connect() -> Result<(), Box<dyn std::error::Error>> {
let urls = vec![not_real.clone(), not_real]; let urls = vec![not_real.clone(), not_real];
let (tmp_dir, file) = setup_tmp_directory(&urls, "wordlist")?; let (tmp_dir, file) = setup_tmp_directory(&urls, "wordlist")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--stdin") .arg("--stdin")
.arg("--wordlist") .arg("--wordlist")
.arg(file.as_os_str()) .arg(file.as_os_str())
.pipe_stdin(file) .stdin(std::fs::File::open(file)?)
.unwrap() .unwrap()
.assert() .assert()
.success() .success()
@@ -70,12 +69,11 @@ fn test_one_good_and_one_bad_target_scan_succeeds() -> Result<(), Box<dyn std::e
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let mut cmd = Command::cargo_bin("feroxbuster").unwrap(); Command::new(cargo_bin!("feroxbuster"))
.arg("--stdin")
cmd.arg("--stdin")
.arg("--wordlist") .arg("--wordlist")
.arg(file.as_os_str()) .arg(file.as_os_str())
.pipe_stdin(file) .stdin(std::fs::File::open(file)?)
.unwrap() .unwrap()
.assert() .assert()
.success() .success()
@@ -96,8 +94,7 @@ fn test_one_good_and_one_bad_target_scan_succeeds() -> Result<(), Box<dyn std::e
fn test_single_target_cannot_connect_due_to_ssl_errors() -> Result<(), Box<dyn std::error::Error>> { fn test_single_target_cannot_connect_due_to_ssl_errors() -> Result<(), Box<dyn std::error::Error>> {
let (tmp_dir, file) = setup_tmp_directory(&["LICENSE".to_string()], "wordlist")?; let (tmp_dir, file) = setup_tmp_directory(&["LICENSE".to_string()], "wordlist")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("https://expired.badssl.com") .arg("https://expired.badssl.com")
.arg("--wordlist") .arg("--wordlist")
@@ -132,13 +129,11 @@ fn test_two_good_targets_scan_succeeds() -> Result<(), Box<dyn std::error::Error
then.status(403).body("this also is a test"); then.status(403).body("this also is a test");
}); });
let mut cmd = Command::cargo_bin("feroxbuster").unwrap(); Command::new(cargo_bin!("feroxbuster"))
.arg("--stdin")
cmd.arg("--stdin")
.arg("--wordlist") .arg("--wordlist")
.arg(file.as_os_str()) .arg(file.as_os_str())
.pipe_stdin(file) .stdin(std::fs::File::open(file)?)
.unwrap()
.assert() .assert()
.success() .success()
.stdout( .stdout(
@@ -168,8 +163,7 @@ fn test_static_wildcard_request_found() -> Result<(), Box<dyn std::error::Error>
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -205,8 +199,7 @@ fn heuristics_static_wildcard_request_with_dont_filter() -> Result<(), Box<dyn s
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -289,8 +282,7 @@ fn heuristics_wildcard_test_with_two_static_wildcards_with_silent_enabled(
.body("this is a testAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); .body("this is a testAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -341,8 +333,7 @@ fn heuristics_wildcard_test_that_auto_filtering_403s_still_allows_for_recursion_
then.status(200); then.status(200);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")

View File

@@ -1,9 +1,11 @@
mod utils; mod utils;
use assert_cmd::Command; use assert_cmd::cargo_bin;
use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::{MockServer, Regex}; use httpmock::{MockServer, Regex};
use predicates::prelude::*; use predicates::prelude::*;
use std::fs::{read_dir, read_to_string}; use std::fs::{read_dir, read_to_string};
use std::process::Command;
use utils::{setup_tmp_directory, teardown_tmp_directory}; use utils::{setup_tmp_directory, teardown_tmp_directory};
#[test] #[test]
@@ -16,8 +18,7 @@ fn main_use_root_owned_file_as_wordlist() {
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -41,8 +42,7 @@ fn main_use_empty_wordlist() -> Result<(), Box<dyn std::error::Error>> {
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -65,14 +65,12 @@ fn main_use_empty_stdin_targets() -> Result<(), Box<dyn std::error::Error>> {
// get_targets is called before scan, so the empty wordlist shouldn't trigger // get_targets is called before scan, so the empty wordlist shouldn't trigger
// the 'Did not find any words' error // the 'Did not find any words' error
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--stdin") .arg("--stdin")
.arg("--wordlist") .arg("--wordlist")
.arg(file.as_os_str()) .arg(file.as_os_str())
.arg("-vvv") .arg("-vvv")
.pipe_stdin(file) .stdin(std::fs::File::open(file)?)
.unwrap()
.assert() .assert()
.success() .success()
.stderr( .stderr(
@@ -106,8 +104,7 @@ fn main_parallel_spawns_children() -> Result<(), Box<dyn std::error::Error>> {
let (tgt_tmp_dir, targets) = let (tgt_tmp_dir, targets) =
setup_tmp_directory(&[t1.url("/"), t2.url("/"), t3.url("/")], "targets")?; setup_tmp_directory(&[t1.url("/"), t2.url("/"), t3.url("/")], "targets")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.env("RUST_LOG", "trace") .env("RUST_LOG", "trace")
.arg("--stdin") .arg("--stdin")
.arg("--parallel") .arg("--parallel")
@@ -117,8 +114,7 @@ fn main_parallel_spawns_children() -> Result<(), Box<dyn std::error::Error>> {
.arg(outfile.as_os_str()) .arg(outfile.as_os_str())
.arg("--wordlist") .arg("--wordlist")
.arg(wordlist.as_os_str()) .arg(wordlist.as_os_str())
.pipe_stdin(targets) .stdin(std::fs::File::open(targets)?)
.unwrap()
.assert() .assert()
.success() .success()
.stderr( .stderr(
@@ -170,8 +166,7 @@ fn main_parallel_creates_output_directory() -> Result<(), Box<dyn std::error::Er
let (tgt_tmp_dir, targets) = let (tgt_tmp_dir, targets) =
setup_tmp_directory(&[t1.url("/"), t2.url("/"), t3.url("/")], "targets")?; setup_tmp_directory(&[t1.url("/"), t2.url("/"), t3.url("/")], "targets")?;
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--stdin") .arg("--stdin")
.arg("--quiet") .arg("--quiet")
.arg("--parallel") .arg("--parallel")
@@ -180,8 +175,7 @@ fn main_parallel_creates_output_directory() -> Result<(), Box<dyn std::error::Er
.arg(outfile.as_os_str()) .arg(outfile.as_os_str())
.arg("--wordlist") .arg("--wordlist")
.arg(wordlist.as_os_str()) .arg(wordlist.as_os_str())
.pipe_stdin(targets) .stdin(std::fs::File::open(targets)?)
.unwrap()
.assert() .assert()
.success() .success()
.stderr( .stderr(
@@ -276,8 +270,7 @@ fn main_download_wordlist_from_url() -> Result<(), Box<dyn std::error::Error>> {
then.status(200); then.status(200);
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.current_dir(&tmp_dir) .current_dir(&tmp_dir)
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))

View File

@@ -1,5 +1,7 @@
use assert_cmd::Command; use assert_cmd::cargo_bin;
use assert_cmd::prelude::*;
use predicates::prelude::*; use predicates::prelude::*;
use std::process::Command;
#[test] #[test]
/// specify an incorrect param (-fc) with --help after it on the command line /// specify an incorrect param (-fc) with --help after it on the command line
@@ -14,8 +16,7 @@ use predicates::prelude::*;
/// the new behavior we expect to see is to print the long form help message, of which /// the new behavior we expect to see is to print the long form help message, of which
/// Ludicrous speed... go! is near the bottom of that output, so we can test for that /// Ludicrous speed... go! is near the bottom of that output, so we can test for that
fn parser_incorrect_param_with_tack_tack_help() { fn parser_incorrect_param_with_tack_tack_help() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("-fc") .arg("-fc")
.arg("--help") .arg("--help")
.assert() .assert()
@@ -36,8 +37,7 @@ fn parser_incorrect_param_with_tack_tack_help() {
/// the new behavior we expect to see is to print the short form help message, of which /// the new behavior we expect to see is to print the short form help message, of which
/// "[CAUTION] 4 -v's is probably too much" is near the bottom of that output, so we can test for that /// "[CAUTION] 4 -v's is probably too much" is near the bottom of that output, so we can test for that
fn parser_incorrect_param_with_tack_h() { fn parser_incorrect_param_with_tack_h() {
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("-fc") .arg("-fc")
.arg("-h") .arg("-h")
.assert() .assert()

View File

@@ -1,4 +1,5 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
@@ -48,8 +49,7 @@ fn auto_bail_cancels_scan_with_403s() {
.body("these guys need to be 403 in order to trigger 90% threshold"); .body("these guys need to be 403 in order to trigger 90% threshold");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -130,8 +130,7 @@ fn auto_bail_cancels_scan_with_429s() {
.body("these guys need to be 403 in order to trigger 90% threshold"); .body("these guys need to be 403 in order to trigger 90% threshold");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -213,8 +212,7 @@ fn auto_tune_slows_scan_with_429s() {
let start = Instant::now(); let start = Instant::now();
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -277,8 +275,7 @@ fn auto_tune_slows_scan_with_403s() {
let start = Instant::now(); let start = Instant::now();
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -342,8 +339,7 @@ fn auto_tune_slows_scan_with_general_errors() {
let start = Instant::now(); let start = Instant::now();
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")

View File

@@ -1,10 +1,12 @@
mod utils; mod utils;
use assert_cmd::Command; use assert_cmd::cargo_bin;
use assert_cmd::prelude::*;
use httpmock::prelude::*; use httpmock::prelude::*;
use httpmock::MockServer; use httpmock::MockServer;
use regex::Regex; use regex::Regex;
use std::fs::{read_to_string, write}; use std::fs::{read_to_string, write};
use std::process::Command;
use utils::{setup_tmp_directory, teardown_tmp_directory}; use utils::{setup_tmp_directory, teardown_tmp_directory};
/// Helper to create a test wordlist with controllable patterns /// Helper to create a test wordlist with controllable patterns
@@ -63,8 +65,7 @@ fn scenario_high_403_rate() {
then.status(403).body("Forbidden"); then.status(403).body("Forbidden");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -124,8 +125,7 @@ fn scenario_high_429_rate() {
then.status(429).body("Too Many Requests"); then.status(429).body("Too Many Requests");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -191,8 +191,7 @@ fn scenario_recovery_pattern() {
then.status(403).body("Forbidden"); then.status(403).body("Forbidden");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -267,8 +266,7 @@ fn scenario_mixed_steady_state() {
then.status(429).body("Too Many Requests"); then.status(429).body("Too Many Requests");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -340,8 +338,7 @@ fn scenario_capped_auto_tune() {
then.status(403).body("Forbidden"); then.status(403).body("Forbidden");
}); });
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")

View File

@@ -1,4 +1,5 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
@@ -19,8 +20,7 @@ fn response_size_limit_small_response_not_truncated() {
then.status(200).body(small_body); then.status(200).body(small_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -55,8 +55,7 @@ fn response_size_limit_large_response_truncated() {
then.status(200).body(&large_body); then.status(200).body(&large_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -109,8 +108,7 @@ fn response_size_limit_mixed_response_sizes() {
then.status(200).body(&large_body); then.status(200).body(&large_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -173,8 +171,7 @@ fn response_size_limit_default_4mb() {
then.status(200).body(&body); then.status(200).body(&body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -206,8 +203,7 @@ fn response_size_limit_very_small_limit() {
then.status(200).body(body); then.status(200).body(body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -242,8 +238,7 @@ fn response_size_limit_with_redirects() {
.body(&large_redirect_body); .body(&large_redirect_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -281,8 +276,7 @@ fn response_size_limit_with_error_responses() {
then.status(500).body(&large_error_body); then.status(500).body(&large_error_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -318,8 +312,7 @@ fn response_size_limit_json_output_includes_truncated_field() {
then.status(200).body(&large_body); then.status(200).body(&large_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -350,8 +343,7 @@ fn response_size_limit_json_output_includes_truncated_field() {
fn response_size_limit_shows_in_banner() { fn response_size_limit_shows_in_banner() {
let (tmp_dir, file) = setup_tmp_directory(&["test".to_string()], "wordlist").unwrap(); let (tmp_dir, file) = setup_tmp_directory(&["test".to_string()], "wordlist").unwrap();
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg("http://127.0.0.1:1") // Non-existent server to trigger quick exit .arg("http://127.0.0.1:1") // Non-existent server to trigger quick exit
.arg("--wordlist") .arg("--wordlist")
@@ -385,8 +377,7 @@ fn response_size_limit_exact_limit() {
then.status(200).body(&exact_body); then.status(200).body(&exact_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -425,8 +416,7 @@ fn response_size_limit_from_config_file() {
then.status(200).body(&large_body); then.status(200).body(&large_body);
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.current_dir(tmp_dir.path()) .current_dir(tmp_dir.path())
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))

View File

@@ -1,10 +1,12 @@
mod utils; mod utils;
use assert_cmd::Command; use assert_cmd::cargo_bin;
use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
use predicates::prelude::*; use predicates::prelude::*;
use std::fs::{read_to_string, write}; use std::fs::{read_to_string, write};
use std::path::Path; use std::path::Path;
use std::process::Command;
use std::time; use std::time;
use utils::{setup_tmp_directory, teardown_tmp_directory}; use utils::{setup_tmp_directory, teardown_tmp_directory};
@@ -67,8 +69,7 @@ fn resume_scan_works() {
let (tmp_dir2, state_file) = setup_tmp_directory(&[state_file_contents], "state-file").unwrap(); let (tmp_dir2, state_file) = setup_tmp_directory(&[state_file_contents], "state-file").unwrap();
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("-vvv") .arg("-vvv")
.arg("--resume-from") .arg("--resume-from")
.arg(state_file.as_os_str()) .arg(state_file.as_os_str())
@@ -115,16 +116,14 @@ fn time_limit_enforced_when_specified() {
let lower_bound = time::Duration::new(5, 0); let lower_bound = time::Duration::new(5, 0);
let upper_bound = time::Duration::new(6, 0); let upper_bound = time::Duration::new(6, 0);
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--stdin") .arg("--stdin")
.arg("-vv") .arg("-vv")
.arg("--wordlist") .arg("--wordlist")
.arg(file.as_os_str()) .arg(file.as_os_str())
.arg("--time-limit") .arg("--time-limit")
.arg("5s") .arg("5s")
.pipe_stdin(targets) .stdin(std::fs::File::open(targets).unwrap())
.unwrap()
.assert() .assert()
.failure(); .failure();

View File

@@ -1,4 +1,5 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
@@ -19,8 +20,7 @@ fn scanner_single_request_scan() -> Result<(), Box<dyn std::error::Error>> {
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -72,8 +72,7 @@ fn scanner_recursive_request_scan() -> Result<(), Box<dyn std::error::Error>> {
.body("this is a test and is more bytes than other ones"); .body("this is a test and is more bytes than other ones");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -135,8 +134,7 @@ fn scanner_recursive_request_scan_using_only_success_responses(
.body("this is a test and is more bytes than other ones"); .body("this is a test and is more bytes than other ones");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -178,8 +176,7 @@ fn scanner_single_request_scan_with_file_output() -> Result<(), Box<dyn std::err
let outfile = tmp_dir.path().join("output"); let outfile = tmp_dir.path().join("output");
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -214,8 +211,7 @@ fn scanner_single_request_scan_with_file_output_and_tack_q(
let outfile = tmp_dir.path().join("output"); let outfile = tmp_dir.path().join("output");
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -250,8 +246,7 @@ fn scanner_single_request_scan_with_invalid_file_output() -> Result<(), Box<dyn
let outfile = tmp_dir.path(); // outfile is a directory let outfile = tmp_dir.path(); // outfile is a directory
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -281,8 +276,7 @@ fn scanner_single_request_quiet_scan() -> Result<(), Box<dyn std::error::Error>>
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -317,8 +311,7 @@ fn scanner_single_request_returns_301_without_location_header(
then.status(301).body("this is a test"); then.status(301).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -358,8 +351,7 @@ fn scanner_single_request_replayed_to_proxy() -> Result<(), Box<dyn std::error::
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -402,8 +394,7 @@ fn scanner_single_request_scan_with_filtered_result() -> Result<(), Box<dyn std:
then.status(200).body("this is a test"); then.status(200).body("this is a test");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -443,8 +434,7 @@ fn scanner_single_request_scan_with_debug_logging() {
let outfile = tmp_dir.path().join("debug.log"); let outfile = tmp_dir.path().join("debug.log");
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -481,8 +471,7 @@ fn scanner_single_request_scan_with_debug_logging_as_json() {
let outfile = tmp_dir.path().join("debug.log"); let outfile = tmp_dir.path().join("debug.log");
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -530,8 +519,7 @@ fn scanner_single_request_scan_with_regex_filtered_result() {
.body("this is a test\nThat rug really tied the room together"); .body("this is a test\nThat rug really tied the room together");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -578,8 +566,7 @@ fn scanner_recursion_works_with_403_directories() {
.body("this is a test\nThat rug really tied the room together"); .body("this is a test\nThat rug really tied the room together");
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -628,8 +615,7 @@ fn rate_limit_enforced_when_specified() {
let now = time::Instant::now(); let now = time::Instant::now();
let lower_bound = time::Duration::new(5, 0); let lower_bound = time::Duration::new(5, 0);
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -665,8 +651,7 @@ fn add_discovered_extension_updates_bars_and_stats() {
assert!(!file_path.exists()); assert!(!file_path.exists());
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -735,8 +720,7 @@ fn collect_backups_makes_appropriate_requests() {
}) })
.collect(); .collect();
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--collect-backups") .arg("--collect-backups")
@@ -831,8 +815,7 @@ fn collect_words_makes_appropriate_requests() {
}) })
.collect(); .collect();
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("-vv") .arg("-vv")
@@ -890,8 +873,7 @@ fn scanner_forced_recursion_ignores_normal_redirect_logic() -> Result<(), Box<dy
let outfile = tmp_dir.path().join("output"); let outfile = tmp_dir.path().join("output");
Command::cargo_bin("feroxbuster") Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")

View File

@@ -1,4 +1,5 @@
mod utils; mod utils;
use assert_cmd::cargo_bin;
use assert_cmd::prelude::*; use assert_cmd::prelude::*;
use httpmock::Method::GET; use httpmock::Method::GET;
use httpmock::MockServer; use httpmock::MockServer;
@@ -26,8 +27,7 @@ fn word_and_status_makes_a_response_unique_and_isnt_seen() -> Result<(), Box<dyn
.body(srv.url("this is a word count supplier")); .body(srv.url("this is a word count supplier"));
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")
@@ -69,8 +69,7 @@ fn bytes_and_status_makes_a_redirect_response_unique_and_isnt_seen(
.body(srv.url("this is a word count supplier")); // redirect + same body .body(srv.url("this is a word count supplier")); // redirect + same body
}); });
let cmd = Command::cargo_bin("feroxbuster") let cmd = Command::new(cargo_bin!("feroxbuster"))
.unwrap()
.arg("--url") .arg("--url")
.arg(srv.url("/")) .arg(srv.url("/"))
.arg("--wordlist") .arg("--wordlist")