PyBreeze 1.0.25__tar.gz → 1.0.26__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pybreeze-1.0.25 → pybreeze-1.0.26}/PKG-INFO +7 -3
- {pybreeze-1.0.25 → pybreeze-1.0.26}/README.md +6 -2
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/extend_english.py +70 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/extend_traditional_chinese.py +70 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/tools/tools_menu.py +41 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/curl_import_gui.py +39 -6
- pybreeze-1.0.26/pybreeze/pybreeze_ui/tools_gui/header_analyzer_gui.py +108 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/response_inspector_gui.py +27 -13
- pybreeze-1.0.26/pybreeze/pybreeze_ui/tools_gui/tool_tabs.py +31 -0
- pybreeze-1.0.26/pybreeze/pybreeze_ui/tools_gui/url_builder_gui.py +89 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/curl_parser.py +186 -20
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/request_codegen.py +8 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/script_templates.py +6 -1
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/exception/exception_tags.py +4 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/exception/exceptions.py +6 -0
- pybreeze-1.0.26/pybreeze/utils/header_tools/header_analyzer.py +318 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/response_inspector/response_analyzer.py +2 -3
- pybreeze-1.0.26/pybreeze/utils/timestamp_tools/__init__.py +0 -0
- pybreeze-1.0.26/pybreeze/utils/url_tools/__init__.py +0 -0
- pybreeze-1.0.26/pybreeze/utils/url_tools/url_convert.py +117 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/PKG-INFO +7 -3
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/SOURCES.txt +8 -1
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pyproject.toml +1 -1
- {pybreeze-1.0.25 → pybreeze-1.0.26}/LICENSE +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/__main__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/mail_thunder_extend/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/mail_thunder_extend/mail_thunder_setting.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/api_testka/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/api_testka/api_testka_process.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/auto_control/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/auto_control/auto_control_process.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/file_automation/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/file_automation/file_automation_process.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/file_runner_process.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/load_density/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/load_density/load_density_process.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/mail_thunder/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/mail_thunder/mail_thunder_process.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/process_executor_utils.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/python_task_process_manager.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/queue_pump.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/test_pioneer/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/test_pioneer/test_pioneer_process_manager.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/web_runner/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend/process_executor/web_runner/web_runner_process.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/update_language_dict.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_command_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_file_viewer_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_host_key_policy.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_key_loader.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_login_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/ssh/ssh_main_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/url/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/connect_gui/url/ai_code_review_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_commands.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_editor_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_items.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_mermaid_parser.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_net_utils.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_property_panel.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_scene.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/diagram_editor/diagram_view.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/editor_main/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/editor_main/file_tree_context_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/editor_main/main_ui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/ai_gui_global_variable.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/code_review/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/code_review/code_review_thread.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/code_review/cot_code_review_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/code_smell_detector.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/first_code_review.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/first_summary_prompt.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/global_rule.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/judge.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/judge_single_review.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/linter.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/step_by_step_analysis.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_code_review_prompt_templates/total_summary.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/cot_prompt_editor_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/prompt_file_io.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_editor_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_templates/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_templates/code_explainer.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/prompt_edit_gui/skills_prompt_templates/code_review.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/skills/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/extend_ai_gui/skills/skills_send_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/jupyter_lab_gui/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/jupyter_lab_gui/jupyter_lab_thread.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/jupyter_lab_gui/jupyter_lab_widget.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/api_testka_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/api_testka_menu/build_api_testka_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/auto_control_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/auto_control_menu/build_autocontrol_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/automation_file_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/automation_file_menu/build_automation_file_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/automation_menu_factory.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/load_density_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/load_density_menu/build_load_density_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/mail_thunder_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/mail_thunder_menu/build_mail_thunder_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/test_pioneer_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/test_pioneer_menu/build_test_pioneer_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/web_runner_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/automation_menu/web_runner_menu/build_webrunner_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/build_menubar.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/extend_jeditor_tab_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/extend_jeditor_tab_menu/jupyter_lab_tab.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/automation_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/automation_menu/build_automation_install_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/install_utils.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/tools_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/install_menu/tools_menu/build_tool_install_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/menu_utils.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/plugin_menu/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/plugin_menu/build_plugin_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/plugin_menu/build_run_with_menu.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/menu/tools/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/show_code_window/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/show_code_window/code_window.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/syntax/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/syntax/syntax_extend.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/syntax/syntax_keyword.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/diff_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/hash_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/http_status_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/json_format_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/jwt_decoder_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/output_actions.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/query_json_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/regex_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/pybreeze_ui/tools_gui/timestamp_gui.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/app_dirs.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/curl_import/request_body.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/diff_tools/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/diff_tools/text_diff.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/exception/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/file_process/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/file_process/get_dir_file_list.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/hash_tools/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/hash_tools/hash_text.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/http_reference → pybreeze-1.0.26/pybreeze/utils/header_tools}/__init__.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/jwt_tools → pybreeze-1.0.26/pybreeze/utils/http_reference}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/http_reference/status_codes.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/json_format/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/json_format/json_process.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/logging → pybreeze-1.0.26/pybreeze/utils/jwt_tools}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/jwt_tools/jwt_decoder.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/manager → pybreeze-1.0.26/pybreeze/utils/logging}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/logging/logger.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/manager/package_manager → pybreeze-1.0.26/pybreeze/utils/manager}/__init__.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/network → pybreeze-1.0.26/pybreeze/utils/manager/package_manager}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/manager/package_manager/package_manager_class.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/query_tools → pybreeze-1.0.26/pybreeze/utils/network}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/network/http_client.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/network/url_validation.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/regex_tools → pybreeze-1.0.26/pybreeze/utils/query_tools}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/query_tools/query_convert.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/response_inspector → pybreeze-1.0.26/pybreeze/utils/regex_tools}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/regex_tools/regex_tester.py +0 -0
- {pybreeze-1.0.25/pybreeze/utils/timestamp_tools → pybreeze-1.0.26/pybreeze/utils/response_inspector}/__init__.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/subprocess_util.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/utils/timestamp_tools/timestamp_converter.py +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/dependency_links.txt +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/requires.txt +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze.egg-info/top_level.txt +0 -0
- {pybreeze-1.0.25 → pybreeze-1.0.26}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pybreeze
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.26
|
|
4
4
|
Summary: IDE for multi automation
|
|
5
5
|
Author-email: JE-Chen <jechenmailman@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/AutomationEditor
|
|
@@ -109,16 +109,18 @@ PyBreeze is not just a code editor — it is a command center for the automation
|
|
|
109
109
|
- Mermaid `flowchart` / `graph` import
|
|
110
110
|
- Save/Open as `.diagram.json`, export to PNG or SVG
|
|
111
111
|
- Undo/redo, align, distribute, grid, snap, and zoom controls
|
|
112
|
-
- **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). The parser is pure logic and never executes the command.
|
|
112
|
+
- **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). A repeated `-H` is handled the way HTTP handles it — the values are combined into one header (with `; ` for cookies) rather than the last one silently winning, and names are matched case-insensitively so an explicit header always beats one implied by another flag. One click also **hands the parsed URL to the URL parser/builder**, query string and all. The parser is pure logic and never executes the command.
|
|
113
113
|
- **JWT Decoder** — Paste a JSON Web Token and read its header and payload as pretty-printed JSON, with standard timestamp claims (`exp`, `iat`, `nbf`, `auth_time`) rendered as readable UTC times. Inspection only — the signature is never verified and the token is never trusted.
|
|
114
114
|
- **Timestamp Converter** — Enter a Unix epoch value (seconds or milliseconds, auto-detected) or an ISO-8601 date-time (with `Z` or an offset) and get every representation back in UTC. Deterministic and independent of the local time zone.
|
|
115
115
|
- **Hash Generator** — Compute SHA-256, SHA-512, SHA-1 and MD5 digests of any text at once. A general-purpose checksum tool (MD5/SHA-1 are provided for interoperability with `usedforsecurity=False`, never for security decisions).
|
|
116
116
|
- **Query ⇄ JSON** — Convert an `application/x-www-form-urlencoded` query string to pretty JSON and back, URL-decoding and -encoding as needed. Repeated keys become JSON arrays and vice versa. Copy the result, open it in an editor tab, or save it to a file.
|
|
117
|
+
- **URL Parser / Builder** — Paste a URL to see its scheme, host, port, path, query, fragment and credentials as an editable JSON object, tweak any part, and turn it back into a URL. Round-trips both ways, brackets IPv6 literals, and re-encodes query parameters for you. The cURL importer can send a request's URL straight here.
|
|
118
|
+
- **HTTP Header Analyzer** — Paste a request or response header block (from dev tools, `curl -i`, or a proxy log) and read back every field plus what is worth knowing about it: names sent more than once, `Set-Cookie` entries missing `Secure` / `HttpOnly` / `SameSite`, a wildcard CORS policy (and the wildcard-plus-credentials combination browsers reject outright), an HSTS `max-age` too short to survive a restart, CSP `unsafe-inline` / `unsafe-eval`, product banners, deprecated headers, and — for responses — the security headers that are absent. Headers carrying credentials are reported by name only; their values are never copied into the report. The Response Inspector hands its headers here in one click.
|
|
117
119
|
- **Regex Tester** — Try a regular expression against sample text with `IGNORECASE` / `MULTILINE` / `DOTALL` / `VERBOSE` flags, and see every match with its offsets, numbered groups and named groups. Invalid patterns report a friendly error instead of crashing.
|
|
118
120
|
- **HTTP Status Reference** — Search the full HTTP status code table (sourced from the standard library, so it stays current) by code prefix or keyword, with the reason phrase, description and status class for each.
|
|
119
121
|
- **Text Diff** — Compare two pieces of text (for example an expected vs. actual API response) side by side and get a unified diff plus a one-line summary of how many lines were added or removed. Copy the diff, open it in an editor tab, or save it to a file.
|
|
120
122
|
- **JSON Format** — Pretty-print or minify a JSON payload, with a clear validation error when the input is not valid JSON. Copy the result, open it in a new editor tab, or save it to a file.
|
|
121
|
-
- **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code or
|
|
123
|
+
- **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code, JWT, or the whole header block directly in its dedicated tool tab, pre-filled.
|
|
122
124
|
- **File Tree Context Menu** — Right-click any file or folder in the project tree to create files/folders, rename, delete, copy absolute or relative paths, or reveal the item in your platform file manager. Renaming or deleting a file that is currently open in an editor tab keeps the tab in sync.
|
|
123
125
|
- **Package Manager** — Install automation modules and build tools directly from the IDE menu without leaving the editor.
|
|
124
126
|
- **Integrated Documentation** — Quick access to documentation and GitHub pages for each automation module directly from the menu bar.
|
|
@@ -254,6 +256,8 @@ PyBreeze UI (PySide6)
|
|
|
254
256
|
│ ├── Timestamp Converter (epoch ⇄ ISO-8601)
|
|
255
257
|
│ ├── Hash Generator (SHA-256/512, SHA-1, MD5)
|
|
256
258
|
│ ├── Query ⇄ JSON Converter
|
|
259
|
+
│ ├── URL Parser / Builder (URL ⇄ JSON parts)
|
|
260
|
+
│ ├── HTTP Header Analyzer (duplicates, cookie flags, security headers)
|
|
257
261
|
│ ├── Regex Tester
|
|
258
262
|
│ ├── HTTP Status Reference
|
|
259
263
|
│ ├── Text Diff
|
|
@@ -76,16 +76,18 @@ PyBreeze is not just a code editor — it is a command center for the automation
|
|
|
76
76
|
- Mermaid `flowchart` / `graph` import
|
|
77
77
|
- Save/Open as `.diagram.json`, export to PNG or SVG
|
|
78
78
|
- Undo/redo, align, distribute, grid, snap, and zoom controls
|
|
79
|
-
- **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). The parser is pure logic and never executes the command.
|
|
79
|
+
- **cURL Import** — Paste a `curl` command copied from your browser's dev tools and generate a ready-to-run script for the target of your choice: **Python `requests`**, an **APITestka Python** snippet (`test_api_method_requests(...)`), an **APITestka JSON action** (`[["AT_test_api_method", {...}]]`) that `execute_files` runs directly, or a **LoadDensity** Locust load-test (`start_test(...)`). (These are the HTTP-oriented modules; a curl request has no meaningful mapping to the browser or desktop-GUI automation modules.) Parses the method, URL, headers, body, basic auth, `-G` query parameters, `-F` multipart form fields (file uploads become `files=open(...)`), the `--json` shortcut (which also sets the JSON `Content-Type`/`Accept`), and `-d @file` bodies (which become `open(...).read()`, while `--data-raw` stays literal) — all with multi-line `\` / `^` continuations. It knows the arity of curl's common flags, so value-taking options like `--max-time 30` or `-o out.json` never leak into the URL; it URL-encodes `--data-urlencode` values the way curl does; and it infers `POST` when a body or form is present and sends JSON bodies as JSON. Targets include Python `requests`, a ready-to-run **pytest test** (a named `test_...` function that sends the request and asserts the status), APITestka (Python and JSON action), and a LoadDensity load test. Pick one from the dropdown, then copy the result, **open it straight into a new editor tab**, or **save it to a `.py` / `.json` file** (the extension follows the chosen target). A repeated `-H` is handled the way HTTP handles it — the values are combined into one header (with `; ` for cookies) rather than the last one silently winning, and names are matched case-insensitively so an explicit header always beats one implied by another flag. One click also **hands the parsed URL to the URL parser/builder**, query string and all. The parser is pure logic and never executes the command.
|
|
80
80
|
- **JWT Decoder** — Paste a JSON Web Token and read its header and payload as pretty-printed JSON, with standard timestamp claims (`exp`, `iat`, `nbf`, `auth_time`) rendered as readable UTC times. Inspection only — the signature is never verified and the token is never trusted.
|
|
81
81
|
- **Timestamp Converter** — Enter a Unix epoch value (seconds or milliseconds, auto-detected) or an ISO-8601 date-time (with `Z` or an offset) and get every representation back in UTC. Deterministic and independent of the local time zone.
|
|
82
82
|
- **Hash Generator** — Compute SHA-256, SHA-512, SHA-1 and MD5 digests of any text at once. A general-purpose checksum tool (MD5/SHA-1 are provided for interoperability with `usedforsecurity=False`, never for security decisions).
|
|
83
83
|
- **Query ⇄ JSON** — Convert an `application/x-www-form-urlencoded` query string to pretty JSON and back, URL-decoding and -encoding as needed. Repeated keys become JSON arrays and vice versa. Copy the result, open it in an editor tab, or save it to a file.
|
|
84
|
+
- **URL Parser / Builder** — Paste a URL to see its scheme, host, port, path, query, fragment and credentials as an editable JSON object, tweak any part, and turn it back into a URL. Round-trips both ways, brackets IPv6 literals, and re-encodes query parameters for you. The cURL importer can send a request's URL straight here.
|
|
85
|
+
- **HTTP Header Analyzer** — Paste a request or response header block (from dev tools, `curl -i`, or a proxy log) and read back every field plus what is worth knowing about it: names sent more than once, `Set-Cookie` entries missing `Secure` / `HttpOnly` / `SameSite`, a wildcard CORS policy (and the wildcard-plus-credentials combination browsers reject outright), an HSTS `max-age` too short to survive a restart, CSP `unsafe-inline` / `unsafe-eval`, product banners, deprecated headers, and — for responses — the security headers that are absent. Headers carrying credentials are reported by name only; their values are never copied into the report. The Response Inspector hands its headers here in one click.
|
|
84
86
|
- **Regex Tester** — Try a regular expression against sample text with `IGNORECASE` / `MULTILINE` / `DOTALL` / `VERBOSE` flags, and see every match with its offsets, numbered groups and named groups. Invalid patterns report a friendly error instead of crashing.
|
|
85
87
|
- **HTTP Status Reference** — Search the full HTTP status code table (sourced from the standard library, so it stays current) by code prefix or keyword, with the reason phrase, description and status class for each.
|
|
86
88
|
- **Text Diff** — Compare two pieces of text (for example an expected vs. actual API response) side by side and get a unified diff plus a one-line summary of how many lines were added or removed. Copy the diff, open it in an editor tab, or save it to a file.
|
|
87
89
|
- **JSON Format** — Pretty-print or minify a JSON payload, with a clear validation error when the input is not valid JSON. Copy the result, open it in a new editor tab, or save it to a file.
|
|
88
|
-
- **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code or
|
|
90
|
+
- **Response Inspector** — Paste a raw HTTP response and get a decoded summary in one step: the status code is looked up in the HTTP reference, headers are parsed, a JSON body is pretty-printed, and any JWTs anywhere in the text (for example an `Authorization: Bearer` header) are decoded with their timestamp claims shown in UTC. Ties the HTTP-status, JSON-format and JWT tools together, and can open a found status code, JWT, or the whole header block directly in its dedicated tool tab, pre-filled.
|
|
89
91
|
- **File Tree Context Menu** — Right-click any file or folder in the project tree to create files/folders, rename, delete, copy absolute or relative paths, or reveal the item in your platform file manager. Renaming or deleting a file that is currently open in an editor tab keeps the tab in sync.
|
|
90
92
|
- **Package Manager** — Install automation modules and build tools directly from the IDE menu without leaving the editor.
|
|
91
93
|
- **Integrated Documentation** — Quick access to documentation and GitHub pages for each automation module directly from the menu bar.
|
|
@@ -221,6 +223,8 @@ PyBreeze UI (PySide6)
|
|
|
221
223
|
│ ├── Timestamp Converter (epoch ⇄ ISO-8601)
|
|
222
224
|
│ ├── Hash Generator (SHA-256/512, SHA-1, MD5)
|
|
223
225
|
│ ├── Query ⇄ JSON Converter
|
|
226
|
+
│ ├── URL Parser / Builder (URL ⇄ JSON parts)
|
|
227
|
+
│ ├── HTTP Header Analyzer (duplicates, cookie flags, security headers)
|
|
224
228
|
│ ├── Regex Tester
|
|
225
229
|
│ ├── HTTP Status Reference
|
|
226
230
|
│ ├── Text Diff
|
|
@@ -331,6 +331,7 @@ pybreeze_english_word_dict = {
|
|
|
331
331
|
"curl_import_target_apitestka_python": "APITestka (Python)",
|
|
332
332
|
"curl_import_target_apitestka_action": "APITestka (JSON action)",
|
|
333
333
|
"curl_import_target_loaddensity_python": "LoadDensity (Python)",
|
|
334
|
+
"curl_import_open_url_button": "Open URL in parser / builder",
|
|
334
335
|
# Shared output actions (copy / open in editor / save to file)
|
|
335
336
|
"output_actions_copy": "Copy",
|
|
336
337
|
"output_actions_open_editor": "Open in editor tab",
|
|
@@ -393,6 +394,20 @@ pybreeze_english_word_dict = {
|
|
|
393
394
|
"query_json_output_label": "Result:",
|
|
394
395
|
"query_json_error": "Could not convert: {error}",
|
|
395
396
|
"query_json_empty_hint": "Enter a query string or a JSON object above.",
|
|
397
|
+
# URL Parser / Builder — Menu
|
|
398
|
+
"extend_tools_menu_url_builder_tab_action": "URL Parser / Builder Tab",
|
|
399
|
+
"extend_tools_menu_url_builder_tab_label": "URL Parser / Builder",
|
|
400
|
+
"extend_tools_menu_url_builder_dock_action": "URL Parser / Builder Dock",
|
|
401
|
+
"extend_tools_menu_url_builder_dock_title": "URL Parser / Builder",
|
|
402
|
+
# URL Parser / Builder — Widget
|
|
403
|
+
"url_builder_input_label": "A URL, or a JSON object of URL parts:",
|
|
404
|
+
"url_builder_input_placeholder":
|
|
405
|
+
"https://user@host:8080/path?a=1#frag or {\"scheme\": \"https\", \"host\": \"host\"}",
|
|
406
|
+
"url_builder_to_json_button": "URL → JSON",
|
|
407
|
+
"url_builder_to_url_button": "JSON → URL",
|
|
408
|
+
"url_builder_output_label": "Result:",
|
|
409
|
+
"url_builder_error": "Could not build URL: {error}",
|
|
410
|
+
"url_builder_empty_hint": "Enter a URL or a JSON object of URL parts above.",
|
|
396
411
|
# Regex Tester — Menu
|
|
397
412
|
"extend_tools_menu_regex_tab_action": "Regex Tester Tab",
|
|
398
413
|
"extend_tools_menu_regex_tab_label": "Regex",
|
|
@@ -453,11 +468,66 @@ pybreeze_english_word_dict = {
|
|
|
453
468
|
"response_output_label": "Analysis:",
|
|
454
469
|
"response_open_jwt_button": "Open JWT in decoder",
|
|
455
470
|
"response_open_status_button": "Open status in reference",
|
|
471
|
+
"response_open_headers_button": "Open headers in analyzer",
|
|
456
472
|
"response_empty_hint": "Paste a response above, then click analyze.",
|
|
457
473
|
"response_status_label": "== Status ==",
|
|
458
474
|
"response_headers_label": "== Headers ==",
|
|
459
475
|
"response_jwt_label": "== JWT(s) found ==",
|
|
460
476
|
"response_body_label": "== Body ==",
|
|
477
|
+
# HTTP Header Analyzer — Menu
|
|
478
|
+
"extend_tools_menu_header_analyzer_tab_action": "HTTP Header Analyzer Tab",
|
|
479
|
+
"extend_tools_menu_header_analyzer_tab_label": "Header Analyzer",
|
|
480
|
+
"extend_tools_menu_header_analyzer_dock_action": "HTTP Header Analyzer Dock",
|
|
481
|
+
"extend_tools_menu_header_analyzer_dock_title": "Header Analyzer",
|
|
482
|
+
# HTTP Header Analyzer — Widget
|
|
483
|
+
"header_analyzer_input_label": "Paste request or response headers:",
|
|
484
|
+
"header_analyzer_input_placeholder":
|
|
485
|
+
"HTTP/1.1 200 OK\nContent-Type: text/html\nSet-Cookie: sid=abc; Path=/",
|
|
486
|
+
"header_analyzer_analyze_button": "Analyze headers",
|
|
487
|
+
"header_analyzer_output_label": "Analysis:",
|
|
488
|
+
"header_analyzer_headers_label": "== Headers ({count}) ==",
|
|
489
|
+
"header_analyzer_duplicates_label": "== Repeated names ==",
|
|
490
|
+
"header_analyzer_findings_label": "== Findings ==",
|
|
491
|
+
"header_analyzer_no_findings": "Nothing worth reporting.",
|
|
492
|
+
"header_analyzer_no_headers": "No header lines found in that text.",
|
|
493
|
+
"header_analyzer_empty_hint": "Paste a header block above, then click analyze.",
|
|
494
|
+
"header_analyzer_level_warning": "WARNING",
|
|
495
|
+
"header_analyzer_level_info": "INFO",
|
|
496
|
+
# HTTP Header Analyzer — Findings ({header} is the header, {detail} its value)
|
|
497
|
+
"header_finding_duplicate_header":
|
|
498
|
+
"{header}: sent {detail} times; the receiver joins the values into one.",
|
|
499
|
+
"header_finding_content_type_options_not_nosniff":
|
|
500
|
+
"{header}: '{detail}' has no effect, only 'nosniff' stops MIME sniffing.",
|
|
501
|
+
"header_finding_hsts_weak_max_age":
|
|
502
|
+
"{header}: max-age={detail} is short; 15552000 (180 days) is the usual minimum.",
|
|
503
|
+
"header_finding_csp_unsafe_directive":
|
|
504
|
+
"{header}: contains '{detail}', which re-allows what the policy should block.",
|
|
505
|
+
"header_finding_cors_wildcard_origin": "{header}: every origin is allowed (*).",
|
|
506
|
+
"header_finding_cors_wildcard_with_credentials":
|
|
507
|
+
"{header}: '*' with Access-Control-Allow-Credentials: true is rejected by browsers.",
|
|
508
|
+
"header_finding_cookie_not_secure":
|
|
509
|
+
"{header}: cookie '{detail}' has no Secure attribute, so it can travel over plain HTTP.",
|
|
510
|
+
"header_finding_cookie_not_httponly":
|
|
511
|
+
"{header}: cookie '{detail}' has no HttpOnly attribute, so scripts can read it.",
|
|
512
|
+
"header_finding_cookie_no_samesite":
|
|
513
|
+
"{header}: cookie '{detail}' has no SameSite attribute; browsers default it to Lax.",
|
|
514
|
+
"header_finding_content_type_no_charset":
|
|
515
|
+
"{header}: '{detail}' names no charset, so the client has to guess the encoding.",
|
|
516
|
+
"header_finding_server_banner": "{header}: '{detail}' reveals the software in use.",
|
|
517
|
+
"header_finding_deprecated_header":
|
|
518
|
+
"{header}: '{detail}' is deprecated and ignored by current browsers.",
|
|
519
|
+
"header_finding_sensitive_header":
|
|
520
|
+
"{header}: carries a credential; mask it before sharing this output.",
|
|
521
|
+
"header_finding_missing_hsts":
|
|
522
|
+
"{header}: not set, so a browser may fall back to plain HTTP.",
|
|
523
|
+
"header_finding_missing_csp":
|
|
524
|
+
"{header}: not set, so nothing limits where scripts may be loaded from.",
|
|
525
|
+
"header_finding_missing_content_type_options":
|
|
526
|
+
"{header}: not set, so a browser may MIME-sniff the response.",
|
|
527
|
+
"header_finding_missing_frame_options":
|
|
528
|
+
"{header}: not set; it (or CSP frame-ancestors) controls who may frame the page.",
|
|
529
|
+
"header_finding_missing_referrer_policy":
|
|
530
|
+
"{header}: not set, so full URLs may leak to other sites.",
|
|
461
531
|
# Diagram Editor — Tools
|
|
462
532
|
"diagram_editor_tool_select": "Select",
|
|
463
533
|
"diagram_editor_tool_rect": "Rect",
|
{pybreeze-1.0.25 → pybreeze-1.0.26}/pybreeze/extend_multi_language/extend_traditional_chinese.py
RENAMED
|
@@ -309,6 +309,7 @@ pybreeze_traditional_chinese_word_dict = {
|
|
|
309
309
|
"curl_import_target_apitestka_python": "APITestka(Python)",
|
|
310
310
|
"curl_import_target_apitestka_action": "APITestka(JSON action)",
|
|
311
311
|
"curl_import_target_loaddensity_python": "LoadDensity(Python)",
|
|
312
|
+
"curl_import_open_url_button": "在 URL 解析/組建器開啟網址",
|
|
312
313
|
# 共用輸出動作(複製 / 開成分頁 / 存檔)
|
|
313
314
|
"output_actions_copy": "複製",
|
|
314
315
|
"output_actions_open_editor": "開成編輯器分頁",
|
|
@@ -371,6 +372,20 @@ pybreeze_traditional_chinese_word_dict = {
|
|
|
371
372
|
"query_json_output_label": "結果:",
|
|
372
373
|
"query_json_error": "無法轉換:{error}",
|
|
373
374
|
"query_json_empty_hint": "請在上方輸入查詢字串或 JSON 物件。",
|
|
375
|
+
# URL 解析/組建器 — 選單
|
|
376
|
+
"extend_tools_menu_url_builder_tab_action": "URL 解析/組建器分頁",
|
|
377
|
+
"extend_tools_menu_url_builder_tab_label": "URL 解析/組建器",
|
|
378
|
+
"extend_tools_menu_url_builder_dock_action": "URL 解析/組建器停駐窗格",
|
|
379
|
+
"extend_tools_menu_url_builder_dock_title": "URL 解析/組建器",
|
|
380
|
+
# URL 解析/組建器 — 介面
|
|
381
|
+
"url_builder_input_label": "一個 URL,或描述 URL 各部分的 JSON 物件:",
|
|
382
|
+
"url_builder_input_placeholder":
|
|
383
|
+
"https://user@host:8080/path?a=1#frag 或 {\"scheme\": \"https\", \"host\": \"host\"}",
|
|
384
|
+
"url_builder_to_json_button": "URL → JSON",
|
|
385
|
+
"url_builder_to_url_button": "JSON → URL",
|
|
386
|
+
"url_builder_output_label": "結果:",
|
|
387
|
+
"url_builder_error": "無法組建 URL:{error}",
|
|
388
|
+
"url_builder_empty_hint": "請在上方輸入 URL 或描述 URL 各部分的 JSON 物件。",
|
|
374
389
|
# 正規表示式測試器 — 選單
|
|
375
390
|
"extend_tools_menu_regex_tab_action": "正規表示式測試器分頁",
|
|
376
391
|
"extend_tools_menu_regex_tab_label": "Regex",
|
|
@@ -431,11 +446,66 @@ pybreeze_traditional_chinese_word_dict = {
|
|
|
431
446
|
"response_output_label": "分析結果:",
|
|
432
447
|
"response_open_jwt_button": "在解碼器開啟 JWT",
|
|
433
448
|
"response_open_status_button": "在參考開啟狀態碼",
|
|
449
|
+
"response_open_headers_button": "在分析器開啟標頭",
|
|
434
450
|
"response_empty_hint": "請先在上方貼上回應,再按分析。",
|
|
435
451
|
"response_status_label": "== 狀態 Status ==",
|
|
436
452
|
"response_headers_label": "== 標頭 Headers ==",
|
|
437
453
|
"response_jwt_label": "== 找到的 JWT ==",
|
|
438
454
|
"response_body_label": "== 內容 Body ==",
|
|
455
|
+
# HTTP 標頭分析器 — 選單
|
|
456
|
+
"extend_tools_menu_header_analyzer_tab_action": "HTTP 標頭分析器分頁",
|
|
457
|
+
"extend_tools_menu_header_analyzer_tab_label": "標頭分析器",
|
|
458
|
+
"extend_tools_menu_header_analyzer_dock_action": "HTTP 標頭分析器停駐窗格",
|
|
459
|
+
"extend_tools_menu_header_analyzer_dock_title": "標頭分析器",
|
|
460
|
+
# HTTP 標頭分析器 — 介面
|
|
461
|
+
"header_analyzer_input_label": "貼上請求或回應的標頭:",
|
|
462
|
+
"header_analyzer_input_placeholder":
|
|
463
|
+
"HTTP/1.1 200 OK\nContent-Type: text/html\nSet-Cookie: sid=abc; Path=/",
|
|
464
|
+
"header_analyzer_analyze_button": "分析標頭",
|
|
465
|
+
"header_analyzer_output_label": "分析結果:",
|
|
466
|
+
"header_analyzer_headers_label": "== 標頭({count})==",
|
|
467
|
+
"header_analyzer_duplicates_label": "== 重複出現的名稱 ==",
|
|
468
|
+
"header_analyzer_findings_label": "== 分析發現 ==",
|
|
469
|
+
"header_analyzer_no_findings": "沒有需要注意的項目。",
|
|
470
|
+
"header_analyzer_no_headers": "這段文字中找不到標頭。",
|
|
471
|
+
"header_analyzer_empty_hint": "請先在上方貼上標頭,再按分析。",
|
|
472
|
+
"header_analyzer_level_warning": "警告",
|
|
473
|
+
"header_analyzer_level_info": "資訊",
|
|
474
|
+
# HTTP 標頭分析器 — 發現({header} 為標頭名稱,{detail} 為其值)
|
|
475
|
+
"header_finding_duplicate_header":
|
|
476
|
+
"{header}:送出 {detail} 次,接收端會把這些值合併成一個。",
|
|
477
|
+
"header_finding_content_type_options_not_nosniff":
|
|
478
|
+
"{header}:'{detail}' 沒有作用,只有 'nosniff' 能阻止 MIME 探測。",
|
|
479
|
+
"header_finding_hsts_weak_max_age":
|
|
480
|
+
"{header}:max-age={detail} 太短,一般至少要 15552000(180 天)。",
|
|
481
|
+
"header_finding_csp_unsafe_directive":
|
|
482
|
+
"{header}:含有 '{detail}',等於把此政策原本要擋下的行為又放行了。",
|
|
483
|
+
"header_finding_cors_wildcard_origin": "{header}:允許任何來源(*)。",
|
|
484
|
+
"header_finding_cors_wildcard_with_credentials":
|
|
485
|
+
"{header}:'*' 搭配 Access-Control-Allow-Credentials: true,瀏覽器會直接拒絕。",
|
|
486
|
+
"header_finding_cookie_not_secure":
|
|
487
|
+
"{header}:cookie '{detail}' 沒有 Secure 屬性,可能以純 HTTP 傳送。",
|
|
488
|
+
"header_finding_cookie_not_httponly":
|
|
489
|
+
"{header}:cookie '{detail}' 沒有 HttpOnly 屬性,指令碼可以讀取。",
|
|
490
|
+
"header_finding_cookie_no_samesite":
|
|
491
|
+
"{header}:cookie '{detail}' 沒有 SameSite 屬性,瀏覽器會預設為 Lax。",
|
|
492
|
+
"header_finding_content_type_no_charset":
|
|
493
|
+
"{header}:'{detail}' 沒有指定 charset,用戶端只能自行猜測編碼。",
|
|
494
|
+
"header_finding_server_banner": "{header}:'{detail}' 洩漏了所使用的軟體。",
|
|
495
|
+
"header_finding_deprecated_header":
|
|
496
|
+
"{header}:'{detail}' 已淘汰,現行瀏覽器不再處理。",
|
|
497
|
+
"header_finding_sensitive_header":
|
|
498
|
+
"{header}:內含憑證,分享這份輸出前請先遮蔽。",
|
|
499
|
+
"header_finding_missing_hsts":
|
|
500
|
+
"{header}:未設定,瀏覽器可能退回純 HTTP。",
|
|
501
|
+
"header_finding_missing_csp":
|
|
502
|
+
"{header}:未設定,沒有任何規則限制指令碼的載入來源。",
|
|
503
|
+
"header_finding_missing_content_type_options":
|
|
504
|
+
"{header}:未設定,瀏覽器可能對回應做 MIME 探測。",
|
|
505
|
+
"header_finding_missing_frame_options":
|
|
506
|
+
"{header}:未設定;此標頭(或 CSP frame-ancestors)決定誰能將頁面內嵌成框架。",
|
|
507
|
+
"header_finding_missing_referrer_policy":
|
|
508
|
+
"{header}:未設定,完整網址可能外洩給其他網站。",
|
|
439
509
|
# Diagram Editor — 工具
|
|
440
510
|
"diagram_editor_tool_select": "選取",
|
|
441
511
|
"diagram_editor_tool_rect": "矩形",
|
|
@@ -20,11 +20,13 @@ from pybreeze.pybreeze_ui.tools_gui.diff_gui import DiffGUI
|
|
|
20
20
|
from pybreeze.pybreeze_ui.tools_gui.json_format_gui import JsonFormatGUI
|
|
21
21
|
from pybreeze.pybreeze_ui.tools_gui.jwt_decoder_gui import JwtDecoderGUI
|
|
22
22
|
from pybreeze.pybreeze_ui.tools_gui.hash_gui import HashGUI
|
|
23
|
+
from pybreeze.pybreeze_ui.tools_gui.header_analyzer_gui import HeaderAnalyzerGUI
|
|
23
24
|
from pybreeze.pybreeze_ui.tools_gui.http_status_gui import HttpStatusGUI
|
|
24
25
|
from pybreeze.pybreeze_ui.tools_gui.query_json_gui import QueryJsonGUI
|
|
25
26
|
from pybreeze.pybreeze_ui.tools_gui.regex_gui import RegexGUI
|
|
26
27
|
from pybreeze.pybreeze_ui.tools_gui.response_inspector_gui import ResponseInspectorGUI
|
|
27
28
|
from pybreeze.pybreeze_ui.tools_gui.timestamp_gui import TimestampGUI
|
|
29
|
+
from pybreeze.pybreeze_ui.tools_gui.url_builder_gui import UrlBuilderGUI
|
|
28
30
|
|
|
29
31
|
if TYPE_CHECKING:
|
|
30
32
|
from pybreeze.pybreeze_ui.editor_main.main_ui import PyBreezeMainWindow
|
|
@@ -156,6 +158,17 @@ def build_tools_menu(ui_we_want_to_set: PyBreezeMainWindow):
|
|
|
156
158
|
))
|
|
157
159
|
ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_query_json_action)
|
|
158
160
|
|
|
161
|
+
# URL Parser / Builder
|
|
162
|
+
ui_we_want_to_set.tools_url_builder_action = QAction(language_wrapper.language_word_dict.get(
|
|
163
|
+
"extend_tools_menu_url_builder_tab_action"
|
|
164
|
+
))
|
|
165
|
+
ui_we_want_to_set.tools_url_builder_action.triggered.connect(lambda: ui_we_want_to_set.tab_widget.addTab(
|
|
166
|
+
UrlBuilderGUI(ui_we_want_to_set), language_wrapper.language_word_dict.get(
|
|
167
|
+
"extend_tools_menu_url_builder_tab_label"
|
|
168
|
+
)
|
|
169
|
+
))
|
|
170
|
+
ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_url_builder_action)
|
|
171
|
+
|
|
159
172
|
# Regex Tester
|
|
160
173
|
ui_we_want_to_set.tools_regex_action = QAction(language_wrapper.language_word_dict.get(
|
|
161
174
|
"extend_tools_menu_regex_tab_action"
|
|
@@ -200,6 +213,17 @@ def build_tools_menu(ui_we_want_to_set: PyBreezeMainWindow):
|
|
|
200
213
|
))
|
|
201
214
|
ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_json_format_action)
|
|
202
215
|
|
|
216
|
+
# HTTP Header Analyzer
|
|
217
|
+
ui_we_want_to_set.tools_header_analyzer_action = QAction(language_wrapper.language_word_dict.get(
|
|
218
|
+
"extend_tools_menu_header_analyzer_tab_action"
|
|
219
|
+
))
|
|
220
|
+
ui_we_want_to_set.tools_header_analyzer_action.triggered.connect(lambda: ui_we_want_to_set.tab_widget.addTab(
|
|
221
|
+
HeaderAnalyzerGUI(ui_we_want_to_set), language_wrapper.language_word_dict.get(
|
|
222
|
+
"extend_tools_menu_header_analyzer_tab_label"
|
|
223
|
+
)
|
|
224
|
+
))
|
|
225
|
+
ui_we_want_to_set.tools_menu.addAction(ui_we_want_to_set.tools_header_analyzer_action)
|
|
226
|
+
|
|
203
227
|
# Response Inspector
|
|
204
228
|
ui_we_want_to_set.tools_response_action = QAction(language_wrapper.language_word_dict.get(
|
|
205
229
|
"extend_tools_menu_response_tab_action"
|
|
@@ -296,6 +320,13 @@ def extend_dock_menu(ui_we_want_to_set: PyBreezeMainWindow):
|
|
|
296
320
|
lambda: add_dock(ui_we_want_to_set, "QueryJson"))
|
|
297
321
|
ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_query_json_dock_action)
|
|
298
322
|
|
|
323
|
+
# URL Parser / Builder Dock
|
|
324
|
+
ui_we_want_to_set.tools_url_builder_dock_action = QAction(language_wrapper.language_word_dict.get(
|
|
325
|
+
"extend_tools_menu_url_builder_dock_action"))
|
|
326
|
+
ui_we_want_to_set.tools_url_builder_dock_action.triggered.connect(
|
|
327
|
+
lambda: add_dock(ui_we_want_to_set, "UrlBuilder"))
|
|
328
|
+
ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_url_builder_dock_action)
|
|
329
|
+
|
|
299
330
|
# Regex Tester Dock
|
|
300
331
|
ui_we_want_to_set.tools_regex_dock_action = QAction(language_wrapper.language_word_dict.get(
|
|
301
332
|
"extend_tools_menu_regex_dock_action"))
|
|
@@ -324,6 +355,13 @@ def extend_dock_menu(ui_we_want_to_set: PyBreezeMainWindow):
|
|
|
324
355
|
lambda: add_dock(ui_we_want_to_set, "JsonFormat"))
|
|
325
356
|
ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_json_format_dock_action)
|
|
326
357
|
|
|
358
|
+
# HTTP Header Analyzer Dock
|
|
359
|
+
ui_we_want_to_set.tools_header_analyzer_dock_action = QAction(language_wrapper.language_word_dict.get(
|
|
360
|
+
"extend_tools_menu_header_analyzer_dock_action"))
|
|
361
|
+
ui_we_want_to_set.tools_header_analyzer_dock_action.triggered.connect(
|
|
362
|
+
lambda: add_dock(ui_we_want_to_set, "HeaderAnalyzer"))
|
|
363
|
+
ui_we_want_to_set.dock_menu.addAction(ui_we_want_to_set.tools_header_analyzer_dock_action)
|
|
364
|
+
|
|
327
365
|
# Response Inspector Dock
|
|
328
366
|
ui_we_want_to_set.tools_response_dock_action = QAction(language_wrapper.language_word_dict.get(
|
|
329
367
|
"extend_tools_menu_response_dock_action"))
|
|
@@ -352,11 +390,14 @@ _DOCK_WIDGETS: dict[str, tuple[str, Callable[[PyBreezeMainWindow], object]]] = {
|
|
|
352
390
|
"Timestamp": ("extend_tools_menu_timestamp_dock_title", lambda win: TimestampGUI(win)),
|
|
353
391
|
"Hash": ("extend_tools_menu_hash_dock_title", lambda win: HashGUI(win)),
|
|
354
392
|
"QueryJson": ("extend_tools_menu_query_json_dock_title", lambda win: QueryJsonGUI(win)),
|
|
393
|
+
"UrlBuilder": ("extend_tools_menu_url_builder_dock_title", lambda win: UrlBuilderGUI(win)),
|
|
355
394
|
"Regex": ("extend_tools_menu_regex_dock_title", lambda win: RegexGUI(win)),
|
|
356
395
|
"HttpStatus": (
|
|
357
396
|
"extend_tools_menu_http_status_dock_title", lambda win: HttpStatusGUI(main_window=win)),
|
|
358
397
|
"Diff": ("extend_tools_menu_diff_dock_title", lambda win: DiffGUI(win)),
|
|
359
398
|
"JsonFormat": ("extend_tools_menu_json_format_dock_title", lambda win: JsonFormatGUI(win)),
|
|
399
|
+
"HeaderAnalyzer": (
|
|
400
|
+
"extend_tools_menu_header_analyzer_dock_title", lambda win: HeaderAnalyzerGUI(win)),
|
|
360
401
|
"ResponseInspector": (
|
|
361
402
|
"extend_tools_menu_response_dock_title", lambda win: ResponseInspectorGUI(win)),
|
|
362
403
|
}
|
|
@@ -4,7 +4,8 @@ Automation engineers routinely copy a request as ``curl`` from browser dev tools
|
|
|
4
4
|
This widget parses that command and generates a runnable script for a chosen
|
|
5
5
|
target (Python ``requests``, APITestka, LoadDensity), which can then be copied,
|
|
6
6
|
opened straight into a new editor tab, or saved to a ``.py`` / ``.json`` file
|
|
7
|
-
via the shared output actions.
|
|
7
|
+
via the shared output actions. The parsed URL can also be handed straight to the
|
|
8
|
+
URL parser/builder tool for further editing.
|
|
8
9
|
"""
|
|
9
10
|
from __future__ import annotations
|
|
10
11
|
|
|
@@ -14,7 +15,9 @@ from PySide6.QtWidgets import (
|
|
|
14
15
|
from je_editor import language_wrapper
|
|
15
16
|
|
|
16
17
|
from pybreeze.pybreeze_ui.tools_gui.output_actions import OutputActions
|
|
17
|
-
from pybreeze.
|
|
18
|
+
from pybreeze.pybreeze_ui.tools_gui.tool_tabs import open_tool_tab
|
|
19
|
+
from pybreeze.pybreeze_ui.tools_gui.url_builder_gui import UrlBuilderGUI
|
|
20
|
+
from pybreeze.utils.curl_import.curl_parser import CurlRequest, parse_curl
|
|
18
21
|
from pybreeze.utils.curl_import.script_templates import TEMPLATE_TARGETS, generate_template
|
|
19
22
|
from pybreeze.utils.exception.exceptions import CurlParseException
|
|
20
23
|
from pybreeze.utils.logging.logger import pybreeze_logger
|
|
@@ -31,8 +34,11 @@ class CurlImportGUI(QWidget):
|
|
|
31
34
|
:param main_window: the window whose ``tab_widget`` "open in editor" uses
|
|
32
35
|
"""
|
|
33
36
|
super().__init__()
|
|
37
|
+
self._main_window = main_window
|
|
34
38
|
# The last successfully generated code (not an error or hint message).
|
|
35
39
|
self._generated_code: str | None = None
|
|
40
|
+
# The request behind that code, so other tools can be handed its parts.
|
|
41
|
+
self._request: CurlRequest | None = None
|
|
36
42
|
word = language_wrapper.language_word_dict
|
|
37
43
|
|
|
38
44
|
self.input_label = QLabel(word.get("curl_import_input_label"))
|
|
@@ -54,6 +60,11 @@ class CurlImportGUI(QWidget):
|
|
|
54
60
|
self.output_edit = QTextEdit()
|
|
55
61
|
self.output_edit.setReadOnly(True)
|
|
56
62
|
|
|
63
|
+
# Cross-tool action: send the parsed URL to the URL parser/builder.
|
|
64
|
+
self.open_url_button = QPushButton(word.get("curl_import_open_url_button"))
|
|
65
|
+
self.open_url_button.clicked.connect(self.open_url_in_builder)
|
|
66
|
+
self.open_url_button.setEnabled(False)
|
|
67
|
+
|
|
57
68
|
# Shared copy / open-in-editor / save actions. The extension and basename
|
|
58
69
|
# follow the selected target; open/save are no-ops until a valid template.
|
|
59
70
|
self.actions = OutputActions(
|
|
@@ -66,7 +77,7 @@ class CurlImportGUI(QWidget):
|
|
|
66
77
|
for widget in (
|
|
67
78
|
self.input_label, self.input_edit,
|
|
68
79
|
self.target_label, self.target_select, self.convert_button,
|
|
69
|
-
self.output_label, self.output_edit,
|
|
80
|
+
self.output_label, self.output_edit, self.open_url_button,
|
|
70
81
|
):
|
|
71
82
|
layout.addWidget(widget)
|
|
72
83
|
layout.addLayout(self.actions.button_row())
|
|
@@ -81,21 +92,43 @@ class CurlImportGUI(QWidget):
|
|
|
81
92
|
if self.input_edit.toPlainText().strip():
|
|
82
93
|
self.convert()
|
|
83
94
|
|
|
95
|
+
def _clear_result(self) -> None:
|
|
96
|
+
"""Forget the last result, so the output and cross-tool actions go inactive."""
|
|
97
|
+
self._generated_code = None
|
|
98
|
+
self._request = None
|
|
99
|
+
self.open_url_button.setEnabled(False)
|
|
100
|
+
|
|
84
101
|
def convert(self) -> None:
|
|
85
102
|
"""Parse the input command and show the template for the chosen target."""
|
|
86
103
|
word = language_wrapper.language_word_dict
|
|
87
104
|
command = self.input_edit.toPlainText().strip()
|
|
88
105
|
if not command:
|
|
89
|
-
self.
|
|
106
|
+
self._clear_result()
|
|
90
107
|
self.output_edit.setPlainText(word.get("curl_import_empty_hint"))
|
|
91
108
|
return
|
|
92
109
|
try:
|
|
93
|
-
|
|
110
|
+
request = parse_curl(command)
|
|
111
|
+
code = generate_template(self.selected_target(), request)
|
|
94
112
|
except CurlParseException as error:
|
|
95
113
|
pybreeze_logger.info("curl_import_gui.py convert failed: %r", error)
|
|
96
|
-
self.
|
|
114
|
+
self._clear_result()
|
|
97
115
|
self.output_edit.setPlainText(
|
|
98
116
|
word.get("curl_import_error").format(error=str(error)))
|
|
99
117
|
return
|
|
100
118
|
self._generated_code = code
|
|
119
|
+
self._request = request
|
|
120
|
+
self.open_url_button.setEnabled(bool(request.url))
|
|
101
121
|
self.output_edit.setPlainText(code)
|
|
122
|
+
|
|
123
|
+
def open_url_in_builder(self) -> QWidget | None:
|
|
124
|
+
"""Open the parsed URL in the URL parser/builder tool, already parsed.
|
|
125
|
+
|
|
126
|
+
The full URL is handed over (query string included), so the builder shows
|
|
127
|
+
the address exactly as curl would send it.
|
|
128
|
+
"""
|
|
129
|
+
if self._request is None or not self._request.url:
|
|
130
|
+
return None
|
|
131
|
+
return open_tool_tab(
|
|
132
|
+
self._main_window,
|
|
133
|
+
UrlBuilderGUI(main_window=self._main_window, initial_url=self._request.full_url),
|
|
134
|
+
"extend_tools_menu_url_builder_tab_label")
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""A tool tab that analyses a pasted block of HTTP headers.
|
|
2
|
+
|
|
3
|
+
Paste request or response headers and read back every field, the names that were
|
|
4
|
+
sent more than once, and what is worth knowing about them — cookie flags, CORS
|
|
5
|
+
and HSTS policies, headers carrying credentials, and the response security
|
|
6
|
+
headers that are missing.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from PySide6.QtWidgets import QLabel, QPushButton, QTextEdit, QVBoxLayout, QWidget
|
|
11
|
+
from je_editor import language_wrapper
|
|
12
|
+
|
|
13
|
+
from pybreeze.pybreeze_ui.tools_gui.output_actions import OutputActions
|
|
14
|
+
from pybreeze.utils.header_tools.header_analyzer import (
|
|
15
|
+
HeaderAnalysis, HeaderFinding, analyze_headers
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _finding_line(finding: HeaderFinding) -> str:
|
|
20
|
+
"""Render one finding as a translated, level-prefixed line."""
|
|
21
|
+
word = language_wrapper.language_word_dict
|
|
22
|
+
level = word.get(f"header_analyzer_level_{finding.level}") or finding.level
|
|
23
|
+
message = word.get(f"header_finding_{finding.code}") or finding.code
|
|
24
|
+
return f"[{level}] {message.format(header=finding.header, detail=finding.detail)}"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def build_header_report(analysis: HeaderAnalysis) -> str:
|
|
28
|
+
"""Render a header analysis into a readable, sectioned report.
|
|
29
|
+
|
|
30
|
+
:param analysis: the analysed header block
|
|
31
|
+
:return: display text, or the "no headers" message when nothing was found
|
|
32
|
+
"""
|
|
33
|
+
word = language_wrapper.language_word_dict
|
|
34
|
+
if not analysis.fields:
|
|
35
|
+
return word.get("header_analyzer_no_headers")
|
|
36
|
+
|
|
37
|
+
lines = [word.get("header_analyzer_headers_label").format(count=len(analysis.fields))]
|
|
38
|
+
lines.extend(f"{header.name}: {header.value}" for header in analysis.fields)
|
|
39
|
+
|
|
40
|
+
if analysis.duplicates:
|
|
41
|
+
lines.extend(["", word.get("header_analyzer_duplicates_label")])
|
|
42
|
+
lines.extend(f"{name} × {count}" for name, count in analysis.duplicates.items())
|
|
43
|
+
|
|
44
|
+
lines.extend(["", word.get("header_analyzer_findings_label")])
|
|
45
|
+
if analysis.findings:
|
|
46
|
+
lines.extend(_finding_line(finding) for finding in analysis.findings)
|
|
47
|
+
else:
|
|
48
|
+
lines.append(word.get("header_analyzer_no_findings"))
|
|
49
|
+
return "\n".join(lines)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class HeaderAnalyzerGUI(QWidget):
|
|
53
|
+
"""Paste HTTP headers and read what they say about the request or response."""
|
|
54
|
+
|
|
55
|
+
def __init__(self, main_window=None, initial_headers: str | None = None) -> None:
|
|
56
|
+
"""
|
|
57
|
+
:param main_window: window whose ``tab_widget`` "open in editor" uses
|
|
58
|
+
:param initial_headers: a header block to pre-fill and analyse on open
|
|
59
|
+
"""
|
|
60
|
+
super().__init__()
|
|
61
|
+
self._analysis: HeaderAnalysis | None = None
|
|
62
|
+
word = language_wrapper.language_word_dict
|
|
63
|
+
|
|
64
|
+
self.input_label = QLabel(word.get("header_analyzer_input_label"))
|
|
65
|
+
self.input_edit = QTextEdit()
|
|
66
|
+
self.input_edit.setPlaceholderText(word.get("header_analyzer_input_placeholder"))
|
|
67
|
+
self.input_edit.setAcceptRichText(False)
|
|
68
|
+
|
|
69
|
+
self.analyze_button = QPushButton(word.get("header_analyzer_analyze_button"))
|
|
70
|
+
self.analyze_button.clicked.connect(self.analyze)
|
|
71
|
+
|
|
72
|
+
self.output_label = QLabel(word.get("header_analyzer_output_label"))
|
|
73
|
+
self.output_edit = QTextEdit()
|
|
74
|
+
self.output_edit.setReadOnly(True)
|
|
75
|
+
|
|
76
|
+
self.actions = OutputActions(
|
|
77
|
+
self, self.output_edit, main_window=main_window,
|
|
78
|
+
basename="headers", extension="txt",
|
|
79
|
+
is_valid=lambda: self._analysis is not None)
|
|
80
|
+
|
|
81
|
+
layout = QVBoxLayout()
|
|
82
|
+
for widget in (
|
|
83
|
+
self.input_label, self.input_edit, self.analyze_button,
|
|
84
|
+
self.output_label, self.output_edit,
|
|
85
|
+
):
|
|
86
|
+
layout.addWidget(widget)
|
|
87
|
+
layout.addLayout(self.actions.button_row())
|
|
88
|
+
self.setLayout(layout)
|
|
89
|
+
|
|
90
|
+
if initial_headers:
|
|
91
|
+
self.input_edit.setPlainText(initial_headers)
|
|
92
|
+
self.analyze()
|
|
93
|
+
|
|
94
|
+
def analyze(self) -> None:
|
|
95
|
+
"""Analyse the pasted headers and show the report."""
|
|
96
|
+
word = language_wrapper.language_word_dict
|
|
97
|
+
text = self.input_edit.toPlainText().strip()
|
|
98
|
+
if not text:
|
|
99
|
+
self._analysis = None
|
|
100
|
+
self.output_edit.setPlainText(word.get("header_analyzer_empty_hint"))
|
|
101
|
+
return
|
|
102
|
+
analysis = analyze_headers(text)
|
|
103
|
+
if not analysis.fields:
|
|
104
|
+
self._analysis = None
|
|
105
|
+
self.output_edit.setPlainText(word.get("header_analyzer_no_headers"))
|
|
106
|
+
return
|
|
107
|
+
self._analysis = analysis
|
|
108
|
+
self.output_edit.setPlainText(build_header_report(analysis))
|