3333from subdomainenum .constants import ACTIVE_TOOLS , detect_tools , get_install_hint
3434from subdomainenum .debug_logger import DebugLogger
3535from subdomainenum .models import EnumMode
36- from subdomainenum .reporter import print_report , to_dict
36+ from subdomainenum .reporter import console , print_report , save_report , to_dict
3737
3838app = typer .Typer (
3939 name = "subdomainenum" ,
4040 help = "Passive and active subdomain enumeration for a target domain." ,
4141 add_completion = False ,
4242)
4343
44- _console = Console (stderr = False )
4544_err = Console (stderr = True )
4645
4746
@@ -194,7 +193,7 @@ def _progress_cb(msg: str) -> None:
194193 report = assess (domain , ** assess_kwargs )
195194 except Exception as exc :
196195 if json_output :
197- _console .print (json .dumps ({"error" : str (exc )}, indent = 2 ))
196+ console .print (json .dumps ({"error" : str (exc )}, indent = 2 ))
198197 else :
199198 _err .print (f"[red]Error:[/red] { exc } " )
200199 raise typer .Exit (code = 1 )
@@ -208,10 +207,15 @@ def _progress_cb(msg: str) -> None:
208207 _print_json (report )
209208 return
210209
211- print_report (report , console = _console )
210+ print_report (report , console = console )
212211
213212 if output :
214- _save_report (report , output )
213+ try :
214+ save_report (output )
215+ console .print (f"[dim]Report saved to[/dim] { output } " )
216+ except (ValueError , OSError ) as exc :
217+ _err .print (f"[red]Error:[/red] Cannot write to { output !r} : { exc } " )
218+ raise typer .Exit (code = 1 )
215219
216220
217221# ---------------------------------------------------------------------------
@@ -233,7 +237,7 @@ def info() -> None:
233237 f"[{ style } ]{ 'yes' if avail else 'no' } [/{ style } ]" ,
234238 get_install_hint (name ) if not avail else "" ,
235239 )
236- _console .print (table )
240+ console .print (table )
237241
238242
239243# ---------------------------------------------------------------------------
@@ -246,36 +250,7 @@ def _print_json(report) -> None:
246250
247251 :param report: :class:`~subdomainenum.models.EnumReport` to serialise.
248252 """
249- _console .print (json .dumps (to_dict (report ), indent = 2 ))
250-
251-
252- def _save_report (report , path : str ) -> None :
253- """Render *report* to a file at *path*.
254-
255- The output format is inferred from the file extension:
256- ``.txt`` → plain text (no ANSI codes), ``.svg`` → SVG image,
257- ``.html`` → self-contained HTML page. Any other extension is
258- treated as plain text.
259-
260- :param report: :class:`~subdomainenum.models.EnumReport` to render.
261- :param path: Destination file path.
262- """
263- from rich .console import Console as RichConsole
264-
265- ext = Path (path ).suffix .lower ()
266-
267- rec_console = RichConsole (record = True , highlight = False , width = 120 )
268- print_report (report , console = rec_console )
269-
270- if ext == ".svg" :
271- content = rec_console .export_svg (title = f"subdomainenum — { report .domain } " )
272- elif ext == ".html" :
273- content = rec_console .export_html (inline_styles = True )
274- else :
275- content = rec_console .export_text ()
276-
277- Path (path ).write_text (content , encoding = "utf-8" )
278- _console .print (f"[dim]Report saved to[/dim] { path } " )
253+ console .print (json .dumps (to_dict (report ), indent = 2 ))
279254
280255
281256if __name__ == "__main__" : # pragma: no cover
0 commit comments