├── src
├── lib
│ ├── tui
│ │ ├── widgets
│ │ │ ├── confirm.rs
│ │ │ ├── mod.rs
│ │ │ ├── popup.rs
│ │ │ ├── field.rs
│ │ │ ├── path_hint.rs
│ │ │ └── worker_info.rs
│ │ ├── mod.rs
│ │ └── app.rs
│ ├── logger
│ │ ├── mod.rs
│ │ ├── traits.rs
│ │ └── file_logger.rs
│ ├── worker
│ │ ├── mod.rs
│ │ ├── messages.rs
│ │ ├── builder.rs
│ │ └── unit.rs
│ └── util.rs
├── lib.rs
└── bin
│ ├── yadb-tui.rs
│ └── yadb-cli.rs
├── .gitignore
├── .github
└── workflows
│ ├── release.yml
│ └── rust-ci.yml
├── LICENSE
├── Cargo.toml
├── README.md
└── Cargo.lock
/src/lib/tui/widgets/confirm.rs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/lib/tui/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod app;
2 | mod widgets;
3 |
--------------------------------------------------------------------------------
/src/lib/logger/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod file_logger;
2 | pub mod traits;
3 |
--------------------------------------------------------------------------------
/src/lib/worker/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod builder;
2 | pub mod messages;
3 | pub mod unit;
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | test_server.py
3 | wordlist.txt
4 | output.txt
5 | todo
6 | .vscode
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod lib {
2 | pub mod logger;
3 | pub mod tui;
4 | pub mod util;
5 | pub mod worker;
6 | }
7 |
--------------------------------------------------------------------------------
/src/lib/tui/widgets/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod confirm;
2 | pub mod field;
3 | pub mod path_hint;
4 | pub mod popup;
5 | pub mod worker_info;
6 |
--------------------------------------------------------------------------------
/src/bin/yadb-tui.rs:
--------------------------------------------------------------------------------
1 | use crossterm::cursor::SetCursorStyle;
2 | use yadb::lib::tui::app::App;
3 |
4 | fn main() -> color_eyre::Result<()> {
5 | color_eyre::install()?;
6 | let terminal = ratatui::init();
7 | _ = crossterm::execute!(std::io::stdout(), SetCursorStyle::SteadyBar);
8 | let result = App::new().run(terminal);
9 | ratatui::restore();
10 | _ = crossterm::execute!(std::io::stdout(), SetCursorStyle::DefaultUserShape);
11 | result
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/util.rs:
--------------------------------------------------------------------------------
1 | pub fn print_logo() {
2 | println!(
3 | "
4 | ▓██ ██▓ ▄▄▄ ▓█████▄ ▄▄▄▄
5 | ▒██ ██▒▒████▄ ▒██▀ ██▌▓█████▄
6 | ▒██ ██░▒██ ▀█▄ ░██ █▌▒██▒ ▄██
7 | ░ ▐██▓░░██▄▄▄▄██ ░▓█▄ ▌▒██░█▀
8 | ░ ██▒▓░ ▓█ ▓██▒░▒████▓ ░▓█ ▀█▓
9 | ██▒▒▒ ▒▒ ▓▒█░ ▒▒▓ ▒ ░▒▓███▀▒
10 | ▓██ ░▒░ ▒ ▒▒ ░ ░ ▒ ▒ ▒░▒ ░
11 | ▒ ▒ ░░ ░ ▒ ░ ░ ░ ░ ░
12 | ░ ░ ░ ░ ░ ░
13 | ░ ░ ░ ░
14 | "
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Build binaries on release
2 |
3 | on:
4 | release:
5 | types: ['published']
6 |
7 | permissions:
8 | contents: write
9 |
10 | env:
11 | CARGO_TERM_COLOR: always
12 |
13 | jobs:
14 | rust-cd:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 | - uses: Swatinem/rust-cache@v2
19 | with:
20 | cache-on-failure: true
21 |
22 | - uses: dtolnay/rust-toolchain@stable
23 | with:
24 | components: clippy
25 |
26 | - name: Build
27 | run: cargo build --release
28 |
29 | - uses: softprops/action-gh-release@v2
30 | with:
31 | files: |
32 | ./target/release/yadb-cli
33 | ./target/release/yadb-tui
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YADB - Yet Another Directory Buster
2 |
3 | Copyright (C) 2025 Bogdan Andreev
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 |
--------------------------------------------------------------------------------
/.github/workflows/rust-ci.yml:
--------------------------------------------------------------------------------
1 | name: Rust CI
2 |
3 | on:
4 | pull_request:
5 | branches: [ "master" ]
6 |
7 | permissions:
8 | checks: write
9 | pull-requests: write
10 | contents: read
11 |
12 | env:
13 | CARGO_TERM_COLOR: always
14 |
15 | jobs:
16 | rust-ci:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: actions/checkout@v4
20 | - uses: Swatinem/rust-cache@v2
21 | with:
22 | cache-on-failure: true
23 | - uses: dtolnay/rust-toolchain@stable
24 | with:
25 | components: clippy
26 |
27 | - name: Check format
28 | run: cargo fmt -- --check
29 |
30 | - name: Run Clippy
31 | run: cargo clippy -- -D warnings
32 |
33 | - name: Build
34 | run: cargo build
35 |
36 | - name: Run tests
37 | run: cargo test --all
38 |
--------------------------------------------------------------------------------
/src/lib/logger/traits.rs:
--------------------------------------------------------------------------------
1 | use std::sync::Mutex;
2 |
3 | use crate::lib::logger::file_logger::FileLogger;
4 |
5 | pub enum LogLevel {
6 | INFO,
7 | WARN,
8 | ERROR,
9 | CRITICAL,
10 | }
11 |
12 | #[derive(Debug)]
13 | pub enum WorkerLogger {
14 | NullLogger(NullLogger),
15 | FileLogger(Mutex),
16 | }
17 |
18 | pub trait Logger: Send + Sync + 'static {
19 | fn log(&self, level: LogLevel, msg: String);
20 | }
21 | #[derive(Default, Debug)]
22 | pub struct NullLogger {}
23 |
24 | impl Logger for NullLogger {
25 | fn log(&self, _level: LogLevel, _msg: String) {}
26 | }
27 |
28 | impl WorkerLogger {
29 | pub fn log(&self, level: LogLevel, msg: String) {
30 | match self {
31 | WorkerLogger::NullLogger(logger) => logger.log(level, msg),
32 | WorkerLogger::FileLogger(logger) => logger.lock().unwrap().log(level, msg),
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "yadb"
3 | description = "Yet Another Directory Buster"
4 | version = "0.3.5"
5 | edition = "2024"
6 | readme = "README.md"
7 | repository = "https://github.com/izya4ka/yadb"
8 | license = "GPL-3.0"
9 | keywords = ["net", "scan", "web", "cli", "tui"]
10 | default-run = "yadb-cli"
11 |
12 | [dependencies]
13 | clap = { version = "4.5.39", features = ["derive"] }
14 | indicatif = "0.17.11"
15 | thiserror = "2.0.12"
16 | console = "0.15.11"
17 | url = "2.5.4"
18 | anyhow = "1.0.98"
19 | chrono = "0.4.41"
20 | ureq = "3.0.12"
21 | ratatui = "0.29.0"
22 | color-eyre = "0.6.5"
23 | crossterm = "0.29.0"
24 | tui-input = "0.14.0"
25 |
26 | [profile.dev]
27 | opt-level = 0
28 | debug = true
29 | incremental = true
30 | codegen-units = 256
31 | lto = false
32 | panic = "unwind"
33 | strip = "none"
34 |
35 | [profile.release]
36 | opt-level = 3
37 | debug = false
38 | lto = "fat"
39 | codegen-units = 1
40 | panic = "abort"
41 | strip = "symbols"
42 | incremental = false
43 |
--------------------------------------------------------------------------------
/src/lib/logger/file_logger.rs:
--------------------------------------------------------------------------------
1 | use super::traits::LogLevel;
2 | use anyhow::Result;
3 | use chrono::Local;
4 | use std::{fs::File, io::Write};
5 |
6 | use crate::lib::logger::traits::Logger;
7 |
8 | #[derive(Default, Debug)]
9 | pub struct FileLogger {
10 | file: Option,
11 | }
12 |
13 | impl FileLogger {
14 | pub fn new(path: String) -> Result {
15 | let file = File::create(path)?;
16 | Ok(FileLogger { file: Some(file) })
17 | }
18 | }
19 |
20 | impl Logger for FileLogger {
21 | fn log(&self, level: LogLevel, msg: String) {
22 | if let Some(mut file) = self.file.as_ref() {
23 | let mut str = String::default();
24 |
25 | str += &Local::now().format("[%H:%M:%S] ").to_string();
26 |
27 | str += match level {
28 | LogLevel::INFO => "[INFO] ",
29 | LogLevel::WARN => "[WARN] ",
30 | LogLevel::ERROR => "[ERROR] ",
31 | LogLevel::CRITICAL => "[CRITICAL] ",
32 | };
33 |
34 | str += &msg;
35 | str += "\n";
36 |
37 | let _ = file.write(str.as_bytes());
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/worker/messages.rs:
--------------------------------------------------------------------------------
1 | use crate::lib::logger::traits::LogLevel;
2 |
3 | pub enum WorkerMessage {
4 | Progress(ProgressMessage),
5 | Log(LogLevel, String),
6 | }
7 | pub enum ProgressMessage {
8 | Total(ProgressChangeMessage),
9 | Current(ProgressChangeMessage),
10 | }
11 |
12 | pub enum ProgressChangeMessage {
13 | SetMessage(String),
14 | SetSize(usize),
15 | Start(usize),
16 | Advance,
17 | Print(String),
18 | Finish,
19 | }
20 |
21 | impl WorkerMessage {
22 | pub fn set_total_size(size: usize) -> WorkerMessage {
23 | WorkerMessage::Progress(ProgressMessage::Total(ProgressChangeMessage::SetSize(size)))
24 | }
25 |
26 | pub fn set_current_size(size: usize) -> WorkerMessage {
27 | WorkerMessage::Progress(ProgressMessage::Current(ProgressChangeMessage::SetSize(
28 | size,
29 | )))
30 | }
31 |
32 | pub fn finish_total() -> WorkerMessage {
33 | WorkerMessage::Progress(ProgressMessage::Total(ProgressChangeMessage::Finish))
34 | }
35 |
36 | pub fn finish_current() -> WorkerMessage {
37 | WorkerMessage::Progress(ProgressMessage::Current(ProgressChangeMessage::Finish))
38 | }
39 |
40 | pub fn log(level: LogLevel, str: String) -> WorkerMessage {
41 | WorkerMessage::Log(level, str)
42 | }
43 |
44 | pub fn advance_current() -> WorkerMessage {
45 | WorkerMessage::Progress(ProgressMessage::Current(ProgressChangeMessage::Advance))
46 | }
47 |
48 | pub fn advance_total() -> WorkerMessage {
49 | WorkerMessage::Progress(ProgressMessage::Total(ProgressChangeMessage::Advance))
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/lib/tui/widgets/popup.rs:
--------------------------------------------------------------------------------
1 | use ratatui::{
2 | buffer::Buffer,
3 | layout::{self, Constraint, Flex, Layout, Rect},
4 | style::{Style, Stylize},
5 | text::{Line, Text},
6 | widgets::{Block, Borders, Clear, Paragraph, Widget},
7 | };
8 |
9 | pub struct Popup<'a> {
10 | // Custom widget properties
11 | content: Text<'a>,
12 | title: String,
13 | }
14 |
15 | impl<'a> Widget for Popup<'a> {
16 | fn render(self, area: Rect, buf: &mut Buffer) {
17 | let area = Self::popup_area(area, 30, 15);
18 | Clear.render(area, buf);
19 |
20 | let title = Line::from(self.title)
21 | .bold()
22 | .style(Style::new().blue())
23 | .centered();
24 |
25 | let block = Block::default()
26 | .borders(Borders::all())
27 | .border_type(ratatui::widgets::BorderType::Double)
28 | .title(title);
29 |
30 | let layout: [Rect; 2] = Layout::new(
31 | layout::Direction::Vertical,
32 | [Constraint::Percentage(80), Constraint::Length(1)],
33 | )
34 | .areas(block.inner(area));
35 |
36 | block.render(area, buf);
37 | let text = Paragraph::new(self.content).centered();
38 | text.render(layout[0], buf);
39 |
40 | Paragraph::new("OK")
41 | .reversed()
42 | .blue()
43 | .render(layout[1], buf);
44 | }
45 | }
46 |
47 | impl<'a> Popup<'a> {
48 | pub fn new(title: String, content: Text<'a>) -> Self {
49 | Self { title, content }
50 | }
51 |
52 | fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
53 | let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
54 | let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
55 | let [area] = vertical.areas(area);
56 | let [area] = horizontal.areas(area);
57 | area
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YADB - Yet Another Directory Buster
2 | 
3 | 
4 | 
5 | 
6 | [](https://ratatui.rs/)
7 | 
8 | 
9 |
10 |
11 | **YADB** is a directory brute-forcing tool written in **Rust**, inspired by `gobuster`.
12 |
13 | ## ✨ Features
14 | - ⚡ **High performance** with multithreading
15 | - 🖥️ **CLI and TUI interface**
16 |
17 | ## 📦 Installation
18 | ```bash
19 | cargo install yadb
20 | ```
21 |
22 | ## 🚀 Usage
23 |
24 | ### CLI
25 |
26 | ```
27 | Usage: yadb-cli [OPTIONS] --wordlist --uri
28 |
29 | Options:
30 | -t, --threads Number of threads [default: 50]
31 | -r, --recursive Recursivly parse directories and files (recursion depth) [default: 0]
32 | -w, --wordlist Path to wordlist
33 | -u, --uri Target URI
34 | -o, --output