Copy disabled (too large)
Download .txt
Showing preview only (25,142K chars total). Download the full file to get everything.
Repository: evilsocket/bettercap-ng
Branch: master
Commit: 8ab80c10a2f0
Files: 445
Total size: 23.9 MB
Directory structure:
gitextract_w8thaqpx/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── config.yml
│ │ └── default_issue.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-and-deploy.yml
│ ├── build-and-push-docker.yml
│ ├── test-on-linux.yml
│ ├── test-on-macos.yml
│ └── test-on-windows.yml
├── .gitignore
├── Dockerfile
├── Dockerfile.arm64
├── LICENSE.md
├── Makefile
├── README.md
├── SECURITY.md
├── bettercap.service
├── caplets/
│ ├── caplet.go
│ ├── caplet_test.go
│ ├── doc.go
│ ├── env.go
│ ├── env_test.go
│ ├── manager.go
│ └── manager_test.go
├── core/
│ ├── banner.go
│ ├── banner_test.go
│ ├── core.go
│ ├── core_android.go
│ ├── core_test.go
│ ├── core_unix.go
│ ├── core_windows.go
│ ├── doc.go
│ └── options.go
├── firewall/
│ ├── doc.go
│ ├── firewall.go
│ ├── firewall_darwin.go
│ ├── firewall_linux.go
│ ├── firewall_windows.go
│ ├── redirection.go
│ └── redirection_test.go
├── go.mod
├── go.sum
├── js/
│ ├── crypto.go
│ ├── data.go
│ ├── data_test.go
│ ├── fs.go
│ ├── fs_test.go
│ ├── http.go
│ ├── init.go
│ ├── log.go
│ ├── random.go
│ └── random_test.go
├── log/
│ ├── doc.go
│ ├── log.go
│ └── log_test.go
├── main.go
├── main_test.go
├── modules/
│ ├── any_proxy/
│ │ ├── any_proxy.go
│ │ └── any_proxy_test.go
│ ├── api_rest/
│ │ ├── api_rest.go
│ │ ├── api_rest_controller.go
│ │ ├── api_rest_record.go
│ │ ├── api_rest_replay.go
│ │ ├── api_rest_test.go
│ │ └── api_rest_ws.go
│ ├── arp_spoof/
│ │ ├── arp_spoof.go
│ │ └── arp_spoof_test.go
│ ├── ble/
│ │ ├── ble_options_darwin.go
│ │ ├── ble_options_linux.go
│ │ ├── ble_recon.go
│ │ ├── ble_recon_events.go
│ │ ├── ble_recon_test.go
│ │ ├── ble_show.go
│ │ ├── ble_show_services.go
│ │ ├── ble_show_sort.go
│ │ └── ble_unsupported.go
│ ├── c2/
│ │ ├── c2.go
│ │ └── c2_test.go
│ ├── can/
│ │ ├── can.go
│ │ ├── can_dbc.go
│ │ ├── can_dbc_compile.go
│ │ ├── can_dbc_load.go
│ │ ├── can_dump_reader.go
│ │ ├── can_fuzz.go
│ │ ├── can_inject.go
│ │ ├── can_message.go
│ │ ├── can_obd2.go
│ │ ├── can_obd2_message.go
│ │ ├── can_obd2_pid_request.go
│ │ ├── can_obd2_pid_response.go
│ │ ├── can_recon.go
│ │ ├── can_show.go
│ │ └── can_test.go
│ ├── caplets/
│ │ └── caplets.go
│ ├── dhcp6_spoof/
│ │ └── dhcp6_spoof.go
│ ├── dns_proxy/
│ │ ├── dns_proxy.go
│ │ ├── dns_proxy_base.go
│ │ ├── dns_proxy_base_filters.go
│ │ ├── dns_proxy_js_query.go
│ │ ├── dns_proxy_js_record.go
│ │ ├── dns_proxy_js_record_edns0.go
│ │ ├── dns_proxy_js_record_svcb.go
│ │ └── dns_proxy_script.go
│ ├── dns_spoof/
│ │ ├── dns_spoof.go
│ │ └── dns_spoof_hosts.go
│ ├── doc.go
│ ├── events_stream/
│ │ ├── events_rotation.go
│ │ ├── events_stream.go
│ │ ├── events_triggers.go
│ │ ├── events_view.go
│ │ ├── events_view_ble.go
│ │ ├── events_view_ble_unsupported.go
│ │ ├── events_view_can.go
│ │ ├── events_view_gateway.go
│ │ ├── events_view_gps.go
│ │ ├── events_view_hid.go
│ │ ├── events_view_http.go
│ │ ├── events_view_wifi.go
│ │ ├── events_view_zeroconf.go
│ │ └── trigger_list.go
│ ├── gps/
│ │ └── gps.go
│ ├── graph/
│ │ ├── create.go
│ │ ├── create_ble.go
│ │ ├── create_ble_unsupported.go
│ │ ├── edge.go
│ │ ├── edges.go
│ │ ├── graph.go
│ │ ├── js_builtin.go
│ │ ├── module.go
│ │ ├── node.go
│ │ ├── stack.go
│ │ ├── to_dot.go
│ │ └── to_json.go
│ ├── hid/
│ │ ├── build_amazon.go
│ │ ├── build_logitech.go
│ │ ├── build_microsoft.go
│ │ ├── builders.go
│ │ ├── command.go
│ │ ├── duckyparser.go
│ │ ├── hid.go
│ │ ├── hid_inject.go
│ │ ├── hid_recon.go
│ │ ├── hid_show.go
│ │ ├── hid_show_sort.go
│ │ ├── hid_sniff.go
│ │ └── keymaps.go
│ ├── http_proxy/
│ │ ├── http_proxy.go
│ │ ├── http_proxy_base.go
│ │ ├── http_proxy_base_cookietracker.go
│ │ ├── http_proxy_base_filters.go
│ │ ├── http_proxy_base_hosttracker.go
│ │ ├── http_proxy_base_sslstriper.go
│ │ ├── http_proxy_cert_cache.go
│ │ ├── http_proxy_js_request.go
│ │ ├── http_proxy_js_response.go
│ │ ├── http_proxy_script.go
│ │ └── http_proxy_test.go
│ ├── http_server/
│ │ └── http_server.go
│ ├── https_proxy/
│ │ └── https_proxy.go
│ ├── https_server/
│ │ └── https_server.go
│ ├── mac_changer/
│ │ └── mac_changer.go
│ ├── modules.go
│ ├── modules_test.go
│ ├── mysql_server/
│ │ └── mysql_server.go
│ ├── ndp_spoof/
│ │ └── ndp_spoof.go
│ ├── net_probe/
│ │ ├── net_probe.go
│ │ ├── net_probe_nbns.go
│ │ ├── net_probe_test.go
│ │ ├── net_probe_upnp.go
│ │ └── net_probe_wsd.go
│ ├── net_recon/
│ │ ├── net_recon.go
│ │ ├── net_recon_test.go
│ │ ├── net_show.go
│ │ └── net_show_sort.go
│ ├── net_sniff/
│ │ ├── net_sniff.go
│ │ ├── net_sniff_context.go
│ │ ├── net_sniff_dns.go
│ │ ├── net_sniff_dot11.go
│ │ ├── net_sniff_event.go
│ │ ├── net_sniff_ftp.go
│ │ ├── net_sniff_fuzz.go
│ │ ├── net_sniff_http.go
│ │ ├── net_sniff_krb5.go
│ │ ├── net_sniff_mdns.go
│ │ ├── net_sniff_ntlm.go
│ │ ├── net_sniff_parsers.go
│ │ ├── net_sniff_sni.go
│ │ ├── net_sniff_stats.go
│ │ ├── net_sniff_tcp.go
│ │ ├── net_sniff_teamviewer.go
│ │ ├── net_sniff_udp.go
│ │ ├── net_sniff_upnp.go
│ │ └── net_sniff_views.go
│ ├── packet_proxy/
│ │ ├── packet_proxy_darwin.go
│ │ ├── packet_proxy_freebsd.go
│ │ ├── packet_proxy_linux.go
│ │ └── packet_proxy_windows.go
│ ├── syn_scan/
│ │ ├── banner_grabbing.go
│ │ ├── dns_grabber.go
│ │ ├── http_grabber.go
│ │ ├── syn_scan.go
│ │ ├── syn_scan_event.go
│ │ ├── syn_scan_parsers.go
│ │ ├── syn_scan_reader.go
│ │ └── tcp_grabber.go
│ ├── tcp_proxy/
│ │ ├── tcp_proxy.go
│ │ ├── tcp_proxy_script.go
│ │ └── tcp_proxy_script_test.go
│ ├── ticker/
│ │ ├── ticker.go
│ │ └── ticker_test.go
│ ├── ui/
│ │ ├── ui/
│ │ │ ├── assets/
│ │ │ │ ├── fontawesome/
│ │ │ │ │ ├── LICENSE.txt
│ │ │ │ │ ├── css/
│ │ │ │ │ │ ├── all.css
│ │ │ │ │ │ ├── brands.css
│ │ │ │ │ │ ├── fontawesome.css
│ │ │ │ │ │ ├── regular.css
│ │ │ │ │ │ ├── solid.css
│ │ │ │ │ │ ├── svg-with-js.css
│ │ │ │ │ │ └── v4-shims.css
│ │ │ │ │ ├── js/
│ │ │ │ │ │ ├── all.js
│ │ │ │ │ │ ├── brands.js
│ │ │ │ │ │ ├── fontawesome.js
│ │ │ │ │ │ ├── regular.js
│ │ │ │ │ │ ├── solid.js
│ │ │ │ │ │ └── v4-shims.js
│ │ │ │ │ ├── less/
│ │ │ │ │ │ ├── _animated.less
│ │ │ │ │ │ ├── _bordered-pulled.less
│ │ │ │ │ │ ├── _core.less
│ │ │ │ │ │ ├── _fixed-width.less
│ │ │ │ │ │ ├── _icons.less
│ │ │ │ │ │ ├── _larger.less
│ │ │ │ │ │ ├── _list.less
│ │ │ │ │ │ ├── _mixins.less
│ │ │ │ │ │ ├── _rotated-flipped.less
│ │ │ │ │ │ ├── _screen-reader.less
│ │ │ │ │ │ ├── _shims.less
│ │ │ │ │ │ ├── _stacked.less
│ │ │ │ │ │ ├── _variables.less
│ │ │ │ │ │ ├── brands.less
│ │ │ │ │ │ ├── fontawesome.less
│ │ │ │ │ │ ├── regular.less
│ │ │ │ │ │ ├── solid.less
│ │ │ │ │ │ └── v4-shims.less
│ │ │ │ │ ├── metadata/
│ │ │ │ │ │ ├── categories.yml
│ │ │ │ │ │ ├── icons.json
│ │ │ │ │ │ ├── icons.yml
│ │ │ │ │ │ ├── shims.json
│ │ │ │ │ │ ├── shims.yml
│ │ │ │ │ │ └── sponsors.yml
│ │ │ │ │ └── scss/
│ │ │ │ │ ├── _animated.scss
│ │ │ │ │ ├── _bordered-pulled.scss
│ │ │ │ │ ├── _core.scss
│ │ │ │ │ ├── _fixed-width.scss
│ │ │ │ │ ├── _icons.scss
│ │ │ │ │ ├── _larger.scss
│ │ │ │ │ ├── _list.scss
│ │ │ │ │ ├── _mixins.scss
│ │ │ │ │ ├── _rotated-flipped.scss
│ │ │ │ │ ├── _screen-reader.scss
│ │ │ │ │ ├── _shims.scss
│ │ │ │ │ ├── _stacked.scss
│ │ │ │ │ ├── _variables.scss
│ │ │ │ │ ├── brands.scss
│ │ │ │ │ ├── fontawesome.scss
│ │ │ │ │ ├── regular.scss
│ │ │ │ │ ├── solid.scss
│ │ │ │ │ └── v4-shims.scss
│ │ │ │ └── openlayers/
│ │ │ │ ├── ol.css
│ │ │ │ └── ol.js
│ │ │ ├── index.html
│ │ │ ├── main.js
│ │ │ ├── polyfills.js
│ │ │ ├── runtime.js
│ │ │ ├── scripts.js
│ │ │ ├── styles.js
│ │ │ └── vendor.js
│ │ └── ui.go
│ ├── update/
│ │ ├── update.go
│ │ └── update_test.go
│ ├── utils/
│ │ ├── view_selector.go
│ │ └── view_selector_test.go
│ ├── wifi/
│ │ ├── wifi.go
│ │ ├── wifi_ap.go
│ │ ├── wifi_assoc.go
│ │ ├── wifi_bruteforce.go
│ │ ├── wifi_bruteforce_darwin.go
│ │ ├── wifi_bruteforce_linux.go
│ │ ├── wifi_bruteforce_unsupported.go
│ │ ├── wifi_csa.go
│ │ ├── wifi_deauth.go
│ │ ├── wifi_events.go
│ │ ├── wifi_fake_auth.go
│ │ ├── wifi_hopping.go
│ │ ├── wifi_inject.go
│ │ ├── wifi_inject_darwin.go
│ │ ├── wifi_recon.go
│ │ ├── wifi_recon_handshakes.go
│ │ ├── wifi_show.go
│ │ ├── wifi_show_sort.go
│ │ └── wifi_test.go
│ ├── wol/
│ │ ├── wol.go
│ │ └── wol_test.go
│ └── zerogod/
│ ├── zeroconf/
│ │ ├── client.go
│ │ ├── connection.go
│ │ ├── doc.go
│ │ ├── server.go
│ │ ├── service.go
│ │ └── utils.go
│ ├── zerogod.go
│ ├── zerogod_acceptor.go
│ ├── zerogod_advertise.go
│ ├── zerogod_browser.go
│ ├── zerogod_discovery.go
│ ├── zerogod_endpoint_update.go
│ ├── zerogod_generic_tcp_handler.go
│ ├── zerogod_http_handler.go
│ ├── zerogod_ipp_get_job_attributes.go
│ ├── zerogod_ipp_get_jobs.go
│ ├── zerogod_ipp_get_printer_attributes.go
│ ├── zerogod_ipp_handler.go
│ ├── zerogod_ipp_primitives.go
│ ├── zerogod_ipp_print_job.go
│ ├── zerogod_ipp_unhandled.go
│ ├── zerogod_ipp_validate_job.go
│ ├── zerogod_known_services.go
│ ├── zerogod_save.go
│ ├── zerogod_service.go
│ ├── zerogod_show.go
│ └── zerogod_test.go
├── network/
│ ├── arp.go
│ ├── arp_parser_darwin.go
│ ├── arp_parser_linux.go
│ ├── arp_parser_windows.go
│ ├── ble.go
│ ├── ble_device.go
│ ├── ble_unsupported.go
│ ├── can.go
│ ├── can_device.go
│ ├── debug.go
│ ├── doc.go
│ ├── hid.go
│ ├── hid_device.go
│ ├── lan.go
│ ├── lan_endpoint.go
│ ├── lan_test.go
│ ├── make_manuf.py
│ ├── manuf/
│ │ ├── cid.csv
│ │ ├── iab.csv
│ │ ├── mam.csv
│ │ ├── oui.csv
│ │ └── oui36.csv
│ ├── manuf.go
│ ├── manuf.go.template
│ ├── meta.go
│ ├── meta_test.go
│ ├── net.go
│ ├── net_darwin.go
│ ├── net_darwin.m
│ ├── net_gateway.go
│ ├── net_gateway_android.go
│ ├── net_linux.go
│ ├── net_test.go
│ ├── net_wifi.go
│ ├── net_windows.go
│ ├── pcap.go
│ ├── services.go
│ ├── wifi.go
│ ├── wifi_ap.go
│ ├── wifi_handshake.go
│ ├── wifi_station.go
│ └── wifi_test.go
├── packets/
│ ├── arp.go
│ ├── arp_test.go
│ ├── dhcp6.go
│ ├── dhcp6_layer.go
│ ├── dhcp6_layer_test.go
│ ├── dhcp6_test.go
│ ├── doc.go
│ ├── dot11.go
│ ├── dot11_test.go
│ ├── dot11_types.go
│ ├── dot11_types_test.go
│ ├── dot11_wps.go
│ ├── dot11_wps_attrs.go
│ ├── icmp6.go
│ ├── icmp6_test.go
│ ├── krb5.go
│ ├── krb5_test.go
│ ├── mdns.go
│ ├── mdns_test.go
│ ├── mysql.go
│ ├── mysql_test.go
│ ├── nbns.go
│ ├── nbns_test.go
│ ├── ntlm.go
│ ├── ntlm_test.go
│ ├── queue.go
│ ├── queue_test.go
│ ├── serialize.go
│ ├── serialize_test.go
│ ├── tcp.go
│ ├── tcp_test.go
│ ├── teamviewer.go
│ ├── udp.go
│ ├── udp_test.go
│ ├── upnp.go
│ └── wsd.go
├── release.py
├── routing/
│ ├── route.go
│ ├── route_test.go
│ ├── tables.go
│ ├── tables_test.go
│ ├── update_darwin.go
│ ├── update_linux.go
│ └── update_windows.go
├── session/
│ ├── command_handler.go
│ ├── command_handler_test.go
│ ├── doc.go
│ ├── environment.go
│ ├── environment_test.go
│ ├── events.go
│ ├── events_ignore_list.go
│ ├── events_test.go
│ ├── module.go
│ ├── module_handler.go
│ ├── module_handler_test.go
│ ├── module_param.go
│ ├── module_param_test.go
│ ├── prompt.go
│ ├── script.go
│ ├── script_builtin.go
│ ├── script_builtin_runtime.go
│ ├── session.go
│ ├── session_completers.go
│ ├── session_core_handlers.go
│ ├── session_json.go
│ ├── session_parse.go
│ ├── session_routing.go
│ ├── session_setup.go
│ ├── session_setup_test.go
│ └── session_test.go
└── tls/
├── cert.go
├── doc.go
├── sign.go
└── tls_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.js linguist-vendored
/Dockerfile linguist-vendored
/release.py linguist-vendored
/**/*.js linguist-vendored
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: evilsocket
patreon: evilsocket
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Bettercap Documentation
url: https://www.bettercap.org/
about: Please read the instructions before asking for help.
================================================
FILE: .github/ISSUE_TEMPLATE/default_issue.md
================================================
---
name: General Issue
about: Write a general issue or bug report.
---
# Prerequisites
Please, before creating this issue make sure that you read the [README](https://github.com/bettercap/bettercap/blob/master/README.md), that you are running the [latest stable version](https://github.com/bettercap/bettercap/releases) and that you already searched [other issues](https://github.com/bettercap/bettercap/issues?q=is%3Aopen+is%3Aissue+label%3Abug) to see if your problem or request was already reported.
! PLEASE REMOVE THIS PART AND LEAVE ONLY THE FOLLOWING SECTIONS IN YOUR REPORT !
---
*Description of the bug or feature request*
### Environment
Please provide:
* Bettercap version you are using ( `bettercap -version` ).
* OS version and architecture you are using.
* Go version if building from sources.
* Command line arguments you are using.
* Caplet code you are using or the interactive session commands.
* **Full debug output** while reproducing the issue ( `bettercap -debug ...` ).
### Steps to Reproduce
1. *First Step*
2. *Second Step*
3. *and so on...*
**Expected behavior:** *What you expected to happen*
**Actual behavior:** *What actually happened*
--
**♥ ANY INCOMPLETE REPORT WILL BE CLOSED RIGHT AWAY ♥**
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
# GitHub Actions
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
================================================
FILE: .github/workflows/build-and-deploy.yml
================================================
name: Build and Deploy
on:
push:
tags:
- 'v*.*.*' # Match version tags
workflow_dispatch:
jobs:
build:
name: ${{ matrix.os.pretty }} ${{ matrix.arch }}
runs-on: ${{ matrix.os.runs-on }}
strategy:
matrix:
os:
- name: darwin
runs-on: [macos-latest]
pretty: 🍎 macOS
- name: linux
runs-on: [ubuntu-latest]
pretty: 🐧 Linux
- name: windows
runs-on: [windows-latest]
pretty: 🪟 Windows
output: bettercap.exe
arch: [amd64, arm64]
go: [1.24.x]
exclude:
- os:
name: darwin
arch: amd64
# Linux ARM64 images are not yet publicly available (https://github.com/actions/runner-images)
- os:
name: linux
arch: arm64
- os:
name: windows
arch: arm64
env:
OUTPUT: ${{ matrix.os.output || 'bettercap' }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: Install Dependencies
if: ${{ matrix.os.name == 'linux' }}
run: sudo apt-get update && sudo apt-get install -y p7zip-full libpcap-dev libnetfilter-queue-dev libusb-1.0-0-dev
- name: Install Dependencies (macOS)
if: ${{ matrix.os.name == 'macos' }}
run: brew install libpcap libusb p7zip
- name: Install libusb via mingw (Windows)
if: ${{ matrix.os.name == 'windows' }}
uses: msys2/setup-msys2@v2
with:
install: |-
mingw64/mingw-w64-x86_64-libusb
mingw64/mingw-w64-x86_64-pkg-config
- name: Install other Dependencies (Windows)
if: ${{ matrix.os.name == 'windows' }}
run: |
choco install openssl.light -y
choco install make -y
choco install 7zip -y
choco install zadig -y
curl -L "https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip" -o "C:\wpcap-sdk.zip"
7z x -y "C:\wpcap-sdk.zip" -o"C:\winpcap"
echo "D:\a\_temp\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Build
run: make -e TARGET="${{ env.OUTPUT }}"
- name: Verify Build
run: |
file "${{ env.OUTPUT }}"
openssl dgst -sha256 "${{ env.OUTPUT }}" | tee bettercap_${{ matrix.os.name }}_${{ matrix.arch }}.sha256
7z a "bettercap_${{ matrix.os.name }}_${{ matrix.arch }}.zip" "${{ env.OUTPUT }}" "bettercap_${{ matrix.os.name }}_${{ matrix.arch }}.sha256"
- name: Upload Artifacts
uses: actions/upload-artifact@v7
with:
name: release-artifacts-${{ matrix.os.name }}-${{ matrix.arch }}
path: |
bettercap_*.zip
bettercap_*.sha256
deploy:
needs: [build]
name: Release
runs-on: ubuntu-latest
steps:
- name: Download Artifacts
uses: actions/download-artifact@v8
with:
pattern: release-artifacts-*
merge-multiple: true
path: dist/
- name: Release Assets
run: ls -l dist
- name: Upload Release Assets
uses: softprops/action-gh-release@v2
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
with:
files: dist/bettercap_*
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
================================================
FILE: .github/workflows/build-and-push-docker.yml
================================================
name: Build and Push Docker Images
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v7
with:
platforms: linux/amd64,linux/arm64
push: true
tags: bettercap/bettercap:latest
================================================
FILE: .github/workflows/test-on-linux.yml
================================================
name: Linux tests
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest]
go-version: ['1.24.x']
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Install Dependencies
run: sudo apt-get update && sudo apt-get install -y p7zip-full libpcap-dev libnetfilter-queue-dev libusb-1.0-0-dev
- name: Run Tests
run: |
env GO111MODULE=on make test
================================================
FILE: .github/workflows/test-on-macos.yml
================================================
name: macOS tests
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
workflow_dispatch:
jobs:
build:
runs-on: macos-latest
strategy:
matrix:
os: [macos-latest]
go-version: ['1.24.x']
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Install Dependencies
run: brew install libpcap libusb p7zip
- name: Run Tests
run: |
env GO111MODULE=on make test
================================================
FILE: .github/workflows/test-on-windows.yml
================================================
name: Windows tests
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
os: [windows-latest]
go-version: ['1.24.x']
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Install libusb via mingw
uses: msys2/setup-msys2@v2
with:
install: |-
mingw64/mingw-w64-x86_64-libusb
mingw64/mingw-w64-x86_64-pkg-config
- name: Install other dependencies
run: |
choco install openssl.light -y
choco install make -y
choco install 7zip -y
choco install zadig -y
curl -L "https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip" -o "C:\wpcap-sdk.zip"
7z x -y "C:\wpcap-sdk.zip" -o"C:\winpcap"
- run: echo "D:\a\_temp\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Run Tests
run: env GO111MODULE=on make test
================================================
FILE: .gitignore
================================================
*.sw*
*.tar.gz
*.prof*
_example/config.js
pcaps
build
bettercap
bettercap.history
*.snap
*.snap.xdelta3
prime/
snap/
stage/
/snap
.idea
/cover.out
/can-data
/test*.yml
/zerochaos.js
================================================
FILE: Dockerfile
================================================
# build stage
FROM golang:1.24-alpine AS build-env
RUN apk add --no-cache ca-certificates
RUN apk add --no-cache bash gcc g++ binutils-gold iptables wireless-tools build-base libpcap-dev libusb-dev linux-headers libnetfilter_queue-dev git
WORKDIR $GOPATH/src/github.com/bettercap/bettercap
ADD . $GOPATH/src/github.com/bettercap/bettercap
RUN make
# get caplets
RUN mkdir -p /usr/local/share/bettercap
RUN git clone https://github.com/bettercap/caplets /usr/local/share/bettercap/caplets
# final stage
FROM alpine
RUN apk add --no-cache ca-certificates
RUN apk add --no-cache bash iproute2 libpcap libusb-dev libnetfilter_queue wireless-tools iw
COPY --from=build-env /go/src/github.com/bettercap/bettercap/bettercap /app/
COPY --from=build-env /usr/local/share/bettercap/caplets /app/
WORKDIR /app
EXPOSE 80 443 53 5300 8080 8081 8082 8083 8000
ENTRYPOINT ["/app/bettercap"]
================================================
FILE: Dockerfile.arm64
================================================
# syntax=docker/dockerfile:1
# build stage for cross-compiling for arm64 using native Go cross-compilation
FROM golang:1.24-bookworm AS builder
# install cross-compilation toolchain and ARM64 libraries
RUN dpkg --add-architecture arm64 && \
apt-get update && apt-get install -y --no-install-recommends \
gcc-aarch64-linux-gnu \
libc6-dev-arm64-cross \
libpcap-dev:arm64 \
libnetfilter-queue-dev:arm64 \
libusb-1.0-0-dev:arm64 \
libbluetooth-dev:arm64 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
# cache go modules (runs natively on x86_64 - fast!)
RUN go env -w GOCACHE=/go-cache
RUN go env -w GOMODCACHE=/gomod-cache
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/gomod-cache go mod tidy
RUN --mount=type=cache,target=/gomod-cache go mod download
# copy source code
COPY . .
# cross-compile for ARM64 using native x86_64 Go compiler
ENV CC=aarch64-linux-gnu-gcc
ENV CGO_ENABLED=1
ENV GOOS=linux
ENV GOARCH=arm64
ENV PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
# build with cgo enabled for native library bindings
RUN --mount=type=cache,target=/gomod-cache --mount=type=cache,target=/go-cache make
# output stage - minimal image containing only the binary
FROM scratch AS output
COPY --from=builder /src/bettercap /bettercap
================================================
FILE: LICENSE.md
================================================
GNU GENERAL PUBLIC LICENSE
==========================
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <<https://www.fsf.org/>>
Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.
## Preamble
The GNU General Public License is a free, copyleft license for software and other
kinds of works.
The licenses for most software and other practical works are designed to take away
your freedom to share and change the works. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change all versions of a
program--to make sure it remains free software for all its users. We, the Free
Software Foundation, use the GNU General Public License for most of our software; it
applies also to any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General
Public Licenses are designed to make sure that you have the freedom to distribute
copies of free software (and charge for them if you wish), that you receive source
code or can get it if you want it, that you can change the software or use pieces of
it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or
asking you to surrender the rights. Therefore, you have certain responsibilities if
you distribute copies of the software, or if you modify it: responsibilities to
respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee,
you must pass on to the recipients the same freedoms that you received. You must make
sure that they, too, receive or can get the source code. And you must show them these
terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert
copyright on the software, and (2) offer you this License giving you legal permission
to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is
no warranty for this free software. For both users' and authors' sake, the GPL
requires that modified versions be marked as changed, so that their problems will not
be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of
the software inside them, although the manufacturer can do so. This is fundamentally
incompatible with the aim of protecting users' freedom to change the software. The
systematic pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we have designed
this version of the GPL to prohibit the practice for those products. If such problems
arise substantially in other domains, we stand ready to extend this provision to
those domains in future versions of the GPL, as needed to protect the freedom of
users.
Finally, every program is threatened constantly by software patents. States should
not allow patents to restrict development and use of software on general-purpose
computers, but in those that do, we wish to avoid the special danger that patents
applied to a free program could make it effectively proprietary. To prevent this, the
GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
## TERMS AND CONDITIONS
### 0. Definitions.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this
License. Each licensee is addressed as “you”. “Licensees” and
“recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in
a fashion requiring copyright permission, other than the making of an exact copy. The
resulting work is called a “modified version” of the earlier work or a
work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on
the Program.
To “propagate” a work means to do anything with it that, without
permission, would make you directly or secondarily liable for infringement under
applicable copyright law, except executing it on a computer or modifying a private
copy. Propagation includes copying, distribution (with or without modification),
making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through a computer
network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the
extent that it includes a convenient and prominently visible feature that (1)
displays an appropriate copyright notice, and (2) tells the user that there is no
warranty for the work (except to the extent that warranties are provided), that
licensees may convey the work under this License, and how to view a copy of this
License. If the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
### 1. Source Code.
The “source code” for a work means the preferred form of the work for
making modifications to it. “Object code” means any non-source form of a
work.
A “Standard Interface” means an interface that either is an official
standard defined by a recognized standards body, or, in the case of interfaces
specified for a particular programming language, one that is widely used among
developers working in that language.
The “System Libraries” of an executable work include anything, other than
the work as a whole, that (a) is included in the normal form of packaging a Major
Component, but which is not part of that Major Component, and (b) serves only to
enable use of the work with that Major Component, or to implement a Standard
Interface for which an implementation is available to the public in source code form.
A “Major Component”, in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system (if any) on which
the executable work runs, or a compiler used to produce the work, or an object code
interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the
source code needed to generate, install, and (for an executable work) run the object
code and to modify the work, including scripts to control those activities. However,
it does not include the work's System Libraries, or general-purpose tools or
generally available free programs which are used unmodified in performing those
activities but which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for the work, and
the source code for shared libraries and dynamically linked subprograms that the work
is specifically designed to require, such as by intimate data communication or
control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate
automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
### 2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the
Program, and are irrevocable provided the stated conditions are met. This License
explicitly affirms your unlimited permission to run the unmodified Program. The
output from running a covered work is covered by this License only if the output,
given its content, constitutes a covered work. This License acknowledges your rights
of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without
conditions so long as your license otherwise remains in force. You may convey covered
works to others for the sole purpose of having them make modifications exclusively
for you, or provide you with facilities for running those works, provided that you
comply with the terms of this License in conveying all material for which you do not
control copyright. Those thus making or running the covered works for you must do so
exclusively on your behalf, under your direction and control, on terms that prohibit
them from making any copies of your copyrighted material outside their relationship
with you.
Conveying under any other circumstances is permitted solely under the conditions
stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any
applicable law fulfilling obligations under article 11 of the WIPO copyright treaty
adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention
of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of
technological measures to the extent such circumvention is effected by exercising
rights under this License with respect to the covered work, and you disclaim any
intention to limit operation or modification of the work as a means of enforcing,
against the work's users, your or third parties' legal rights to forbid circumvention
of technological measures.
### 4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any
medium, provided that you conspicuously and appropriately publish on each copy an
appropriate copyright notice; keep intact all notices stating that this License and
any non-permissive terms added in accord with section 7 apply to the code; keep
intact all notices of the absence of any warranty; and give all recipients a copy of
this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer
support or warranty protection for a fee.
### 5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from
the Program, in the form of source code under the terms of section 4, provided that
you also meet all of these conditions:
* **a)** The work must carry prominent notices stating that you modified it, and giving a
relevant date.
* **b)** The work must carry prominent notices stating that it is released under this
License and any conditions added under section 7. This requirement modifies the
requirement in section 4 to “keep intact all notices”.
* **c)** You must license the entire work, as a whole, under this License to anyone who
comes into possession of a copy. This License will therefore apply, along with any
applicable section 7 additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no permission to license the
work in any other way, but it does not invalidate such permission if you have
separately received it.
* **d)** If the work has interactive user interfaces, each must display Appropriate Legal
Notices; however, if the Program has interactive interfaces that do not display
Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are
not by their nature extensions of the covered work, and which are not combined with
it such as to form a larger program, in or on a volume of a storage or distribution
medium, is called an “aggregate” if the compilation and its resulting
copyright are not used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work in an aggregate
does not cause this License to apply to the other parts of the aggregate.
### 6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and
5, provided that you also convey the machine-readable Corresponding Source under the
terms of this License, in one of these ways:
* **a)** Convey the object code in, or embodied in, a physical product (including a
physical distribution medium), accompanied by the Corresponding Source fixed on a
durable physical medium customarily used for software interchange.
* **b)** Convey the object code in, or embodied in, a physical product (including a
physical distribution medium), accompanied by a written offer, valid for at least
three years and valid for as long as you offer spare parts or customer support for
that product model, to give anyone who possesses the object code either (1) a copy of
the Corresponding Source for all the software in the product that is covered by this
License, on a durable physical medium customarily used for software interchange, for
a price no more than your reasonable cost of physically performing this conveying of
source, or (2) access to copy the Corresponding Source from a network server at no
charge.
* **c)** Convey individual copies of the object code with a copy of the written offer to
provide the Corresponding Source. This alternative is allowed only occasionally and
noncommercially, and only if you received the object code with such an offer, in
accord with subsection 6b.
* **d)** Convey the object code by offering access from a designated place (gratis or for
a charge), and offer equivalent access to the Corresponding Source in the same way
through the same place at no further charge. You need not require recipients to copy
the Corresponding Source along with the object code. If the place to copy the object
code is a network server, the Corresponding Source may be on a different server
(operated by you or a third party) that supports equivalent copying facilities,
provided you maintain clear directions next to the object code saying where to find
the Corresponding Source. Regardless of what server hosts the Corresponding Source,
you remain obligated to ensure that it is available for as long as needed to satisfy
these requirements.
* **e)** Convey the object code using peer-to-peer transmission, provided you inform
other peers where the object code and Corresponding Source of the work are being
offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the
Corresponding Source as a System Library, need not be included in conveying the
object code work.
A “User Product” is either (1) a “consumer product”, which
means any tangible personal property which is normally used for personal, family, or
household purposes, or (2) anything designed or sold for incorporation into a
dwelling. In determining whether a product is a consumer product, doubtful cases
shall be resolved in favor of coverage. For a particular product received by a
particular user, “normally used” refers to a typical or common use of
that class of product, regardless of the status of the particular user or of the way
in which the particular user actually uses, or expects or is expected to use, the
product. A product is a consumer product regardless of whether the product has
substantial commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
“Installation Information” for a User Product means any methods,
procedures, authorization keys, or other information required to install and execute
modified versions of a covered work in that User Product from a modified version of
its Corresponding Source. The information must suffice to ensure that the continued
functioning of the modified object code is in no case prevented or interfered with
solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for
use in, a User Product, and the conveying occurs as part of a transaction in which
the right of possession and use of the User Product is transferred to the recipient
in perpetuity or for a fixed term (regardless of how the transaction is
characterized), the Corresponding Source conveyed under this section must be
accompanied by the Installation Information. But this requirement does not apply if
neither you nor any third party retains the ability to install modified object code
on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to
continue to provide support service, warranty, or updates for a work that has been
modified or installed by the recipient, or for the User Product in which it has been
modified or installed. Access to a network may be denied when the modification itself
materially and adversely affects the operation of the network or violates the rules
and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with
this section must be in a format that is publicly documented (and with an
implementation available to the public in source code form), and must require no
special password or key for unpacking, reading or copying.
### 7. Additional Terms.
“Additional permissions” are terms that supplement the terms of this
License by making exceptions from one or more of its conditions. Additional
permissions that are applicable to the entire Program shall be treated as though they
were included in this License, to the extent that they are valid under applicable
law. If additional permissions apply only to part of the Program, that part may be
used separately under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any
additional permissions from that copy, or from any part of it. (Additional
permissions may be written to require their own removal in certain cases when you
modify the work.) You may place additional permissions on material, added by you to a
covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a
covered work, you may (if authorized by the copyright holders of that material)
supplement the terms of this License with terms:
* **a)** Disclaiming warranty or limiting liability differently from the terms of
sections 15 and 16 of this License; or
* **b)** Requiring preservation of specified reasonable legal notices or author
attributions in that material or in the Appropriate Legal Notices displayed by works
containing it; or
* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that
modified versions of such material be marked in reasonable ways as different from the
original version; or
* **d)** Limiting the use for publicity purposes of names of licensors or authors of the
material; or
* **e)** Declining to grant rights under trademark law for use of some trade names,
trademarks, or service marks; or
* **f)** Requiring indemnification of licensors and authors of that material by anyone
who conveys the material (or modified versions of it) with contractual assumptions of
liability to the recipient, for any liability that these contractual assumptions
directly impose on those licensors and authors.
All other non-permissive additional terms are considered “further
restrictions” within the meaning of section 10. If the Program as you received
it, or any part of it, contains a notice stating that it is governed by this License
along with a term that is a further restriction, you may remove that term. If a
license document contains a further restriction but permits relicensing or conveying
under this License, you may add to a covered work material governed by the terms of
that license document, provided that the further restriction does not survive such
relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in
the relevant source files, a statement of the additional terms that apply to those
files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a
separately written license, or stated as exceptions; the above requirements apply
either way.
### 8. Termination.
You may not propagate or modify a covered work except as expressly provided under
this License. Any attempt otherwise to propagate or modify it is void, and will
automatically terminate your rights under this License (including any patent licenses
granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a
particular copyright holder is reinstated (a) provisionally, unless and until the
copyright holder explicitly and finally terminates your license, and (b) permanently,
if the copyright holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently
if the copyright holder notifies you of the violation by some reasonable means, this
is the first time you have received notice of violation of this License (for any
work) from that copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of
parties who have received copies or rights from you under this License. If your
rights have been terminated and not permanently reinstated, you do not qualify to
receive new licenses for the same material under section 10.
### 9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the
Program. Ancillary propagation of a covered work occurring solely as a consequence of
using peer-to-peer transmission to receive a copy likewise does not require
acceptance. However, nothing other than this License grants you permission to
propagate or modify any covered work. These actions infringe copyright if you do not
accept this License. Therefore, by modifying or propagating a covered work, you
indicate your acceptance of this License to do so.
### 10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license
from the original licensors, to run, modify and propagate that work, subject to this
License. You are not responsible for enforcing compliance by third parties with this
License.
An “entity transaction” is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an organization, or
merging organizations. If propagation of a covered work results from an entity
transaction, each party to that transaction who receives a copy of the work also
receives whatever licenses to the work the party's predecessor in interest had or
could give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if the predecessor
has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or
affirmed under this License. For example, you may not impose a license fee, royalty,
or other charge for exercise of rights granted under this License, and you may not
initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging
that any patent claim is infringed by making, using, selling, offering for sale, or
importing the Program or any portion of it.
### 11. Patents.
A “contributor” is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The work thus
licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims owned or
controlled by the contributor, whether already acquired or hereafter acquired, that
would be infringed by some manner, permitted by this License, of making, using, or
selling its contributor version, but do not include claims that would be infringed
only as a consequence of further modification of the contributor version. For
purposes of this definition, “control” includes the right to grant patent
sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license
under the contributor's essential patent claims, to make, use, sell, offer for sale,
import and otherwise run, modify and propagate the contents of its contributor
version.
In the following three paragraphs, a “patent license” is any express
agreement or commitment, however denominated, not to enforce a patent (such as an
express permission to practice a patent or covenant not to sue for patent
infringement). To “grant” such a patent license to a party means to make
such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the
Corresponding Source of the work is not available for anyone to copy, free of charge
and under the terms of this License, through a publicly available network server or
other readily accessible means, then you must either (1) cause the Corresponding
Source to be so available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner consistent with
the requirements of this License, to extend the patent license to downstream
recipients. “Knowingly relying” means you have actual knowledge that, but
for the patent license, your conveying the covered work in a country, or your
recipient's use of the covered work in a country, would infringe one or more
identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you
convey, or propagate by procuring conveyance of, a covered work, and grant a patent
license to some of the parties receiving the covered work authorizing them to use,
propagate, modify or convey a specific copy of the covered work, then the patent
license you grant is automatically extended to all recipients of the covered work and
works based on it.
A patent license is “discriminatory” if it does not include within the
scope of its coverage, prohibits the exercise of, or is conditioned on the
non-exercise of one or more of the rights that are specifically granted under this
License. You may not convey a covered work if you are a party to an arrangement with
a third party that is in the business of distributing software, under which you make
payment to the third party based on the extent of your activity of conveying the
work, and under which the third party grants, to any of the parties who would receive
the covered work from you, a discriminatory patent license (a) in connection with
copies of the covered work conveyed by you (or copies made from those copies), or (b)
primarily for and in connection with specific products or compilations that contain
the covered work, unless you entered into that arrangement, or that patent license
was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied
license or other defenses to infringement that may otherwise be available to you
under applicable patent law.
### 12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise)
that contradict the conditions of this License, they do not excuse you from the
conditions of this License. If you cannot convey a covered work so as to satisfy
simultaneously your obligations under this License and any other pertinent
obligations, then as a consequence you may not convey it at all. For example, if you
agree to terms that obligate you to collect a royalty for further conveying from
those to whom you convey the Program, the only way you could satisfy both those terms
and this License would be to refrain entirely from conveying the Program.
### 13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or
combine any covered work with a work licensed under version 3 of the GNU Affero
General Public License into a single combined work, and to convey the resulting work.
The terms of this License will continue to apply to the part which is the covered
work, but the special requirements of the GNU Affero General Public License, section
13, concerning interaction through a network will apply to the combination as such.
### 14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU
General Public License from time to time. Such new versions will be similar in spirit
to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that
a certain numbered version of the GNU General Public License “or any later
version” applies to it, you have the option of following the terms and
conditions either of that numbered version or of any later version published by the
Free Software Foundation. If the Program does not specify a version number of the GNU
General Public License, you may choose any version ever published by the Free
Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU
General Public License can be used, that proxy's public statement of acceptance of a
version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no
additional obligations are imposed on any author or copyright holder as a result of
your choosing to follow a later version.
### 15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
### 16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE
OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
### 17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be
given local legal effect according to their terms, reviewing courts shall apply local
law that most closely approximates an absolute waiver of all civil liability in
connection with the Program, unless a warranty or assumption of liability accompanies
a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
## How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to
the public, the best way to achieve this is to make it free software which everyone
can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them
to the start of each source file to most effectively state the exclusion of warranty;
and each file should have at least the “copyright” line and a pointer to
where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this
when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'show c' for details.
The hypothetical commands 'show w' and 'show c' should show the appropriate parts of
the General Public License. Of course, your program's commands might be different;
for a GUI interface, you would use an “about box”.
You should also get your employer (if you work as a programmer) or school, if any, to
sign a “copyright disclaimer” for the program, if necessary. For more
information on this, and how to apply and follow the GNU GPL, see
<<https://www.gnu.org/licenses/>>.
The GNU General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may consider it
more useful to permit linking proprietary applications with the library. If this is
what you want to do, use the GNU Lesser General Public License instead of this
License. But first, please read
<<https://www.gnu.org/philosophy/why-not-lgpl.html>>.
================================================
FILE: Makefile
================================================
TARGET ?= bettercap
PACKAGES ?= core firewall log modules network packets session tls
PREFIX ?= /usr/local
GO ?= go
GOFMT ?= gofmt
all: build
build: resources
$(GO) build $(GOFLAGS) -o $(TARGET) .
build_with_race_detector: resources
$(GO) build $(GOFLAGS) -race -o $(TARGET) .
resources: network/manuf.go
network/manuf.go:
@python3 ./network/make_manuf.py
install:
@mkdir -p $(DESTDIR)$(PREFIX)/share/bettercap/caplets
@cp bettercap $(DESTDIR)$(PREFIX)/bin/
docker:
@docker build -t bettercap:latest .
test:
$(GO) test -covermode=atomic -coverprofile=cover.out ./...
html_coverage: test
$(GO) tool cover -html=cover.out -o cover.out.html
benchmark: server_deps
$(GO) test -v -run=doNotRunTests -bench=. -benchmem ./...
fmt:
$(GOFMT) -s -w $(PACKAGES)
clean:
$(RM) $(TARGET)
$(RM) -r build
build-arm64: clean
docker build -f Dockerfile.arm64 \
--target=output \
--output type=local,dest=. \
.
sync-arm64:
rsync -rvzc ./bettercap pi@10.0.0.2:/home/pi/
.PHONY: all build build_with_race_detector resources install docker test html_coverage benchmark fmt clean
================================================
FILE: README.md
================================================
<p align="center">
<small>Join the project community on our server!</small>
<br/><br/>
<a href="https://discord.gg/https://discord.gg/btZpkp45gQ" target="_blank" title="Join our community!">
<img src="https://dcbadge.limes.pink/api/server/https://discord.gg/btZpkp45gQ"/>
</a>
</p>
<hr/>
<p align="center">
<img alt="BetterCap" src="https://raw.githubusercontent.com/bettercap/media/master/logo.png" height="140" />
<p align="center">
<a href="https://github.com/bettercap/bettercap/releases/latest"><img alt="Release" src="https://img.shields.io/github/release/bettercap/bettercap.svg?style=flat-square"></a>
<a href="https://github.com/bettercap/bettercap/blob/master/LICENSE.md"><img alt="Software License" src="https://img.shields.io/badge/license-GPL3-brightgreen.svg?style=flat-square"></a>
<a href="https://github.com/bettercap/bettercap/actions/workflows/test-on-linux.yml"><img alt="Tests on Linux" src="https://github.com/bettercap/bettercap/actions/workflows/test-on-linux.yml/badge.svg"></a>
<a href="https://github.com/bettercap/bettercap/actions/workflows/test-on-macos.yml"><img alt="Tests on macOS" src="https://github.com/bettercap/bettercap/actions/workflows/test-on-macos.yml/badge.svg"></a>
<a href="https://github.com/bettercap/bettercap/actions/workflows/test-on-windows.yml"><img alt="Tests on Windows" src="https://github.com/bettercap/bettercap/actions/workflows/test-on-windows.yml/badge.svg"></a>
<a href="https://hub.docker.com/r/bettercap/bettercap"><img alt="Docker Hub" src="https://img.shields.io/docker/v/bettercap/bettercap?logo=docker"></a>
<img src="https://img.shields.io/badge/human-coded-brightgreen?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1wZXJzb24tc3RhbmRpbmctaWNvbiBsdWNpZGUtcGVyc29uLXN0YW5kaW5nIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjUiIHI9IjEiLz48cGF0aCBkPSJtOSAyMCAzLTYgMyA2Ii8+PHBhdGggZD0ibTYgOCA2IDIgNi0yIi8+PHBhdGggZD0iTTEyIDEwdjQiLz48L3N2Zz4=" alt="This project is 100% made by humans."/>
</p>
</p>
bettercap is a powerful, easily extensible and portable framework written in Go which aims to offer to security researchers, red teamers and reverse engineers an **easy to use**, **all-in-one solution** with all the features they might possibly need for performing reconnaissance and attacking [WiFi](https://www.bettercap.org/modules/wifi/) networks, [Bluetooth Low Energy](https://www.bettercap.org/modules/ble/) devices, [CAN-bus](https://www.bettercap.org/modules/canbus/), wireless [HID](https://www.bettercap.org/modules/hid/) devices and [Ethernet](https://www.bettercap.org/modules/ethernet) networks.

## Main Features
* **WiFi** networks scanning, [deauthentication attack](https://www.evilsocket.net/2018/07/28/Project-PITA-Writeup-build-a-mini-mass-deauther-using-bettercap-and-a-Raspberry-Pi-Zero-W/), [clientless PMKID association attack](https://www.evilsocket.net/2019/02/13/Pwning-WiFi-networks-with-bettercap-and-the-PMKID-client-less-attack/) and automatic WPA/WPA2/WPA3 client handshakes capture.
* **Bluetooth Low Energy** devices scanning, characteristics enumeration, reading and writing.
* 2.4Ghz wireless devices scanning and **MouseJacking** attacks with over-the-air HID frames injection (with DuckyScript support).
* **CAN-bus** and **DBC** support for decoding, injecting and fuzzing frames.
* Passive and active IP network hosts probing and recon.
* **ARP, DNS, NDP and DHCPv6 spoofers** for MITM attacks on IPv4 and IPv6 based networks.
* **Proxies at packet level, TCP level and HTTP/HTTPS** application level fully scriptable with easy to implement **javascript plugins**.
* A powerful **network sniffer** for **credentials harvesting** which can also be used as a **network protocol fuzzer**.
* A very fast port scanner.
* A powerful [REST API](https://www.bettercap.org/modules/core/api.rest/) with support for asynchronous events notification on websocket to orchestrate your attacks easily.
* **A very convenient [web UI](https://www.bettercap.org/usage/web_ui/).**
* [More!](https://www.bettercap.org/modules/)
## Contributors
<a href="https://github.com/bettercap/bettercap/graphs/contributors">
<img src="https://contrib.rocks/image?repo=bettercap/bettercap" alt="bettercap project contributors" />
</a>
## License
`bettercap` is made with ♥ and released under the GPL 3 license.
## Stargazers over time
[](https://starchart.cc/bettercap/bettercap)
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Feature updates and security fixes are streamlined only to the latest version, make sure to check [the release page](https://github.com/bettercap/bettercap/releases) periodically.
## Reporting a Vulnerability
For non critical bugs and vulnerabilities feel free to open an issue and tag `@evilsocket`, for more severe reports send an email to `evilsocket AT gmail DOT com`.
================================================
FILE: bettercap.service
================================================
[Unit]
Description=bettercap api.rest service.
Documentation=https://bettercap.org
Wants=network.target
After=network.target
[Service]
Type=simple
PermissionsStartOnly=true
ExecStart=/usr/local/bin/bettercap -no-colors -eval "set events.stream.output /var/log/bettercap.log; api.rest on"
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
================================================
FILE: caplets/caplet.go
================================================
package caplets
import (
"fmt"
"path/filepath"
"strings"
"github.com/evilsocket/islazy/fs"
)
type Script struct {
Path string `json:"path"`
Size int64 `json:"size"`
Code []string `json:"code"`
}
func newScript(path string, size int64) Script {
return Script{
Path: path,
Size: size,
Code: make([]string, 0),
}
}
type Caplet struct {
Script
Name string `json:"name"`
Scripts []Script `json:"scripts"`
}
func NewCaplet(name string, path string, size int64) Caplet {
return Caplet{
Script: newScript(path, size),
Name: name,
Scripts: make([]Script, 0),
}
}
func (cap *Caplet) Eval(argv []string, lineCb func(line string) error) error {
if argv == nil {
argv = []string{}
}
// the caplet might include other files (include directive, proxy modules, etc),
// temporarily change the working directory
return fs.Chdir(filepath.Dir(cap.Path), func() error {
for _, line := range cap.Code {
// skip empty lines and comments
if line == "" || line[0] == '#' {
continue
}
// replace $0 with argv[0], $1 with argv[1] and so on
for i, arg := range argv {
what := fmt.Sprintf("$%d", i)
line = strings.Replace(line, what, arg, -1)
}
if err := lineCb(line); err != nil {
return err
}
}
return nil
})
}
================================================
FILE: caplets/caplet_test.go
================================================
package caplets
import (
"errors"
"io/ioutil"
"os"
"strings"
"testing"
)
func TestNewCaplet(t *testing.T) {
name := "test-caplet"
path := "/path/to/caplet.cap"
size := int64(1024)
cap := NewCaplet(name, path, size)
if cap.Name != name {
t.Errorf("expected name %s, got %s", name, cap.Name)
}
if cap.Path != path {
t.Errorf("expected path %s, got %s", path, cap.Path)
}
if cap.Size != size {
t.Errorf("expected size %d, got %d", size, cap.Size)
}
if cap.Code == nil {
t.Error("Code should not be nil")
}
if cap.Scripts == nil {
t.Error("Scripts should not be nil")
}
}
func TestCapletEval(t *testing.T) {
tests := []struct {
name string
code []string
argv []string
wantLines []string
wantErr bool
}{
{
name: "empty code",
code: []string{},
argv: nil,
wantLines: []string{},
wantErr: false,
},
{
name: "skip comments and empty lines",
code: []string{
"# this is a comment",
"",
"set test value",
"# another comment",
"set another value",
},
argv: nil,
wantLines: []string{
"set test value",
"set another value",
},
wantErr: false,
},
{
name: "variable substitution",
code: []string{
"set param $0",
"set value $1",
"run $0 $1 $2",
},
argv: []string{"arg0", "arg1", "arg2"},
wantLines: []string{
"set param arg0",
"set value arg1",
"run arg0 arg1 arg2",
},
wantErr: false,
},
{
name: "multiple occurrences of same variable",
code: []string{
"$0 $0 $1 $0",
},
argv: []string{"foo", "bar"},
wantLines: []string{
"foo foo bar foo",
},
wantErr: false,
},
{
name: "missing argv values",
code: []string{
"set $0 $1 $2",
},
argv: []string{"only_one"},
wantLines: []string{
"set only_one $1 $2",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tempFile, err := ioutil.TempFile("", "test-*.cap")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFile.Name())
tempFile.Close()
cap := NewCaplet("test", tempFile.Name(), 100)
cap.Code = tt.code
var gotLines []string
err = cap.Eval(tt.argv, func(line string) error {
gotLines = append(gotLines, line)
return nil
})
if (err != nil) != tt.wantErr {
t.Errorf("Eval() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(gotLines) != len(tt.wantLines) {
t.Errorf("got %d lines, want %d", len(gotLines), len(tt.wantLines))
return
}
for i, line := range gotLines {
if line != tt.wantLines[i] {
t.Errorf("line %d: got %q, want %q", i, line, tt.wantLines[i])
}
}
})
}
}
func TestCapletEvalError(t *testing.T) {
tempFile, err := ioutil.TempFile("", "test-*.cap")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFile.Name())
tempFile.Close()
cap := NewCaplet("test", tempFile.Name(), 100)
cap.Code = []string{
"first line",
"error line",
"third line",
}
expectedErr := errors.New("test error")
var executedLines []string
err = cap.Eval(nil, func(line string) error {
executedLines = append(executedLines, line)
if line == "error line" {
return expectedErr
}
return nil
})
if err != expectedErr {
t.Errorf("expected error %v, got %v", expectedErr, err)
}
// Should have executed first two lines before error
if len(executedLines) != 2 {
t.Errorf("expected 2 executed lines, got %d", len(executedLines))
}
}
func TestCapletEvalWithChdirPath(t *testing.T) {
// Create a temporary caplet file to test with
tempFile, err := ioutil.TempFile("", "test-*.cap")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFile.Name())
tempFile.Close()
cap := NewCaplet("test", tempFile.Name(), 100)
cap.Code = []string{"test command"}
executed := false
err = cap.Eval(nil, func(line string) error {
executed = true
return nil
})
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !executed {
t.Error("callback was not executed")
}
}
func TestNewScript(t *testing.T) {
path := "/path/to/script.js"
size := int64(2048)
script := newScript(path, size)
if script.Path != path {
t.Errorf("expected path %s, got %s", path, script.Path)
}
if script.Size != size {
t.Errorf("expected size %d, got %d", size, script.Size)
}
if script.Code == nil {
t.Error("Code should not be nil")
}
if len(script.Code) != 0 {
t.Errorf("expected empty Code slice, got %d elements", len(script.Code))
}
}
func TestCapletEvalCommentAtStartOfLine(t *testing.T) {
tempFile, err := ioutil.TempFile("", "test-*.cap")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFile.Name())
tempFile.Close()
cap := NewCaplet("test", tempFile.Name(), 100)
cap.Code = []string{
"# comment",
" # not a comment (has space before #)",
" # not a comment (has tab before #)",
"command # inline comment",
}
var gotLines []string
err = cap.Eval(nil, func(line string) error {
gotLines = append(gotLines, line)
return nil
})
if err != nil {
t.Errorf("unexpected error: %v", err)
}
expectedLines := []string{
" # not a comment (has space before #)",
" # not a comment (has tab before #)",
"command # inline comment",
}
if len(gotLines) != len(expectedLines) {
t.Errorf("got %d lines, want %d", len(gotLines), len(expectedLines))
return
}
for i, line := range gotLines {
if line != expectedLines[i] {
t.Errorf("line %d: got %q, want %q", i, line, expectedLines[i])
}
}
}
func TestCapletEvalArgvSubstitutionEdgeCases(t *testing.T) {
tests := []struct {
name string
code string
argv []string
wantLine string
}{
{
name: "double digit substitution $10",
code: "$1$0",
argv: []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"},
wantLine: "10",
},
{
name: "no space between variables",
code: "$0$1$2",
argv: []string{"a", "b", "c"},
wantLine: "abc",
},
{
name: "variables in quotes",
code: `"$0" '$1'`,
argv: []string{"foo", "bar"},
wantLine: `"foo" 'bar'`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tempFile, err := ioutil.TempFile("", "test-*.cap")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFile.Name())
tempFile.Close()
cap := NewCaplet("test", tempFile.Name(), 100)
cap.Code = []string{tt.code}
var gotLine string
err = cap.Eval(tt.argv, func(line string) error {
gotLine = line
return nil
})
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if gotLine != tt.wantLine {
t.Errorf("got line %q, want %q", gotLine, tt.wantLine)
}
})
}
}
func TestCapletStructFields(t *testing.T) {
// Test that Caplet properly embeds Script
tempFile, err := ioutil.TempFile("", "test-*.cap")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFile.Name())
tempFile.Close()
cap := NewCaplet("test", tempFile.Name(), 100)
// These fields should be accessible due to embedding
_ = cap.Path
_ = cap.Size
_ = cap.Code
// And these are Caplet's own fields
_ = cap.Name
_ = cap.Scripts
}
func BenchmarkCapletEval(b *testing.B) {
cap := NewCaplet("bench", "/tmp/bench.cap", 100)
cap.Code = []string{
"set param1 $0",
"set param2 $1",
"# comment line",
"",
"run command $0 $1 $2",
"another command",
}
argv := []string{"arg0", "arg1", "arg2"}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = cap.Eval(argv, func(line string) error {
// Do nothing, just measure evaluation overhead
return nil
})
}
}
func BenchmarkVariableSubstitution(b *testing.B) {
line := "command $0 $1 $2 $3 $4 $5 $6 $7 $8 $9"
argv := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := line
for j, arg := range argv {
what := "$" + string(rune('0'+j))
result = strings.Replace(result, what, arg, -1)
}
}
}
================================================
FILE: caplets/doc.go
================================================
// Package caplets contains functions to enumerate, load and execute caplets.
package caplets
================================================
FILE: caplets/env.go
================================================
package caplets
import (
"os"
"path/filepath"
"runtime"
"github.com/evilsocket/islazy/str"
"github.com/mitchellh/go-homedir"
)
const (
EnvVarName = "CAPSPATH"
Suffix = ".cap"
InstallArchive = "https://github.com/bettercap/caplets/archive/master.zip"
)
func getDefaultInstallBase() string {
if runtime.GOOS == "windows" {
return filepath.Join(os.Getenv("ALLUSERSPROFILE"), "bettercap")
}
return "/usr/local/share/bettercap/"
}
func getUserHomeDir() string {
usr, _ := homedir.Dir()
return usr
}
var (
InstallBase = ""
InstallPathArchive = ""
InstallPath = ""
ArchivePath = ""
LoadPaths = []string(nil)
)
func Setup(base string) error {
InstallBase = base
InstallPathArchive = filepath.Join(InstallBase, "caplets-master")
InstallPath = filepath.Join(InstallBase, "caplets")
ArchivePath = filepath.Join(os.TempDir(), "caplets.zip")
LoadPaths = []string{
"./",
"./caplets/",
InstallPath,
filepath.Join(getUserHomeDir(), "caplets"),
}
for _, path := range str.SplitBy(str.Trim(os.Getenv(EnvVarName)), string(os.PathListSeparator)) {
if path = str.Trim(path); len(path) > 0 {
LoadPaths = append(LoadPaths, path)
}
}
for i, path := range LoadPaths {
LoadPaths[i], _ = filepath.Abs(path)
}
return nil
}
func init() {
// init with defaults
Setup(getDefaultInstallBase())
}
================================================
FILE: caplets/env_test.go
================================================
package caplets
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
func TestGetDefaultInstallBase(t *testing.T) {
base := getDefaultInstallBase()
if runtime.GOOS == "windows" {
expected := filepath.Join(os.Getenv("ALLUSERSPROFILE"), "bettercap")
if base != expected {
t.Errorf("on windows, expected %s, got %s", expected, base)
}
} else {
expected := "/usr/local/share/bettercap/"
if base != expected {
t.Errorf("on non-windows, expected %s, got %s", expected, base)
}
}
}
func TestGetUserHomeDir(t *testing.T) {
home := getUserHomeDir()
// Should return a non-empty string
if home == "" {
t.Error("getUserHomeDir returned empty string")
}
// Should be an absolute path
if !filepath.IsAbs(home) {
t.Errorf("expected absolute path, got %s", home)
}
}
func TestSetup(t *testing.T) {
// Save original values
origInstallBase := InstallBase
origInstallPathArchive := InstallPathArchive
origInstallPath := InstallPath
origArchivePath := ArchivePath
origLoadPaths := LoadPaths
// Test with custom base
testBase := "/custom/base"
err := Setup(testBase)
if err != nil {
t.Errorf("Setup returned error: %v", err)
}
// Check that paths are set correctly
if InstallBase != testBase {
t.Errorf("expected InstallBase %s, got %s", testBase, InstallBase)
}
expectedArchivePath := filepath.Join(testBase, "caplets-master")
if InstallPathArchive != expectedArchivePath {
t.Errorf("expected InstallPathArchive %s, got %s", expectedArchivePath, InstallPathArchive)
}
expectedInstallPath := filepath.Join(testBase, "caplets")
if InstallPath != expectedInstallPath {
t.Errorf("expected InstallPath %s, got %s", expectedInstallPath, InstallPath)
}
expectedTempPath := filepath.Join(os.TempDir(), "caplets.zip")
if ArchivePath != expectedTempPath {
t.Errorf("expected ArchivePath %s, got %s", expectedTempPath, ArchivePath)
}
// Check LoadPaths contains expected paths
expectedInLoadPaths := []string{
"./",
"./caplets/",
InstallPath,
filepath.Join(getUserHomeDir(), "caplets"),
}
for _, expected := range expectedInLoadPaths {
absExpected, _ := filepath.Abs(expected)
found := false
for _, path := range LoadPaths {
if path == absExpected {
found = true
break
}
}
if !found {
t.Errorf("expected path %s not found in LoadPaths", absExpected)
}
}
// All paths should be absolute
for _, path := range LoadPaths {
if !filepath.IsAbs(path) {
t.Errorf("LoadPath %s is not absolute", path)
}
}
// Restore original values
InstallBase = origInstallBase
InstallPathArchive = origInstallPathArchive
InstallPath = origInstallPath
ArchivePath = origArchivePath
LoadPaths = origLoadPaths
}
func TestSetupWithEnvironmentVariable(t *testing.T) {
// Save original values
origEnv := os.Getenv(EnvVarName)
origLoadPaths := LoadPaths
// Set environment variable with multiple paths
testPaths := []string{"/path1", "/path2", "/path3"}
os.Setenv(EnvVarName, strings.Join(testPaths, string(os.PathListSeparator)))
// Run setup
err := Setup("/test/base")
if err != nil {
t.Errorf("Setup returned error: %v", err)
}
// Check that custom paths from env var are in LoadPaths
for _, testPath := range testPaths {
absTestPath, _ := filepath.Abs(testPath)
found := false
for _, path := range LoadPaths {
if path == absTestPath {
found = true
break
}
}
if !found {
t.Errorf("expected env path %s not found in LoadPaths", absTestPath)
}
}
// Restore original values
if origEnv == "" {
os.Unsetenv(EnvVarName)
} else {
os.Setenv(EnvVarName, origEnv)
}
LoadPaths = origLoadPaths
}
func TestSetupWithEmptyEnvironmentVariable(t *testing.T) {
// Save original values
origEnv := os.Getenv(EnvVarName)
origLoadPaths := LoadPaths
// Set empty environment variable
os.Setenv(EnvVarName, "")
// Count LoadPaths before setup
err := Setup("/test/base")
if err != nil {
t.Errorf("Setup returned error: %v", err)
}
// Should have only the default paths (4)
if len(LoadPaths) != 4 {
t.Errorf("expected 4 default LoadPaths, got %d", len(LoadPaths))
}
// Restore original values
if origEnv == "" {
os.Unsetenv(EnvVarName)
} else {
os.Setenv(EnvVarName, origEnv)
}
LoadPaths = origLoadPaths
}
func TestSetupWithWhitespaceInEnvironmentVariable(t *testing.T) {
// Save original values
origEnv := os.Getenv(EnvVarName)
origLoadPaths := LoadPaths
// Set environment variable with whitespace
testPaths := []string{" /path1 ", " ", "/path2 "}
os.Setenv(EnvVarName, strings.Join(testPaths, string(os.PathListSeparator)))
// Run setup
err := Setup("/test/base")
if err != nil {
t.Errorf("Setup returned error: %v", err)
}
// Should have added only non-empty paths after trimming
expectedPaths := []string{"/path1", "/path2"}
foundCount := 0
for _, expectedPath := range expectedPaths {
absExpected, _ := filepath.Abs(expectedPath)
for _, path := range LoadPaths {
if path == absExpected {
foundCount++
break
}
}
}
if foundCount != len(expectedPaths) {
t.Errorf("expected to find %d paths from env, found %d", len(expectedPaths), foundCount)
}
// Restore original values
if origEnv == "" {
os.Unsetenv(EnvVarName)
} else {
os.Setenv(EnvVarName, origEnv)
}
LoadPaths = origLoadPaths
}
func TestConstants(t *testing.T) {
// Test that constants have expected values
if EnvVarName != "CAPSPATH" {
t.Errorf("expected EnvVarName to be 'CAPSPATH', got %s", EnvVarName)
}
if Suffix != ".cap" {
t.Errorf("expected Suffix to be '.cap', got %s", Suffix)
}
if InstallArchive != "https://github.com/bettercap/caplets/archive/master.zip" {
t.Errorf("unexpected InstallArchive value: %s", InstallArchive)
}
}
func TestInit(t *testing.T) {
// The init function should have been called already
// Check that paths are initialized
if InstallBase == "" {
t.Error("InstallBase not initialized")
}
if InstallPath == "" {
t.Error("InstallPath not initialized")
}
if InstallPathArchive == "" {
t.Error("InstallPathArchive not initialized")
}
if ArchivePath == "" {
t.Error("ArchivePath not initialized")
}
if LoadPaths == nil || len(LoadPaths) == 0 {
t.Error("LoadPaths not initialized")
}
}
func TestSetupMultipleTimes(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
// Setup multiple times with different bases
bases := []string{"/base1", "/base2", "/base3"}
for _, base := range bases {
err := Setup(base)
if err != nil {
t.Errorf("Setup(%s) returned error: %v", base, err)
}
// Check that InstallBase is updated
if InstallBase != base {
t.Errorf("expected InstallBase %s, got %s", base, InstallBase)
}
// LoadPaths should be recreated each time
if len(LoadPaths) < 4 {
t.Errorf("LoadPaths should have at least 4 entries, got %d", len(LoadPaths))
}
}
// Restore original values
LoadPaths = origLoadPaths
}
func BenchmarkSetup(b *testing.B) {
// Save original values
origEnv := os.Getenv(EnvVarName)
// Set a complex environment
paths := []string{"/p1", "/p2", "/p3", "/p4", "/p5"}
os.Setenv(EnvVarName, strings.Join(paths, string(os.PathListSeparator)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
Setup("/benchmark/base")
}
// Restore
if origEnv == "" {
os.Unsetenv(EnvVarName)
} else {
os.Setenv(EnvVarName, origEnv)
}
}
================================================
FILE: caplets/manager.go
================================================
package caplets
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"github.com/evilsocket/islazy/fs"
)
var (
cache = make(map[string]*Caplet)
cacheLock = sync.Mutex{}
)
func List() []*Caplet {
caplets := make([]*Caplet, 0)
for _, searchPath := range LoadPaths {
files, _ := filepath.Glob(searchPath + "/*" + Suffix)
files2, _ := filepath.Glob(searchPath + "/*/*" + Suffix)
for _, fileName := range append(files, files2...) {
if _, err := os.Stat(fileName); err == nil {
base := strings.Replace(fileName, searchPath+string(os.PathSeparator), "", -1)
base = strings.Replace(base, Suffix, "", -1)
if caplet, err := Load(base); err != nil {
fmt.Fprintf(os.Stderr, "wtf: %v\n", err)
} else {
caplets = append(caplets, caplet)
}
}
}
}
sort.Slice(caplets, func(i, j int) bool {
return strings.Compare(caplets[i].Name, caplets[j].Name) == -1
})
return caplets
}
func Load(name string) (*Caplet, error) {
cacheLock.Lock()
defer cacheLock.Unlock()
if caplet, found := cache[name]; found {
return caplet, nil
}
baseName := name
names := []string{}
if !strings.HasSuffix(name, Suffix) {
name += Suffix
}
if !filepath.IsAbs(name) {
for _, path := range LoadPaths {
names = append(names, filepath.Join(path, name))
}
} else {
names = append(names, name)
}
for _, fileName := range names {
if stats, err := os.Stat(fileName); err == nil {
cap := &Caplet{
Script: newScript(fileName, stats.Size()),
Name: baseName,
Scripts: make([]Script, 0),
}
cache[name] = cap
if reader, err := fs.LineReader(fileName); err != nil {
return nil, fmt.Errorf("error reading caplet %s: %v", fileName, err)
} else {
for line := range reader {
cap.Code = append(cap.Code, line)
}
// the caplet has a dedicated folder
if strings.Contains(baseName, "/") || strings.Contains(baseName, "\\") {
dir := filepath.Dir(fileName)
// get all secondary .cap and .js files
if files, err := ioutil.ReadDir(dir); err == nil && len(files) > 0 {
for _, f := range files {
subFileName := filepath.Join(dir, f.Name())
if subFileName != fileName && (strings.HasSuffix(subFileName, ".cap") || strings.HasSuffix(subFileName, ".js")) {
if reader, err := fs.LineReader(subFileName); err == nil {
script := newScript(subFileName, f.Size())
for line := range reader {
script.Code = append(script.Code, line)
}
cap.Scripts = append(cap.Scripts, script)
}
}
}
}
}
}
return cap, nil
}
}
return nil, fmt.Errorf("caplet %s not found", name)
}
================================================
FILE: caplets/manager_test.go
================================================
package caplets
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"testing"
)
func createTestCaplet(t testing.TB, dir string, name string, content []string) string {
filename := filepath.Join(dir, name)
data := strings.Join(content, "\n")
err := ioutil.WriteFile(filename, []byte(data), 0644)
if err != nil {
t.Fatalf("failed to create test caplet: %v", err)
}
return filename
}
func TestList(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Create temp directories
tempDir, err := ioutil.TempDir("", "caplets-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
// Create subdirectories
dir1 := filepath.Join(tempDir, "dir1")
dir2 := filepath.Join(tempDir, "dir2")
subdir := filepath.Join(dir1, "subdir")
os.Mkdir(dir1, 0755)
os.Mkdir(dir2, 0755)
os.Mkdir(subdir, 0755)
// Create test caplets
createTestCaplet(t, dir1, "test1.cap", []string{"# Test caplet 1", "set test 1"})
createTestCaplet(t, dir1, "test2.cap", []string{"# Test caplet 2", "set test 2"})
createTestCaplet(t, dir2, "test3.cap", []string{"# Test caplet 3", "set test 3"})
createTestCaplet(t, subdir, "nested.cap", []string{"# Nested caplet", "set nested test"})
// Also create a non-caplet file
ioutil.WriteFile(filepath.Join(dir1, "notacaplet.txt"), []byte("not a caplet"), 0644)
// Set LoadPaths
LoadPaths = []string{dir1, dir2}
// Call List()
caplets := List()
// Check results
if len(caplets) != 4 {
t.Errorf("expected 4 caplets, got %d", len(caplets))
}
// Check names (should be sorted)
expectedNames := []string{filepath.Join("subdir", "nested"), "test1", "test2", "test3"}
sort.Strings(expectedNames)
gotNames := make([]string, len(caplets))
for i, cap := range caplets {
gotNames[i] = cap.Name
}
for i, expected := range expectedNames {
if i >= len(gotNames) || gotNames[i] != expected {
t.Errorf("expected caplet %d to be %s, got %s", i, expected, gotNames[i])
}
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func TestListEmptyDirectories(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Create temp directory
tempDir, err := ioutil.TempDir("", "caplets-empty-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
// Set LoadPaths to empty directory
LoadPaths = []string{tempDir}
// Call List()
caplets := List()
// Should return empty list
if len(caplets) != 0 {
t.Errorf("expected 0 caplets, got %d", len(caplets))
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func TestLoad(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Create temp directory
tempDir, err := ioutil.TempDir("", "caplets-load-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
// Create test caplet
capletContent := []string{
"# Test caplet",
"set param value",
"",
"# Another comment",
"run command",
}
createTestCaplet(t, tempDir, "test.cap", capletContent)
// Set LoadPaths
LoadPaths = []string{tempDir}
// Test loading without .cap extension
cap, err := Load("test")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if cap == nil {
t.Error("caplet is nil")
} else {
if cap.Name != "test" {
t.Errorf("expected name 'test', got %s", cap.Name)
}
if len(cap.Code) != len(capletContent) {
t.Errorf("expected %d lines, got %d", len(capletContent), len(cap.Code))
}
}
// Test loading from cache
// Note: The Load function caches with the suffix, so we need to use the same name with suffix
cap2, err := Load("test.cap")
if err != nil {
t.Errorf("unexpected error on cache hit: %v", err)
}
if cap2 == nil {
t.Error("caplet is nil on cache hit")
}
// Test loading with .cap extension
// Note: Load caches by the name parameter, so "test.cap" is a different cache key
cap3, err := Load("test.cap")
if err != nil {
t.Errorf("unexpected error with .cap extension: %v", err)
}
if cap3 == nil {
t.Error("caplet is nil")
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func TestLoadAbsolutePath(t *testing.T) {
// Save original values
origCache := cache
cache = make(map[string]*Caplet)
// Create temp file
tempFile, err := ioutil.TempFile("", "test-absolute-*.cap")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tempFile.Name())
// Write content
content := "# Absolute path test\nset test absolute"
tempFile.WriteString(content)
tempFile.Close()
// Load with absolute path
cap, err := Load(tempFile.Name())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if cap == nil {
t.Error("caplet is nil")
} else {
if cap.Path != tempFile.Name() {
t.Errorf("expected path %s, got %s", tempFile.Name(), cap.Path)
}
}
// Restore original values
cache = origCache
}
func TestLoadNotFound(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Set empty LoadPaths
LoadPaths = []string{}
// Try to load non-existent caplet
cap, err := Load("nonexistent")
if err == nil {
t.Error("expected error for non-existent caplet")
}
if cap != nil {
t.Error("expected nil caplet for non-existent file")
}
if !strings.Contains(err.Error(), "not found") {
t.Errorf("expected 'not found' error, got: %v", err)
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func TestLoadWithFolder(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Create temp directory structure
tempDir, err := ioutil.TempDir("", "caplets-folder-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
// Create a caplet folder
capletDir := filepath.Join(tempDir, "mycaplet")
os.Mkdir(capletDir, 0755)
// Create main caplet file
mainContent := []string{"# Main caplet", "set main test"}
createTestCaplet(t, capletDir, "mycaplet.cap", mainContent)
// Create additional files
jsContent := []string{"// JavaScript file", "console.log('test');"}
createTestCaplet(t, capletDir, "script.js", jsContent)
capContent := []string{"# Sub caplet", "set sub test"}
createTestCaplet(t, capletDir, "sub.cap", capContent)
// Create a file that should be ignored
ioutil.WriteFile(filepath.Join(capletDir, "readme.txt"), []byte("readme"), 0644)
// Set LoadPaths
LoadPaths = []string{tempDir}
// Load the caplet
cap, err := Load("mycaplet/mycaplet")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if cap == nil {
t.Fatal("caplet is nil")
}
// Check main caplet
if cap.Name != "mycaplet/mycaplet" {
t.Errorf("expected name 'mycaplet/mycaplet', got %s", cap.Name)
}
if len(cap.Code) != len(mainContent) {
t.Errorf("expected %d lines in main, got %d", len(mainContent), len(cap.Code))
}
// Check additional scripts
if len(cap.Scripts) != 2 {
t.Errorf("expected 2 additional scripts, got %d", len(cap.Scripts))
}
// Find and check the .js file
foundJS := false
foundCap := false
for _, script := range cap.Scripts {
if strings.HasSuffix(script.Path, "script.js") {
foundJS = true
if len(script.Code) != len(jsContent) {
t.Errorf("expected %d lines in JS, got %d", len(jsContent), len(script.Code))
}
}
if strings.HasSuffix(script.Path, "sub.cap") {
foundCap = true
if len(script.Code) != len(capContent) {
t.Errorf("expected %d lines in sub.cap, got %d", len(capContent), len(script.Code))
}
}
}
if !foundJS {
t.Error("script.js not found in Scripts")
}
if !foundCap {
t.Error("sub.cap not found in Scripts")
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func TestCacheConcurrency(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Create temp directory
tempDir, err := ioutil.TempDir("", "caplets-concurrent-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
// Create test caplets
for i := 0; i < 5; i++ {
name := fmt.Sprintf("test%d.cap", i)
content := []string{fmt.Sprintf("# Test %d", i)}
createTestCaplet(t, tempDir, name, content)
}
// Set LoadPaths
LoadPaths = []string{tempDir}
// Run concurrent loads
var wg sync.WaitGroup
errors := make(chan error, 50)
for i := 0; i < 10; i++ {
for j := 0; j < 5; j++ {
wg.Add(1)
go func(idx int) {
defer wg.Done()
name := fmt.Sprintf("test%d", idx)
_, err := Load(name)
if err != nil {
errors <- err
}
}(j)
}
}
wg.Wait()
close(errors)
// Check for errors
for err := range errors {
t.Errorf("concurrent load error: %v", err)
}
// Verify cache has all entries
if len(cache) != 5 {
t.Errorf("expected 5 cached entries, got %d", len(cache))
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func TestLoadPathPriority(t *testing.T) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Create temp directories
tempDir1, _ := ioutil.TempDir("", "caplets-priority1-")
tempDir2, _ := ioutil.TempDir("", "caplets-priority2-")
defer os.RemoveAll(tempDir1)
defer os.RemoveAll(tempDir2)
// Create same-named caplet in both directories
createTestCaplet(t, tempDir1, "test.cap", []string{"# From dir1"})
createTestCaplet(t, tempDir2, "test.cap", []string{"# From dir2"})
// Set LoadPaths with tempDir1 first
LoadPaths = []string{tempDir1, tempDir2}
// Load caplet
cap, err := Load("test")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
// Should load from first directory
if cap != nil && len(cap.Code) > 0 {
if cap.Code[0] != "# From dir1" {
t.Error("caplet not loaded from first directory in LoadPaths")
}
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func BenchmarkLoad(b *testing.B) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
// Create temp directory
tempDir, _ := ioutil.TempDir("", "caplets-bench-")
defer os.RemoveAll(tempDir)
// Create test caplet
content := make([]string, 100)
for i := range content {
content[i] = fmt.Sprintf("command %d", i)
}
createTestCaplet(b, tempDir, "bench.cap", content)
// Set LoadPaths
LoadPaths = []string{tempDir}
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Clear cache to measure loading time
cache = make(map[string]*Caplet)
Load("bench")
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func BenchmarkLoadFromCache(b *testing.B) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
cache = make(map[string]*Caplet)
// Create temp directory
tempDir, _ := ioutil.TempDir("", "caplets-bench-cache-")
defer os.RemoveAll(tempDir)
// Create test caplet
createTestCaplet(b, tempDir, "bench.cap", []string{"# Benchmark"})
// Set LoadPaths
LoadPaths = []string{tempDir}
// Pre-load into cache
Load("bench")
b.ResetTimer()
for i := 0; i < b.N; i++ {
Load("bench")
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
func BenchmarkList(b *testing.B) {
// Save original values
origLoadPaths := LoadPaths
origCache := cache
// Create temp directory
tempDir, _ := ioutil.TempDir("", "caplets-bench-list-")
defer os.RemoveAll(tempDir)
// Create multiple caplets
for i := 0; i < 20; i++ {
name := fmt.Sprintf("test%d.cap", i)
createTestCaplet(b, tempDir, name, []string{fmt.Sprintf("# Test %d", i)})
}
// Set LoadPaths
LoadPaths = []string{tempDir}
b.ResetTimer()
for i := 0; i < b.N; i++ {
cache = make(map[string]*Caplet)
List()
}
// Restore original values
LoadPaths = origLoadPaths
cache = origCache
}
================================================
FILE: core/banner.go
================================================
package core
const (
Name = "bettercap"
Version = "2.41.5"
Author = "Simone 'evilsocket' Margaritelli"
Website = "https://bettercap.org/"
)
================================================
FILE: core/banner_test.go
================================================
package core
import (
"regexp"
"testing"
)
func TestBannerName(t *testing.T) {
if Name != "bettercap" {
t.Fatalf("expected '%s', got '%s'", "bettercap", Name)
}
}
func TestBannerWebsite(t *testing.T) {
if Website != "https://bettercap.org/" {
t.Fatalf("expected '%s', got '%s'", "https://bettercap.org/", Website)
}
}
func TestBannerVersion(t *testing.T) {
match, err := regexp.MatchString(`\d+.\d+`, Version)
if err != nil {
t.Fatalf("unable to perform regex on Version constant")
}
if !match {
t.Fatalf("expected Version constant in format '%s', got '%s'", "X.X", Version)
}
}
func TestBannerAuthor(t *testing.T) {
if Author != "Simone 'evilsocket' Margaritelli" {
t.Fatalf("expected '%s', got '%s'", "Simone 'evilsocket' Margaritelli", Author)
}
}
================================================
FILE: core/core.go
================================================
package core
import (
"os/exec"
"sort"
"github.com/bettercap/bettercap/v2/log"
"github.com/evilsocket/islazy/str"
)
func UniqueInts(a []int, sorted bool) []int {
tmp := make(map[int]bool, len(a))
uniq := make([]int, 0, len(a))
for _, n := range a {
tmp[n] = true
}
for n := range tmp {
uniq = append(uniq, n)
}
if sorted {
sort.Ints(uniq)
}
return uniq
}
func HasBinary(executable string) bool {
if path, err := exec.LookPath(executable); err != nil || path == "" {
return false
}
return true
}
func Exec(executable string, args []string) (string, error) {
path, err := exec.LookPath(executable)
if err != nil {
log.Warning("executable %s not found in $PATH", executable)
return "", err
}
raw, err := exec.Command(path, args...).CombinedOutput()
log.Debug("exec=%s args=%v ret_err=%v ret_out=%s", path, args, err, string(raw))
if err != nil {
return str.Trim(string(raw)), err
} else {
return str.Trim(string(raw)), nil
}
}
================================================
FILE: core/core_android.go
================================================
//go:build android
// +build android
package core
func Shell(cmd string) (string, error) {
return Exec("/system/bin/sh", []string{"-c", cmd})
}
================================================
FILE: core/core_test.go
================================================
package core
import (
"os"
"testing"
"github.com/evilsocket/islazy/fs"
)
func hasInt(a []int, v int) bool {
for _, n := range a {
if n == v {
return true
}
}
return false
}
func sameInts(a []int, b []int, ordered bool) bool {
if len(a) != len(b) {
return false
}
if ordered {
for i, v := range a {
if v != b[i] {
return false
}
}
} else {
for _, v := range a {
if !hasInt(b, v) {
return false
}
}
}
return true
}
func TestCoreUniqueIntsUnsorted(t *testing.T) {
var units = []struct {
from []int
to []int
}{
{[]int{}, []int{}},
{[]int{1, 1, 1, 1, 1}, []int{1}},
{[]int{1, 2, 1, 2, 3, 4}, []int{1, 2, 3, 4}},
{[]int{4, 3, 4, 3, 2, 2}, []int{4, 3, 2}},
{[]int{8, 3, 8, 4, 6, 1}, []int{8, 3, 4, 6, 1}},
}
for _, u := range units {
got := UniqueInts(u.from, false)
if !sameInts(got, u.to, false) {
t.Fatalf("expected '%v', got '%v'", u.to, got)
}
}
}
func TestCoreUniqueIntsSorted(t *testing.T) {
var units = []struct {
from []int
to []int
}{
{[]int{}, []int{}},
{[]int{1, 1, 1, 1, 1}, []int{1}},
{[]int{1, 2, 1, 2, 3, 4}, []int{1, 2, 3, 4}},
{[]int{4, 3, 4, 3, 2, 2}, []int{2, 3, 4}},
{[]int{8, 3, 8, 4, 6, 1}, []int{1, 3, 4, 6, 8}},
}
for _, u := range units {
got := UniqueInts(u.from, true)
if !sameInts(got, u.to, true) {
t.Fatalf("expected '%v', got '%v'", u.to, got)
}
}
}
func TestCoreExists(t *testing.T) {
var units = []struct {
what string
exists bool
}{
{".", true},
{"/", true},
{"wuuut", false},
{"/wuuu.t", false},
{os.Args[0], true},
}
for _, u := range units {
got := fs.Exists(u.what)
if got != u.exists {
t.Fatalf("expected '%v', got '%v'", u.exists, got)
}
}
}
func TestHasBinary(t *testing.T) {
tests := []struct {
name string
executable string
expected bool
}{
{
name: "common shell",
executable: "sh",
expected: true,
},
{
name: "echo command",
executable: "echo",
expected: true,
},
{
name: "non-existent binary",
executable: "this-binary-definitely-does-not-exist-12345",
expected: false,
},
{
name: "empty string",
executable: "",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := HasBinary(tt.executable)
if got != tt.expected {
t.Errorf("HasBinary(%q) = %v, want %v", tt.executable, got, tt.expected)
}
})
}
}
func TestExec(t *testing.T) {
tests := []struct {
name string
executable string
args []string
wantError bool
contains string
}{
{
name: "echo with args",
executable: "echo",
args: []string{"hello", "world"},
wantError: false,
contains: "hello world",
},
{
name: "echo empty",
executable: "echo",
args: []string{},
wantError: false,
contains: "",
},
{
name: "non-existent command",
executable: "this-command-does-not-exist-12345",
args: []string{},
wantError: true,
contains: "",
},
{
name: "true command",
executable: "true",
args: []string{},
wantError: false,
contains: "",
},
{
name: "false command",
executable: "false",
args: []string{},
wantError: true,
contains: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Skip platform-specific commands if not available
if !HasBinary(tt.executable) && !tt.wantError {
t.Skipf("%s not found in PATH", tt.executable)
}
output, err := Exec(tt.executable, tt.args)
if tt.wantError {
if err == nil {
t.Errorf("Exec(%q, %v) expected error but got none", tt.executable, tt.args)
}
} else {
if err != nil {
t.Errorf("Exec(%q, %v) unexpected error: %v", tt.executable, tt.args, err)
}
if tt.contains != "" && output != tt.contains {
t.Errorf("Exec(%q, %v) = %q, want %q", tt.executable, tt.args, output, tt.contains)
}
}
})
}
}
func TestExecWithOutput(t *testing.T) {
// Test that Exec properly captures and trims output
if HasBinary("printf") {
output, err := Exec("printf", []string{" hello world \n"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if output != "hello world" {
t.Errorf("expected trimmed output 'hello world', got %q", output)
}
}
}
func BenchmarkUniqueInts(b *testing.B) {
// Create a slice with duplicates
input := make([]int, 1000)
for i := 0; i < 1000; i++ {
input[i] = i % 100 // This creates 10 duplicates of each number 0-99
}
b.Run("unsorted", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = UniqueInts(input, false)
}
})
b.Run("sorted", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = UniqueInts(input, true)
}
})
}
================================================
FILE: core/core_unix.go
================================================
//go:build !windows && !android
// +build !windows,!android
package core
func Shell(cmd string) (string, error) {
return Exec("/bin/sh", []string{"-c", cmd})
}
================================================
FILE: core/core_windows.go
================================================
package core
func Shell(cmd string) (string, error) {
return Exec("cmd.exe", []string{"/c", cmd})
}
================================================
FILE: core/doc.go
================================================
// Package core contains basic utility functions.
package core
================================================
FILE: core/options.go
================================================
package core
import (
"flag"
)
type Options struct {
InterfaceName string
Gateway string
Caplet string
AutoStart string
Debug bool
Silent bool
NoColors bool
NoHistory bool
PrintVersion bool
EnvFile string
Commands string
CpuProfile string
MemProfile string
CapletsPath string
Script string
PcapBufSize int
}
func ParseOptions() (Options, error) {
var o Options
flag.StringVar(&o.InterfaceName, "iface", "", "Network interface to bind to, if empty the default interface will be auto selected.")
flag.StringVar(&o.Gateway, "gateway-override", "", "Use the provided IP address instead of the default gateway. If not specified or invalid, the default gateway will be used.")
flag.StringVar(&o.AutoStart, "autostart", "events.stream", "Comma separated list of modules to auto start.")
flag.StringVar(&o.Caplet, "caplet", "", "Read commands from this file and execute them in the interactive session.")
flag.BoolVar(&o.Debug, "debug", false, "Print debug messages.")
flag.BoolVar(&o.PrintVersion, "version", false, "Print the version and exit.")
flag.BoolVar(&o.Silent, "silent", false, "Suppress all logs which are not errors.")
flag.BoolVar(&o.NoColors, "no-colors", false, "Disable output color effects.")
flag.BoolVar(&o.NoHistory, "no-history", false, "Disable interactive session history file.")
flag.StringVar(&o.EnvFile, "env-file", "", "Load environment variables from this file if found, set to empty to disable environment persistence.")
flag.StringVar(&o.Commands, "eval", "", "Run one or more commands separated by ; in the interactive session, used to set variables via command line.")
flag.StringVar(&o.CpuProfile, "cpu-profile", "", "Write cpu profile `file`.")
flag.StringVar(&o.MemProfile, "mem-profile", "", "Write memory profile to `file`.")
flag.StringVar(&o.CapletsPath, "caplets-path", "", "Specify an alternative base path for caplets.")
flag.StringVar(&o.Script, "script", "", "Load a session script.")
flag.IntVar(&o.PcapBufSize, "pcap-buf-size", -1, "PCAP buffer size, leave to 0 for the default value.")
flag.Parse()
return o, nil
}
================================================
FILE: firewall/doc.go
================================================
// Package firewall contains the OS specific implementation of the FirewallManager interface.
package firewall
================================================
FILE: firewall/firewall.go
================================================
package firewall
type FirewallManager interface {
IsForwardingEnabled() bool
EnableForwarding(enabled bool) error
EnableRedirection(r *Redirection, enabled bool) error
Restore()
}
================================================
FILE: firewall/firewall_darwin.go
================================================
package firewall
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
"github.com/bettercap/bettercap/v2/core"
"github.com/bettercap/bettercap/v2/network"
"github.com/evilsocket/islazy/str"
)
var (
sysCtlParser = regexp.MustCompile(`([^:]+):\s*(.+)`)
pfFilePath = fmt.Sprintf("/tmp/bcap_pf_%d.conf", os.Getpid())
)
type PfFirewall struct {
iface *network.Endpoint
filename string
forwarding bool
enabled bool
}
func Make(iface *network.Endpoint) FirewallManager {
firewall := &PfFirewall{
iface: iface,
filename: pfFilePath,
forwarding: false,
enabled: false,
}
firewall.forwarding = firewall.IsForwardingEnabled()
return firewall
}
func (f PfFirewall) sysCtlRead(param string) (string, error) {
if out, err := core.Exec("sysctl", []string{param}); err != nil {
return "", err
} else if m := sysCtlParser.FindStringSubmatch(out); len(m) == 3 && m[1] == param {
return m[2], nil
} else {
return "", fmt.Errorf("Unexpected sysctl output: %s", out)
}
}
func (f PfFirewall) sysCtlWrite(param string, value string) (string, error) {
args := []string{"-w", fmt.Sprintf("%s=%s", param, value)}
_, err := core.Exec("sysctl", args)
if err != nil {
return "", err
}
// make sure we actually wrote the value
if out, err := f.sysCtlRead(param); err != nil {
return "", err
} else if out != value {
return "", fmt.Errorf("Expected value for '%s' is %s, found %s", param, value, out)
} else {
return out, nil
}
}
func (f PfFirewall) IsForwardingEnabled() bool {
out, err := f.sysCtlRead("net.inet.ip.forwarding")
if err != nil {
log.Printf("ERROR: %s", err)
return false
}
return strings.HasSuffix(out, ": 1")
}
func (f PfFirewall) enableParam(param string, enabled bool) error {
var value string
if enabled {
value = "1"
} else {
value = "0"
}
if _, err := f.sysCtlWrite(param, value); err != nil {
return err
} else {
return nil
}
}
func (f PfFirewall) EnableForwarding(enabled bool) error {
return f.enableParam("net.inet.ip.forwarding", enabled)
}
func (f PfFirewall) generateRule(r *Redirection) string {
src_a := "any"
dst_a := "any"
if r.SrcAddress != "" {
src_a = r.SrcAddress
}
if r.DstAddress != "" {
dst_a = r.DstAddress
}
return fmt.Sprintf("rdr pass on %s proto %s from any to %s port %d -> %s port %d",
r.Interface, r.Protocol, src_a, r.SrcPort, dst_a, r.DstPort)
}
func (f *PfFirewall) enable(enabled bool) {
f.enabled = enabled
if enabled {
core.Exec("pfctl", []string{"-e"})
} else {
core.Exec("pfctl", []string{"-d"})
}
}
func (f PfFirewall) EnableRedirection(r *Redirection, enabled bool) error {
rule := f.generateRule(r)
if enabled {
fd, err := os.OpenFile(f.filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
return err
}
defer fd.Close()
if _, err = fd.WriteString(rule + "\n"); err != nil {
return err
}
// enable pf
f.enable(true)
// load the rule
if _, err := core.Exec("pfctl", []string{"-f", f.filename}); err != nil {
return err
}
} else {
fd, err := os.Open(f.filename)
if err == nil {
defer fd.Close()
lines := ""
scanner := bufio.NewScanner(fd)
for scanner.Scan() {
line := str.Trim(scanner.Text())
if line != rule {
lines += line + "\n"
}
}
if str.Trim(lines) == "" {
os.Remove(f.filename)
f.enable(false)
} else {
ioutil.WriteFile(f.filename, []byte(lines), 0600)
}
}
}
return nil
}
func (f PfFirewall) Restore() {
f.EnableForwarding(f.forwarding)
if f.enabled {
f.enable(false)
}
os.Remove(f.filename)
}
================================================
FILE: firewall/firewall_linux.go
================================================
package firewall
import (
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/bettercap/bettercap/v2/core"
"github.com/bettercap/bettercap/v2/network"
"github.com/evilsocket/islazy/fs"
"github.com/evilsocket/islazy/str"
)
type LinuxFirewall struct {
iface *network.Endpoint
forwarding bool
restore bool
redirections map[string]*Redirection
}
const (
IPV4ForwardingFile = "/proc/sys/net/ipv4/ip_forward"
IPV6ForwardingFile = "/proc/sys/net/ipv6/conf/all/forwarding"
)
func Make(iface *network.Endpoint) FirewallManager {
firewall := &LinuxFirewall{
iface: iface,
forwarding: false,
restore: false,
redirections: make(map[string]*Redirection),
}
firewall.forwarding = firewall.IsForwardingEnabled()
return firewall
}
func (f LinuxFirewall) enableFeature(filename string, enable bool) error {
var value string
if enable {
value = "1"
} else {
value = "0"
}
fd, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
return err
}
defer fd.Close()
_, err = fd.WriteString(value)
return err
}
func (f LinuxFirewall) IsForwardingEnabled() bool {
if out, err := ioutil.ReadFile(IPV4ForwardingFile); err != nil {
return false
} else {
return str.Trim(string(out)) == "1"
}
}
func (f LinuxFirewall) EnableForwarding(enabled bool) error {
if err := f.enableFeature(IPV4ForwardingFile, enabled); err != nil {
return err
}
if fs.Exists(IPV6ForwardingFile) {
return f.enableFeature(IPV6ForwardingFile, enabled)
}
f.restore = true
return nil
}
func (f *LinuxFirewall) getCommandLine(r *Redirection, enabled bool) (cmdLine []string) {
action := "-A"
destination := ""
if !enabled {
action = "-D"
}
if strings.Count(r.DstAddress, ":") < 2 {
destination = r.DstAddress
} else {
destination = fmt.Sprintf("[%s]", r.DstAddress)
}
if r.SrcAddress == "" {
cmdLine = []string{
"-t", "nat",
action, "PREROUTING",
"-i", r.Interface,
"-p", r.Protocol,
"--dport", fmt.Sprintf("%d", r.SrcPort),
"-j", "DNAT",
"--to", fmt.Sprintf("%s:%d", destination, r.DstPort),
}
} else {
cmdLine = []string{
"-t", "nat",
action, "PREROUTING",
"-i", r.Interface,
"-p", r.Protocol,
"-d", r.SrcAddress,
"--dport", fmt.Sprintf("%d", r.SrcPort),
"-j", "DNAT",
"--to", fmt.Sprintf("%s:%d", destination, r.DstPort),
}
}
return
}
func (f *LinuxFirewall) EnableRedirection(r *Redirection, enabled bool) error {
cmdLine := f.getCommandLine(r, enabled)
rkey := r.String()
_, found := f.redirections[rkey]
cmd := ""
if strings.Count(r.DstAddress, ":") < 2 {
cmd = "iptables"
} else {
cmd = "ip6tables"
}
if enabled {
if found {
return fmt.Errorf("Redirection '%s' already enabled.", rkey)
}
f.redirections[rkey] = r
// accept all
if _, err := core.Exec(cmd, []string{"-P", "FORWARD", "ACCEPT"}); err != nil {
return err
} else if _, err := core.Exec(cmd, cmdLine); err != nil {
return err
}
} else {
if !found {
return nil
}
delete(f.redirections, r.String())
if _, err := core.Exec(cmd, cmdLine); err != nil {
return err
}
}
return nil
}
func (f LinuxFirewall) Restore() {
if f.restore == false {
return
}
for _, r := range f.redirections {
if err := f.EnableRedirection(r, false); err != nil {
fmt.Printf("%s", err)
}
}
if err := f.EnableForwarding(f.forwarding); err != nil {
fmt.Printf("%s", err)
}
}
================================================
FILE: firewall/firewall_windows.go
================================================
package firewall
import (
"fmt"
"strings"
"github.com/bettercap/bettercap/v2/core"
"github.com/bettercap/bettercap/v2/network"
)
type WindowsFirewall struct {
iface *network.Endpoint
forwarding bool
redirections map[string]*Redirection
}
func Make(iface *network.Endpoint) FirewallManager {
firewall := &WindowsFirewall{
iface: iface,
forwarding: false,
redirections: make(map[string]*Redirection, 0),
}
firewall.forwarding = firewall.IsForwardingEnabled()
return firewall
}
func (f WindowsFirewall) IsForwardingEnabled() bool {
if out, err := core.Exec("netsh", []string{"interface", "ipv4", "dump"}); err != nil {
fmt.Printf("%s\n", err)
return false
} else {
return strings.Contains(out, "forwarding=enabled")
}
}
func (f WindowsFirewall) EnableForwarding(enabled bool) error {
v := "enabled"
if enabled == false {
v = "disabled"
}
if _, err := core.Exec("netsh", []string{"interface", "ipv4", "set", "interface", fmt.Sprintf("%d", f.iface.Index), fmt.Sprintf("forwarding=\"%s\"", v)}); err != nil {
return err
}
return nil
}
func (f WindowsFirewall) generateRule(r *Redirection, enabled bool) []string {
// https://stackoverflow.com/questions/24646165/netsh-port-forwarding-from-local-port-to-local-port-not-working
rule := []string{
fmt.Sprintf("listenport=%d", r.SrcPort),
}
if enabled {
rule = append(rule, fmt.Sprintf("connectport=%d", r.DstPort))
rule = append(rule, fmt.Sprintf("connectaddress=%s", r.DstAddress))
rule = append(rule, fmt.Sprintf("protocol=%s", r.Protocol))
}
return rule
}
func (f *WindowsFirewall) AllowPort(port int, address string, proto string, allow bool) error {
ruleName := fmt.Sprintf("bettercap-rule-%s-%s-%d", address, proto, port)
nameField := fmt.Sprintf(`name="%s"`, ruleName)
protoField := fmt.Sprintf("protocol=%s", proto)
// ipField := fmt.Sprintf("lolcalip=%s", address)
portField := fmt.Sprintf("localport=%d", port)
cmd := []string{}
if allow {
cmd = []string{"advfirewall", "firewall", "add", "rule", nameField, protoField, "dir=in", portField, "action=allow"}
} else {
cmd = []string{"advfirewall", "firewall", "delete", "rule", nameField, protoField, portField}
}
if _, err := core.Exec("netsh", cmd); err != nil {
return err
}
return nil
}
func (f *WindowsFirewall) EnableRedirection(r *Redirection, enabled bool) error {
if err := f.AllowPort(r.SrcPort, r.DstAddress, r.Protocol, enabled); err != nil {
return err
} else if err := f.AllowPort(r.DstPort, r.DstAddress, r.Protocol, enabled); err != nil {
return err
}
rule := f.generateRule(r, enabled)
if enabled {
rule = append([]string{"interface", "portproxy", "add", "v4tov4"}, rule...)
} else {
rule = append([]string{"interface", "portproxy", "delete", "v4tov4"}, rule...)
}
if _, err := core.Exec("netsh", rule); err != nil {
return err
}
return nil
}
func (f WindowsFirewall) Restore() {
for _, r := range f.redirections {
if err := f.EnableRedirection(r, false); err != nil {
fmt.Printf("%s", err)
}
}
if err := f.EnableForwarding(f.forwarding); err != nil {
fmt.Printf("%s", err)
}
}
================================================
FILE: firewall/redirection.go
================================================
package firewall
import "fmt"
type Redirection struct {
Interface string
Protocol string
SrcAddress string
SrcPort int
DstAddress string
DstPort int
}
func NewRedirection(iface string, proto string, port_from int, addr_to string, port_to int) *Redirection {
return &Redirection{
Interface: iface,
Protocol: proto,
SrcAddress: "",
SrcPort: port_from,
DstAddress: addr_to,
DstPort: port_to,
}
}
func (r Redirection) String() string {
return fmt.Sprintf("[%s] (%s) %s:%d -> %s:%d", r.Interface, r.Protocol, r.SrcAddress, r.SrcPort, r.DstAddress, r.DstPort)
}
================================================
FILE: firewall/redirection_test.go
================================================
package firewall
import (
"testing"
)
func TestNewRedirection(t *testing.T) {
iface := "eth0"
proto := "tcp"
portFrom := 8080
addrTo := "192.168.1.100"
portTo := 9090
r := NewRedirection(iface, proto, portFrom, addrTo, portTo)
if r == nil {
t.Fatal("NewRedirection returned nil")
}
if r.Interface != iface {
t.Errorf("expected Interface %s, got %s", iface, r.Interface)
}
if r.Protocol != proto {
t.Errorf("expected Protocol %s, got %s", proto, r.Protocol)
}
if r.SrcAddress != "" {
t.Errorf("expected empty SrcAddress, got %s", r.SrcAddress)
}
if r.SrcPort != portFrom {
t.Errorf("expected SrcPort %d, got %d", portFrom, r.SrcPort)
}
if r.DstAddress != addrTo {
t.Errorf("expected DstAddress %s, got %s", addrTo, r.DstAddress)
}
if r.DstPort != portTo {
t.Errorf("expected DstPort %d, got %d", portTo, r.DstPort)
}
}
func TestRedirectionString(t *testing.T) {
tests := []struct {
name string
r Redirection
want string
}{
{
name: "basic redirection",
r: Redirection{
Interface: "eth0",
Protocol: "tcp",
SrcAddress: "",
SrcPort: 8080,
DstAddress: "192.168.1.100",
DstPort: 9090,
},
want: "[eth0] (tcp) :8080 -> 192.168.1.100:9090",
},
{
name: "with source address",
r: Redirection{
Interface: "wlan0",
Protocol: "udp",
SrcAddress: "192.168.1.50",
SrcPort: 53,
DstAddress: "8.8.8.8",
DstPort: 53,
},
want: "[wlan0] (udp) 192.168.1.50:53 -> 8.8.8.8:53",
},
{
name: "localhost redirection",
r: Redirection{
Interface: "lo",
Protocol: "tcp",
SrcAddress: "127.0.0.1",
SrcPort: 80,
DstAddress: "127.0.0.1",
DstPort: 8080,
},
want: "[lo] (tcp) 127.0.0.1:80 -> 127.0.0.1:8080",
},
{
name: "high port numbers",
r: Redirection{
Interface: "eth1",
Protocol: "tcp",
SrcAddress: "",
SrcPort: 65535,
DstAddress: "10.0.0.1",
DstPort: 65534,
},
want: "[eth1] (tcp) :65535 -> 10.0.0.1:65534",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.r.String()
if got != tt.want {
t.Errorf("String() = %q, want %q", got, tt.want)
}
})
}
}
func TestNewRedirectionVariousProtocols(t *testing.T) {
protocols := []string{"tcp", "udp", "icmp", "any"}
for _, proto := range protocols {
t.Run(proto, func(t *testing.T) {
r := NewRedirection("eth0", proto, 1234, "10.0.0.1", 5678)
if r.Protocol != proto {
t.Errorf("expected protocol %s, got %s", proto, r.Protocol)
}
})
}
}
func TestNewRedirectionVariousInterfaces(t *testing.T) {
interfaces := []string{"eth0", "wlan0", "lo", "docker0", "br0", "tun0"}
for _, iface := range interfaces {
t.Run(iface, func(t *testing.T) {
r := NewRedirection(iface, "tcp", 80, "192.168.1.1", 8080)
if r.Interface != iface {
t.Errorf("expected interface %s, got %s", iface, r.Interface)
}
})
}
}
func TestRedirectionStringEmptyFields(t *testing.T) {
tests := []struct {
name string
r Redirection
want string
}{
{
name: "empty interface",
r: Redirection{
Interface: "",
Protocol: "tcp",
SrcAddress: "",
SrcPort: 80,
DstAddress: "192.168.1.1",
DstPort: 8080,
},
want: "[] (tcp) :80 -> 192.168.1.1:8080",
},
{
name: "empty protocol",
r: Redirection{
Interface: "eth0",
Protocol: "",
SrcAddress: "",
SrcPort: 80,
DstAddress: "192.168.1.1",
DstPort: 8080,
},
want: "[eth0] () :80 -> 192.168.1.1:8080",
},
{
name: "empty destination",
r: Redirection{
Interface: "eth0",
Protocol: "tcp",
SrcAddress: "",
SrcPort: 80,
DstAddress: "",
DstPort: 8080,
},
want: "[eth0] (tcp) :80 -> :8080",
},
{
name: "all empty strings",
r: Redirection{
Interface: "",
Protocol: "",
SrcAddress: "",
SrcPort: 0,
DstAddress: "",
DstPort: 0,
},
want: "[] () :0 -> :0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.r.String()
if got != tt.want {
t.Errorf("String() = %q, want %q", got, tt.want)
}
})
}
}
func TestRedirectionStructCopy(t *testing.T) {
// Test that Redirection can be safely copied
original := NewRedirection("eth0", "tcp", 80, "192.168.1.1", 8080)
original.SrcAddress = "10.0.0.1"
// Create a copy
copy := *original
// Modify the copy
copy.Interface = "wlan0"
copy.SrcPort = 443
// Verify original is unchanged
if original.Interface != "eth0" {
t.Error("original Interface was modified")
}
if original.SrcPort != 80 {
t.Error("original SrcPort was modified")
}
// Verify copy has new values
if copy.Interface != "wlan0" {
t.Error("copy Interface was not set correctly")
}
if copy.SrcPort != 443 {
t.Error("copy SrcPort was not set correctly")
}
}
func BenchmarkNewRedirection(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = NewRedirection("eth0", "tcp", 80, "192.168.1.1", 8080)
}
}
func BenchmarkRedirectionString(b *testing.B) {
r := Redirection{
Interface: "eth0",
Protocol: "tcp",
SrcAddress: "192.168.1.50",
SrcPort: 8080,
DstAddress: "192.168.1.100",
DstPort: 9090,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = r.String()
}
}
func BenchmarkRedirectionStringEmpty(b *testing.B) {
r := Redirection{
Interface: "eth0",
Protocol: "tcp",
SrcAddress: "",
SrcPort: 8080,
DstAddress: "192.168.1.100",
DstPort: 9090,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = r.String()
}
}
================================================
FILE: go.mod
================================================
module github.com/bettercap/bettercap/v2
go 1.23.0
toolchain go1.24.4
require (
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/adrianmo/go-nmea v1.10.0
github.com/antchfx/jsonquery v1.3.6
github.com/bettercap/gatt v0.0.0-20240808115956-ec4935e8c4a0
github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb
github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf
github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/dustin/go-humanize v1.0.1
github.com/elazarl/goproxy v1.7.2
github.com/evilsocket/islazy v1.11.0
github.com/florianl/go-nfqueue/v2 v2.0.0
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe
github.com/google/go-github v17.0.0+incompatible
github.com/google/gousb v1.1.3
github.com/gopacket/gopacket v1.3.1
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/hashicorp/go-bexpr v0.1.14
github.com/inconshreveable/go-vhost v1.0.0
github.com/jpillora/go-tld v1.2.1
github.com/malfunkt/iprange v0.9.0
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b
github.com/miekg/dns v1.1.67
github.com/mitchellh/go-homedir v1.1.0
github.com/phin1x/go-ipp v1.6.1
github.com/robertkrimen/otto v0.5.1
github.com/stratoberry/go-gpsd v1.3.0
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64
go.einride.tech/can v0.14.0
golang.org/x/net v0.42.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/antchfx/xpath v1.3.4 // indirect
github.com/chzyer/logex v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/kr/binarydist v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/pointerstructure v1.2.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
golang.org/x/mod v0.26.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.27.0 // indirect
golang.org/x/tools v0.35.0 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect
)
================================================
FILE: go.sum
================================================
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/adrianmo/go-nmea v1.10.0 h1:L1aYaebZ4cXFCoXNSeDeQa0tApvSKvIbqMsK+iaRiCo=
github.com/adrianmo/go-nmea v1.10.0/go.mod h1:u8bPnpKt/D/5rll/5l9f6iDfeq5WZW0+/SXdkwix6Tg=
github.com/antchfx/jsonquery v1.3.6 h1:TaSfeAh7n6T11I74bsZ1FswreIfrbJ0X+OyLflx6mx4=
github.com/antchfx/jsonquery v1.3.6/go.mod h1:fGzSGJn9Y826Qd3pC8Wx45avuUwpkePsACQJYy+58BU=
github.com/antchfx/xpath v1.3.2/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/antchfx/xpath v1.3.4 h1:1ixrW1VnXd4HurCj7qnqnR0jo14g8JMe20Fshg1Vgz4=
github.com/antchfx/xpath v1.3.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/bettercap/gatt v0.0.0-20240808115956-ec4935e8c4a0 h1:HiFUGV/7eGWG/YJAf9HcKOUmxIj+7LVzC8zD57VX1qo=
github.com/bettercap/gatt v0.0.0-20240808115956-ec4935e8c4a0/go.mod h1:oafnPgaBI4gqJiYkueCyR4dqygiWGXTGOE0gmmAVeeQ=
github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb h1:JWAAJk4ny+bT3VrtcX+e7mcmWtWUeUM0xVcocSAUuWc=
github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb/go.mod h1:g6WiaSRgMTiChuk7jYyFSEtpgaw1F0wAsBfspG3bu0M=
github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf h1:pwGPRc5PIp4KCF9QbKn0iLVMhfigUMw4IzGZEZ81m1I=
github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf/go.mod h1:03rWiUf60r1miMVzMEtgtkq7RdZniecZFw3/Zgvyxcs=
github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3 h1:pC4ZAk7UtDIbrRKzMMiIL1TVkiKlgtgcJodqKB53Rl4=
github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3/go.mod h1:kqVwnx6DKuOHMZcBnzsgp2Lq2JZHDtFtm92b5hxdRaM=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/evilsocket/islazy v1.11.0 h1:B5w6uuS6ki6iDG+aH/RFeoMb8ijQh/pGabewqp2UeJ0=
github.com/evilsocket/islazy v1.11.0/go.mod h1:muYH4x5MB5YRdkxnrOtrXLIBX6LySj1uFIqys94LKdo=
github.com/florianl/go-nfqueue/v2 v2.0.0 h1:NTCxS9b0GSbHkWv1a7oOvZn679fsyDkaSkRvOYpQ9Oo=
github.com/florianl/go-nfqueue/v2 v2.0.0/go.mod h1:M2tBLIj62QpwqjwV0qfcjqGOqP3qiTuXr2uSRBXH9Qk=
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe h1:8P+/htb3mwwpeGdJg69yBF/RofK7c6Fjz5Ypa/bTqbY=
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gousb v1.1.3 h1:xt6M5TDsGSZ+rlomz5Si5Hmd/Fvbmo2YCJHN+yGaK4o=
github.com/google/gousb v1.1.3/go.mod h1:GGWUkK0gAXDzxhwrzetW592aOmkkqSGcj5KLEgmCVUg=
github.com/gopacket/gopacket v1.3.1 h1:ZppWyLrOJNZPe5XkdjLbtuTkfQoxQ0xyMJzQCqtqaPU=
github.com/gopacket/gopacket v1.3.1/go.mod h1:3I13qcqSpB2R9fFQg866OOgzylYkZxLTmkvcXhvf6qg=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/go-bexpr v0.1.14 h1:uKDeyuOhWhT1r5CiMTjdVY4Aoxdxs6EtwgTGnlosyp4=
github.com/hashicorp/go-bexpr v0.1.14/go.mod h1:gN7hRKB3s7yT+YvTdnhZVLTENejvhlkZ8UE4YVBS+Q8=
github.com/inconshreveable/go-vhost v1.0.0 h1:IK4VZTlXL4l9vz2IZoiSFbYaaqUW7dXJAiPriUN5Ur8=
github.com/inconshreveable/go-vhost v1.0.0/go.mod h1:aA6DnFhALT3zH0y+A39we+zbrdMC2N0X/q21e6FI0LU=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jpillora/go-tld v1.2.1 h1:kDKOkmXLlskqjcvNs7w5XHLep7c8WM7Xd4HQjxllVMk=
github.com/jpillora/go-tld v1.2.1/go.mod h1:plzIl7xr5UWKGy7R+giuv+L/nOjrPjsoWxy/ST9OBUk=
github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo=
github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/malfunkt/iprange v0.9.0 h1:VCs0PKLUPotNVQTpVNszsut4lP7OCGNBwX+lOYBrnVQ=
github.com/malfunkt/iprange v0.9.0/go.mod h1:TRGqO/f95gh3LOndUGTL46+W0GXA91WTqyZ0Quwvt4U=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b h1:r12blE3QRYlW1WBiBEe007O6NrTb/P54OjR5d4WLEGk=
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b/go.mod h1:p4K2+UAoap8Jzsadsxc0KG0OZjmmCthTPUyZqAVkjBY=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab h1:n8cgpHzJ5+EDyDri2s/GC7a9+qK3/YEGnBsd0uS/8PY=
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab/go.mod h1:y1pL58r5z2VvAjeG1VLGc8zOQgSOzbKN7kMHPvFXJ+8=
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/phin1x/go-ipp v1.6.1 h1:oxJXi92BO2FZhNcG3twjnxKFH1liTQ46vbbZx+IN/80=
github.com/phin1x/go-ipp v1.6.1/go.mod h1:GZwyNds6grdLi2xRBX22Cvt7Dh7ITWsML0bjrqBF5uo=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robertkrimen/otto v0.5.1 h1:avDI4ToRk8k1hppLdYFTuuzND41n37vPGJU7547dGf0=
github.com/robertkrimen/otto v0.5.1/go.mod h1:bS433I4Q9p+E5pZLu7r17vP6FkE6/wLxBdmKjoqJXF8=
github.com/stratoberry/go-gpsd v1.3.0 h1:JxJOEC4SgD0QY65AE7B1CtJtweP73nqJghZeLNU9J+c=
github.com/stratoberry/go-gpsd v1.3.0/go.mod h1:nVf/vTgfYxOMxiQdy9BtJjojbFRtG8H3wNula++VgkU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64 h1:l/T7dYuJEQZOwVOpjIXr1180aM9PZL/d1MnMVIxefX4=
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64/go.mod h1:Q1NAJOuRdQCqN/VIWdnaaEhV8LpeO2rtlBP7/iDJNII=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.einride.tech/can v0.14.0 h1:OkQ0jsjCk4ijgTMjD43V1NKQyDztpX7Vo/NrvmnsAXE=
go.einride.tech/can v0.14.0/go.mod h1:615YuRGnWfndMGD+f3Ud1sp1xJLP1oj14dKRtb2CXDQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
================================================
FILE: js/crypto.go
================================================
package js
import (
"crypto/sha1"
"github.com/robertkrimen/otto"
)
func cryptoSha1(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("Crypto.sha1: expected 1 argument, %d given instead.", argc)
}
arg := argv[0]
if (!arg.IsString()) {
return ReportError("Crypto.sha1: single argument must be a string.")
}
hasher := sha1.New()
hasher.Write([]byte(arg.String()))
v, err := otto.ToValue(string(hasher.Sum(nil)))
if err != nil {
return ReportError("Crypto.sha1: could not convert to string: %s", err)
}
return v
}
================================================
FILE: js/data.go
================================================
package js
import (
"bytes"
"compress/gzip"
"encoding/base64"
"github.com/robertkrimen/otto"
)
func textEncode(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("textEncode: expected 1 argument, %d given instead.", argc)
}
arg := argv[0]
if (!arg.IsString()) {
return ReportError("textEncode: single argument must be a string.")
}
encoded := []byte(arg.String())
vm := otto.New()
v, err := vm.ToValue(encoded)
if err != nil {
return ReportError("textEncode: could not convert to []uint8: %s", err.Error())
}
return v
}
func textDecode(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("textDecode: expected 1 argument, %d given instead.", argc)
}
arg, err := argv[0].Export()
if err != nil {
return ReportError("textDecode: could not export argument value: %s", err.Error())
}
byteArr, ok := arg.([]uint8)
if !ok {
return ReportError("textDecode: single argument must be of type []uint8.")
}
decoded := string(byteArr)
v, err := otto.ToValue(decoded)
if err != nil {
return ReportError("textDecode: could not convert to string: %s", err.Error())
}
return v
}
func btoa(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("btoa: expected 1 argument, %d given instead.", argc)
}
arg := argv[0]
if (!arg.IsString()) {
return ReportError("btoa: single argument must be a string.")
}
encoded := base64.StdEncoding.EncodeToString([]byte(arg.String()))
v, err := otto.ToValue(encoded)
if err != nil {
return ReportError("btoa: could not convert to string: %s", err.Error())
}
return v
}
func atob(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("atob: expected 1 argument, %d given instead.", argc)
}
arg := argv[0]
if (!arg.IsString()) {
return ReportError("atob: single argument must be a string.")
}
decoded, err := base64.StdEncoding.DecodeString(arg.String())
if err != nil {
return ReportError("atob: could not decode string: %s", err.Error())
}
v, err := otto.ToValue(string(decoded))
if err != nil {
return ReportError("atob: could not convert to string: %s", err.Error())
}
return v
}
func gzipCompress(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("gzipCompress: expected 1 argument, %d given instead.", argc)
}
arg := argv[0]
if (!arg.IsString()) {
return ReportError("gzipCompress: single argument must be a string.")
}
uncompressedBytes := []byte(arg.String())
var writerBuffer bytes.Buffer
gzipWriter := gzip.NewWriter(&writerBuffer)
_, err := gzipWriter.Write(uncompressedBytes)
if err != nil {
return ReportError("gzipCompress: could not compress data: %s", err.Error())
}
gzipWriter.Close()
compressedBytes := writerBuffer.Bytes()
v, err := otto.ToValue(string(compressedBytes))
if err != nil {
return ReportError("gzipCompress: could not convert to string: %s", err.Error())
}
return v
}
func gzipDecompress(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("gzipDecompress: expected 1 argument, %d given instead.", argc)
}
compressedBytes := []byte(argv[0].String())
readerBuffer := bytes.NewBuffer(compressedBytes)
gzipReader, err := gzip.NewReader(readerBuffer)
if err != nil {
return ReportError("gzipDecompress: could not create gzip reader: %s", err.Error())
}
var decompressedBuffer bytes.Buffer
_, err = decompressedBuffer.ReadFrom(gzipReader)
if err != nil {
return ReportError("gzipDecompress: could not decompress data: %s", err.Error())
}
decompressedBytes := decompressedBuffer.Bytes()
v, err := otto.ToValue(string(decompressedBytes))
if err != nil {
return ReportError("gzipDecompress: could not convert to string: %s", err.Error())
}
return v
}
================================================
FILE: js/data_test.go
================================================
package js
import (
"encoding/base64"
"strings"
"testing"
"github.com/robertkrimen/otto"
)
func TestBtoa(t *testing.T) {
vm := otto.New()
tests := []struct {
name string
input string
expected string
}{
{
name: "simple string",
input: "hello world",
expected: base64.StdEncoding.EncodeToString([]byte("hello world")),
},
{
name: "empty string",
input: "",
expected: base64.StdEncoding.EncodeToString([]byte("")),
},
{
name: "special characters",
input: "!@#$%^&*()_+-=[]{}|;:,.<>?",
expected: base64.StdEncoding.EncodeToString([]byte("!@#$%^&*()_+-=[]{}|;:,.<>?")),
},
{
name: "unicode string",
input: "Hello 世界 🌍",
expected: base64.StdEncoding.EncodeToString([]byte("Hello 世界 🌍")),
},
{
name: "newlines and tabs",
input: "line1\nline2\ttab",
expected: base64.StdEncoding.EncodeToString([]byte("line1\nline2\ttab")),
},
{
name: "long string",
input: strings.Repeat("a", 1000),
expected: base64.StdEncoding.EncodeToString([]byte(strings.Repeat("a", 1000))),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create call with argument
arg, _ := vm.ToValue(tt.input)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := btoa(call)
// Check if result is an error
if result.IsUndefined() {
t.Fatal("btoa returned undefined")
}
// Get string value
resultStr, err := result.ToString()
if err != nil {
t.Fatalf("failed to convert result to string: %v", err)
}
if resultStr != tt.expected {
t.Errorf("btoa(%q) = %q, want %q", tt.input, resultStr, tt.expected)
}
})
}
}
func TestAtob(t *testing.T) {
vm := otto.New()
tests := []struct {
name string
input string
expected string
wantError bool
}{
{
name: "simple base64",
input: base64.StdEncoding.EncodeToString([]byte("hello world")),
expected: "hello world",
},
{
name: "empty base64",
input: base64.StdEncoding.EncodeToString([]byte("")),
expected: "",
},
{
name: "special characters base64",
input: base64.StdEncoding.EncodeToString([]byte("!@#$%^&*()_+-=[]{}|;:,.<>?")),
expected: "!@#$%^&*()_+-=[]{}|;:,.<>?",
},
{
name: "unicode base64",
input: base64.StdEncoding.EncodeToString([]byte("Hello 世界 🌍")),
expected: "Hello 世界 🌍",
},
{
name: "invalid base64",
input: "not valid base64!",
wantError: true,
},
{
name: "invalid padding",
input: "SGVsbG8gV29ybGQ", // Missing padding
wantError: true,
},
{
name: "long base64",
input: base64.StdEncoding.EncodeToString([]byte(strings.Repeat("a", 1000))),
expected: strings.Repeat("a", 1000),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create call with argument
arg, _ := vm.ToValue(tt.input)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := atob(call)
// Get string value
resultStr, err := result.ToString()
if err != nil && !tt.wantError {
t.Fatalf("failed to convert result to string: %v", err)
}
if tt.wantError {
// Should return undefined (NullValue) on error
if !result.IsUndefined() {
t.Errorf("expected undefined for error case, got %q", resultStr)
}
} else {
if resultStr != tt.expected {
t.Errorf("atob(%q) = %q, want %q", tt.input, resultStr, tt.expected)
}
}
})
}
}
func TestGzipCompress(t *testing.T) {
vm := otto.New()
tests := []struct {
name string
input string
}{
{
name: "simple string",
input: "hello world",
},
{
name: "empty string",
input: "",
},
{
name: "repeated pattern",
input: strings.Repeat("abcd", 100),
},
{
name: "random text",
input: "The quick brown fox jumps over the lazy dog. " + strings.Repeat("Lorem ipsum dolor sit amet. ", 10),
},
{
name: "unicode text",
input: "Hello 世界 🌍 " + strings.Repeat("测试数据 ", 50),
},
{
name: "binary-like data",
input: string([]byte{0, 1, 2, 3, 255, 254, 253, 252}),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create call with argument
arg, _ := vm.ToValue(tt.input)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := gzipCompress(call)
// Get compressed data
compressed, err := result.ToString()
if err != nil {
t.Fatalf("failed to convert result to string: %v", err)
}
// Verify it's actually compressed (for non-empty strings, compressed should be different)
if tt.input != "" && compressed == tt.input {
t.Error("compressed data is same as input")
}
// Verify gzip header (should start with 0x1f, 0x8b)
if len(compressed) >= 2 {
if compressed[0] != 0x1f || compressed[1] != 0x8b {
t.Error("compressed data doesn't have valid gzip header")
}
}
// Now decompress to verify
argCompressed, _ := vm.ToValue(compressed)
callDecompress := otto.FunctionCall{
ArgumentList: []otto.Value{argCompressed},
}
resultDecompressed := gzipDecompress(callDecompress)
decompressed, err := resultDecompressed.ToString()
if err != nil {
t.Fatalf("failed to decompress: %v", err)
}
if decompressed != tt.input {
t.Errorf("round-trip failed: got %q, want %q", decompressed, tt.input)
}
})
}
}
func TestGzipCompressInvalidArgs(t *testing.T) {
vm := otto.New()
tests := []struct {
name string
args []otto.Value
}{
{
name: "no arguments",
args: []otto.Value{},
},
{
name: "too many arguments",
args: func() []otto.Value {
arg1, _ := vm.ToValue("test")
arg2, _ := vm.ToValue("extra")
return []otto.Value{arg1, arg2}
}(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := otto.FunctionCall{
ArgumentList: tt.args,
}
result := gzipCompress(call)
// Should return undefined (NullValue) on error
if !result.IsUndefined() {
resultStr, _ := result.ToString()
t.Errorf("expected undefined for error case, got %q", resultStr)
}
})
}
}
func TestGzipDecompress(t *testing.T) {
vm := otto.New()
// First compress some data
originalData := "This is test data for decompression"
arg, _ := vm.ToValue(originalData)
compressCall := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
compressedResult := gzipCompress(compressCall)
compressedData, _ := compressedResult.ToString()
t.Run("valid decompression", func(t *testing.T) {
argCompressed, _ := vm.ToValue(compressedData)
decompressCall := otto.FunctionCall{
ArgumentList: []otto.Value{argCompressed},
}
result := gzipDecompress(decompressCall)
decompressed, err := result.ToString()
if err != nil {
t.Fatalf("failed to convert result to string: %v", err)
}
if decompressed != originalData {
t.Errorf("decompressed data doesn't match original: got %q, want %q", decompressed, originalData)
}
})
t.Run("invalid gzip data", func(t *testing.T) {
argInvalid, _ := vm.ToValue("not gzip data")
call := otto.FunctionCall{
ArgumentList: []otto.Value{argInvalid},
}
result := gzipDecompress(call)
// Should return undefined (NullValue) on error
if !result.IsUndefined() {
resultStr, _ := result.ToString()
t.Errorf("expected undefined for error case, got %q", resultStr)
}
})
t.Run("corrupted gzip data", func(t *testing.T) {
// Create corrupted gzip by taking valid gzip and modifying it
corruptedData := compressedData[:len(compressedData)/2] + "corrupted"
argCorrupted, _ := vm.ToValue(corruptedData)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argCorrupted},
}
result := gzipDecompress(call)
// Should return undefined (NullValue) on error
if !result.IsUndefined() {
resultStr, _ := result.ToString()
t.Errorf("expected undefined for error case, got %q", resultStr)
}
})
}
func TestGzipDecompressInvalidArgs(t *testing.T) {
vm := otto.New()
tests := []struct {
name string
args []otto.Value
}{
{
name: "no arguments",
args: []otto.Value{},
},
{
name: "too many arguments",
args: func() []otto.Value {
arg1, _ := vm.ToValue("test")
arg2, _ := vm.ToValue("extra")
return []otto.Value{arg1, arg2}
}(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := otto.FunctionCall{
ArgumentList: tt.args,
}
result := gzipDecompress(call)
// Should return undefined (NullValue) on error
if !result.IsUndefined() {
resultStr, _ := result.ToString()
t.Errorf("expected undefined for error case, got %q", resultStr)
}
})
}
}
func TestBtoaAtobRoundTrip(t *testing.T) {
vm := otto.New()
testStrings := []string{
"simple",
"",
"with spaces and\nnewlines\ttabs",
"special!@#$%^&*()_+-=[]{}|;:,.<>?",
"unicode 世界 🌍",
strings.Repeat("long string ", 100),
}
for _, original := range testStrings {
t.Run(original, func(t *testing.T) {
// Encode with btoa
argOriginal, _ := vm.ToValue(original)
encodeCall := otto.FunctionCall{
ArgumentList: []otto.Value{argOriginal},
}
encoded := btoa(encodeCall)
encodedStr, _ := encoded.ToString()
// Decode with atob
argEncoded, _ := vm.ToValue(encodedStr)
decodeCall := otto.FunctionCall{
ArgumentList: []otto.Value{argEncoded},
}
decoded := atob(decodeCall)
decodedStr, _ := decoded.ToString()
if decodedStr != original {
t.Errorf("round-trip failed: got %q, want %q", decodedStr, original)
}
})
}
}
func TestGzipCompressDecompressRoundTrip(t *testing.T) {
vm := otto.New()
testData := []string{
"simple",
"",
strings.Repeat("repetitive data ", 100),
"unicode 世界 🌍 " + strings.Repeat("测试 ", 50),
string([]byte{0, 1, 2, 3, 255, 254, 253, 252}),
}
for _, original := range testData {
t.Run(original, func(t *testing.T) {
// Compress
argOriginal, _ := vm.ToValue(original)
compressCall := otto.FunctionCall{
ArgumentList: []otto.Value{argOriginal},
}
compressed := gzipCompress(compressCall)
compressedStr, _ := compressed.ToString()
// Decompress
argCompressed, _ := vm.ToValue(compressedStr)
decompressCall := otto.FunctionCall{
ArgumentList: []otto.Value{argCompressed},
}
decompressed := gzipDecompress(decompressCall)
decompressedStr, _ := decompressed.ToString()
if decompressedStr != original {
t.Errorf("round-trip failed: got %q, want %q", decompressedStr, original)
}
})
}
}
func BenchmarkBtoa(b *testing.B) {
vm := otto.New()
arg, _ := vm.ToValue("The quick brown fox jumps over the lazy dog")
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = btoa(call)
}
}
func BenchmarkAtob(b *testing.B) {
vm := otto.New()
encoded := base64.StdEncoding.EncodeToString([]byte("The quick brown fox jumps over the lazy dog"))
arg, _ := vm.ToValue(encoded)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = atob(call)
}
}
func BenchmarkGzipCompress(b *testing.B) {
vm := otto.New()
data := strings.Repeat("The quick brown fox jumps over the lazy dog. ", 10)
arg, _ := vm.ToValue(data)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gzipCompress(call)
}
}
func BenchmarkGzipDecompress(b *testing.B) {
vm := otto.New()
// First compress some data
data := strings.Repeat("The quick brown fox jumps over the lazy dog. ", 10)
argData, _ := vm.ToValue(data)
compressCall := otto.FunctionCall{
ArgumentList: []otto.Value{argData},
}
compressed := gzipCompress(compressCall)
compressedStr, _ := compressed.ToString()
// Benchmark decompression
argCompressed, _ := vm.ToValue(compressedStr)
decompressCall := otto.FunctionCall{
ArgumentList: []otto.Value{argCompressed},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gzipDecompress(decompressCall)
}
}
================================================
FILE: js/fs.go
================================================
package js
import (
"os"
"github.com/robertkrimen/otto"
)
func mkdirAll(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("mkdirAll: expected 1 argument, %d given instead.", argc)
}
path := argv[0].String()
err := os.MkdirAll(path, 0755)
if err != nil {
return ReportError("Could not create directory %s: %s", path, err)
}
return otto.NullValue()
}
func readDir(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("readDir: expected 1 argument, %d given instead.", argc)
}
path := argv[0].String()
dir, err := os.ReadDir(path)
if err != nil {
return ReportError("Could not read directory %s: %s", path, err)
}
entry_list := []string{}
for _, file := range dir {
entry_list = append(entry_list, file.Name())
}
v, err := otto.Otto.ToValue(*call.Otto, entry_list)
if err != nil {
return ReportError("Could not convert to array: %s", err)
}
return v
}
func readFile(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 1 {
return ReportError("readFile: expected 1 argument, %d given instead.", argc)
}
filename := argv[0].String()
raw, err := os.ReadFile(filename)
if err != nil {
return ReportError("Could not read file %s: %s", filename, err)
}
v, err := otto.ToValue(string(raw))
if err != nil {
return ReportError("Could not convert to string: %s", err)
}
return v
}
func writeFile(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 2 {
return ReportError("writeFile: expected 2 arguments, %d given instead.", argc)
}
filename := argv[0].String()
data := argv[1].String()
err := os.WriteFile(filename, []byte(data), 0644)
if err != nil {
return ReportError("Could not write %d bytes to %s: %s", len(data), filename, err)
}
return otto.NullValue()
}
func appendFile(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc != 2 {
return ReportError("appendFile: expected 2 arguments, %d given instead.", argc)
}
filename := argv[0].String()
data := argv[1].String()
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return ReportError("Could not open file %s for appending: %s", filename, err)
}
defer file.Close()
_, err = file.Write([]byte(data))
if err != nil {
return ReportError("Could not append %d bytes to %s: %s", len(data), filename, err)
}
return otto.NullValue()
}
================================================
FILE: js/fs_test.go
================================================
package js
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/robertkrimen/otto"
)
func TestReadDir(t *testing.T) {
vm := otto.New()
// Create a temporary directory for testing
tmpDir, err := os.MkdirTemp("", "js_test_readdir_*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
// Create some test files and subdirectories
testFiles := []string{"file1.txt", "file2.log", ".hidden"}
testDirs := []string{"subdir1", "subdir2"}
for _, name := range testFiles {
if err := os.WriteFile(filepath.Join(tmpDir, name), []byte("test"), 0644); err != nil {
t.Fatalf("failed to create test file %s: %v", name, err)
}
}
for _, name := range testDirs {
if err := os.Mkdir(filepath.Join(tmpDir, name), 0755); err != nil {
t.Fatalf("failed to create test dir %s: %v", name, err)
}
}
t.Run("valid directory", func(t *testing.T) {
arg, _ := vm.ToValue(tmpDir)
call := otto.FunctionCall{
Otto: vm,
ArgumentList: []otto.Value{arg},
}
result := readDir(call)
// Check if result is not undefined
if result.IsUndefined() {
t.Fatal("readDir returned undefined")
}
// Convert to Go slice
export, err := result.Export()
if err != nil {
t.Fatalf("failed to export result: %v", err)
}
entries, ok := export.([]string)
if !ok {
t.Fatalf("expected []string, got %T", export)
}
// Check all expected entries are present
expectedEntries := append(testFiles, testDirs...)
if len(entries) != len(expectedEntries) {
t.Errorf("expected %d entries, got %d", len(expectedEntries), len(entries))
}
// Check each entry exists
for _, expected := range expectedEntries {
found := false
for _, entry := range entries {
if entry == expected {
found = true
break
}
}
if !found {
t.Errorf("expected entry %s not found", expected)
}
}
})
t.Run("non-existent directory", func(t *testing.T) {
arg, _ := vm.ToValue("/path/that/does/not/exist")
call := otto.FunctionCall{
Otto: vm,
ArgumentList: []otto.Value{arg},
}
result := readDir(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined for non-existent directory")
}
})
t.Run("file instead of directory", func(t *testing.T) {
// Create a file
testFile := filepath.Join(tmpDir, "notadir.txt")
os.WriteFile(testFile, []byte("test"), 0644)
arg, _ := vm.ToValue(testFile)
call := otto.FunctionCall{
Otto: vm,
ArgumentList: []otto.Value{arg},
}
result := readDir(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined when passing file instead of directory")
}
})
t.Run("invalid arguments", func(t *testing.T) {
tests := []struct {
name string
args []otto.Value
}{
{
name: "no arguments",
args: []otto.Value{},
},
{
name: "too many arguments",
args: func() []otto.Value {
arg1, _ := vm.ToValue(tmpDir)
arg2, _ := vm.ToValue("extra")
return []otto.Value{arg1, arg2}
}(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := otto.FunctionCall{
Otto: vm,
ArgumentList: tt.args,
}
result := readDir(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined for invalid arguments")
}
})
}
})
t.Run("empty directory", func(t *testing.T) {
emptyDir := filepath.Join(tmpDir, "empty")
os.Mkdir(emptyDir, 0755)
arg, _ := vm.ToValue(emptyDir)
call := otto.FunctionCall{
Otto: vm,
ArgumentList: []otto.Value{arg},
}
result := readDir(call)
if result.IsUndefined() {
t.Fatal("readDir returned undefined for empty directory")
}
export, _ := result.Export()
entries, _ := export.([]string)
if len(entries) != 0 {
t.Errorf("expected 0 entries for empty directory, got %d", len(entries))
}
})
}
func TestReadFile(t *testing.T) {
vm := otto.New()
// Create a temporary directory for testing
tmpDir, err := os.MkdirTemp("", "js_test_readfile_*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
t.Run("valid file", func(t *testing.T) {
testContent := "Hello, World!\nThis is a test file.\n特殊字符测试 🌍"
testFile := filepath.Join(tmpDir, "test.txt")
os.WriteFile(testFile, []byte(testContent), 0644)
arg, _ := vm.ToValue(testFile)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := readFile(call)
if result.IsUndefined() {
t.Fatal("readFile returned undefined")
}
content, err := result.ToString()
if err != nil {
t.Fatalf("failed to convert result to string: %v", err)
}
if content != testContent {
t.Errorf("expected content %q, got %q", testContent, content)
}
})
t.Run("non-existent file", func(t *testing.T) {
arg, _ := vm.ToValue("/path/that/does/not/exist.txt")
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := readFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined for non-existent file")
}
})
t.Run("directory instead of file", func(t *testing.T) {
arg, _ := vm.ToValue(tmpDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := readFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined when passing directory instead of file")
}
})
t.Run("empty file", func(t *testing.T) {
emptyFile := filepath.Join(tmpDir, "empty.txt")
os.WriteFile(emptyFile, []byte(""), 0644)
arg, _ := vm.ToValue(emptyFile)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := readFile(call)
if result.IsUndefined() {
t.Fatal("readFile returned undefined for empty file")
}
content, _ := result.ToString()
if content != "" {
t.Errorf("expected empty string, got %q", content)
}
})
t.Run("binary file", func(t *testing.T) {
binaryContent := []byte{0, 1, 2, 3, 255, 254, 253, 252}
binaryFile := filepath.Join(tmpDir, "binary.bin")
os.WriteFile(binaryFile, binaryContent, 0644)
arg, _ := vm.ToValue(binaryFile)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := readFile(call)
if result.IsUndefined() {
t.Fatal("readFile returned undefined for binary file")
}
content, _ := result.ToString()
if content != string(binaryContent) {
t.Error("binary content mismatch")
}
})
t.Run("invalid arguments", func(t *testing.T) {
tests := []struct {
name string
args []otto.Value
}{
{
name: "no arguments",
args: []otto.Value{},
},
{
name: "too many arguments",
args: func() []otto.Value {
arg1, _ := vm.ToValue("file.txt")
arg2, _ := vm.ToValue("extra")
return []otto.Value{arg1, arg2}
}(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := otto.FunctionCall{
ArgumentList: tt.args,
}
result := readFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined for invalid arguments")
}
})
}
})
t.Run("large file", func(t *testing.T) {
// Create a 1MB file
largeContent := strings.Repeat("A", 1024*1024)
largeFile := filepath.Join(tmpDir, "large.txt")
os.WriteFile(largeFile, []byte(largeContent), 0644)
arg, _ := vm.ToValue(largeFile)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := readFile(call)
if result.IsUndefined() {
t.Fatal("readFile returned undefined for large file")
}
content, _ := result.ToString()
if len(content) != len(largeContent) {
t.Errorf("expected content length %d, got %d", len(largeContent), len(content))
}
})
}
func TestWriteFile(t *testing.T) {
vm := otto.New()
// Create a temporary directory for testing
tmpDir, err := os.MkdirTemp("", "js_test_writefile_*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
t.Run("write new file", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "new_file.txt")
testContent := "Hello, World!\nThis is a new file.\n特殊字符测试 🌍"
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(testContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := writeFile(call)
// writeFile returns null on success
if !result.IsNull() {
t.Error("expected null return value for successful write")
}
// Verify file was created with correct content
content, err := os.ReadFile(testFile)
if err != nil {
t.Fatalf("failed to read written file: %v", err)
}
if string(content) != testContent {
t.Errorf("expected content %q, got %q", testContent, string(content))
}
// Check file permissions
info, _ := os.Stat(testFile)
if runtime.GOOS == "windows" {
// On Windows, permissions are different - just check that file exists and is readable
if info.Mode()&0400 == 0 {
t.Error("expected file to be readable on Windows")
}
} else {
// On Unix-like systems, check exact permissions
if info.Mode().Perm() != 0644 {
t.Errorf("expected permissions 0644, got %v", info.Mode().Perm())
}
}
})
t.Run("overwrite existing file", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "existing.txt")
oldContent := "Old content"
newContent := "New content that is longer than the old content"
// Create initial file
os.WriteFile(testFile, []byte(oldContent), 0644)
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(newContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := writeFile(call)
if !result.IsNull() {
t.Error("expected null return value for successful write")
}
// Verify file was overwritten
content, _ := os.ReadFile(testFile)
if string(content) != newContent {
t.Errorf("expected content %q, got %q", newContent, string(content))
}
})
t.Run("write to non-existent directory", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "nonexistent", "subdir", "file.txt")
testContent := "test"
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(testContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := writeFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined when writing to non-existent directory")
}
})
t.Run("write empty content", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "empty.txt")
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue("")
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := writeFile(call)
if !result.IsNull() {
t.Error("expected null return value for successful write")
}
// Verify empty file was created
content, _ := os.ReadFile(testFile)
if len(content) != 0 {
t.Errorf("expected empty file, got %d bytes", len(content))
}
})
t.Run("invalid arguments", func(t *testing.T) {
tests := []struct {
name string
args []otto.Value
}{
{
name: "no arguments",
args: []otto.Value{},
},
{
name: "one argument",
args: func() []otto.Value {
arg, _ := vm.ToValue("file.txt")
return []otto.Value{arg}
}(),
},
{
name: "too many arguments",
args: func() []otto.Value {
arg1, _ := vm.ToValue("file.txt")
arg2, _ := vm.ToValue("content")
arg3, _ := vm.ToValue("extra")
return []otto.Value{arg1, arg2, arg3}
}(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := otto.FunctionCall{
ArgumentList: tt.args,
}
result := writeFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined for invalid arguments")
}
})
}
})
t.Run("write binary content", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "binary.bin")
binaryContent := string([]byte{0, 1, 2, 3, 255, 254, 253, 252})
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(binaryContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := writeFile(call)
if !result.IsNull() {
t.Error("expected null return value for successful write")
}
// Verify binary content
content, _ := os.ReadFile(testFile)
if string(content) != binaryContent {
t.Error("binary content mismatch")
}
})
}
func TestAppendFile(t *testing.T) {
vm := otto.New()
// Create a temporary directory for testing
tmpDir, err := os.MkdirTemp("", "js_test_appendfile_*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
t.Run("append to new file", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "new_append.txt")
testContent := "Hello, World!\nThis is appended content.\n特殊字符测试 🌍"
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(testContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := appendFile(call)
// appendFile returns null on success
if !result.IsNull() {
t.Error("expected null return value for successful append")
}
// Verify file was created with correct content
content, err := os.ReadFile(testFile)
if err != nil {
t.Fatalf("failed to read appended file: %v", err)
}
if string(content) != testContent {
t.Errorf("expected content %q, got %q", testContent, string(content))
}
// Check file permissions
info, _ := os.Stat(testFile)
if runtime.GOOS == "windows" {
// On Windows, permissions are different - just check that file exists and is readable
if info.Mode()&0400 == 0 {
t.Error("expected file to be readable on Windows")
}
} else {
// On Unix-like systems, check exact permissions
if info.Mode().Perm() != 0644 {
t.Errorf("expected permissions 0644, got %v", info.Mode().Perm())
}
}
})
t.Run("append to existing file", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "existing_append.txt")
initialContent := "Initial content\n"
appendContent := "Appended content\n"
expectedContent := initialContent + appendContent
// Create initial file
os.WriteFile(testFile, []byte(initialContent), 0644)
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(appendContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := appendFile(call)
if !result.IsNull() {
t.Error("expected null return value for successful append")
}
// Verify content was appended
content, _ := os.ReadFile(testFile)
if string(content) != expectedContent {
t.Errorf("expected content %q, got %q", expectedContent, string(content))
}
})
t.Run("multiple appends", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "multi_append.txt")
contents := []string{"Line 1\n", "Line 2\n", "Line 3\n"}
expectedContent := strings.Join(contents, "")
argFile, _ := vm.ToValue(testFile)
// Append multiple times
for _, content := range contents {
argContent, _ := vm.ToValue(content)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := appendFile(call)
if !result.IsNull() {
t.Errorf("expected null return value for append of %q", content)
}
}
// Verify all content was appended
finalContent, _ := os.ReadFile(testFile)
if string(finalContent) != expectedContent {
t.Errorf("expected content %q, got %q", expectedContent, string(finalContent))
}
})
t.Run("append to non-existent directory", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "nonexistent", "subdir", "file.txt")
testContent := "test"
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(testContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := appendFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined when appending to non-existent directory")
}
})
t.Run("append empty content", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "empty_append.txt")
initialContent := "Initial content"
// Create initial file
os.WriteFile(testFile, []byte(initialContent), 0644)
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue("")
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := appendFile(call)
if !result.IsNull() {
t.Error("expected null return value for successful append")
}
// Verify content unchanged (empty append)
content, _ := os.ReadFile(testFile)
if string(content) != initialContent {
t.Errorf("expected content %q, got %q", initialContent, string(content))
}
})
t.Run("invalid arguments", func(t *testing.T) {
tests := []struct {
name string
args []otto.Value
}{
{
name: "no arguments",
args: []otto.Value{},
},
{
name: "one argument",
args: func() []otto.Value {
arg, _ := vm.ToValue("file.txt")
return []otto.Value{arg}
}(),
},
{
name: "too many arguments",
args: func() []otto.Value {
arg1, _ := vm.ToValue("file.txt")
arg2, _ := vm.ToValue("content")
arg3, _ := vm.ToValue("extra")
return []otto.Value{arg1, arg2, arg3}
}(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := otto.FunctionCall{
ArgumentList: tt.args,
}
result := appendFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined for invalid arguments")
}
})
}
})
t.Run("append binary content", func(t *testing.T) {
testFile := filepath.Join(tmpDir, "binary_append.bin")
initialContent := []byte{0, 1, 2, 3}
appendContent := string([]byte{255, 254, 253, 252})
expectedContent := string(initialContent) + appendContent
// Create initial file with binary content
os.WriteFile(testFile, initialContent, 0644)
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(appendContent)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := appendFile(call)
if !result.IsNull() {
t.Error("expected null return value for successful append")
}
// Verify binary content was appended correctly
content, _ := os.ReadFile(testFile)
if string(content) != expectedContent {
t.Error("binary content append mismatch")
}
})
t.Run("append to read-only file", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping read-only test on Windows")
}
testFile := filepath.Join(tmpDir, "readonly.txt")
initialContent := "Initial content\n"
// Create file and make it read-only
os.WriteFile(testFile, []byte(initialContent), 0644)
os.Chmod(testFile, 0444) // read-only
defer os.Chmod(testFile, 0644) // restore for cleanup
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue("This should fail")
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
result := appendFile(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined when appending to read-only file")
}
})
}
func TestMkdirAll(t *testing.T) {
vm := otto.New()
// Create a temporary directory for testing
tmpDir, err := os.MkdirTemp("", "js_test_mkdirall_*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
t.Run("create single directory", func(t *testing.T) {
testDir := filepath.Join(tmpDir, "single")
arg, _ := vm.ToValue(testDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := mkdirAll(call)
// mkdirAll returns null on success
if !result.IsNull() {
t.Error("expected null return value for successful directory creation")
}
// Verify directory was created
info, err := os.Stat(testDir)
if err != nil {
t.Fatalf("directory was not created: %v", err)
}
if !info.IsDir() {
t.Error("expected directory, got file")
}
// Check permissions
if runtime.GOOS != "windows" {
if info.Mode().Perm() != 0755 {
t.Errorf("expected permissions 0755, got %v", info.Mode().Perm())
}
}
})
t.Run("create nested directories", func(t *testing.T) {
testDir := filepath.Join(tmpDir, "nested", "sub", "directories")
arg, _ := vm.ToValue(testDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := mkdirAll(call)
if !result.IsNull() {
t.Error("expected null return value for successful nested directory creation")
}
// Verify all directories in the path were created
currentPath := tmpDir
for _, part := range []string{"nested", "sub", "directories"} {
currentPath = filepath.Join(currentPath, part)
info, err := os.Stat(currentPath)
if err != nil {
t.Fatalf("directory %s was not created: %v", currentPath, err)
}
if !info.IsDir() {
t.Errorf("expected %s to be a directory", currentPath)
}
}
})
t.Run("create existing directory", func(t *testing.T) {
testDir := filepath.Join(tmpDir, "existing")
// Create directory first
os.Mkdir(testDir, 0755)
arg, _ := vm.ToValue(testDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := mkdirAll(call)
// Should succeed (mkdirAll is idempotent)
if !result.IsNull() {
t.Error("expected null return value when creating existing directory")
}
// Verify directory still exists
info, err := os.Stat(testDir)
if err != nil {
t.Fatalf("existing directory check failed: %v", err)
}
if !info.IsDir() {
t.Error("expected directory to still exist")
}
})
t.Run("create with file in path", func(t *testing.T) {
// Create a file that will block directory creation
blockingFile := filepath.Join(tmpDir, "blocking_file.txt")
os.WriteFile(blockingFile, []byte("blocking"), 0644)
testDir := filepath.Join(blockingFile, "subdir")
arg, _ := vm.ToValue(testDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := mkdirAll(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined when file blocks directory creation")
}
})
t.Run("create in read-only directory", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Skipping read-only test on Windows")
}
readOnlyDir := filepath.Join(tmpDir, "readonly")
os.Mkdir(readOnlyDir, 0755)
os.Chmod(readOnlyDir, 0555) // read-only
defer os.Chmod(readOnlyDir, 0755) // restore for cleanup
testDir := filepath.Join(readOnlyDir, "should_fail")
arg, _ := vm.ToValue(testDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := mkdirAll(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined when creating directory in read-only parent")
}
})
t.Run("create with special characters", func(t *testing.T) {
testDir := filepath.Join(tmpDir, "special-chars_123", "with.dots", "and spaces")
arg, _ := vm.ToValue(testDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
result := mkdirAll(call)
if !result.IsNull() {
t.Error("expected null return value for directory with special characters")
}
// Verify directory was created
info, err := os.Stat(testDir)
if err != nil {
t.Fatalf("directory with special characters was not created: %v", err)
}
if !info.IsDir() {
t.Error("expected directory")
}
})
t.Run("invalid arguments", func(t *testing.T) {
tests := []struct {
name string
args []otto.Value
}{
{
name: "no arguments",
args: []otto.Value{},
},
{
name: "too many arguments",
args: func() []otto.Value {
arg1, _ := vm.ToValue("/some/path")
arg2, _ := vm.ToValue("extra")
return []otto.Value{arg1, arg2}
}(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := otto.FunctionCall{
ArgumentList: tt.args,
}
result := mkdirAll(call)
// Should return undefined (error)
if !result.IsUndefined() {
t.Error("expected undefined for invalid arguments")
}
})
}
})
}
func TestFileSystemIntegration(t *testing.T) {
vm := otto.New()
// Create a temporary directory for testing
tmpDir, err := os.MkdirTemp("", "js_test_integration_*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
t.Run("write, append, then read file", func(t *testing.T) {
testDir := filepath.Join(tmpDir, "nested", "sub", "directories")
testFile := filepath.Join(testDir, "roundtrip.txt")
initialContent := "Round-trip test content\nLine 2\nLine 3\n"
appendedContent := "Appended content\n"
expectedContent := initialContent + appendedContent
// Create subdirectories
argDir, _ := vm.ToValue(testDir)
mkdirCall := otto.FunctionCall{
ArgumentList: []otto.Value{argDir},
}
mkdirResult := mkdirAll(mkdirCall)
if !mkdirResult.IsNull() {
t.Error("mkdirAll failed")
}
// Write file
argFile, _ := vm.ToValue(testFile)
argInitial, _ := vm.ToValue(initialContent)
writeCall := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argInitial},
}
writeResult := writeFile(writeCall)
if !writeResult.IsNull() {
t.Fatal("write failed")
}
// Append content
argAppend, _ := vm.ToValue(appendedContent)
appendCall := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argAppend},
}
appendResult := appendFile(appendCall)
if !appendResult.IsNull() {
t.Fatal("append failed")
}
// Read file back
readCall := otto.FunctionCall{
ArgumentList: []otto.Value{argFile},
}
readResult := readFile(readCall)
if readResult.IsUndefined() {
t.Fatal("read failed")
}
readContent, _ := readResult.ToString()
if readContent != expectedContent {
t.Errorf("round-trip failed: expected %q, got %q", expectedContent, readContent)
}
})
t.Run("create files then list directory", func(t *testing.T) {
// Create multiple files
files := []string{"file1.txt", "file2.txt", "file3.txt"}
for _, name := range files {
path := filepath.Join(tmpDir, name)
argFile, _ := vm.ToValue(path)
argContent, _ := vm.ToValue("content of " + name)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
writeFile(call)
}
// List directory
argDir, _ := vm.ToValue(tmpDir)
listCall := otto.FunctionCall{
Otto: vm,
ArgumentList: []otto.Value{argDir},
}
listResult := readDir(listCall)
if listResult.IsUndefined() {
t.Fatal("readDir failed")
}
export, _ := listResult.Export()
entries, _ := export.([]string)
// Check all files are listed
for _, expected := range files {
found := false
for _, entry := range entries {
if entry == expected {
found = true
break
}
}
if !found {
t.Errorf("expected file %s not found in directory listing", expected)
}
}
})
}
func BenchmarkReadFile(b *testing.B) {
vm := otto.New()
// Create test file
tmpFile, _ := os.CreateTemp("", "bench_readfile_*")
defer os.Remove(tmpFile.Name())
content := strings.Repeat("Benchmark test content line\n", 100)
os.WriteFile(tmpFile.Name(), []byte(content), 0644)
arg, _ := vm.ToValue(tmpFile.Name())
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = readFile(call)
}
}
func BenchmarkWriteFile(b *testing.B) {
vm := otto.New()
tmpDir, _ := os.MkdirTemp("", "bench_writefile_*")
defer os.RemoveAll(tmpDir)
content := strings.Repeat("Benchmark test content line\n", 100)
b.ResetTimer()
for i := 0; i < b.N; i++ {
testFile := filepath.Join(tmpDir, fmt.Sprintf("bench_%d.txt", i))
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(content)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
_ = writeFile(call)
}
}
func BenchmarkAppendFile(b *testing.B) {
vm := otto.New()
tmpDir, _ := os.MkdirTemp("", "bench_appendfile_*")
defer os.RemoveAll(tmpDir)
// Create initial file with some content
testFile := filepath.Join(tmpDir, "bench_append.txt")
initialContent := "Initial content for benchmark\n"
os.WriteFile(testFile, []byte(initialContent), 0644)
content := strings.Repeat("Benchmark append line\n", 10)
argFile, _ := vm.ToValue(testFile)
argContent, _ := vm.ToValue(content)
call := otto.FunctionCall{
ArgumentList: []otto.Value{argFile, argContent},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = appendFile(call)
}
}
func BenchmarkMkdirAll(b *testing.B) {
vm := otto.New()
tmpDir, _ := os.MkdirTemp("", "bench_mkdirall_*")
defer os.RemoveAll(tmpDir)
b.ResetTimer()
for i := 0; i < b.N; i++ {
testDir := filepath.Join(tmpDir, fmt.Sprintf("bench_%d", i), "nested", "sub", "directories")
arg, _ := vm.ToValue(testDir)
call := otto.FunctionCall{
ArgumentList: []otto.Value{arg},
}
_ = mkdirAll(call)
}
}
func BenchmarkReadDir(b *testing.B) {
vm := otto.New()
// Create test directory with files
tmpDir, _ := os.MkdirTemp("", "bench_readdir_*")
defer os.RemoveAll(tmpDir)
// Create 100 files
for i := 0; i < 100; i++ {
name := filepath.Join(tmpDir, fmt.Sprintf("file_%d.txt", i))
os.WriteFile(name, []byte("test"), 0644)
}
arg, _ := vm.ToValue(tmpDir)
call := otto.FunctionCall{
Otto: vm,
ArgumentList: []otto.Value{arg},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = readDir(call)
}
}
================================================
FILE: js/http.go
================================================
package js
import (
"bytes"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"github.com/robertkrimen/otto"
)
type httpPackage struct {
}
type httpResponse struct {
Error error
Response *http.Response
Raw []byte
Body string
JSON interface{}
}
func (c httpPackage) Encode(s string) string {
return url.QueryEscape(s)
}
func (c httpPackage) Request(method string, uri string,
headers map[string]string,
form map[string]string,
json string) httpResponse {
var reader io.Reader
if form != nil {
data := url.Values{}
for k, v := range form {
data.Set(k, v)
}
reader = bytes.NewBufferString(data.Encode())
} else if json != "" {
reader = strings.NewReader(json)
}
req, err := http.NewRequest(method, uri, reader)
if err != nil {
return httpResponse{Error: err}
}
if form != nil {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} else if json != "" {
req.Header.Set("Content-Type", "application/json")
}
for name, value := range headers {
req.Header.Add(name, value)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return httpResponse{Error: err}
}
defer resp.Body.Close()
raw, err := io.ReadAll(resp.Body)
if err != nil {
return httpResponse{Error: err}
}
res := httpResponse{
Response: resp,
Raw: raw,
Body: string(raw),
}
if resp.StatusCode != http.StatusOK {
res.Error = fmt.Errorf("%s", resp.Status)
}
return res
}
func (c httpPackage) Get(url string, headers map[string]string) httpResponse {
return c.Request("GET", url, headers, nil, "")
}
func (c httpPackage) PostForm(url string, headers map[string]string, form map[string]string) httpResponse {
return c.Request("POST", url, headers, form, "")
}
func (c httpPackage) PostJSON(url string, headers map[string]string, json string) httpResponse {
return c.Request("POST", url, headers, nil, json)
}
func httpRequest(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
if argc < 2 {
return ReportError("httpRequest: expected 2 or more, %d given instead.", argc)
}
method := argv[0].String()
url := argv[1].String()
client := &http.Client{}
req, err := http.NewRequest(method, url, nil)
if argc >= 3 {
data := argv[2].String()
req, err = http.NewRequest(method, url, bytes.NewBuffer([]byte(data)))
if err != nil {
return ReportError("Could create request to url %s: %s", url, err)
}
if argc > 3 {
headers := argv[3].Object()
for _, key := range headers.Keys() {
v, err := headers.Get(key)
if err != nil {
return ReportError("Could add header %s to request: %s", key, err)
}
req.Header.Add(key, v.String())
}
}
} else if err != nil {
return ReportError("Could create request to url %s: %s", url, err)
}
resp, err := client.Do(req)
if err != nil {
return ReportError("Could not request url %s: %s", url, err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return ReportError("Could not read response: %s", err)
}
object, err := otto.New().Object("({})")
if err != nil {
return ReportError("Could not create response object: %s", err)
}
err = object.Set("body", string(body))
if err != nil {
return ReportError("Could not populate response object: %s", err)
}
v, err := otto.ToValue(object)
if err != nil {
return ReportError("Could not convert to object: %s", err)
}
return v
}
================================================
FILE: js/init.go
================================================
package js
import (
"github.com/evilsocket/islazy/log"
"github.com/evilsocket/islazy/plugin"
"github.com/robertkrimen/otto"
)
var NullValue = otto.Value{}
func ReportError(format string, args ...interface{}) otto.Value {
log.Error(format, args...)
return NullValue
}
func init() {
// TODO: refactor this in packages
plugin.Defines["mkdirAll"] = mkdirAll
plugin.Defines["readDir"] = readDir
plugin.Defines["readFile"] = readFile
plugin.Defines["writeFile"] = writeFile
plugin.Defines["appendFile"] = appendFile
plugin.Defines["log"] = flog
plugin.Defines["log_debug"] = log_debug
plugin.Defines["log_info"] = log_info
plugin.Defines["log_warn"] = log_warn
plugin.Defines["log_error"] = log_error
plugin.Defines["log_fatal"] = log_fatal
plugin.Defines["Crypto"] = map[string]interface{}{
"sha1": cryptoSha1,
}
plugin.Defines["btoa"] = btoa
plugin.Defines["atob"] = atob
plugin.Defines["gzipCompress"] = gzipCompress
plugin.Defines["gzipDecompress"] = gzipDecompress
plugin.Defines["textEncode"] = textEncode
plugin.Defines["textDecode"] = textDecode
plugin.Defines["httpRequest"] = httpRequest
plugin.Defines["http"] = httpPackage{}
plugin.Defines["random"] = randomPackage{}
}
================================================
FILE: js/log.go
================================================
package js
import (
"github.com/evilsocket/islazy/log"
"github.com/robertkrimen/otto"
)
func flog(call otto.FunctionCall) otto.Value {
for _, v := range call.ArgumentList {
log.Info("%s", v.String())
}
return otto.Value{}
}
func log_debug(call otto.FunctionCall) otto.Value {
for _, v := range call.ArgumentList {
log.Debug("%s", v.String())
}
return otto.Value{}
}
func log_info(call otto.FunctionCall) otto.Value {
for _, v := range call.ArgumentList {
log.Info("%s", v.String())
}
return otto.Value{}
}
func log_warn(call otto.FunctionCall) otto.Value {
for _, v := range call.ArgumentList {
log.Warning("%s", v.String())
}
return otto.Value{}
}
func log_error(call otto.FunctionCall) otto.Value {
for _, v := range call.ArgumentList {
log.Error("%s", v.String())
}
return otto.Value{}
}
func log_fatal(call otto.FunctionCall) otto.Value {
for _, v := range call.ArgumentList {
log.Fatal("%s", v.String())
}
return otto.Value{}
}
================================================
FILE: js/random.go
================================================
package js
import (
"math/rand"
"net"
"github.com/bettercap/bettercap/v2/network"
)
type randomPackage struct {
}
func (c randomPackage) String(size int, charset string) string {
runes := []rune(charset)
nrunes := len(runes)
buf := make([]rune, size)
for i := range buf {
buf[i] = runes[rand.Intn(nrunes)]
}
return string(buf)
}
func (c randomPackage) Mac() string {
hw := make([]byte, 6)
rand.Read(hw)
return network.NormalizeMac(net.HardwareAddr(hw).String())
}
================================================
FILE: js/random_test.go
================================================
package js
import (
"net"
"regexp"
"strings"
"testing"
)
func TestRandomString(t *testing.T) {
r := randomPackage{}
tests := []struct {
name string
size int
charset string
}{
{
name: "alphanumeric",
size: 10,
charset: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
},
{
name: "numbers only",
size: 20,
charset: "0123456789",
},
{
name: "lowercase letters",
size: 15,
charset: "abcdefghijklmnopqrstuvwxyz",
},
{
name: "uppercase letters",
size: 8,
charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
},
{
name: "special characters",
size: 12,
charset: "!@#$%^&*()_+-=[]{}|;:,.<>?",
},
{
name: "unicode characters",
size: 5,
charset: "αβγδεζηθικλμνξοπρστυφχψω",
},
{
name: "mixed unicode and ascii",
size: 10,
charset: "abc123αβγ",
},
{
name: "single character",
size: 100,
charset: "a",
},
{
name: "empty size",
size: 0,
charset: "abcdef",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := r.String(tt.size, tt.charset)
// Check length
if len([]rune(result)) != tt.size {
t.Errorf("expected length %d, got %d", tt.size, len([]rune(result)))
}
// Check that all characters are from the charset
for _, char := range result {
if !strings.ContainsRune(tt.charset, char) {
t.Errorf("character %c not in charset %s", char, tt.charset)
}
}
})
}
}
func TestRandomStringDistribution(t *testing.T) {
r := randomPackage{}
charset := "ab"
size := 1000
// Generate many single-character strings
counts := make(map[rune]int)
for i := 0; i < size; i++ {
result := r.String(1, charset)
if len(result) == 1 {
counts[rune(result[0])]++
}
}
// Check that both characters appear (very high probability)
if len(counts) != 2 {
t.Errorf("expected both characters to appear, got %d unique characters", len(counts))
}
// Check distribution is reasonable (not perfect due to randomness)
for char, count := range counts {
ratio := float64(count) / float64(size)
if ratio < 0.3 || ratio > 0.7 {
t.Errorf("character %c appeared %d times (%.2f%%), expected around 50%%",
char, count, ratio*100)
}
}
}
func TestRandomMac(t *testing.T) {
r := randomPackage{}
macRegex := regexp.MustCompile(`^([0-9a-f]{2}:){5}[0-9a-f]{2}$`)
// Generate multiple MAC addresses
macs := make(map[string]bool)
for i := 0; i < 100; i++ {
mac := r.Mac()
// Check format
if !macRegex.MatchString(mac) {
t.Errorf("invalid MAC format: %s", mac)
}
// Check it's a valid MAC
_, err := net.ParseMAC(mac)
if err != nil {
t.Errorf("invalid MAC address: %s, error: %v", mac, err)
}
// Store for uniqueness check
macs[mac] = true
}
// Check that we get different MACs (very high probability)
if len(macs) < 95 {
t.Errorf("expected at least 95 unique MACs out of 100, got %d", len(macs))
}
}
func TestRandomMacNormalization(t *testing.T) {
r := randomPackage{}
// Generate several MACs and check they're normalized
for i := 0; i < 10; i++ {
mac := r.Mac()
// Check lowercase
if mac != strings.ToLower(mac) {
t.Errorf("MAC not normalized to lowercase: %s", mac)
}
// Check separator is colon
if strings.Contains(mac, "-") {
t.Errorf("MAC contains hyphen instead of colon: %s", mac)
}
// Check length
if len(mac) != 17 { // 6 bytes * 2 chars + 5 colons
t.Errorf("MAC has wrong length: %s (len=%d)", mac, len(mac))
}
}
}
func TestRandomStringEdgeCases(t *testing.T) {
r := randomPackage{}
// Test with various edge cases
tests := []struct {
name string
size int
charset string
}{
{
name: "zero size",
size: 0,
charset: "abc",
},
{
name: "very large size",
size: 10000,
charset: "abc",
},
{
name: "size larger than charset",
size: 10,
charset: "ab",
},
{
name: "single char charset with large size",
size: 1000,
charset: "x",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := r.String(tt.size, tt.charset)
if len([]rune(result)) != tt.size {
t.Errorf("expected length %d, got %d", tt.size, len([]rune(result)))
}
// Check all characters are from charset
for _, c := range result {
if !strings.ContainsRune(tt.charset, c) {
t.Errorf("character %c not in charset %s", c, tt.charset)
}
}
})
}
}
func TestRandomStringNegativeSize(t *testing.T) {
r := randomPackage{}
// Test that negative size causes panic
defer func() {
if r := recover(); r == nil {
t.Error("expected panic for negative size but didn't get one")
}
}()
// This should panic
_ = r.String(-1, "abc")
}
func TestRandomPackageInstance(t *testing.T) {
// Test that we can create multiple instances
r1 := randomPackage{}
r2 := randomPackage{}
// Both should work independently
s1 := r1.String(5, "abc")
s2 := r2.String(5, "xyz")
if len(s1) != 5 {
t.Errorf("r1.String returned wrong length: %d", len(s1))
}
if len(s2) != 5 {
t.Errorf("r2.String returned wrong length: %d", len(s2))
}
// Check correct charset usage
for _, c := range s1 {
if !strings.ContainsRune("abc", c) {
t.Errorf("r1 produced character outside charset: %c", c)
}
}
for _, c := range s2 {
if !strings.ContainsRune("xyz", c) {
t.Errorf("r2 produced character outside charset: %c", c)
}
}
}
func BenchmarkRandomString(b *testing.B) {
r := randomPackage{}
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012
gitextract_w8thaqpx/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── config.yml
│ │ └── default_issue.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-and-deploy.yml
│ ├── build-and-push-docker.yml
│ ├── test-on-linux.yml
│ ├── test-on-macos.yml
│ └── test-on-windows.yml
├── .gitignore
├── Dockerfile
├── Dockerfile.arm64
├── LICENSE.md
├── Makefile
├── README.md
├── SECURITY.md
├── bettercap.service
├── caplets/
│ ├── caplet.go
│ ├── caplet_test.go
│ ├── doc.go
│ ├── env.go
│ ├── env_test.go
│ ├── manager.go
│ └── manager_test.go
├── core/
│ ├── banner.go
│ ├── banner_test.go
│ ├── core.go
│ ├── core_android.go
│ ├── core_test.go
│ ├── core_unix.go
│ ├── core_windows.go
│ ├── doc.go
│ └── options.go
├── firewall/
│ ├── doc.go
│ ├── firewall.go
│ ├── firewall_darwin.go
│ ├── firewall_linux.go
│ ├── firewall_windows.go
│ ├── redirection.go
│ └── redirection_test.go
├── go.mod
├── go.sum
├── js/
│ ├── crypto.go
│ ├── data.go
│ ├── data_test.go
│ ├── fs.go
│ ├── fs_test.go
│ ├── http.go
│ ├── init.go
│ ├── log.go
│ ├── random.go
│ └── random_test.go
├── log/
│ ├── doc.go
│ ├── log.go
│ └── log_test.go
├── main.go
├── main_test.go
├── modules/
│ ├── any_proxy/
│ │ ├── any_proxy.go
│ │ └── any_proxy_test.go
│ ├── api_rest/
│ │ ├── api_rest.go
│ │ ├── api_rest_controller.go
│ │ ├── api_rest_record.go
│ │ ├── api_rest_replay.go
│ │ ├── api_rest_test.go
│ │ └── api_rest_ws.go
│ ├── arp_spoof/
│ │ ├── arp_spoof.go
│ │ └── arp_spoof_test.go
│ ├── ble/
│ │ ├── ble_options_darwin.go
│ │ ├── ble_options_linux.go
│ │ ├── ble_recon.go
│ │ ├── ble_recon_events.go
│ │ ├── ble_recon_test.go
│ │ ├── ble_show.go
│ │ ├── ble_show_services.go
│ │ ├── ble_show_sort.go
│ │ └── ble_unsupported.go
│ ├── c2/
│ │ ├── c2.go
│ │ └── c2_test.go
│ ├── can/
│ │ ├── can.go
│ │ ├── can_dbc.go
│ │ ├── can_dbc_compile.go
│ │ ├── can_dbc_load.go
│ │ ├── can_dump_reader.go
│ │ ├── can_fuzz.go
│ │ ├── can_inject.go
│ │ ├── can_message.go
│ │ ├── can_obd2.go
│ │ ├── can_obd2_message.go
│ │ ├── can_obd2_pid_request.go
│ │ ├── can_obd2_pid_response.go
│ │ ├── can_recon.go
│ │ ├── can_show.go
│ │ └── can_test.go
│ ├── caplets/
│ │ └── caplets.go
│ ├── dhcp6_spoof/
│ │ └── dhcp6_spoof.go
│ ├── dns_proxy/
│ │ ├── dns_proxy.go
│ │ ├── dns_proxy_base.go
│ │ ├── dns_proxy_base_filters.go
│ │ ├── dns_proxy_js_query.go
│ │ ├── dns_proxy_js_record.go
│ │ ├── dns_proxy_js_record_edns0.go
│ │ ├── dns_proxy_js_record_svcb.go
│ │ └── dns_proxy_script.go
│ ├── dns_spoof/
│ │ ├── dns_spoof.go
│ │ └── dns_spoof_hosts.go
│ ├── doc.go
│ ├── events_stream/
│ │ ├── events_rotation.go
│ │ ├── events_stream.go
│ │ ├── events_triggers.go
│ │ ├── events_view.go
│ │ ├── events_view_ble.go
│ │ ├── events_view_ble_unsupported.go
│ │ ├── events_view_can.go
│ │ ├── events_view_gateway.go
│ │ ├── events_view_gps.go
│ │ ├── events_view_hid.go
│ │ ├── events_view_http.go
│ │ ├── events_view_wifi.go
│ │ ├── events_view_zeroconf.go
│ │ └── trigger_list.go
│ ├── gps/
│ │ └── gps.go
│ ├── graph/
│ │ ├── create.go
│ │ ├── create_ble.go
│ │ ├── create_ble_unsupported.go
│ │ ├── edge.go
│ │ ├── edges.go
│ │ ├── graph.go
│ │ ├── js_builtin.go
│ │ ├── module.go
│ │ ├── node.go
│ │ ├── stack.go
│ │ ├── to_dot.go
│ │ └── to_json.go
│ ├── hid/
│ │ ├── build_amazon.go
│ │ ├── build_logitech.go
│ │ ├── build_microsoft.go
│ │ ├── builders.go
│ │ ├── command.go
│ │ ├── duckyparser.go
│ │ ├── hid.go
│ │ ├── hid_inject.go
│ │ ├── hid_recon.go
│ │ ├── hid_show.go
│ │ ├── hid_show_sort.go
│ │ ├── hid_sniff.go
│ │ └── keymaps.go
│ ├── http_proxy/
│ │ ├── http_proxy.go
│ │ ├── http_proxy_base.go
│ │ ├── http_proxy_base_cookietracker.go
│ │ ├── http_proxy_base_filters.go
│ │ ├── http_proxy_base_hosttracker.go
│ │ ├── http_proxy_base_sslstriper.go
│ │ ├── http_proxy_cert_cache.go
│ │ ├── http_proxy_js_request.go
│ │ ├── http_proxy_js_response.go
│ │ ├── http_proxy_script.go
│ │ └── http_proxy_test.go
│ ├── http_server/
│ │ └── http_server.go
│ ├── https_proxy/
│ │ └── https_proxy.go
│ ├── https_server/
│ │ └── https_server.go
│ ├── mac_changer/
│ │ └── mac_changer.go
│ ├── modules.go
│ ├── modules_test.go
│ ├── mysql_server/
│ │ └── mysql_server.go
│ ├── ndp_spoof/
│ │ └── ndp_spoof.go
│ ├── net_probe/
│ │ ├── net_probe.go
│ │ ├── net_probe_nbns.go
│ │ ├── net_probe_test.go
│ │ ├── net_probe_upnp.go
│ │ └── net_probe_wsd.go
│ ├── net_recon/
│ │ ├── net_recon.go
│ │ ├── net_recon_test.go
│ │ ├── net_show.go
│ │ └── net_show_sort.go
│ ├── net_sniff/
│ │ ├── net_sniff.go
│ │ ├── net_sniff_context.go
│ │ ├── net_sniff_dns.go
│ │ ├── net_sniff_dot11.go
│ │ ├── net_sniff_event.go
│ │ ├── net_sniff_ftp.go
│ │ ├── net_sniff_fuzz.go
│ │ ├── net_sniff_http.go
│ │ ├── net_sniff_krb5.go
│ │ ├── net_sniff_mdns.go
│ │ ├── net_sniff_ntlm.go
│ │ ├── net_sniff_parsers.go
│ │ ├── net_sniff_sni.go
│ │ ├── net_sniff_stats.go
│ │ ├── net_sniff_tcp.go
│ │ ├── net_sniff_teamviewer.go
│ │ ├── net_sniff_udp.go
│ │ ├── net_sniff_upnp.go
│ │ └── net_sniff_views.go
│ ├── packet_proxy/
│ │ ├── packet_proxy_darwin.go
│ │ ├── packet_proxy_freebsd.go
│ │ ├── packet_proxy_linux.go
│ │ └── packet_proxy_windows.go
│ ├── syn_scan/
│ │ ├── banner_grabbing.go
│ │ ├── dns_grabber.go
│ │ ├── http_grabber.go
│ │ ├── syn_scan.go
│ │ ├── syn_scan_event.go
│ │ ├── syn_scan_parsers.go
│ │ ├── syn_scan_reader.go
│ │ └── tcp_grabber.go
│ ├── tcp_proxy/
│ │ ├── tcp_proxy.go
│ │ ├── tcp_proxy_script.go
│ │ └── tcp_proxy_script_test.go
│ ├── ticker/
│ │ ├── ticker.go
│ │ └── ticker_test.go
│ ├── ui/
│ │ ├── ui/
│ │ │ ├── assets/
│ │ │ │ ├── fontawesome/
│ │ │ │ │ ├── LICENSE.txt
│ │ │ │ │ ├── css/
│ │ │ │ │ │ ├── all.css
│ │ │ │ │ │ ├── brands.css
│ │ │ │ │ │ ├── fontawesome.css
│ │ │ │ │ │ ├── regular.css
│ │ │ │ │ │ ├── solid.css
│ │ │ │ │ │ ├── svg-with-js.css
│ │ │ │ │ │ └── v4-shims.css
│ │ │ │ │ ├── js/
│ │ │ │ │ │ ├── all.js
│ │ │ │ │ │ ├── brands.js
│ │ │ │ │ │ ├── fontawesome.js
│ │ │ │ │ │ ├── regular.js
│ │ │ │ │ │ ├── solid.js
│ │ │ │ │ │ └── v4-shims.js
│ │ │ │ │ ├── less/
│ │ │ │ │ │ ├── _animated.less
│ │ │ │ │ │ ├── _bordered-pulled.less
│ │ │ │ │ │ ├── _core.less
│ │ │ │ │ │ ├── _fixed-width.less
│ │ │ │ │ │ ├── _icons.less
│ │ │ │ │ │ ├── _larger.less
│ │ │ │ │ │ ├── _list.less
│ │ │ │ │ │ ├── _mixins.less
│ │ │ │ │ │ ├── _rotated-flipped.less
│ │ │ │ │ │ ├── _screen-reader.less
│ │ │ │ │ │ ├── _shims.less
│ │ │ │ │ │ ├── _stacked.less
│ │ │ │ │ │ ├── _variables.less
│ │ │ │ │ │ ├── brands.less
│ │ │ │ │ │ ├── fontawesome.less
│ │ │ │ │ │ ├── regular.less
│ │ │ │ │ │ ├── solid.less
│ │ │ │ │ │ └── v4-shims.less
│ │ │ │ │ ├── metadata/
│ │ │ │ │ │ ├── categories.yml
│ │ │ │ │ │ ├── icons.json
│ │ │ │ │ │ ├── icons.yml
│ │ │ │ │ │ ├── shims.json
│ │ │ │ │ │ ├── shims.yml
│ │ │ │ │ │ └── sponsors.yml
│ │ │ │ │ └── scss/
│ │ │ │ │ ├── _animated.scss
│ │ │ │ │ ├── _bordered-pulled.scss
│ │ │ │ │ ├── _core.scss
│ │ │ │ │ ├── _fixed-width.scss
│ │ │ │ │ ├── _icons.scss
│ │ │ │ │ ├── _larger.scss
│ │ │ │ │ ├── _list.scss
│ │ │ │ │ ├── _mixins.scss
│ │ │ │ │ ├── _rotated-flipped.scss
│ │ │ │ │ ├── _screen-reader.scss
│ │ │ │ │ ├── _shims.scss
│ │ │ │ │ ├── _stacked.scss
│ │ │ │ │ ├── _variables.scss
│ │ │ │ │ ├── brands.scss
│ │ │ │ │ ├── fontawesome.scss
│ │ │ │ │ ├── regular.scss
│ │ │ │ │ ├── solid.scss
│ │ │ │ │ └── v4-shims.scss
│ │ │ │ └── openlayers/
│ │ │ │ ├── ol.css
│ │ │ │ └── ol.js
│ │ │ ├── index.html
│ │ │ ├── main.js
│ │ │ ├── polyfills.js
│ │ │ ├── runtime.js
│ │ │ ├── scripts.js
│ │ │ ├── styles.js
│ │ │ └── vendor.js
│ │ └── ui.go
│ ├── update/
│ │ ├── update.go
│ │ └── update_test.go
│ ├── utils/
│ │ ├── view_selector.go
│ │ └── view_selector_test.go
│ ├── wifi/
│ │ ├── wifi.go
│ │ ├── wifi_ap.go
│ │ ├── wifi_assoc.go
│ │ ├── wifi_bruteforce.go
│ │ ├── wifi_bruteforce_darwin.go
│ │ ├── wifi_bruteforce_linux.go
│ │ ├── wifi_bruteforce_unsupported.go
│ │ ├── wifi_csa.go
│ │ ├── wifi_deauth.go
│ │ ├── wifi_events.go
│ │ ├── wifi_fake_auth.go
│ │ ├── wifi_hopping.go
│ │ ├── wifi_inject.go
│ │ ├── wifi_inject_darwin.go
│ │ ├── wifi_recon.go
│ │ ├── wifi_recon_handshakes.go
│ │ ├── wifi_show.go
│ │ ├── wifi_show_sort.go
│ │ └── wifi_test.go
│ ├── wol/
│ │ ├── wol.go
│ │ └── wol_test.go
│ └── zerogod/
│ ├── zeroconf/
│ │ ├── client.go
│ │ ├── connection.go
│ │ ├── doc.go
│ │ ├── server.go
│ │ ├── service.go
│ │ └── utils.go
│ ├── zerogod.go
│ ├── zerogod_acceptor.go
│ ├── zerogod_advertise.go
│ ├── zerogod_browser.go
│ ├── zerogod_discovery.go
│ ├── zerogod_endpoint_update.go
│ ├── zerogod_generic_tcp_handler.go
│ ├── zerogod_http_handler.go
│ ├── zerogod_ipp_get_job_attributes.go
│ ├── zerogod_ipp_get_jobs.go
│ ├── zerogod_ipp_get_printer_attributes.go
│ ├── zerogod_ipp_handler.go
│ ├── zerogod_ipp_primitives.go
│ ├── zerogod_ipp_print_job.go
│ ├── zerogod_ipp_unhandled.go
│ ├── zerogod_ipp_validate_job.go
│ ├── zerogod_known_services.go
│ ├── zerogod_save.go
│ ├── zerogod_service.go
│ ├── zerogod_show.go
│ └── zerogod_test.go
├── network/
│ ├── arp.go
│ ├── arp_parser_darwin.go
│ ├── arp_parser_linux.go
│ ├── arp_parser_windows.go
│ ├── ble.go
│ ├── ble_device.go
│ ├── ble_unsupported.go
│ ├── can.go
│ ├── can_device.go
│ ├── debug.go
│ ├── doc.go
│ ├── hid.go
│ ├── hid_device.go
│ ├── lan.go
│ ├── lan_endpoint.go
│ ├── lan_test.go
│ ├── make_manuf.py
│ ├── manuf/
│ │ ├── cid.csv
│ │ ├── iab.csv
│ │ ├── mam.csv
│ │ ├── oui.csv
│ │ └── oui36.csv
│ ├── manuf.go
│ ├── manuf.go.template
│ ├── meta.go
│ ├── meta_test.go
│ ├── net.go
│ ├── net_darwin.go
│ ├── net_darwin.m
│ ├── net_gateway.go
│ ├── net_gateway_android.go
│ ├── net_linux.go
│ ├── net_test.go
│ ├── net_wifi.go
│ ├── net_windows.go
│ ├── pcap.go
│ ├── services.go
│ ├── wifi.go
│ ├── wifi_ap.go
│ ├── wifi_handshake.go
│ ├── wifi_station.go
│ └── wifi_test.go
├── packets/
│ ├── arp.go
│ ├── arp_test.go
│ ├── dhcp6.go
│ ├── dhcp6_layer.go
│ ├── dhcp6_layer_test.go
│ ├── dhcp6_test.go
│ ├── doc.go
│ ├── dot11.go
│ ├── dot11_test.go
│ ├── dot11_types.go
│ ├── dot11_types_test.go
│ ├── dot11_wps.go
│ ├── dot11_wps_attrs.go
│ ├── icmp6.go
│ ├── icmp6_test.go
│ ├── krb5.go
│ ├── krb5_test.go
│ ├── mdns.go
│ ├── mdns_test.go
│ ├── mysql.go
│ ├── mysql_test.go
│ ├── nbns.go
│ ├── nbns_test.go
│ ├── ntlm.go
│ ├── ntlm_test.go
│ ├── queue.go
│ ├── queue_test.go
│ ├── serialize.go
│ ├── serialize_test.go
│ ├── tcp.go
│ ├── tcp_test.go
│ ├── teamviewer.go
│ ├── udp.go
│ ├── udp_test.go
│ ├── upnp.go
│ └── wsd.go
├── release.py
├── routing/
│ ├── route.go
│ ├── route_test.go
│ ├── tables.go
│ ├── tables_test.go
│ ├── update_darwin.go
│ ├── update_linux.go
│ └── update_windows.go
├── session/
│ ├── command_handler.go
│ ├── command_handler_test.go
│ ├── doc.go
│ ├── environment.go
│ ├── environment_test.go
│ ├── events.go
│ ├── events_ignore_list.go
│ ├── events_test.go
│ ├── module.go
│ ├── module_handler.go
│ ├── module_handler_test.go
│ ├── module_param.go
│ ├── module_param_test.go
│ ├── prompt.go
│ ├── script.go
│ ├── script_builtin.go
│ ├── script_builtin_runtime.go
│ ├── session.go
│ ├── session_completers.go
│ ├── session_core_handlers.go
│ ├── session_json.go
│ ├── session_parse.go
│ ├── session_routing.go
│ ├── session_setup.go
│ ├── session_setup_test.go
│ └── session_test.go
└── tls/
├── cert.go
├── doc.go
├── sign.go
└── tls_test.go
Showing preview only (707K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (7941 symbols across 350 files)
FILE: caplets/caplet.go
type Script (line 11) | type Script struct
function newScript (line 17) | func newScript(path string, size int64) Script {
type Caplet (line 25) | type Caplet struct
method Eval (line 39) | func (cap *Caplet) Eval(argv []string, lineCb func(line string) error)...
function NewCaplet (line 31) | func NewCaplet(name string, path string, size int64) Caplet {
FILE: caplets/caplet_test.go
function TestNewCaplet (line 11) | func TestNewCaplet(t *testing.T) {
function TestCapletEval (line 35) | func TestCapletEval(t *testing.T) {
function TestCapletEvalError (line 142) | func TestCapletEvalError(t *testing.T) {
function TestCapletEvalWithChdirPath (line 178) | func TestCapletEvalWithChdirPath(t *testing.T) {
function TestNewScript (line 204) | func TestNewScript(t *testing.T) {
function TestCapletEvalCommentAtStartOfLine (line 224) | func TestCapletEvalCommentAtStartOfLine(t *testing.T) {
function TestCapletEvalArgvSubstitutionEdgeCases (line 268) | func TestCapletEvalArgvSubstitutionEdgeCases(t *testing.T) {
function TestCapletStructFields (line 324) | func TestCapletStructFields(t *testing.T) {
function BenchmarkCapletEval (line 345) | func BenchmarkCapletEval(b *testing.B) {
function BenchmarkVariableSubstitution (line 366) | func BenchmarkVariableSubstitution(b *testing.B) {
FILE: caplets/env.go
constant EnvVarName (line 13) | EnvVarName = "CAPSPATH"
constant Suffix (line 14) | Suffix = ".cap"
constant InstallArchive (line 15) | InstallArchive = "https://github.com/bettercap/caplets/archive/master.zip"
function getDefaultInstallBase (line 18) | func getDefaultInstallBase() string {
function getUserHomeDir (line 25) | func getUserHomeDir() string {
function Setup (line 38) | func Setup(base string) error {
function init (line 64) | func init() {
FILE: caplets/env_test.go
function TestGetDefaultInstallBase (line 11) | func TestGetDefaultInstallBase(t *testing.T) {
function TestGetUserHomeDir (line 27) | func TestGetUserHomeDir(t *testing.T) {
function TestSetup (line 41) | func TestSetup(t *testing.T) {
function TestSetupWithEnvironmentVariable (line 114) | func TestSetupWithEnvironmentVariable(t *testing.T) {
function TestSetupWithEmptyEnvironmentVariable (line 153) | func TestSetupWithEmptyEnvironmentVariable(t *testing.T) {
function TestSetupWithWhitespaceInEnvironmentVariable (line 181) | func TestSetupWithWhitespaceInEnvironmentVariable(t *testing.T) {
function TestConstants (line 222) | func TestConstants(t *testing.T) {
function TestInit (line 237) | func TestInit(t *testing.T) {
function TestSetupMultipleTimes (line 261) | func TestSetupMultipleTimes(t *testing.T) {
function BenchmarkSetup (line 289) | func BenchmarkSetup(b *testing.B) {
FILE: caplets/manager.go
function List (line 20) | func List() []*Caplet {
function Load (line 47) | func Load(name string) (*Caplet, error) {
FILE: caplets/manager_test.go
function createTestCaplet (line 14) | func createTestCaplet(t testing.TB, dir string, name string, content []s...
function TestList (line 24) | func TestList(t *testing.T) {
function TestListEmptyDirectories (line 86) | func TestListEmptyDirectories(t *testing.T) {
function TestLoad (line 115) | func TestLoad(t *testing.T) {
function TestLoadAbsolutePath (line 182) | func TestLoadAbsolutePath(t *testing.T) {
function TestLoadNotFound (line 216) | func TestLoadNotFound(t *testing.T) {
function TestLoadWithFolder (line 242) | func TestLoadWithFolder(t *testing.T) {
function TestCacheConcurrency (line 328) | func TestCacheConcurrency(t *testing.T) {
function TestLoadPathPriority (line 387) | func TestLoadPathPriority(t *testing.T) {
function BenchmarkLoad (line 424) | func BenchmarkLoad(b *testing.B) {
function BenchmarkLoadFromCache (line 455) | func BenchmarkLoadFromCache(b *testing.B) {
function BenchmarkList (line 484) | func BenchmarkList(b *testing.B) {
FILE: core/banner.go
constant Name (line 4) | Name = "bettercap"
constant Version (line 5) | Version = "2.41.5"
constant Author (line 6) | Author = "Simone 'evilsocket' Margaritelli"
constant Website (line 7) | Website = "https://bettercap.org/"
FILE: core/banner_test.go
function TestBannerName (line 8) | func TestBannerName(t *testing.T) {
function TestBannerWebsite (line 13) | func TestBannerWebsite(t *testing.T) {
function TestBannerVersion (line 19) | func TestBannerVersion(t *testing.T) {
function TestBannerAuthor (line 29) | func TestBannerAuthor(t *testing.T) {
FILE: core/core.go
function UniqueInts (line 11) | func UniqueInts(a []int, sorted bool) []int {
function HasBinary (line 30) | func HasBinary(executable string) bool {
function Exec (line 37) | func Exec(executable string, args []string) (string, error) {
FILE: core/core_android.go
function Shell (line 6) | func Shell(cmd string) (string, error) {
FILE: core/core_test.go
function hasInt (line 10) | func hasInt(a []int, v int) bool {
function sameInts (line 19) | func sameInts(a []int, b []int, ordered bool) bool {
function TestCoreUniqueIntsUnsorted (line 41) | func TestCoreUniqueIntsUnsorted(t *testing.T) {
function TestCoreUniqueIntsSorted (line 61) | func TestCoreUniqueIntsSorted(t *testing.T) {
function TestCoreExists (line 81) | func TestCoreExists(t *testing.T) {
function TestHasBinary (line 101) | func TestHasBinary(t *testing.T) {
function TestExec (line 139) | func TestExec(t *testing.T) {
function TestExecWithOutput (line 209) | func TestExecWithOutput(t *testing.T) {
function BenchmarkUniqueInts (line 222) | func BenchmarkUniqueInts(b *testing.B) {
FILE: core/core_unix.go
function Shell (line 6) | func Shell(cmd string) (string, error) {
FILE: core/core_windows.go
function Shell (line 3) | func Shell(cmd string) (string, error) {
FILE: core/options.go
type Options (line 7) | type Options struct
function ParseOptions (line 26) | func ParseOptions() (Options, error) {
FILE: firewall/firewall.go
type FirewallManager (line 3) | type FirewallManager interface
FILE: firewall/firewall_darwin.go
type PfFirewall (line 23) | type PfFirewall struct
method sysCtlRead (line 43) | func (f PfFirewall) sysCtlRead(param string) (string, error) {
method sysCtlWrite (line 53) | func (f PfFirewall) sysCtlWrite(param string, value string) (string, e...
method IsForwardingEnabled (line 70) | func (f PfFirewall) IsForwardingEnabled() bool {
method enableParam (line 80) | func (f PfFirewall) enableParam(param string, enabled bool) error {
method EnableForwarding (line 95) | func (f PfFirewall) EnableForwarding(enabled bool) error {
method generateRule (line 99) | func (f PfFirewall) generateRule(r *Redirection) string {
method enable (line 115) | func (f *PfFirewall) enable(enabled bool) {
method EnableRedirection (line 124) | func (f PfFirewall) EnableRedirection(r *Redirection, enabled bool) er...
method Restore (line 171) | func (f PfFirewall) Restore() {
function Make (line 30) | func Make(iface *network.Endpoint) FirewallManager {
FILE: firewall/firewall_linux.go
type LinuxFirewall (line 16) | type LinuxFirewall struct
method enableFeature (line 41) | func (f LinuxFirewall) enableFeature(filename string, enable bool) err...
method IsForwardingEnabled (line 59) | func (f LinuxFirewall) IsForwardingEnabled() bool {
method EnableForwarding (line 68) | func (f LinuxFirewall) EnableForwarding(enabled bool) error {
method getCommandLine (line 81) | func (f *LinuxFirewall) getCommandLine(r *Redirection, enabled bool) (...
method EnableRedirection (line 121) | func (f *LinuxFirewall) EnableRedirection(r *Redirection, enabled bool...
method Restore (line 161) | func (f LinuxFirewall) Restore() {
constant IPV4ForwardingFile (line 24) | IPV4ForwardingFile = "/proc/sys/net/ipv4/ip_forward"
constant IPV6ForwardingFile (line 25) | IPV6ForwardingFile = "/proc/sys/net/ipv6/conf/all/forwarding"
function Make (line 28) | func Make(iface *network.Endpoint) FirewallManager {
FILE: firewall/firewall_windows.go
type WindowsFirewall (line 11) | type WindowsFirewall struct
method IsForwardingEnabled (line 29) | func (f WindowsFirewall) IsForwardingEnabled() bool {
method EnableForwarding (line 38) | func (f WindowsFirewall) EnableForwarding(enabled bool) error {
method generateRule (line 51) | func (f WindowsFirewall) generateRule(r *Redirection, enabled bool) []...
method AllowPort (line 66) | func (f *WindowsFirewall) AllowPort(port int, address string, proto st...
method EnableRedirection (line 88) | func (f *WindowsFirewall) EnableRedirection(r *Redirection, enabled bo...
method Restore (line 109) | func (f WindowsFirewall) Restore() {
function Make (line 17) | func Make(iface *network.Endpoint) FirewallManager {
FILE: firewall/redirection.go
type Redirection (line 5) | type Redirection struct
method String (line 25) | func (r Redirection) String() string {
function NewRedirection (line 14) | func NewRedirection(iface string, proto string, port_from int, addr_to s...
FILE: firewall/redirection_test.go
function TestNewRedirection (line 7) | func TestNewRedirection(t *testing.T) {
function TestRedirectionString (line 45) | func TestRedirectionString(t *testing.T) {
function TestNewRedirectionVariousProtocols (line 111) | func TestNewRedirectionVariousProtocols(t *testing.T) {
function TestNewRedirectionVariousInterfaces (line 124) | func TestNewRedirectionVariousInterfaces(t *testing.T) {
function TestRedirectionStringEmptyFields (line 137) | func TestRedirectionStringEmptyFields(t *testing.T) {
function TestRedirectionStructCopy (line 203) | func TestRedirectionStructCopy(t *testing.T) {
function BenchmarkNewRedirection (line 232) | func BenchmarkNewRedirection(b *testing.B) {
function BenchmarkRedirectionString (line 238) | func BenchmarkRedirectionString(b *testing.B) {
function BenchmarkRedirectionStringEmpty (line 254) | func BenchmarkRedirectionStringEmpty(b *testing.B) {
FILE: js/crypto.go
function cryptoSha1 (line 9) | func cryptoSha1(call otto.FunctionCall) otto.Value {
FILE: js/data.go
function textEncode (line 11) | func textEncode(call otto.FunctionCall) otto.Value {
function textDecode (line 33) | func textDecode(call otto.FunctionCall) otto.Value {
function btoa (line 58) | func btoa(call otto.FunctionCall) otto.Value {
function atob (line 79) | func atob(call otto.FunctionCall) otto.Value {
function gzipCompress (line 104) | func gzipCompress(call otto.FunctionCall) otto.Value {
function gzipDecompress (line 136) | func gzipDecompress(call otto.FunctionCall) otto.Value {
FILE: js/data_test.go
function TestBtoa (line 11) | func TestBtoa(t *testing.T) {
function TestAtob (line 79) | func TestAtob(t *testing.T) {
function TestGzipCompress (line 155) | func TestGzipCompress(t *testing.T) {
function TestGzipCompressInvalidArgs (line 235) | func TestGzipCompressInvalidArgs(t *testing.T) {
function TestGzipDecompress (line 273) | func TestGzipDecompress(t *testing.T) {
function TestGzipDecompressInvalidArgs (line 336) | func TestGzipDecompressInvalidArgs(t *testing.T) {
function TestBtoaAtobRoundTrip (line 374) | func TestBtoaAtobRoundTrip(t *testing.T) {
function TestGzipCompressDecompressRoundTrip (line 413) | func TestGzipCompressDecompressRoundTrip(t *testing.T) {
function BenchmarkBtoa (line 451) | func BenchmarkBtoa(b *testing.B) {
function BenchmarkAtob (line 464) | func BenchmarkAtob(b *testing.B) {
function BenchmarkGzipCompress (line 478) | func BenchmarkGzipCompress(b *testing.B) {
function BenchmarkGzipDecompress (line 492) | func BenchmarkGzipDecompress(b *testing.B) {
FILE: js/fs.go
function mkdirAll (line 9) | func mkdirAll(call otto.FunctionCall) otto.Value {
function readDir (line 26) | func readDir(call otto.FunctionCall) otto.Value {
function readFile (line 52) | func readFile(call otto.FunctionCall) otto.Value {
function writeFile (line 72) | func writeFile(call otto.FunctionCall) otto.Value {
function appendFile (line 90) | func appendFile(call otto.FunctionCall) otto.Value {
FILE: js/fs_test.go
function TestReadDir (line 14) | func TestReadDir(t *testing.T) {
function TestReadFile (line 181) | func TestReadFile(t *testing.T) {
function TestWriteFile (line 347) | func TestWriteFile(t *testing.T) {
function TestAppendFile (line 533) | func TestAppendFile(t *testing.T) {
function TestMkdirAll (line 783) | func TestMkdirAll(t *testing.T) {
function TestFileSystemIntegration (line 987) | func TestFileSystemIntegration(t *testing.T) {
function BenchmarkReadFile (line 1098) | func BenchmarkReadFile(b *testing.B) {
function BenchmarkWriteFile (line 1119) | func BenchmarkWriteFile(b *testing.B) {
function BenchmarkAppendFile (line 1139) | func BenchmarkAppendFile(b *testing.B) {
function BenchmarkMkdirAll (line 1164) | func BenchmarkMkdirAll(b *testing.B) {
function BenchmarkReadDir (line 1181) | func BenchmarkReadDir(b *testing.B) {
FILE: js/http.go
type httpPackage (line 14) | type httpPackage struct
method Encode (line 25) | func (c httpPackage) Encode(s string) string {
method Request (line 29) | func (c httpPackage) Request(method string, uri string,
method Get (line 84) | func (c httpPackage) Get(url string, headers map[string]string) httpRe...
method PostForm (line 88) | func (c httpPackage) PostForm(url string, headers map[string]string, f...
method PostJSON (line 92) | func (c httpPackage) PostJSON(url string, headers map[string]string, j...
type httpResponse (line 17) | type httpResponse struct
function httpRequest (line 96) | func httpRequest(call otto.FunctionCall) otto.Value {
FILE: js/init.go
function ReportError (line 11) | func ReportError(format string, args ...interface{}) otto.Value {
function init (line 16) | func init() {
FILE: js/log.go
function flog (line 8) | func flog(call otto.FunctionCall) otto.Value {
function log_debug (line 15) | func log_debug(call otto.FunctionCall) otto.Value {
function log_info (line 22) | func log_info(call otto.FunctionCall) otto.Value {
function log_warn (line 29) | func log_warn(call otto.FunctionCall) otto.Value {
function log_error (line 36) | func log_error(call otto.FunctionCall) otto.Value {
function log_fatal (line 43) | func log_fatal(call otto.FunctionCall) otto.Value {
FILE: js/random.go
type randomPackage (line 10) | type randomPackage struct
method String (line 13) | func (c randomPackage) String(size int, charset string) string {
method Mac (line 23) | func (c randomPackage) Mac() string {
FILE: js/random_test.go
function TestRandomString (line 10) | func TestRandomString(t *testing.T) {
function TestRandomStringDistribution (line 84) | func TestRandomStringDistribution(t *testing.T) {
function TestRandomMac (line 113) | func TestRandomMac(t *testing.T) {
function TestRandomMacNormalization (line 143) | func TestRandomMacNormalization(t *testing.T) {
function TestRandomStringEdgeCases (line 167) | func TestRandomStringEdgeCases(t *testing.T) {
function TestRandomStringNegativeSize (line 216) | func TestRandomStringNegativeSize(t *testing.T) {
function TestRandomPackageInstance (line 230) | func TestRandomPackageInstance(t *testing.T) {
function BenchmarkRandomString (line 259) | func BenchmarkRandomString(b *testing.B) {
function BenchmarkRandomMac (line 282) | func BenchmarkRandomMac(b *testing.B) {
function BenchmarkRandomStringCharsets (line 290) | func BenchmarkRandomStringCharsets(b *testing.B) {
FILE: log/log.go
type logFunction (line 7) | type logFunction
function Debug (line 11) | func Debug(format string, args ...interface{}) {
function Info (line 17) | func Info(format string, args ...interface{}) {
function Warning (line 23) | func Warning(format string, args ...interface{}) {
function Error (line 29) | func Error(format string, args ...interface{}) {
function Fatal (line 35) | func Fatal(format string, args ...interface{}) {
FILE: log/log_test.go
function mockLogger (line 14) | func mockLogger(level log.Verbosity, format string, args ...interface{}) {
function reset (line 21) | func reset() {
function TestLoggerNil (line 28) | func TestLoggerNil(t *testing.T) {
function TestDebug (line 58) | func TestDebug(t *testing.T) {
function TestInfo (line 68) | func TestInfo(t *testing.T) {
function TestWarning (line 78) | func TestWarning(t *testing.T) {
function TestError (line 88) | func TestError(t *testing.T) {
function TestFatal (line 98) | func TestFatal(t *testing.T) {
FILE: main.go
function main (line 20) | func main() {
function exitPrompt (line 101) | func exitPrompt() bool {
FILE: main_test.go
function TestExitPrompt (line 9) | func TestExitPrompt(t *testing.T) {
function TestVersionString (line 70) | func TestVersionString(t *testing.T) {
function formatVersion (line 86) | func formatVersion(name, version, os, arch, goVersion string) string {
FILE: modules/any_proxy/any_proxy.go
type AnyProxy (line 13) | type AnyProxy struct
method Name (line 70) | func (mod *AnyProxy) Name() string {
method Description (line 74) | func (mod *AnyProxy) Description() string {
method Author (line 78) | func (mod *AnyProxy) Author() string {
method Configure (line 82) | func (mod *AnyProxy) Configure() error {
method Start (line 173) | func (mod *AnyProxy) Start() error {
method Stop (line 181) | func (mod *AnyProxy) Stop() error {
function NewAnyProxy (line 20) | func NewAnyProxy(s *session.Session) *AnyProxy {
FILE: modules/any_proxy/any_proxy_test.go
function createMockSession (line 18) | func createMockSession(t *testing.T) *session.Session {
function TestNewAnyProxy (line 29) | func TestNewAnyProxy(t *testing.T) {
function TestPortParsingLogic (line 74) | func TestPortParsingLogic(t *testing.T) {
function parsePortsString (line 129) | func parsePortsString(portsStr string) ([]int, error) {
function TestStartStop (line 175) | func TestStartStop(t *testing.T) {
function TestPortParsingErrors (line 190) | func TestPortParsingErrors(t *testing.T) {
function BenchmarkPortParsing (line 213) | func BenchmarkPortParsing(b *testing.B) {
FILE: modules/api_rest/api_rest.go
type RestAPI (line 21) | type RestAPI struct
method Name (line 169) | func (mod *RestAPI) Name() string {
method Description (line 173) | func (mod *RestAPI) Description() string {
method Author (line 177) | func (mod *RestAPI) Author() string {
method isTLS (line 181) | func (mod *RestAPI) isTLS() bool {
method Configure (line 185) | func (mod *RestAPI) Configure() error {
method Start (line 270) | func (mod *RestAPI) Start() error {
method Stop (line 296) | func (mod *RestAPI) Stop() error {
function NewRestAPI (line 45) | func NewRestAPI(s *session.Session) *RestAPI {
type JSSessionRequest (line 161) | type JSSessionRequest struct
type JSSessionResponse (line 165) | type JSSessionResponse struct
FILE: modules/api_rest/api_rest_controller.go
type CommandRequest (line 24) | type CommandRequest struct
type APIResponse (line 28) | type APIResponse struct
method setAuthFailed (line 33) | func (mod *RestAPI) setAuthFailed(w http.ResponseWriter, r *http.Request) {
method toJSON (line 41) | func (mod *RestAPI) toJSON(w http.ResponseWriter, o interface{}) {
method setSecurityHeaders (line 48) | func (mod *RestAPI) setSecurityHeaders(w http.ResponseWriter) {
method checkAuth (line 59) | func (mod *RestAPI) checkAuth(r *http.Request) bool {
method patchFrame (line 72) | func (mod *RestAPI) patchFrame(buf []byte) (frame map[string]interface{}...
method showSession (line 100) | func (mod *RestAPI) showSession(w http.ResponseWriter, r *http.Request) {
method showBLE (line 136) | func (mod *RestAPI) showBLE(w http.ResponseWriter, r *http.Request) {
method showHID (line 149) | func (mod *RestAPI) showHID(w http.ResponseWriter, r *http.Request) {
method showEnv (line 162) | func (mod *RestAPI) showEnv(w http.ResponseWriter, r *http.Request) {
method showGateway (line 166) | func (mod *RestAPI) showGateway(w http.ResponseWriter, r *http.Request) {
method showInterface (line 170) | func (mod *RestAPI) showInterface(w http.ResponseWriter, r *http.Request) {
method showModules (line 174) | func (mod *RestAPI) showModules(w http.ResponseWriter, r *http.Request) {
method showLAN (line 178) | func (mod *RestAPI) showLAN(w http.ResponseWriter, r *http.Request) {
method showOptions (line 191) | func (mod *RestAPI) showOptions(w http.ResponseWriter, r *http.Request) {
method showPackets (line 195) | func (mod *RestAPI) showPackets(w http.ResponseWriter, r *http.Request) {
method showStartedAt (line 199) | func (mod *RestAPI) showStartedAt(w http.ResponseWriter, r *http.Request) {
method showWiFi (line 203) | func (mod *RestAPI) showWiFi(w http.ResponseWriter, r *http.Request) {
method runSessionCommand (line 218) | func (mod *RestAPI) runSessionCommand(w http.ResponseWriter, r *http.Req...
method getEvents (line 247) | func (mod *RestAPI) getEvents(limit int) []session.Event {
method showEvents (line 266) | func (mod *RestAPI) showEvents(w http.ResponseWriter, r *http.Request) {
method clearEvents (line 311) | func (mod *RestAPI) clearEvents(w http.ResponseWriter, r *http.Request) {
method corsRoute (line 315) | func (mod *RestAPI) corsRoute(w http.ResponseWriter, r *http.Request) {
method sessionRoute (line 320) | func (mod *RestAPI) sessionRoute(w http.ResponseWriter, r *http.Request) {
method readFile (line 380) | func (mod *RestAPI) readFile(fileName string, w http.ResponseWriter, r *...
method writeFile (line 395) | func (mod *RestAPI) writeFile(fileName string, w http.ResponseWriter, r ...
method eventsRoute (line 418) | func (mod *RestAPI) eventsRoute(w http.ResponseWriter, r *http.Request) {
method fileRoute (line 435) | func (mod *RestAPI) fileRoute(w http.ResponseWriter, r *http.Request) {
FILE: modules/api_rest/api_rest_record.go
method errAlreadyRecording (line 19) | func (mod *RestAPI) errAlreadyRecording() error {
method recordState (line 23) | func (mod *RestAPI) recordState() error {
method recorder (line 44) | func (mod *RestAPI) recorder() {
method startRecording (line 80) | func (mod *RestAPI) startRecording(filename string) (err error) {
method stopRecording (line 103) | func (mod *RestAPI) stopRecording() error {
FILE: modules/api_rest/api_rest_replay.go
method errAlreadyReplaying (line 17) | func (mod *RestAPI) errAlreadyReplaying() error {
method startReplay (line 21) | func (mod *RestAPI) startReplay(filename string) (err error) {
method stopReplay (line 74) | func (mod *RestAPI) stopReplay() error {
FILE: modules/api_rest/api_rest_test.go
function createMockSession (line 20) | func createMockSession(t *testing.T) *session.Session {
function TestNewRestAPI (line 31) | func TestNewRestAPI(t *testing.T) {
function TestIsTLS (line 92) | func TestIsTLS(t *testing.T) {
function TestStateStore (line 126) | func TestStateStore(t *testing.T) {
function TestParameters (line 153) | func TestParameters(t *testing.T) {
function TestJSSessionStructs (line 183) | func TestJSSessionStructs(t *testing.T) {
function TestDefaultValues (line 202) | func TestDefaultValues(t *testing.T) {
function TestRunningState (line 228) | func TestRunningState(t *testing.T) {
function TestRecordingState (line 240) | func TestRecordingState(t *testing.T) {
function TestReplayingState (line 256) | func TestReplayingState(t *testing.T) {
function TestConfigureErrors (line 272) | func TestConfigureErrors(t *testing.T) {
function TestServerConfiguration (line 308) | func TestServerConfiguration(t *testing.T) {
function TestQuitChannel (line 332) | func TestQuitChannel(t *testing.T) {
function TestRecordWaitGroup (line 362) | func TestRecordWaitGroup(t *testing.T) {
function TestStartErrors (line 392) | func TestStartErrors(t *testing.T) {
function TestConfigureAlreadyRunning (line 404) | func TestConfigureAlreadyRunning(t *testing.T) {
function TestServerAddr (line 420) | func TestServerAddr(t *testing.T) {
function TestTLSConfiguration (line 437) | func TestTLSConfiguration(t *testing.T) {
function BenchmarkNewRestAPI (line 453) | func BenchmarkNewRestAPI(b *testing.B) {
function BenchmarkIsTLS (line 462) | func BenchmarkIsTLS(b *testing.B) {
function BenchmarkConfigure (line 474) | func BenchmarkConfigure(b *testing.B) {
function TestCommandRequest (line 487) | func TestCommandRequest(t *testing.T) {
function TestAPIResponse (line 497) | func TestAPIResponse(t *testing.T) {
function TestCheckAuthNoCredentials (line 512) | func TestCheckAuthNoCredentials(t *testing.T) {
function TestCheckAuthWithCredentials (line 524) | func TestCheckAuthWithCredentials(t *testing.T) {
function TestGetEventsEmpty (line 553) | func TestGetEventsEmpty(t *testing.T) {
function TestGetEventsWithLimit (line 573) | func TestGetEventsWithLimit(t *testing.T) {
function TestSetSecurityHeaders (line 602) | func TestSetSecurityHeaders(t *testing.T) {
function TestCorsRoute (line 630) | func TestCorsRoute(t *testing.T) {
function TestToJSON (line 644) | func TestToJSON(t *testing.T) {
FILE: modules/api_rest/api_rest_ws.go
constant writeWait (line 16) | writeWait = 10 * time.Second
constant pongWait (line 18) | pongWait = 60 * time.Second
constant pingPeriod (line 20) | pingPeriod = (pongWait * 9) / 10
method streamEvent (line 23) | func (mod *RestAPI) streamEvent(ws *websocket.Conn, event session.Event)...
method sendPing (line 41) | func (mod *RestAPI) sendPing(ws *websocket.Conn) error {
method streamWriter (line 51) | func (mod *RestAPI) streamWriter(ws *websocket.Conn, w http.ResponseWrit...
method streamReader (line 91) | func (mod *RestAPI) streamReader(ws *websocket.Conn) {
method startStreamingEvents (line 105) | func (mod *RestAPI) startStreamingEvents(w http.ResponseWriter, r *http....
FILE: modules/arp_spoof/arp_spoof.go
type ArpSpoofer (line 17) | type ArpSpoofer struct
method Name (line 100) | func (mod ArpSpoofer) Name() string {
method Description (line 104) | func (mod ArpSpoofer) Description() string {
method Author (line 108) | func (mod ArpSpoofer) Author() string {
method Configure (line 112) | func (mod *ArpSpoofer) Configure() error {
method Start (line 144) | func (mod *ArpSpoofer) Start() error {
method unSpoof (line 190) | func (mod *ArpSpoofer) unSpoof() error {
method Stop (line 214) | func (mod *ArpSpoofer) Stop() error {
method isWhitelisted (line 223) | func (mod *ArpSpoofer) isWhitelisted(ip string, mac net.HardwareAddr) ...
method getTargets (line 239) | func (mod *ArpSpoofer) getTargets(probe bool) map[string]net.HardwareA...
method arpSpoofTargets (line 265) | func (mod *ArpSpoofer) arpSpoofTargets(saddr net.IP, smac net.Hardware...
function NewArpSpoofer (line 30) | func NewArpSpoofer(s *session.Session) *ArpSpoofer {
FILE: modules/arp_spoof/arp_spoof_test.go
type MockFirewall (line 19) | type MockFirewall struct
method IsForwardingEnabled (line 31) | func (m *MockFirewall) IsForwardingEnabled() bool {
method EnableForwarding (line 35) | func (m *MockFirewall) EnableForwarding(enabled bool) error {
method EnableRedirection (line 40) | func (m *MockFirewall) EnableRedirection(r *firewall.Redirection, enab...
method DisableRedirection (line 54) | func (m *MockFirewall) DisableRedirection(r *firewall.Redirection, ena...
method Restore (line 58) | func (m *MockFirewall) Restore() {
function NewMockFirewall (line 24) | func NewMockFirewall() *MockFirewall {
type MockPacketQueue (line 64) | type MockPacketQueue struct
method Send (line 81) | func (m *MockPacketQueue) Send(data []byte) error {
method GetSentPackets (line 96) | func (m *MockPacketQueue) GetSentPackets() [][]byte {
method ClearSentPackets (line 102) | func (m *MockPacketQueue) ClearSentPackets() {
function NewMockPacketQueue (line 70) | func NewMockPacketQueue() *MockPacketQueue {
type MockSession (line 109) | type MockSession struct
method FindMAC (line 125) | func (m *MockSession) FindMAC(ip net.IP, probe bool) (net.HardwareAddr...
method Skip (line 137) | func (m *MockSession) Skip(ip net.IP) bool {
function setupMockSession (line 117) | func setupMockSession(mockSess *MockSession) {
type MockNetRecon (line 145) | type MockNetRecon struct
method Name (line 170) | func (m *MockNetRecon) Name() string {
method Description (line 174) | func (m *MockNetRecon) Description() string {
method Author (line 178) | func (m *MockNetRecon) Author() string {
method Configure (line 182) | func (m *MockNetRecon) Configure() error {
method Start (line 186) | func (m *MockNetRecon) Start() error {
method Stop (line 190) | func (m *MockNetRecon) Stop() error {
function NewMockNetRecon (line 149) | func NewMockNetRecon(s *session.Session) *MockNetRecon {
function createMockSession (line 195) | func createMockSession() (*MockSession, *MockPacketQueue, *MockFirewall) {
function TestNewArpSpoofer (line 263) | func TestNewArpSpoofer(t *testing.T) {
function TestArpSpooferConfigure (line 304) | func TestArpSpooferConfigure(t *testing.T) {
function TestArpSpooferStartStop (line 440) | func TestArpSpooferStartStop(t *testing.T) {
function TestArpSpooferBanMode (line 488) | func TestArpSpooferBanMode(t *testing.T) {
function TestArpSpooferWhitelisting (line 541) | func TestArpSpooferWhitelisting(t *testing.T) {
function TestArpSpooferFullDuplex (line 572) | func TestArpSpooferFullDuplex(t *testing.T) {
function TestArpSpooferInternalMode (line 613) | func TestArpSpooferInternalMode(t *testing.T) {
function TestArpSpooferGetTargets (line 661) | func TestArpSpooferGetTargets(t *testing.T) {
function TestArpSpooferSkipRestore (line 700) | func TestArpSpooferSkipRestore(t *testing.T) {
function TestArpSpooferEmptyTargets (line 727) | func TestArpSpooferEmptyTargets(t *testing.T) {
function BenchmarkArpSpooferGetTargets (line 747) | func BenchmarkArpSpooferGetTargets(b *testing.B) {
function BenchmarkArpSpooferWhitelisting (line 768) | func BenchmarkArpSpooferWhitelisting(b *testing.B) {
FILE: modules/ble/ble_options_darwin.go
function getClientOptions (line 7) | func getClientOptions(deviceID int) []gatt.Option {
FILE: modules/ble/ble_options_linux.go
function getClientOptions (line 8) | func getClientOptions(deviceID int) []gatt.Option {
FILE: modules/ble/ble_recon.go
type BLERecon (line 21) | type BLERecon struct
method Name (line 132) | func (mod BLERecon) Name() string {
method Description (line 136) | func (mod BLERecon) Description() string {
method Author (line 140) | func (mod BLERecon) Author() string {
method isEnumerating (line 144) | func (mod *BLERecon) isEnumerating() bool {
method Configure (line 157) | func (mod *BLERecon) Configure() (err error) {
method Start (line 195) | func (mod *BLERecon) Start() error {
method Stop (line 227) | func (mod *BLERecon) Stop() error {
method pruner (line 240) | func (mod *BLERecon) pruner() {
method setCurrentDevice (line 255) | func (mod *BLERecon) setCurrentDevice(dev *network.BLEDevice) {
method writeBuffer (line 261) | func (mod *BLERecon) writeBuffer(mac string, uuid gatt.UUID, data []by...
method enumAllTheThings (line 267) | func (mod *BLERecon) enumAllTheThings(mac string) error {
function NewBLERecon (line 36) | func NewBLERecon(s *session.Session) *BLERecon {
type dummyWriter (line 148) | type dummyWriter struct
method Write (line 152) | func (w dummyWriter) Write(p []byte) (n int, err error) {
constant blePrompt (line 193) | blePrompt = "{blb}{fw}BLE {fb}{reset} {bold}» {reset}"
FILE: modules/ble/ble_recon_events.go
method onStateChanged (line 10) | func (mod *BLERecon) onStateChanged(dev gatt.Device, s gatt.State) {
method onPeriphDiscovered (line 32) | func (mod *BLERecon) onPeriphDiscovered(p gatt.Peripheral, a *gatt.Adver...
method onPeriphDisconnected (line 36) | func (mod *BLERecon) onPeriphDisconnected(p gatt.Peripheral, err error) {
method onPeriphConnected (line 45) | func (mod *BLERecon) onPeriphConnected(p gatt.Peripheral, err error) {
FILE: modules/ble/ble_recon_test.go
function createMockSession (line 19) | func createMockSession(t *testing.T) *session.Session {
function TestNewBLERecon (line 30) | func TestNewBLERecon(t *testing.T) {
function TestIsEnumerating (line 103) | func TestIsEnumerating(t *testing.T) {
function TestDummyWriter (line 116) | func TestDummyWriter(t *testing.T) {
function TestParameters (line 133) | func TestParameters(t *testing.T) {
function TestRunningState (line 156) | func TestRunningState(t *testing.T) {
function TestChannels (line 168) | func TestChannels(t *testing.T) {
function TestClearHandler (line 173) | func TestClearHandler(t *testing.T) {
function TestBLEPrompt (line 178) | func TestBLEPrompt(t *testing.T) {
function TestSetCurrentDevice (line 185) | func TestSetCurrentDevice(t *testing.T) {
function TestViewSelector (line 199) | func TestViewSelector(t *testing.T) {
function TestBLEAliveInterval (line 209) | func TestBLEAliveInterval(t *testing.T) {
function TestColNames (line 216) | func TestColNames(t *testing.T) {
function TestDoFilter (line 235) | func TestDoFilter(t *testing.T) {
function TestShow (line 246) | func TestShow(t *testing.T) {
function TestConfigure (line 251) | func TestConfigure(t *testing.T) {
function TestGetRow (line 256) | func TestGetRow(t *testing.T) {
function TestDoSelection (line 265) | func TestDoSelection(t *testing.T) {
function TestWriteBuffer (line 270) | func TestWriteBuffer(t *testing.T) {
function TestEnumAllTheThings (line 275) | func TestEnumAllTheThings(t *testing.T) {
function BenchmarkNewBLERecon (line 281) | func BenchmarkNewBLERecon(b *testing.B) {
function BenchmarkIsEnumerating (line 291) | func BenchmarkIsEnumerating(b *testing.B) {
function BenchmarkDummyWriter (line 301) | func BenchmarkDummyWriter(b *testing.B) {
function BenchmarkDoFilter (line 313) | func BenchmarkDoFilter(b *testing.B) {
FILE: modules/ble/ble_show.go
method getRow (line 20) | func (mod *BLERecon) getRow(dev *network.BLEDevice, withName bool) []str...
method doFilter (line 58) | func (mod *BLERecon) doFilter(dev *network.BLEDevice) bool {
method doSelection (line 67) | func (mod *BLERecon) doSelection() (devices []*network.BLEDevice, err er...
method colNames (line 111) | func (mod *BLERecon) colNames(withName bool) []string {
method Show (line 129) | func (mod *BLERecon) Show() error {
FILE: modules/ble/ble_show_services.go
function parseProperties (line 171) | func parseProperties(ch *gatt.Characteristic) (props []string, isReadabl...
function parseRawData (line 208) | func parseRawData(raw []byte) string {
function parseAppearance (line 221) | func parseAppearance(raw []byte) string {
function parsePNPID (line 230) | func parsePNPID(raw []byte) []string {
function parseConnectionParams (line 251) | func parseConnectionParams(raw []byte) []string {
function parsePrivacyFlag (line 265) | func parsePrivacyFlag(raw []byte) string {
method showServices (line 272) | func (mod *BLERecon) showServices(p gatt.Peripheral, services []*gatt.Se...
FILE: modules/ble/ble_show_sort.go
type ByBLERSSISorter (line 10) | type ByBLERSSISorter
method Len (line 12) | func (a ByBLERSSISorter) Len() int { return len(a) }
method Swap (line 13) | func (a ByBLERSSISorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 14) | func (a ByBLERSSISorter) Less(i, j int) bool {
type ByBLEMacSorter (line 21) | type ByBLEMacSorter
method Len (line 23) | func (a ByBLEMacSorter) Len() int { return len(a) }
method Swap (line 24) | func (a ByBLEMacSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 25) | func (a ByBLEMacSorter) Less(i, j int) bool {
type ByBLESeenSorter (line 29) | type ByBLESeenSorter
method Len (line 31) | func (a ByBLESeenSorter) Len() int { return len(a) }
method Swap (line 32) | func (a ByBLESeenSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 33) | func (a ByBLESeenSorter) Less(i, j int) bool { return a[i].LastSeen.Be...
FILE: modules/ble/ble_unsupported.go
type BLERecon (line 10) | type BLERecon struct
method Name (line 34) | func (mod BLERecon) Name() string {
method Description (line 38) | func (mod BLERecon) Description() string {
method Author (line 42) | func (mod BLERecon) Author() string {
method Configure (line 46) | func (mod *BLERecon) Configure() (err error) {
method Start (line 50) | func (mod *BLERecon) Start() error {
method Stop (line 54) | func (mod *BLERecon) Stop() error {
function NewBLERecon (line 14) | func NewBLERecon(s *session.Session) *BLERecon {
FILE: modules/c2/c2.go
type settings (line 18) | type settings struct
type C2 (line 33) | type C2 struct
method Name (line 203) | func (mod *C2) Name() string {
method Description (line 207) | func (mod *C2) Description() string {
method Author (line 211) | func (mod *C2) Author() string {
method Configure (line 215) | func (mod *C2) Configure() (err error) {
method onPrint (line 314) | func (mod *C2) onPrint(format string, args ...interface{}) {
method onEvent (line 326) | func (mod *C2) onEvent(e session.Event) {
method Start (line 357) | func (mod *C2) Start() error {
method Stop (line 379) | func (mod *C2) Stop() error {
type eventContext (line 45) | type eventContext struct
function NewC2 (line 50) | func NewC2(s *session.Session) *C2 {
FILE: modules/c2/c2_test.go
function createMockSession (line 16) | func createMockSession(t *testing.T) *session.Session {
function TestNewC2 (line 27) | func TestNewC2(t *testing.T) {
function TestDefaultSettings (line 113) | func TestDefaultSettings(t *testing.T) {
function TestRunningState (line 135) | func TestRunningState(t *testing.T) {
function TestEventContext (line 147) | func TestEventContext(t *testing.T) {
function TestChannelHandlers (line 164) | func TestChannelHandlers(t *testing.T) {
function TestTemplateHandlers (line 203) | func TestTemplateHandlers(t *testing.T) {
function TestClearNonExistent (line 242) | func TestClearNonExistent(t *testing.T) {
function TestParameters (line 269) | func TestParameters(t *testing.T) {
function TestTemplateExecution (line 300) | func TestTemplateExecution(t *testing.T) {
function BenchmarkNewC2 (line 313) | func BenchmarkNewC2(b *testing.B) {
function BenchmarkChannelSet (line 322) | func BenchmarkChannelSet(b *testing.B) {
function BenchmarkTemplateSet (line 340) | func BenchmarkTemplateSet(b *testing.B) {
FILE: modules/can/can.go
type CANModule (line 13) | type CANModule struct
method Name (line 123) | func (mod *CANModule) Name() string {
method Description (line 127) | func (mod *CANModule) Description() string {
method Author (line 131) | func (mod *CANModule) Author() string {
function NewCanModule (line 29) | func NewCanModule(s *session.Session) *CANModule {
FILE: modules/can/can_dbc.go
type DBC (line 12) | type DBC struct
method Loaded (line 19) | func (dbc *DBC) Loaded() bool {
method LoadFile (line 26) | func (dbc *DBC) LoadFile(mod *CANModule, path string) error {
method LoadData (line 34) | func (dbc *DBC) LoadData(mod *CANModule, name string, input []byte) er...
method Parse (line 56) | func (dbc *DBC) Parse(mod *CANModule, msg *Message) bool {
method MessagesBySender (line 102) | func (dbc *DBC) MessagesBySender(senderId string) []*descriptor.Message {
method MessageById (line 121) | func (dbc *DBC) MessageById(frameID uint32) *descriptor.Message {
method Messages (line 135) | func (dbc *DBC) Messages() []*descriptor.Message {
method AvailableMessages (line 146) | func (dbc *DBC) AvailableMessages() []string {
method Senders (line 154) | func (dbc *DBC) Senders() []string {
FILE: modules/can/can_dbc_compile.go
type CompileResult (line 12) | type CompileResult struct
function dbcCompile (line 17) | func dbcCompile(sourceFile string, data []byte) (result *CompileResult, ...
type compileError (line 33) | type compileError struct
method Error (line 38) | func (e *compileError) Error() string {
type compiler (line 42) | type compiler struct
method addWarning (line 48) | func (c *compiler) addWarning(warning error) {
method collectDescriptors (line 52) | func (c *compiler) collectDescriptors() {
method addMetadata (line 98) | func (c *compiler) addMetadata() {
method sortDescriptors (line 201) | func (c *compiler) sortDescriptors() {
FILE: modules/can/can_dbc_load.go
method dbcLoad (line 3) | func (mod *CANModule) dbcLoad(name string) error {
FILE: modules/can/can_dump_reader.go
type dumpEntry (line 20) | type dumpEntry struct
function parseTimeval (line 26) | func parseTimeval(timeval string) (time.Time, error) {
method startDumpReader (line 45) | func (mod *CANModule) startDumpReader() error {
FILE: modules/can/can_fuzz.go
method fuzzSelectFrame (line 15) | func (mod *CANModule) fuzzSelectFrame(id string, rng *rand.Rand) (uint64...
method fuzzGenerateFrame (line 38) | func (mod *CANModule) fuzzGenerateFrame(frameID uint64, size int, rng *r...
method Fuzz (line 81) | func (mod *CANModule) Fuzz(id string, optSize string) error {
FILE: modules/can/can_inject.go
method Inject (line 10) | func (mod *CANModule) Inject(expr string) (err error) {
FILE: modules/can/can_message.go
type Message (line 8) | type Message struct
function NewCanMessage (line 19) | func NewCanMessage(frame can.Frame) Message {
FILE: modules/can/can_obd2.go
type OBD2 (line 8) | type OBD2 struct
method Enabled (line 14) | func (obd *OBD2) Enabled() bool {
method Enable (line 20) | func (obd *OBD2) Enable(enable bool) {
method Parse (line 26) | func (obd *OBD2) Parse(mod *CANModule, msg *Message) bool {
FILE: modules/can/can_obd2_message.go
constant OBD2BroadcastRequestID (line 16) | OBD2BroadcastRequestID = 0x7DF
constant OBD2ECUResponseMinID (line 17) | OBD2ECUResponseMinID = 0x7E0
constant OBD2ECUResponseMaxID (line 18) | OBD2ECUResponseMaxID = 0x7EF
constant OBD2BroadcastRequestID29bit (line 19) | OBD2BroadcastRequestID29bit = 0x18DB33F1
constant OBD2ECUResponseMinID29bit (line 20) | OBD2ECUResponseMinID29bit = 0x18DAF100
constant OBD2ECUResponseMaxID29bit (line 21) | OBD2ECUResponseMaxID29bit = 0x18DAF1FF
type OBD2Service (line 23) | type OBD2Service
method String (line 25) | func (s OBD2Service) String() string {
type OBD2MessageType (line 52) | type OBD2MessageType
method String (line 59) | func (t OBD2MessageType) String() string {
constant OBD2MessageTypeRequest (line 55) | OBD2MessageTypeRequest OBD2MessageType = iota
constant OBD2MessageTypeResponse (line 56) | OBD2MessageTypeResponse
type OBD2Message (line 67) | type OBD2Message struct
FILE: modules/can/can_obd2_pid_request.go
type OBD2PID (line 189) | type OBD2PID struct
method String (line 194) | func (p OBD2PID) String() string {
function lookupPID (line 201) | func lookupPID(svcID uint8, data []uint8) OBD2PID {
method ParseRequest (line 224) | func (msg *OBD2Message) ParseRequest(frame can.Frame) bool {
FILE: modules/can/can_obd2_pid_response.go
method ParseResponse (line 7) | func (msg *OBD2Message) ParseResponse(frame can.Frame) bool {
FILE: modules/can/can_recon.go
method Configure (line 13) | func (mod *CANModule) Configure() error {
method isFilteredOut (line 59) | func (mod *CANModule) isFilteredOut(frame can.Frame, msg Message) bool {
method onFrame (line 76) | func (mod *CANModule) onFrame(frame can.Frame) {
constant canPrompt (line 90) | canPrompt = "{br}{fw}{env.can.device} {fb}{reset} {bold}» {reset}"
method Start (line 92) | func (mod *CANModule) Start() error {
method Stop (line 109) | func (mod *CANModule) Stop() error {
FILE: modules/can/can_show.go
method getRow (line 18) | func (mod *CANModule) getRow(dev *network.CANDevice) []string {
method Show (line 37) | func (mod *CANModule) Show() (err error) {
FILE: modules/can/can_test.go
function createMockSession (line 16) | func createMockSession(t *testing.T) *session.Session {
function TestNewCanModule (line 27) | func TestNewCanModule(t *testing.T) {
function TestRunningState (line 105) | func TestRunningState(t *testing.T) {
function TestClearHandler (line 117) | func TestClearHandler(t *testing.T) {
function TestInjectNotRunning (line 122) | func TestInjectNotRunning(t *testing.T) {
function TestFuzzNotRunning (line 139) | func TestFuzzNotRunning(t *testing.T) {
function TestParameters (line 156) | func TestParameters(t *testing.T) {
function TestDBC (line 181) | func TestDBC(t *testing.T) {
function TestOBD2 (line 188) | func TestOBD2(t *testing.T) {
function TestShowHandler (line 195) | func TestShowHandler(t *testing.T) {
function TestDefaultTransport (line 200) | func TestDefaultTransport(t *testing.T) {
function TestDefaultDevice (line 209) | func TestDefaultDevice(t *testing.T) {
function TestFilterExpression (line 218) | func TestFilterExpression(t *testing.T) {
function TestDBCStruct (line 233) | func TestDBCStruct(t *testing.T) {
function TestOBD2Struct (line 241) | func TestOBD2Struct(t *testing.T) {
function TestCANMessage (line 249) | func TestCANMessage(t *testing.T) {
function TestDefaultParameters (line 271) | func TestDefaultParameters(t *testing.T) {
function TestHandlerExecution (line 297) | func TestHandlerExecution(t *testing.T) {
function TestModuleFields (line 333) | func TestModuleFields(t *testing.T) {
function TestDBCLoadHandler (line 351) | func TestDBCLoadHandler(t *testing.T) {
function BenchmarkNewCanModule (line 376) | func BenchmarkNewCanModule(b *testing.B) {
function BenchmarkClearHandler (line 385) | func BenchmarkClearHandler(b *testing.B) {
function BenchmarkInjectHandler (line 390) | func BenchmarkInjectHandler(b *testing.B) {
FILE: modules/caplets/caplets.go
type CapletsModule (line 19) | type CapletsModule struct
method Name (line 49) | func (mod *CapletsModule) Name() string {
method Description (line 53) | func (mod *CapletsModule) Description() string {
method Author (line 57) | func (mod *CapletsModule) Author() string {
method Configure (line 61) | func (mod *CapletsModule) Configure() error {
method Stop (line 65) | func (mod *CapletsModule) Stop() error {
method Start (line 69) | func (mod *CapletsModule) Start() error {
method Show (line 73) | func (mod *CapletsModule) Show() error {
method Paths (line 99) | func (mod *CapletsModule) Paths() error {
method Update (line 115) | func (mod *CapletsModule) Update() error {
function NewCapletsModule (line 23) | func NewCapletsModule(s *session.Session) *CapletsModule {
FILE: modules/dhcp6_spoof/dhcp6_spoof.go
type DHCP6Spoofer (line 28) | type DHCP6Spoofer struct
method Name (line 68) | func (mod DHCP6Spoofer) Name() string {
method Description (line 72) | func (mod DHCP6Spoofer) Description() string {
method Author (line 76) | func (mod DHCP6Spoofer) Author() string {
method Configure (line 80) | func (mod *DHCP6Spoofer) Configure() error {
method dhcp6For (line 116) | func (mod *DHCP6Spoofer) dhcp6For(what dhcp6.MessageType, to dhcp6.Pac...
method dhcpAdvertise (line 128) | func (mod *DHCP6Spoofer) dhcpAdvertise(pkt gopacket.Packet, solicit dh...
method dhcpReply (line 229) | func (mod *DHCP6Spoofer) dhcpReply(toType string, pkt gopacket.Packet,...
method duidMatches (line 323) | func (mod *DHCP6Spoofer) duidMatches(dhcp dhcp6.Packet) bool {
method onPacket (line 332) | func (mod *DHCP6Spoofer) onPacket(pkt gopacket.Packet) {
method Start (line 362) | func (mod *DHCP6Spoofer) Start() error {
method Stop (line 383) | func (mod *DHCP6Spoofer) Stop() error {
function NewDHCP6Spoofer (line 39) | func NewDHCP6Spoofer(s *session.Session) *DHCP6Spoofer {
FILE: modules/dns_proxy/dns_proxy.go
type DnsProxy (line 11) | type DnsProxy struct
method Author (line 16) | func (mod *DnsProxy) Author() string {
method Configure (line 20) | func (mod *DnsProxy) Configure() error {
method Description (line 92) | func (mod *DnsProxy) Description() string {
method Name (line 96) | func (mod *DnsProxy) Name() string {
method Start (line 171) | func (mod *DnsProxy) Start() error {
method Stop (line 181) | func (mod *DnsProxy) Stop() error {
function NewDnsProxy (line 100) | func NewDnsProxy(s *session.Session) *DnsProxy {
FILE: modules/dns_proxy/dns_proxy_base.go
constant dialTimeout (line 22) | dialTimeout = 2 * time.Second
constant readTimeout (line 23) | readTimeout = 2 * time.Second
constant writeTimeout (line 24) | writeTimeout = 2 * time.Second
type DNSProxy (line 27) | type DNSProxy struct
method shouldProxy (line 46) | func (p *DNSProxy) shouldProxy(clientIP string) bool {
method Configure (line 64) | func (p *DNSProxy) Configure(address string, dnsPort int, doRedirect b...
method dnsWorker (line 180) | func (p *DNSProxy) dnsWorker() error {
method Debug (line 185) | func (p *DNSProxy) Debug(format string, args ...interface{}) {
method Info (line 189) | func (p *DNSProxy) Info(format string, args ...interface{}) {
method Warning (line 193) | func (p *DNSProxy) Warning(format string, args ...interface{}) {
method Error (line 197) | func (p *DNSProxy) Error(format string, args ...interface{}) {
method Fatal (line 201) | func (p *DNSProxy) Fatal(format string, args ...interface{}) {
method Start (line 217) | func (p *DNSProxy) Start() {
method Stop (line 229) | func (p *DNSProxy) Stop() error {
function NewDNSProxy (line 205) | func NewDNSProxy(s *session.Session, tag string) *DNSProxy {
FILE: modules/dns_proxy/dns_proxy_base_filters.go
function questionsToStrings (line 9) | func questionsToStrings(qs []dns.Question) []string {
function recordsToStrings (line 17) | func recordsToStrings(rrs []dns.RR) []string {
function tabsToSpaces (line 27) | func tabsToSpaces(s string) string {
method logRequestAction (line 31) | func (p *DNSProxy) logRequestAction(m *dns.Msg, clientIP string) {
method logResponseAction (line 41) | func (p *DNSProxy) logResponseAction(m *dns.Msg, clientIP string) {
method onRequestFilter (line 57) | func (p *DNSProxy) onRequestFilter(query *dns.Msg, clientIP string) (req...
method onResponseFilter (line 86) | func (p *DNSProxy) onResponseFilter(req, res *dns.Msg, clientIP string) ...
FILE: modules/dns_proxy/dns_proxy_js_query.go
type JSQuery (line 16) | type JSQuery struct
method NewHash (line 189) | func (j *JSQuery) NewHash() string {
method ToQuery (line 295) | func (j *JSQuery) ToQuery() *dns.Msg {
method UpdateHash (line 358) | func (j *JSQuery) UpdateHash() {
method WasModified (line 362) | func (j *JSQuery) WasModified() bool {
method CheckIfModifiedAndUpdateHash (line 367) | func (j *JSQuery) CheckIfModifiedAndUpdateHash() bool {
type JSQueryHeader (line 28) | type JSQueryHeader struct
function jsPropToMap (line 42) | func jsPropToMap(obj map[string]interface{}, key string) map[string]inte...
function jsPropToMapArray (line 50) | func jsPropToMapArray(obj map[string]interface{}, key string) []map[stri...
function jsPropToString (line 58) | func jsPropToString(obj map[string]interface{}, key string) string {
function jsPropToStringArray (line 66) | func jsPropToStringArray(obj map[string]interface{}, key string) []string {
function jsPropToUint8 (line 74) | func jsPropToUint8(obj map[string]interface{}, key string) uint8 {
function jsPropToUint8Array (line 84) | func jsPropToUint8Array(obj map[string]interface{}, key string) []uint8 {
function jsPropToUint16 (line 103) | func jsPropToUint16(obj map[string]interface{}, key string) uint16 {
function jsPropToUint16Array (line 113) | func jsPropToUint16Array(obj map[string]interface{}, key string) []uint16 {
function jsPropToUint32 (line 132) | func jsPropToUint32(obj map[string]interface{}, key string) uint32 {
function jsPropToUint64 (line 142) | func jsPropToUint64(obj map[string]interface{}, key string) uint64 {
function uint8ArrayToInt64Array (line 173) | func uint8ArrayToInt64Array(arr []uint8) []int64 {
function uint16ArrayToInt64Array (line 181) | func uint16ArrayToInt64Array(arr []uint16) []int64 {
function NewJSQuery (line 220) | func NewJSQuery(query *dns.Msg, clientIP string) (jsQuery *JSQuery) {
FILE: modules/dns_proxy/dns_proxy_js_record.go
function NewJSResourceRecord (line 11) | func NewJSResourceRecord(rr dns.RR) (jsRecord map[string]interface{}, er...
function ToRR (line 364) | func ToRR(jsRecord map[string]interface{}) (rr dns.RR, err error) {
FILE: modules/dns_proxy/dns_proxy_js_record_edns0.go
function NewJSEDNS0 (line 11) | func NewJSEDNS0(e dns.EDNS0) (jsEDNS0 map[string]interface{}, err error) {
function ToEDNS0 (line 109) | func ToEDNS0(jsEDNS0 map[string]interface{}) (e dns.EDNS0, err error) {
FILE: modules/dns_proxy/dns_proxy_js_record_svcb.go
function NewJSSVCBKeyValue (line 11) | func NewJSSVCBKeyValue(kv dns.SVCBKeyValue) (map[string]interface{}, err...
function ToSVCBKeyValue (line 59) | func ToSVCBKeyValue(jsKv map[string]interface{}) (dns.SVCBKeyValue, erro...
FILE: modules/dns_proxy/dns_proxy_script.go
type DnsProxyScript (line 15) | type DnsProxyScript struct
method OnRequest (line 79) | func (s *DnsProxyScript) OnRequest(req *dns.Msg, clientIP string) (jsr...
method OnResponse (line 97) | func (s *DnsProxyScript) OnResponse(req, res *dns.Msg, clientIP string...
method OnCommand (line 113) | func (s *DnsProxyScript) OnCommand(cmd string) bool {
function LoadDnsProxyScript (line 23) | func LoadDnsProxyScript(path string, sess *session.Session) (err error, ...
FILE: modules/dns_spoof/dns_spoof.go
type DNSSpoofer (line 22) | type DNSSpoofer struct
method Name (line 83) | func (mod DNSSpoofer) Name() string {
method Description (line 87) | func (mod DNSSpoofer) Description() string {
method Author (line 91) | func (mod DNSSpoofer) Author() string {
method Configure (line 95) | func (mod *DNSSpoofer) Configure() error {
method onPacket (line 277) | func (mod *DNSSpoofer) onPacket(pkt gopacket.Packet) {
method Start (line 305) | func (mod *DNSSpoofer) Start() error {
method Stop (line 326) | func (mod *DNSSpoofer) Stop() error {
function NewDNSSpoofer (line 32) | func NewDNSSpoofer(s *session.Session) *DNSSpoofer {
function DnsReply (line 153) | func DnsReply(s *session.Session, TTL uint32, pkt gopacket.Packet, peth ...
FILE: modules/dns_spoof/dns_spoof_hosts.go
type HostEntry (line 17) | type HostEntry struct
method Matches (line 24) | func (e HostEntry) Matches(host string) bool {
type Hosts (line 29) | type Hosts
method Resolve (line 76) | func (h Hosts) Resolve(host string) net.IP {
function NewHostEntry (line 31) | func NewHostEntry(host string, address net.IP) HostEntry {
function HostsFromFile (line 50) | func HostsFromFile(filename string, defaultAddress net.IP) (err error, e...
FILE: modules/events_stream/events_rotation.go
method doRotation (line 10) | func (mod *EventsStream) doRotation() {
FILE: modules/events_stream/events_stream.go
type rotation (line 18) | type rotation struct
type EventsStream (line 27) | type EventsStream struct
method Name (line 226) | func (mod *EventsStream) Name() string {
method Description (line 230) | func (mod *EventsStream) Description() string {
method Author (line 234) | func (mod *EventsStream) Author() string {
method Configure (line 238) | func (mod *EventsStream) Configure() (err error) {
method Start (line 277) | func (mod *EventsStream) Start() error {
method Show (line 310) | func (mod *EventsStream) Show(limit int) error {
method startWaitingFor (line 336) | func (mod *EventsStream) startWaitingFor(tag string, timeout int) error {
method Stop (line 360) | func (mod *EventsStream) Stop() error {
function NewEventsStream (line 43) | func NewEventsStream(s *session.Session) *EventsStream {
FILE: modules/events_stream/events_triggers.go
method addTrigger (line 9) | func (mod *EventsStream) addTrigger(tag string, command string) error {
method clearTrigger (line 18) | func (mod *EventsStream) clearTrigger(id string) error {
method showTriggers (line 25) | func (mod *EventsStream) showTriggers() error {
method dispatchTriggers (line 49) | func (mod *EventsStream) dispatchTriggers(e session.Event) {
FILE: modules/events_stream/events_view.go
method viewLogEvent (line 20) | func (mod *EventsStream) viewLogEvent(output io.Writer, e session.Event) {
method viewEndpointEvent (line 28) | func (mod *EventsStream) viewEndpointEvent(output io.Writer, e session.E...
method viewModuleEvent (line 67) | func (mod *EventsStream) viewModuleEvent(output io.Writer, e session.Eve...
method viewSnifferEvent (line 76) | func (mod *EventsStream) viewSnifferEvent(output io.Writer, e session.Ev...
method viewSynScanEvent (line 87) | func (mod *EventsStream) viewSynScanEvent(output io.Writer, e session.Ev...
method viewUpdateEvent (line 96) | func (mod *EventsStream) viewUpdateEvent(output io.Writer, e session.Eve...
method Render (line 106) | func (mod *EventsStream) Render(output io.Writer, e session.Event) {
method View (line 144) | func (mod *EventsStream) View(e session.Event, refresh bool) {
FILE: modules/events_stream/events_view_ble.go
method viewBLEEvent (line 16) | func (mod *EventsStream) viewBLEEvent(output io.Writer, e session.Event) {
FILE: modules/events_stream/events_view_ble_unsupported.go
method viewBLEEvent (line 12) | func (mod *EventsStream) viewBLEEvent(output io.Writer, e session.Event) {
FILE: modules/events_stream/events_view_can.go
method viewCANDeviceNew (line 16) | func (mod *EventsStream) viewCANDeviceNew(output io.Writer, e session.Ev...
method viewCANRawMessage (line 25) | func (mod *EventsStream) viewCANRawMessage(output io.Writer, e session.E...
method viewCANDBCMessage (line 37) | func (mod *EventsStream) viewCANDBCMessage(output io.Writer, e session.E...
method viewCANOBDMessage (line 57) | func (mod *EventsStream) viewCANOBDMessage(output io.Writer, e session.E...
method viewCANEvent (line 80) | func (mod *EventsStream) viewCANEvent(output io.Writer, e session.Event) {
FILE: modules/events_stream/events_view_gateway.go
method viewGatewayEvent (line 12) | func (mod *EventsStream) viewGatewayEvent(output io.Writer, e session.Ev...
FILE: modules/events_stream/events_view_gps.go
method viewGPSEvent (line 11) | func (mod *EventsStream) viewGPSEvent(output io.Writer, e session.Event) {
FILE: modules/events_stream/events_view_hid.go
method viewHIDEvent (line 13) | func (mod *EventsStream) viewHIDEvent(output io.Writer, e session.Event) {
FILE: modules/events_stream/events_view_http.go
method shouldDumpHttpRequest (line 24) | func (mod *EventsStream) shouldDumpHttpRequest(req net_sniff.HTTPRequest...
method shouldDumpHttpResponse (line 42) | func (mod *EventsStream) shouldDumpHttpResponse(res net_sniff.HTTPRespon...
method dumpForm (line 62) | func (mod *EventsStream) dumpForm(body []byte) string {
method dumpText (line 85) | func (mod *EventsStream) dumpText(body []byte) string {
method dumpGZIP (line 89) | func (mod *EventsStream) dumpGZIP(body []byte) string {
method dumpJSON (line 110) | func (mod *EventsStream) dumpJSON(body []byte) string {
method dumpXML (line 123) | func (mod *EventsStream) dumpXML(body []byte) string {
method dumpRaw (line 128) | func (mod *EventsStream) dumpRaw(body []byte) string {
method viewHttpRequest (line 132) | func (mod *EventsStream) viewHttpRequest(output io.Writer, e session.Eve...
method viewHttpResponse (line 174) | func (mod *EventsStream) viewHttpResponse(output io.Writer, e session.Ev...
method viewHttpEvent (line 206) | func (mod *EventsStream) viewHttpEvent(output io.Writer, e session.Event) {
FILE: modules/events_stream/events_view_wifi.go
method viewWiFiApEvent (line 16) | func (mod *EventsStream) viewWiFiApEvent(output io.Writer, e session.Eve...
method viewWiFiClientProbeEvent (line 49) | func (mod *EventsStream) viewWiFiClientProbeEvent(output io.Writer, e se...
method viewWiFiHandshakeEvent (line 71) | func (mod *EventsStream) viewWiFiHandshakeEvent(output io.Writer, e sess...
method viewWiFiClientEvent (line 100) | func (mod *EventsStream) viewWiFiClientEvent(output io.Writer, e session...
method viewWiFiDeauthEvent (line 122) | func (mod *EventsStream) viewWiFiDeauthEvent(output io.Writer, e session...
method viewWiFiBruteforceEvent (line 135) | func (mod *EventsStream) viewWiFiBruteforceEvent(output io.Writer, e ses...
method viewWiFiEvent (line 145) | func (mod *EventsStream) viewWiFiEvent(output io.Writer, e session.Event) {
FILE: modules/events_stream/events_view_zeroconf.go
method viewZeroConfEvent (line 14) | func (mod *EventsStream) viewZeroConfEvent(output io.Writer, e session.E...
FILE: modules/events_stream/trigger_list.go
type Trigger (line 19) | type Trigger struct
type TriggerList (line 24) | type TriggerList struct
method Add (line 35) | func (l *TriggerList) Add(tag string, command string) (error, string) {
method Del (line 60) | func (l *TriggerList) Del(id string) (err error) {
method Each (line 71) | func (l *TriggerList) Each(cb func(id string, t Trigger)) {
method Completer (line 79) | func (l *TriggerList) Completer(prefix string) []string {
method Dispatch (line 89) | func (l *TriggerList) Dispatch(e session.Event) (ident string, cmd str...
function NewTriggerList (line 29) | func NewTriggerList() *TriggerList {
FILE: modules/gps/gps.go
type GPS (line 18) | type GPS struct
method Name (line 90) | func (mod *GPS) Name() string {
method Description (line 94) | func (mod *GPS) Description() string {
method Author (line 98) | func (mod *GPS) Author() string {
method Configure (line 102) | func (mod *GPS) Configure() (err error) {
method readLine (line 126) | func (mod *GPS) readLine() (line string, err error) {
method Show (line 143) | func (mod *GPS) Show() error {
method readFromSerial (line 156) | func (mod *GPS) readFromSerial() {
method runFromGPSD (line 180) | func (mod *GPS) runFromGPSD() {
method Start (line 203) | func (mod *GPS) Start() error {
method Stop (line 223) | func (mod *GPS) Stop() error {
function NewGPS (line 35) | func NewGPS(s *session.Session) *GPS {
FILE: modules/graph/create.go
method createIPGraph (line 9) | func (mod *Module) createIPGraph(endpoint *network.Endpoint) (*Node, boo...
method createDot11ApGraph (line 44) | func (mod *Module) createDot11ApGraph(ap *network.AccessPoint) (*Node, b...
method createDot11SSIDGraph (line 59) | func (mod *Module) createDot11SSIDGraph(hex string, ssid string) (*Node,...
method createDot11StaGraph (line 74) | func (mod *Module) createDot11StaGraph(station *network.Station) (*Node,...
method createDot11Graph (line 89) | func (mod *Module) createDot11Graph(ap *network.AccessPoint, station *ne...
method createDot11ProbeGraph (line 120) | func (mod *Module) createDot11ProbeGraph(ssid string, station *network.S...
method connectAsSame (line 151) | func (mod *Module) connectAsSame(a, b *Node) error {
FILE: modules/graph/create_ble.go
method createBLEServerGraph (line 8) | func (mod *Module) createBLEServerGraph(dev *network.BLEDevice) (*Node, ...
FILE: modules/graph/create_ble_unsupported.go
method createBLEServerGraph (line 8) | func (mod *Module) createBLEServerGraph(dev *network.BLEDevice) (*Node, ...
FILE: modules/graph/edge.go
type EdgeType (line 10) | type EdgeType
constant Is (line 13) | Is EdgeType = "is"
constant ProbesFor (line 14) | ProbesFor EdgeType = "probes_for"
constant ProbedBy (line 15) | ProbedBy EdgeType = "probed_by"
constant ConnectsTo (line 16) | ConnectsTo EdgeType = "connects_to"
constant Manages (line 17) | Manages EdgeType = "manages"
type EdgeEvent (line 20) | type EdgeEvent struct
type Edge (line 26) | type Edge struct
method Dot (line 32) | func (e Edge) Dot(left, right *Node, width float64) string {
FILE: modules/graph/edges.go
constant edgesIndexName (line 14) | edgesIndexName = "edges.json"
type EdgesTo (line 16) | type EdgesTo
type EdgesCallback (line 18) | type EdgesCallback
type Edges (line 20) | type Edges struct
method flush (line 57) | func (e *Edges) flush() error {
method Flush (line 74) | func (e *Edges) Flush() error {
method ForEachEdge (line 80) | func (e *Edges) ForEachEdge(cb EdgesCallback) error {
method ForEachEdgeFrom (line 95) | func (e *Edges) ForEachEdgeFrom(nodeID string, cb EdgesCallback) error {
method IsConnected (line 110) | func (e *Edges) IsConnected(nodeID string) bool {
method FindEdges (line 121) | func (e *Edges) FindEdges(fromID, toID string, doSort bool) []Edge {
method Connect (line 140) | func (e *Edges) Connect(fromID, toID string, edge Edge) error {
type edgesJSON (line 28) | type edgesJSON struct
function LoadEdges (line 34) | func LoadEdges(basePath string) (*Edges, error) {
FILE: modules/graph/graph.go
type NodeCallback (line 16) | type NodeCallback
type EdgeCallback (line 17) | type EdgeCallback
type Graph (line 19) | type Graph struct
method EachNode (line 38) | func (g *Graph) EachNode(cb NodeCallback) error {
method EachEdge (line 58) | func (g *Graph) EachEdge(cb EdgeCallback) error {
method Traverse (line 81) | func (g *Graph) Traverse(root string, onNode NodeCallback, onEdge Edge...
method IsConnected (line 157) | func (g *Graph) IsConnected(nodeType string, nodeID string) bool {
method Dot (line 161) | func (g *Graph) Dot(filter, layout, name string, disconnected bool) (s...
method JSON (line 250) | func (g *Graph) JSON(filter string, disconnected bool) (string, int, i...
method FindNode (line 310) | func (g *Graph) FindNode(t NodeType, id string) (*Node, error) {
method FindOtherTypes (line 322) | func (g *Graph) FindOtherTypes(t NodeType, id string) ([]*Node, error) {
method CreateNode (line 343) | func (g *Graph) CreateNode(t NodeType, id string, entity interface{}, ...
method UpdateNode (line 364) | func (g *Graph) UpdateNode(node *Node) error {
method FindLastEdgeOfType (line 376) | func (g *Graph) FindLastEdgeOfType(from, to *Node, edgeType EdgeType) ...
method FindLastRecentEdgeOfType (line 390) | func (g *Graph) FindLastRecentEdgeOfType(from, to *Node, edgeType Edge...
method CreateEdge (line 408) | func (g *Graph) CreateEdge(from, to *Node, edgeType EdgeType) (*Edge, ...
function NewGraph (line 26) | func NewGraph(path string) (*Graph, error) {
FILE: modules/graph/js_builtin.go
type graphPackage (line 7) | type graphPackage struct
method IsConnected (line 9) | func (g graphPackage) IsConnected(nodeType, nodeID string) bool {
FILE: modules/graph/module.go
constant ifaceAnnotation (line 20) | ifaceAnnotation = "<interface>"
constant edgeStaleTime (line 21) | edgeStaleTime = time.Hour * 24
type dotSettings (line 26) | type dotSettings struct
type jsonSettings (line 32) | type jsonSettings struct
type settings (line 36) | type settings struct
type Module (line 44) | type Module struct
method Name (line 145) | func (mod *Module) Name() string {
method Description (line 149) | func (mod *Module) Description() string {
method Author (line 153) | func (mod *Module) Author() string {
method updateSettings (line 157) | func (mod *Module) updateSettings() error {
method Configure (line 196) | func (mod *Module) Configure() (err error) {
method onEvent (line 261) | func (mod *Module) onEvent(e session.Event) {
method Start (line 328) | func (mod *Module) Start() error {
method Stop (line 345) | func (mod *Module) Stop() error {
function init (line 55) | func init() {
function NewModule (line 59) | func NewModule(s *session.Session) *Module {
FILE: modules/graph/node.go
type NodeType (line 13) | type NodeType
constant SSID (line 16) | SSID NodeType = "ssid"
constant BLEServer (line 17) | BLEServer NodeType = "ble_server"
constant Station (line 18) | Station NodeType = "station"
constant AccessPoint (line 19) | AccessPoint NodeType = "access_point"
constant Endpoint (line 20) | Endpoint NodeType = "endpoint"
constant Gateway (line 21) | Gateway NodeType = "gateway"
type Node (line 51) | type Node struct
method String (line 94) | func (n Node) String() string {
method Label (line 101) | func (n Node) Label() string {
method Dot (line 149) | func (n Node) Dot(isTarget bool) string {
method ToMap (line 160) | func (n Node) ToMap() (map[string]interface{}, error) {
function ReadNode (line 61) | func ReadNode(fileName string) (*Node, error) {
function WriteNode (line 71) | func WriteNode(fileName string, node *Node, update bool) error {
function CreateNode (line 86) | func CreateNode(fileName string, node *Node) error {
function UpdateNode (line 90) | func UpdateNode(fileName string, node *Node) error {
FILE: modules/graph/stack.go
type entry (line 5) | type entry struct
type Stack (line 10) | type Stack struct
method Push (line 16) | func (stk *Stack) Push(data interface{}) {
method Pop (line 29) | func (stk *Stack) Pop() interface{} {
function NewStack (line 43) | func NewStack() *Stack {
FILE: modules/graph/to_dot.go
method generateDotGraph (line 9) | func (mod *Module) generateDotGraph(bssid string) error {
FILE: modules/graph/to_json.go
method generateJSONGraph (line 9) | func (mod *Module) generateJSONGraph(bssid string) error {
FILE: modules/hid/build_amazon.go
constant amzFrameDelay (line 8) | amzFrameDelay = 5
type AmazonBuilder (line 11) | type AmazonBuilder struct
method frameFor (line 14) | func (b AmazonBuilder) frameFor(cmd *Command) []byte {
method BuildFrames (line 21) | func (b AmazonBuilder) BuildFrames(dev *network.HIDDevice, commands []...
FILE: modules/hid/build_logitech.go
constant ltFrameDelay (line 8) | ltFrameDelay = 12
type LogitechBuilder (line 16) | type LogitechBuilder struct
method frameFor (line 19) | func (b LogitechBuilder) frameFor(cmd *Command) []byte {
method BuildFrames (line 34) | func (b LogitechBuilder) BuildFrames(dev *network.HIDDevice, commands ...
FILE: modules/hid/build_microsoft.go
type MicrosoftBuilder (line 9) | type MicrosoftBuilder struct
method frameFor (line 13) | func (b MicrosoftBuilder) frameFor(template []byte, cmd *Command) []by...
method BuildFrames (line 35) | func (b MicrosoftBuilder) BuildFrames(dev *network.HIDDevice, commands...
FILE: modules/hid/builders.go
type FrameBuilder (line 7) | type FrameBuilder interface
function availBuilders (line 17) | func availBuilders() []string {
function builderFromName (line 25) | func builderFromName(name string) FrameBuilder {
FILE: modules/hid/command.go
type Frame (line 7) | type Frame struct
function NewFrame (line 12) | func NewFrame(buf []byte, delay int) Frame {
type Command (line 19) | type Command struct
method AddFrame (line 26) | func (cmd *Command) AddFrame(buf []byte, delay int) {
method IsHID (line 33) | func (cmd Command) IsHID() bool {
method IsSleep (line 37) | func (cmd Command) IsSleep() bool {
FILE: modules/hid/duckyparser.go
type DuckyParser (line 11) | type DuckyParser struct
method parseLiteral (line 15) | func (p DuckyParser) parseLiteral(what string, kmap KeyMap) (*Command,...
method parseModifier (line 27) | func (p DuckyParser) parseModifier(line string, kmap KeyMap, modMask b...
method parseNumber (line 42) | func (p DuckyParser) parseNumber(from string) (int, error) {
method parseString (line 56) | func (p DuckyParser) parseString(from string) (string, error) {
method lineIs (line 64) | func (p DuckyParser) lineIs(line string, tokens ...string) bool {
method Parse (line 73) | func (p DuckyParser) Parse(kmap KeyMap, path string) (cmds []*Command,...
FILE: modules/hid/hid.go
type HIDRecon (line 17) | type HIDRecon struct
method Name (line 157) | func (mod HIDRecon) Name() string {
method Description (line 161) | func (mod HIDRecon) Description() string {
method Author (line 165) | func (mod HIDRecon) Author() string {
method Configure (line 178) | func (mod *HIDRecon) Configure() error {
method forceStop (line 231) | func (mod *HIDRecon) forceStop() error {
method Stop (line 239) | func (mod *HIDRecon) Stop() error {
function NewHIDRecon (line 45) | func NewHIDRecon(s *session.Session) *HIDRecon {
type dummyWriter (line 169) | type dummyWriter struct
method Write (line 173) | func (w dummyWriter) Write(p []byte) (n int, err error) {
FILE: modules/hid/hid_inject.go
method isInjecting (line 14) | func (mod *HIDRecon) isInjecting() bool {
method setInjectionMode (line 18) | func (mod *HIDRecon) setInjectionMode(address string) error {
function errNoDevice (line 29) | func errNoDevice(addr string) error {
function errNoType (line 33) | func errNoType(addr string) error {
function errNotSupported (line 37) | func errNotSupported(dev *network.HIDDevice) error {
function errNoKeyMap (line 41) | func errNoKeyMap(layout string) error {
method prepInjection (line 45) | func (mod *HIDRecon) prepInjection() (error, *network.HIDDevice, []*Comm...
method doInjection (line 93) | func (mod *HIDRecon) doInjection() {
FILE: modules/hid/hid_recon.go
method doHopping (line 10) | func (mod *HIDRecon) doHopping() {
method onDeviceDetected (line 43) | func (mod *HIDRecon) onDeviceDetected(buf []byte) {
method devPruner (line 71) | func (mod *HIDRecon) devPruner() {
constant hidPrompt (line 89) | hidPrompt = "{by}{fw}HID {fb}{reset} {bold}» {reset}"
method Start (line 91) | func (mod *HIDRecon) Start() error {
FILE: modules/hid/hid_show.go
method getRow (line 20) | func (mod *HIDRecon) getRow(dev *network.HIDDevice) []string {
method doFilter (line 39) | func (mod *HIDRecon) doFilter(dev *network.HIDDevice) bool {
method doSelection (line 46) | func (mod *HIDRecon) doSelection() (err error, devices []*network.HIDDev...
method colNames (line 88) | func (mod *HIDRecon) colNames() []string {
method Show (line 99) | func (mod *HIDRecon) Show() (err error) {
FILE: modules/hid/hid_show_sort.go
type ByHIDMacSorter (line 7) | type ByHIDMacSorter
method Len (line 9) | func (a ByHIDMacSorter) Len() int { return len(a) }
method Swap (line 10) | func (a ByHIDMacSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 11) | func (a ByHIDMacSorter) Less(i, j int) bool {
type ByHIDSeenSorter (line 15) | type ByHIDSeenSorter
method Len (line 17) | func (a ByHIDSeenSorter) Len() int { return len(a) }
method Swap (line 18) | func (a ByHIDSeenSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 19) | func (a ByHIDSeenSorter) Less(i, j int) bool { return a[i].LastSeen.Be...
FILE: modules/hid/hid_sniff.go
method isSniffing (line 16) | func (mod *HIDRecon) isSniffing() bool {
method setSniffMode (line 20) | func (mod *HIDRecon) setSniffMode(mode string, silent bool) error {
method doPing (line 48) | func (mod *HIDRecon) doPing() {
method onSniffedBuffer (line 77) | func (mod *HIDRecon) onSniffedBuffer(buf []byte) {
FILE: modules/hid/keymaps.go
type KeyMap (line 7) | type KeyMap
function KeyMapFor (line 2102) | func KeyMapFor(lang string) KeyMap {
function SupportedLayouts (line 2116) | func SupportedLayouts() []string {
FILE: modules/http_proxy/http_proxy.go
type HttpProxy (line 9) | type HttpProxy struct
method Name (line 74) | func (mod *HttpProxy) Name() string {
method Description (line 78) | func (mod *HttpProxy) Description() string {
method Author (line 82) | func (mod *HttpProxy) Author() string {
method Configure (line 86) | func (mod *HttpProxy) Configure() error {
method Start (line 131) | func (mod *HttpProxy) Start() error {
method Stop (line 141) | func (mod *HttpProxy) Stop() error {
function NewHttpProxy (line 14) | func NewHttpProxy(s *session.Session) *HttpProxy {
FILE: modules/http_proxy/http_proxy_base.go
constant httpReadTimeout (line 35) | httpReadTimeout = 5 * time.Second
constant httpWriteTimeout (line 36) | httpWriteTimeout = 10 * time.Second
type HTTPProxy (line 39) | type HTTPProxy struct
method Debug (line 111) | func (p *HTTPProxy) Debug(format string, args ...interface{}) {
method Info (line 115) | func (p *HTTPProxy) Info(format string, args ...interface{}) {
method Warning (line 119) | func (p *HTTPProxy) Warning(format string, args ...interface{}) {
method Error (line 123) | func (p *HTTPProxy) Error(format string, args ...interface{}) {
method Fatal (line 127) | func (p *HTTPProxy) Fatal(format string, args ...interface{}) {
method doProxy (line 131) | func (p *HTTPProxy) doProxy(req *http.Request) bool {
method shouldProxy (line 148) | func (p *HTTPProxy) shouldProxy(req *http.Request) bool {
method Configure (line 174) | func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort ...
method TLSConfigFromCA (line 265) | func (p *HTTPProxy) TLSConfigFromCA(ca *tls.Certificate) func(host str...
method ConfigureTLS (line 300) | func (p *HTTPProxy) ConfigureTLS(address string, proxyPort int, httpPo...
method httpWorker (line 332) | func (p *HTTPProxy) httpWorker() error {
method httpsWorker (line 360) | func (p *HTTPProxy) httpsWorker() error {
method Start (line 413) | func (p *HTTPProxy) Start() {
method Stop (line 436) | func (p *HTTPProxy) Stop() error {
function stripPort (line 61) | func stripPort(s string) string {
type dummyLogger (line 69) | type dummyLogger struct
method Printf (line 73) | func (l dummyLogger) Printf(format string, v ...interface{}) {
function NewHTTPProxy (line 77) | func NewHTTPProxy(s *session.Session, tag string) *HTTPProxy {
type dumbResponseWriter (line 337) | type dumbResponseWriter struct
method Header (line 341) | func (dumb dumbResponseWriter) Header() http.Header {
method Write (line 345) | func (dumb dumbResponseWriter) Write(buf []byte) (int, error) {
method WriteHeader (line 352) | func (dumb dumbResponseWriter) WriteHeader(code int) {
method Hijack (line 356) | func (dumb dumbResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, ...
FILE: modules/http_proxy/http_proxy_base_cookietracker.go
type CookieTracker (line 13) | type CookieTracker struct
method domainOf (line 24) | func (t *CookieTracker) domainOf(req *http.Request) string {
method keyOf (line 32) | func (t *CookieTracker) keyOf(req *http.Request) string {
method IsClean (line 38) | func (t *CookieTracker) IsClean(req *http.Request) bool {
method Track (line 62) | func (t *CookieTracker) Track(req *http.Request) {
method Expire (line 68) | func (t *CookieTracker) Expire(req *http.Request) *http.Response {
function NewCookieTracker (line 18) | func NewCookieTracker() *CookieTracker {
FILE: modules/http_proxy/http_proxy_base_filters.go
method fixRequestHeaders (line 14) | func (p *HTTPProxy) fixRequestHeaders(req *http.Request) {
method onRequestFilter (line 22) | func (p *HTTPProxy) onRequestFilter(req *http.Request, ctx *goproxy.Prox...
method getHeader (line 56) | func (p *HTTPProxy) getHeader(res *http.Response, header string) string {
method isScriptInjectable (line 68) | func (p *HTTPProxy) isScriptInjectable(res *http.Response) (bool, string) {
method doScriptInjection (line 77) | func (p *HTTPProxy) doScriptInjection(res *http.Response, cType string) ...
method onResponseFilter (line 102) | func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.Pr...
method logRequestAction (line 134) | func (p *HTTPProxy) logRequestAction(req *http.Request, jsreq *JSRequest) {
method logResponseAction (line 150) | func (p *HTTPProxy) logResponseAction(req *http.Request, jsres *JSRespon...
FILE: modules/http_proxy/http_proxy_base_hosttracker.go
type Host (line 8) | type Host struct
function NewHost (line 14) | func NewHost(name string) *Host {
type HostTracker (line 35) | type HostTracker struct
method Track (line 48) | func (t *HostTracker) Track(host, stripped string) {
method Unstrip (line 55) | func (t *HostTracker) Unstrip(stripped string) *Host {
method Strip (line 64) | func (t *HostTracker) Strip(unstripped string) *Host {
function NewHostTracker (line 41) | func NewHostTracker() *HostTracker {
FILE: modules/http_proxy/http_proxy_base_sslstriper.go
type SSLStripper (line 32) | type SSLStripper struct
method Enabled (line 53) | func (s *SSLStripper) Enabled() bool {
method onPacket (line 57) | func (s *SSLStripper) onPacket(pkt gopacket.Packet) {
method Enable (line 81) | func (s *SSLStripper) Enable(enabled bool) {
method isContentStrippable (line 116) | func (s *SSLStripper) isContentStrippable(res *http.Response) bool {
method stripURL (line 128) | func (s *SSLStripper) stripURL(url string) string {
method Preprocess (line 136) | func (s *SSLStripper) Preprocess(req *http.Request, ctx *goproxy.Proxy...
method fixCookiesInHeader (line 162) | func (s *SSLStripper) fixCookiesInHeader(res *http.Response) {
method fixResponseHeaders (line 190) | func (s *SSLStripper) fixResponseHeaders(res *http.Response) {
method Process (line 209) | func (s *SSLStripper) Process(res *http.Response, ctx *goproxy.ProxyCt...
function NewSSLStripper (line 41) | func NewSSLStripper(s *session.Session, enabled bool) *SSLStripper {
FILE: modules/http_proxy/http_proxy_cert_cache.go
function keyFor (line 14) | func keyFor(domain string, port int) string {
function getCachedCert (line 18) | func getCachedCert(domain string, port int) *tls.Certificate {
function setCachedCert (line 27) | func setCachedCert(domain string, port int, cert *tls.Certificate) {
FILE: modules/http_proxy/http_proxy_js_request.go
type JSRequest (line 15) | type JSRequest struct
method NewHash (line 77) | func (j *JSRequest) NewHash() string {
method UpdateHash (line 93) | func (j *JSRequest) UpdateHash() {
method WasModified (line 97) | func (j *JSRequest) WasModified() bool {
method CheckIfModifiedAndUpdateHash (line 106) | func (j *JSRequest) CheckIfModifiedAndUpdateHash() bool {
method GetHeader (line 119) | func (j *JSRequest) GetHeader(name, deflt string) string {
method GetHeaders (line 137) | func (j *JSRequest) GetHeaders(name string) []string {
method SetHeader (line 156) | func (j *JSRequest) SetHeader(name, value string) {
method RemoveHeader (line 184) | func (j *JSRequest) RemoveHeader(name string) {
method ReadBody (line 203) | func (j *JSRequest) ReadBody() string {
method ParseForm (line 217) | func (j *JSRequest) ParseForm() map[string]string {
method ToRequest (line 240) | func (j *JSRequest) ToRequest() (req *http.Request) {
function NewJSRequest (line 35) | func NewJSRequest(req *http.Request) *JSRequest {
FILE: modules/http_proxy/http_proxy_js_response.go
type JSResponse (line 13) | type JSResponse struct
method NewHash (line 56) | func (j *JSResponse) NewHash() string {
method UpdateHash (line 60) | func (j *JSResponse) UpdateHash() {
method WasModified (line 64) | func (j *JSResponse) WasModified() bool {
method CheckIfModifiedAndUpdateHash (line 79) | func (j *JSResponse) CheckIfModifiedAndUpdateHash() bool {
method GetHeader (line 100) | func (j *JSResponse) GetHeader(name, deflt string) string {
method GetHeaders (line 118) | func (j *JSResponse) GetHeaders(name string) []string {
method SetHeader (line 137) | func (j *JSResponse) SetHeader(name, value string) {
method RemoveHeader (line 165) | func (j *JSResponse) RemoveHeader(name string) {
method ClearBody (line 184) | func (j *JSResponse) ClearBody() {
method ToResponse (line 189) | func (j *JSResponse) ToResponse(req *http.Request) (resp *http.Respons...
method ReadBody (line 208) | func (j *JSResponse) ReadBody() string {
function NewJSResponse (line 25) | func NewJSResponse(res *http.Response) *JSResponse {
FILE: modules/http_proxy/http_proxy_script.go
type HttpProxyScript (line 15) | type HttpProxyScript struct
method OnRequest (line 79) | func (s *HttpProxyScript) OnRequest(original *http.Request) (jsreq *JS...
method OnResponse (line 97) | func (s *HttpProxyScript) OnResponse(res *http.Response) (jsreq *JSReq...
method OnCommand (line 113) | func (s *HttpProxyScript) OnCommand(cmd string) bool {
function LoadHttpProxyScript (line 23) | func LoadHttpProxyScript(path string, sess *session.Session) (err error,...
FILE: modules/http_proxy/http_proxy_test.go
type MockFirewall (line 23) | type MockFirewall struct
method IsForwardingEnabled (line 35) | func (m *MockFirewall) IsForwardingEnabled() bool {
method EnableForwarding (line 39) | func (m *MockFirewall) EnableForwarding(enabled bool) error {
method EnableRedirection (line 44) | func (m *MockFirewall) EnableRedirection(r *firewall.Redirection, enab...
method DisableRedirection (line 58) | func (m *MockFirewall) DisableRedirection(r *firewall.Redirection, ena...
method Restore (line 62) | func (m *MockFirewall) Restore() {
function NewMockFirewall (line 28) | func NewMockFirewall() *MockFirewall {
function createMockSession (line 68) | func createMockSession() (*session.Session, *MockFirewall) {
function TestNewHttpProxy (line 123) | func TestNewHttpProxy(t *testing.T) {
function TestHttpProxyConfigure (line 174) | func TestHttpProxyConfigure(t *testing.T) {
function TestHttpProxyStartStop (line 350) | func TestHttpProxyStartStop(t *testing.T) {
function TestHttpProxyAlreadyStarted (line 400) | func TestHttpProxyAlreadyStarted(t *testing.T) {
function TestHTTPProxyDoProxy (line 426) | func TestHTTPProxyDoProxy(t *testing.T) {
function TestHTTPProxyShouldProxy (line 475) | func TestHTTPProxyShouldProxy(t *testing.T) {
function TestHTTPProxyStripPort (line 547) | func TestHTTPProxyStripPort(t *testing.T) {
function TestHTTPProxyJavaScriptInjection (line 568) | func TestHTTPProxyJavaScriptInjection(t *testing.T) {
function TestHTTPProxyWithTestServer (line 618) | func TestHTTPProxyWithTestServer(t *testing.T) {
function TestHTTPProxyScriptLoading (line 648) | func TestHTTPProxyScriptLoading(t *testing.T) {
function BenchmarkHTTPProxyShouldProxy (line 680) | func BenchmarkHTTPProxyShouldProxy(b *testing.B) {
function BenchmarkHTTPProxyStripPort (line 698) | func BenchmarkHTTPProxyStripPort(b *testing.B) {
FILE: modules/http_server/http_server.go
type HttpServer (line 15) | type HttpServer struct
method Name (line 55) | func (mod *HttpServer) Name() string {
method Description (line 59) | func (mod *HttpServer) Description() string {
method Author (line 63) | func (mod *HttpServer) Author() string {
method Configure (line 67) | func (mod *HttpServer) Configure() error {
method Start (line 107) | func (mod *HttpServer) Start() error {
method Stop (line 122) | func (mod *HttpServer) Stop() error {
function NewHttpServer (line 20) | func NewHttpServer(s *session.Session) *HttpServer {
FILE: modules/https_proxy/https_proxy.go
type HttpsProxy (line 12) | type HttpsProxy struct
method Name (line 89) | func (mod *HttpsProxy) Name() string {
method Description (line 93) | func (mod *HttpsProxy) Description() string {
method Author (line 97) | func (mod *HttpsProxy) Author() string {
method Configure (line 101) | func (mod *HttpsProxy) Configure() error {
method Start (line 174) | func (mod *HttpsProxy) Start() error {
method Stop (line 184) | func (mod *HttpsProxy) Stop() error {
function NewHttpsProxy (line 17) | func NewHttpsProxy(s *session.Session) *HttpsProxy {
FILE: modules/https_server/https_server.go
type HttpsServer (line 17) | type HttpsServer struct
method Name (line 71) | func (mod *HttpsServer) Name() string {
method Description (line 75) | func (mod *HttpsServer) Description() string {
method Author (line 79) | func (mod *HttpsServer) Author() string {
method Configure (line 83) | func (mod *HttpsServer) Configure() error {
method Start (line 154) | func (mod *HttpsServer) Start() error {
method Stop (line 168) | func (mod *HttpsServer) Stop() error {
function NewHttpsServer (line 24) | func NewHttpsServer(s *session.Session) *HttpsServer {
FILE: modules/mac_changer/mac_changer.go
type MacChanger (line 16) | type MacChanger struct
method Name (line 53) | func (mod *MacChanger) Name() string {
method Description (line 57) | func (mod *MacChanger) Description() string {
method Author (line 61) | func (mod *MacChanger) Author() string {
method Configure (line 65) | func (mod *MacChanger) Configure() (err error) {
method setMac (line 84) | func (mod *MacChanger) setMac(mac net.HardwareAddr) error {
method Start (line 111) | func (mod *MacChanger) Start() error {
method Stop (line 125) | func (mod *MacChanger) Stop() error {
function NewMacChanger (line 23) | func NewMacChanger(s *session.Session) *MacChanger {
FILE: modules/modules.go
function LoadModules (line 41) | func LoadModules(sess *session.Session) {
FILE: modules/modules_test.go
function TestLoadModulesWithNilSession (line 7) | func TestLoadModulesWithNilSession(t *testing.T) {
FILE: modules/mysql_server/mysql_server.go
type MySQLServer (line 17) | type MySQLServer struct
method Name (line 64) | func (mod *MySQLServer) Name() string {
method Description (line 68) | func (mod *MySQLServer) Description() string {
method Author (line 72) | func (mod *MySQLServer) Author() string {
method Configure (line 76) | func (mod *MySQLServer) Configure() error {
method Start (line 99) | func (mod *MySQLServer) Start() error {
method Stop (line 178) | func (mod *MySQLServer) Stop() error {
function NewMySQLServer (line 25) | func NewMySQLServer(s *session.Session) *MySQLServer {
FILE: modules/ndp_spoof/ndp_spoof.go
type NDPSpoofer (line 15) | type NDPSpoofer struct
method Name (line 81) | func (mod NDPSpoofer) Name() string {
method Description (line 85) | func (mod NDPSpoofer) Description() string {
method Author (line 89) | func (mod NDPSpoofer) Author() string {
method Configure (line 93) | func (mod *NDPSpoofer) Configure() error {
method Start (line 148) | func (mod *NDPSpoofer) Start() error {
method Stop (line 197) | func (mod *NDPSpoofer) Stop() error {
method getTargets (line 205) | func (mod *NDPSpoofer) getTargets(probe bool) map[string]net.HardwareA...
function NewNDPSpoofer (line 26) | func NewNDPSpoofer(s *session.Session) *NDPSpoofer {
FILE: modules/net_probe/net_probe.go
type Probes (line 13) | type Probes struct
type Prober (line 20) | type Prober struct
method Name (line 70) | func (mod Prober) Name() string {
method Description (line 74) | func (mod Prober) Description() string {
method Author (line 78) | func (mod Prober) Author() string {
method Configure (line 82) | func (mod *Prober) Configure() error {
method Start (line 100) | func (mod *Prober) Start() error {
method Stop (line 158) | func (mod *Prober) Stop() error {
function NewProber (line 27) | func NewProber(s *session.Session) *Prober {
FILE: modules/net_probe/net_probe_nbns.go
method sendProbeNBNS (line 10) | func (mod *Prober) sendProbeNBNS(from net.IP, from_hw net.HardwareAddr, ...
FILE: modules/net_probe/net_probe_test.go
type MockQueue (line 18) | type MockQueue struct
method Send (line 32) | func (m *MockQueue) Send(data []byte) error {
method GetSentPackets (line 47) | func (m *MockQueue) GetSentPackets() [][]byte {
method ClearSentPackets (line 53) | func (m *MockQueue) ClearSentPackets() {
method Stop (line 59) | func (m *MockQueue) Stop() {
function NewMockQueue (line 25) | func NewMockQueue() *MockQueue {
type MockSession (line 66) | type MockSession struct
method Run (line 72) | func (m *MockSession) Run(cmd string) error {
method Skip (line 104) | func (m *MockSession) Skip(ip net.IP) bool {
type MockNetRecon (line 112) | type MockNetRecon struct
method Name (line 137) | func (m *MockNetRecon) Name() string {
method Description (line 141) | func (m *MockNetRecon) Description() string {
method Author (line 145) | func (m *MockNetRecon) Author() string {
method Configure (line 149) | func (m *MockNetRecon) Configure() error {
method Start (line 153) | func (m *MockNetRecon) Start() error {
method Stop (line 157) | func (m *MockNetRecon) Stop() error {
function NewMockNetRecon (line 116) | func NewMockNetRecon(s *session.Session) *MockNetRecon {
function createMockSession (line 162) | func createMockSession() (*MockSession, *MockQueue) {
function TestNewProber (line 221) | func TestNewProber(t *testing.T) {
function TestProberConfigure (line 247) | func TestProberConfigure(t *testing.T) {
type MockProber (line 349) | type MockProber struct
method sendProbeNBNS (line 357) | func (m *MockProber) sendProbeNBNS(from net.IP, from_hw net.HardwareAd...
method sendProbeUPNP (line 362) | func (m *MockProber) sendProbeUPNP(from net.IP, from_hw net.HardwareAd...
method sendProbeWSD (line 367) | func (m *MockProber) sendProbeWSD(from net.IP, from_hw net.HardwareAdd...
function TestProberStartStop (line 372) | func TestProberStartStop(t *testing.T) {
function TestProberMonitorMode (line 410) | func TestProberMonitorMode(t *testing.T) {
function TestProberHandlers (line 434) | func TestProberHandlers(t *testing.T) {
function TestProberSelectiveProbes (line 480) | func TestProberSelectiveProbes(t *testing.T) {
function TestIPRangeExpansion (line 553) | func TestIPRangeExpansion(t *testing.T) {
function BenchmarkProberConfiguration (line 583) | func BenchmarkProberConfiguration(b *testing.B) {
function BenchmarkIPRangeExpansion (line 601) | func BenchmarkIPRangeExpansion(b *testing.B) {
FILE: modules/net_probe/net_probe_upnp.go
method sendProbeUPNP (line 10) | func (mod *Prober) sendProbeUPNP(from net.IP, from_hw net.HardwareAddr) {
FILE: modules/net_probe/net_probe_wsd.go
method sendProbeWSD (line 10) | func (mod *Prober) sendProbeWSD(from net.IP, from_hw net.HardwareAddr) {
FILE: modules/net_recon/net_recon.go
type Discovery (line 12) | type Discovery struct
method Name (line 69) | func (mod Discovery) Name() string {
method Description (line 73) | func (mod Discovery) Description() string {
method Author (line 77) | func (mod Discovery) Author() string {
method runDiff (line 81) | func (mod *Discovery) runDiff(cache network.ArpTable) {
method Configure (line 101) | func (mod *Discovery) Configure() error {
method Start (line 105) | func (mod *Discovery) Start() error {
method Stop (line 124) | func (mod *Discovery) Stop() error {
function NewDiscovery (line 17) | func NewDiscovery(s *session.Session) *Discovery {
FILE: modules/net_recon/net_recon_test.go
function mockArpUpdate (line 20) | func mockArpUpdate(iface string) (network.ArpTable, error) {
type MockLAN (line 28) | type MockLAN struct
method AddIfNew (line 45) | func (m *MockLAN) AddIfNew(ip, mac string) {
method Remove (line 60) | func (m *MockLAN) Remove(ip, mac string) {
method Clear (line 70) | func (m *MockLAN) Clear() {
method EachHost (line 80) | func (m *MockLAN) EachHost(cb func(mac string, e *network.Endpoint)) {
method List (line 89) | func (m *MockLAN) List() []*network.Endpoint {
method WasMissed (line 100) | func (m *MockLAN) WasMissed(mac string) bool {
method Get (line 107) | func (m *MockLAN) Get(mac string) *network.Endpoint {
function NewMockLAN (line 36) | func NewMockLAN() *MockLAN {
function createMockSession (line 115) | func createMockSession() *session.Session {
function TestNewDiscovery (line 151) | func TestNewDiscovery(t *testing.T) {
function TestRunDiff (line 172) | func TestRunDiff(t *testing.T) {
function TestConfigure (line 277) | func TestConfigure(t *testing.T) {
function TestStartStop (line 287) | func TestStartStop(t *testing.T) {
function TestShowMethods (line 318) | func TestShowMethods(t *testing.T) {
function TestDoSelection (line 323) | func TestDoSelection(t *testing.T) {
function TestHandlers (line 408) | func TestHandlers(t *testing.T) {
function TestGetRow (line 472) | func TestGetRow(t *testing.T) {
function TestDoFilter (line 522) | func TestDoFilter(t *testing.T) {
function BenchmarkRunDiff (line 618) | func BenchmarkRunDiff(b *testing.B) {
FILE: modules/net_recon/net_show.go
constant AliveTimeInterval (line 21) | AliveTimeInterval = time.Duration(10) * time.Second
constant PresentTimeInterval (line 22) | PresentTimeInterval = time.Duration(1) * time.Minute
constant JustJoinedTimeInterval (line 23) | JustJoinedTimeInterval = time.Duration(10) * time.Second
type ProtoPair (line 26) | type ProtoPair struct
type ProtoPairList (line 31) | type ProtoPairList
method Len (line 33) | func (p ProtoPairList) Len() int { return len(p) }
method Less (line 34) | func (p ProtoPairList) Less(i, j int) bool { return p[i].Hits < p[j].H...
method Swap (line 35) | func (p ProtoPairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
method getRow (line 37) | func (mod *Discovery) getRow(e *network.Endpoint, withMeta bool) [][]str...
method doFilter (line 126) | func (mod *Discovery) doFilter(target *network.Endpoint) bool {
method doSelection (line 138) | func (mod *Discovery) doSelection(arg string) (err error, targets []*net...
method colNames (line 195) | func (mod *Discovery) colNames(hasMeta bool) []string {
method showStatusBar (line 217) | func (mod *Discovery) showStatusBar() {
method Show (line 231) | func (mod *Discovery) Show(arg string) (err error) {
method showMeta (line 277) | func (mod *Discovery) showMeta(arg string) (err error) {
FILE: modules/net_recon/net_show_sort.go
type ByAddressSorter (line 9) | type ByAddressSorter
method Len (line 11) | func (a ByAddressSorter) Len() int { return len(a) }
method Swap (line 12) | func (a ByAddressSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 13) | func (a ByAddressSorter) Less(i, j int) bool {
type ByIpSorter (line 20) | type ByIpSorter
method Len (line 22) | func (a ByIpSorter) Len() int { return len(a) }
method Swap (line 23) | func (a ByIpSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 24) | func (a ByIpSorter) Less(i, j int) bool {
type ByMacSorter (line 28) | type ByMacSorter
method Len (line 30) | func (a ByMacSorter) Len() int { return len(a) }
method Swap (line 31) | func (a ByMacSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 32) | func (a ByMacSorter) Less(i, j int) bool {
type BySeenSorter (line 36) | type BySeenSorter
method Len (line 38) | func (a BySeenSorter) Len() int { return len(a) }
method Swap (line 39) | func (a BySeenSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 40) | func (a BySeenSorter) Less(i, j int) bool { return a[i].LastSeen.Befor...
type BySentSorter (line 42) | type BySentSorter
method Len (line 52) | func (a BySentSorter) Len() int { return len(a) }
method Swap (line 53) | func (a BySentSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 54) | func (a BySentSorter) Less(i, j int) bool {
function trafficOf (line 44) | func trafficOf(ip string) *packets.Traffic {
type ByRcvdSorter (line 60) | type ByRcvdSorter
method Len (line 62) | func (a ByRcvdSorter) Len() int { return len(a) }
method Swap (line 63) | func (a ByRcvdSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 64) | func (a ByRcvdSorter) Less(i, j int) bool {
FILE: modules/net_sniff/net_sniff.go
type Sniffer (line 13) | type Sniffer struct
method Name (line 123) | func (mod Sniffer) Name() string {
method Description (line 127) | func (mod Sniffer) Description() string {
method Author (line 131) | func (mod Sniffer) Author() string {
method isLocalPacket (line 135) | func (mod Sniffer) isLocalPacket(packet gopacket.Packet) bool {
method onPacketMatched (line 154) | func (mod *Sniffer) onPacketMatched(pkt gopacket.Packet) {
method Configure (line 160) | func (mod *Sniffer) Configure() error {
method Start (line 176) | func (mod *Sniffer) Start() error {
method Stop (line 231) | func (mod *Sniffer) Stop() error {
function NewSniffer (line 26) | func NewSniffer(s *session.Session) *Sniffer {
FILE: modules/net_sniff/net_sniff_context.go
type SnifferContext (line 18) | type SnifferContext struct
method Log (line 131) | func (c *SnifferContext) Log(sess *session.Session) {
method Close (line 140) | func (c *SnifferContext) Close() {
method GetContext (line 32) | func (mod *Sniffer) GetContext() (error, *SnifferContext) {
function NewSnifferContext (line 106) | func NewSnifferContext() *SnifferContext {
FILE: modules/net_sniff/net_sniff_dns.go
function dnsParser (line 12) | func dnsParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet,...
FILE: modules/net_sniff/net_sniff_dot11.go
function onDOT11 (line 8) | func onDOT11(radiotap *layers.RadioTap, dot11 *layers.Dot11, pkt gopacke...
FILE: modules/net_sniff/net_sniff_event.go
type SniffData (line 10) | type SniffData
type SnifferEvent (line 12) | type SnifferEvent struct
method Push (line 32) | func (e SnifferEvent) Push() {
function NewSnifferEvent (line 21) | func NewSnifferEvent(t time.Time, proto string, src string, dst string, ...
FILE: modules/net_sniff/net_sniff_ftp.go
function ftpParser (line 18) | func ftpParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet,...
FILE: modules/net_sniff/net_sniff_fuzz.go
method fuzz (line 24) | func (mod *Sniffer) fuzz(data []byte) int {
method doFuzzing (line 37) | func (mod *Sniffer) doFuzzing(pkt gopacket.Packet) {
method configureFuzzing (line 71) | func (mod *Sniffer) configureFuzzing() (err error) {
method StartFuzzing (line 95) | func (mod *Sniffer) StartFuzzing() error {
method StopFuzzing (line 115) | func (mod *Sniffer) StopFuzzing() error {
FILE: modules/net_sniff/net_sniff_http.go
type HTTPRequest (line 20) | type HTTPRequest struct
method IsType (line 30) | func (r HTTPRequest) IsType(ctype string) bool {
type HTTPResponse (line 34) | type HTTPResponse struct
method IsType (line 45) | func (r HTTPResponse) IsType(ctype string) bool {
function toSerializableRequest (line 49) | func toSerializableRequest(req *http.Request) HTTPRequest {
function toSerializableResponse (line 75) | func toSerializableResponse(res *http.Response) HTTPResponse {
function httpParser (line 120) | func httpParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet...
FILE: modules/net_sniff/net_sniff_krb5.go
function krb5Parser (line 15) | func krb5Parser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet...
FILE: modules/net_sniff/net_sniff_mdns.go
function mdnsParser (line 16) | func mdnsParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet...
FILE: modules/net_sniff/net_sniff_ntlm.go
function isNtlm (line 23) | func isNtlm(s string) bool {
function isChallenge (line 27) | func isChallenge(s string) bool {
function isResponse (line 31) | func isResponse(s string) bool {
function ntlmParser (line 35) | func ntlmParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet...
FILE: modules/net_sniff/net_sniff_parsers.go
function onUNK (line 16) | func onUNK(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet, ver...
function mainParser (line 36) | func mainParser(pkt gopacket.Packet, verbose bool) bool {
FILE: modules/net_sniff/net_sniff_sni.go
function sniParser (line 18) | func sniParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet,...
FILE: modules/net_sniff/net_sniff_stats.go
type SnifferStats (line 9) | type SnifferStats struct
method Print (line 31) | func (s *SnifferStats) Print() error {
function NewSnifferStats (line 19) | func NewSnifferStats() *SnifferStats {
FILE: modules/net_sniff/net_sniff_tcp.go
function onTCP (line 21) | func onTCP(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet, ver...
FILE: modules/net_sniff/net_sniff_teamviewer.go
function teamViewerParser (line 14) | func teamViewerParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket....
FILE: modules/net_sniff/net_sniff_udp.go
function onUDP (line 20) | func onUDP(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet, ver...
FILE: modules/net_sniff/net_sniff_upnp.go
function upnpParser (line 16) | func upnpParser(srcIP, dstIP net.IP, payload []byte, pkt gopacket.Packet...
FILE: modules/net_sniff/net_sniff_views.go
function vIP (line 13) | func vIP(ip net.IP) string {
function vPort (line 31) | func vPort(p interface{}) string {
function vURL (line 48) | func vURL(u string) string {
FILE: modules/packet_proxy/packet_proxy_darwin.go
type PacketProxy (line 7) | type PacketProxy struct
method Name (line 17) | func (mod PacketProxy) Name() string {
method Description (line 21) | func (mod PacketProxy) Description() string {
method Author (line 25) | func (mod PacketProxy) Author() string {
method Configure (line 29) | func (mod *PacketProxy) Configure() (err error) {
method Start (line 33) | func (mod *PacketProxy) Start() error {
method Stop (line 37) | func (mod *PacketProxy) Stop() error {
function NewPacketProxy (line 11) | func NewPacketProxy(s *session.Session) *PacketProxy {
FILE: modules/packet_proxy/packet_proxy_freebsd.go
type PacketProxy (line 7) | type PacketProxy struct
method Name (line 17) | func (mod PacketProxy) Name() string {
method Description (line 21) | func (mod PacketProxy) Description() string {
method Author (line 25) | func (mod PacketProxy) Author() string {
method Configure (line 29) | func (mod *PacketProxy) Configure() (err error) {
method Start (line 33) | func (mod *PacketProxy) Start() error {
method Stop (line 37) | func (mod *PacketProxy) Stop() error {
function NewPacketProxy (line 11) | func NewPacketProxy(s *session.Session) *PacketProxy {
FILE: modules/packet_proxy/packet_proxy_linux.go
type PacketProxy (line 19) | type PacketProxy struct
method Name (line 78) | func (mod PacketProxy) Name() string {
method Description (line 82) | func (mod PacketProxy) Description() string {
method Author (line 86) | func (mod PacketProxy) Author() string {
method destroyQueue (line 90) | func (mod *PacketProxy) destroyQueue() {
method runRule (line 99) | func (mod *PacketProxy) runRule(enable bool) (err error) {
method Configure (line 125) | func (mod *PacketProxy) Configure() (err error) {
method Start (line 212) | func (mod *PacketProxy) Start() error {
method Stop (line 224) | func (mod *PacketProxy) Stop() (err error) {
function NewPacketProxy (line 35) | func NewPacketProxy(s *session.Session) *PacketProxy {
function dummyCallback (line 199) | func dummyCallback(attribute nfqueue.Attribute) int {
FILE: modules/packet_proxy/packet_proxy_windows.go
type PacketProxy (line 7) | type PacketProxy struct
method Name (line 17) | func (mod PacketProxy) Name() string {
method Description (line 21) | func (mod PacketProxy) Description() string {
method Author (line 25) | func (mod PacketProxy) Author() string {
method Configure (line 29) | func (mod *PacketProxy) Configure() (err error) {
method Start (line 33) | func (mod *PacketProxy) Start() error {
method Stop (line 37) | func (mod *PacketProxy) Stop() error {
function NewPacketProxy (line 11) | func NewPacketProxy(s *session.Session) *PacketProxy {
FILE: modules/syn_scan/banner_grabbing.go
constant bannerGrabTimeout (line 10) | bannerGrabTimeout = time.Duration(5) * time.Second
type bannerGrabberFn (line 12) | type bannerGrabberFn
type grabberJob (line 14) | type grabberJob struct
method bannerGrabber (line 19) | func (mod *SynScanner) bannerGrabber(arg async.Job) {
FILE: modules/syn_scan/dns_grabber.go
function grabChaos (line 12) | func grabChaos(addr string, q string) string {
function dnsGrabber (line 26) | func dnsGrabber(mod *SynScanner, ip string, port int) string {
FILE: modules/syn_scan/http_grabber.go
function isTitleElement (line 12) | func isTitleElement(n *html.Node) bool {
function searchForTitle (line 16) | func searchForTitle(n *html.Node) string {
function httpGrabber (line 30) | func httpGrabber(mod *SynScanner, ip string, port int) string {
FILE: modules/syn_scan/syn_scan.go
constant synSourcePort (line 20) | synSourcePort = 666
type synScannerStats (line 22) | type synScannerStats struct
type SynScanner (line 31) | type SynScanner struct
method Name (line 102) | func (mod *SynScanner) Name() string {
method Description (line 106) | func (mod *SynScanner) Description() string {
method Author (line 110) | func (mod *SynScanner) Author() string {
method Configure (line 114) | func (mod *SynScanner) Configure() (err error) {
method Start (line 129) | func (mod *SynScanner) Start() error {
method showProgress (line 140) | func (mod *SynScanner) showProgress() error {
method Stop (line 155) | func (mod *SynScanner) Stop() error {
method scanWorker (line 168) | func (mod *SynScanner) scanWorker(job async.Job) {
method synScan (line 200) | func (mod *SynScanner) synScan() error {
function NewSynScanner (line 45) | func NewSynScanner(s *session.Session) *SynScanner {
function plural (line 133) | func plural(n uint64) string {
type scanJob (line 163) | type scanJob struct
FILE: modules/syn_scan/syn_scan_event.go
type SynScanEvent (line 8) | type SynScanEvent struct
method Push (line 22) | func (e SynScanEvent) Push() {
function NewSynScanEvent (line 14) | func NewSynScanEvent(address string, h *network.Endpoint, port int) SynS...
FILE: modules/syn_scan/syn_scan_parsers.go
method parseTargets (line 13) | func (mod *SynScanner) parseTargets(arg string) error {
method parsePorts (line 32) | func (mod *SynScanner) parsePorts(args []string) (err error) {
FILE: modules/syn_scan/syn_scan_reader.go
type OpenPort (line 14) | type OpenPort struct
method onPacket (line 21) | func (mod *SynScanner) onPacket(pkt gopacket.Packet) {
FILE: modules/syn_scan/tcp_grabber.go
function cleanBanner (line 11) | func cleanBanner(banner string) string {
function tcpGrabber (line 21) | func tcpGrabber(mod *SynScanner, ip string, port int) string {
FILE: modules/tcp_proxy/tcp_proxy.go
type TcpProxy (line 15) | type TcpProxy struct
method Name (line 77) | func (mod *TcpProxy) Name() string {
method Description (line 81) | func (mod *TcpProxy) Description() string {
method Author (line 85) | func (mod *TcpProxy) Author() string {
method Configure (line 89) | func (mod *TcpProxy) Configure() error {
method doPipe (line 155) | func (mod *TcpProxy) doPipe(from, to net.Addr, src *net.TCPConn, dst i...
method handleConnection (line 195) | func (mod *TcpProxy) handleConnection(c *net.TCPConn) {
method Start (line 223) | func (mod *TcpProxy) Start() error {
method Stop (line 243) | func (mod *TcpProxy) Stop() error {
function NewTcpProxy (line 25) | func NewTcpProxy(s *session.Session) *TcpProxy {
FILE: modules/tcp_proxy/tcp_proxy_script.go
type TcpProxyScript (line 16) | type TcpProxyScript struct
method OnData (line 50) | func (s *TcpProxyScript) OnData(from, to net.Addr, data []byte, callba...
function LoadTcpProxyScript (line 21) | func LoadTcpProxyScript(path string, sess *session.Session) (err error, ...
function toByteArray (line 65) | func toByteArray(ret interface{}) []byte {
FILE: modules/tcp_proxy/tcp_proxy_script_test.go
function TestOnData_NoReturn (line 10) | func TestOnData_NoReturn(t *testing.T) {
function TestOnData_ReturnsArrayOfIntegers (line 37) | func TestOnData_ReturnsArrayOfIntegers(t *testing.T) {
function TestOnData_ReturnsDynamicArray (line 77) | func TestOnData_ReturnsDynamicArray(t *testing.T) {
function TestOnData_ReturnsMixedArray (line 120) | func TestOnData_ReturnsMixedArray(t *testing.T) {
FILE: modules/ticker/ticker.go
type Params (line 11) | type Params struct
type Ticker (line 17) | type Ticker struct
method Name (line 72) | func (mod *Ticker) Name() string {
method Description (line 76) | func (mod *Ticker) Description() string {
method Author (line 80) | func (mod *Ticker) Author() string {
method Configure (line 84) | func (mod *Ticker) Configure() error {
method worker (line 108) | func (mod *Ticker) worker(name string, params *Params) {
method Start (line 140) | func (mod *Ticker) Start() error {
method Stop (line 150) | func (mod *Ticker) Stop() error {
method createNamed (line 159) | func (mod *Ticker) createNamed(name string, period int, commands strin...
method destroyNamed (line 177) | func (mod *Ticker) destroyNamed(name string) error {
function NewTicker (line 24) | func NewTicker(s *session.Session) *Ticker {
type TickEvent (line 106) | type TickEvent struct
FILE: modules/ticker/ticker_test.go
function createMockSession (line 16) | func createMockSession(t *testing.T) *session.Session {
function TestNewTicker (line 27) | func TestNewTicker(t *testing.T) {
function TestTickerConfigure (line 89) | func TestTickerConfigure(t *testing.T) {
function TestTickerStartStop (line 112) | func TestTickerStartStop(t *testing.T) {
function TestTickerAlreadyStarted (line 146) | func TestTickerAlreadyStarted(t *testing.T) {
function TestTickerNamedOperations (line 164) | func TestTickerNamedOperations(t *testing.T) {
function TestTickerHandlers (line 203) | func TestTickerHandlers(t *testing.T) {
function TestTickerWorker (line 280) | func TestTickerWorker(t *testing.T) {
function TestTickerParams (line 313) | func TestTickerParams(t *testing.T) {
function TestTickerMultipleNamed (line 331) | func TestTickerMultipleNamed(t *testing.T) {
function TestTickEvent (line 366) | func TestTickEvent(t *testing.T) {
function BenchmarkTickerCreate (line 374) | func BenchmarkTickerCreate(b *testing.B) {
function BenchmarkTickerStartStop (line 393) | func BenchmarkTickerStartStop(b *testing.B) {
FILE: modules/ui/ui.go
type UIModule (line 19) | type UIModule struct
method Name (line 57) | func (mod *UIModule) Name() string {
method Description (line 61) | func (mod *UIModule) Description() string {
method Author (line 65) | func (mod *UIModule) Author() string {
method Configure (line 69) | func (mod *UIModule) Configure() (err error) {
method Start (line 90) | func (mod *UIModule) Start() error {
method Stop (line 109) | func (mod *UIModule) Stop() error {
function NewUIModule (line 25) | func NewUIModule(s *session.Session) *UIModule {
FILE: modules/ui/ui/assets/fontawesome/js/all.js
function bunker (line 35) | function bunker(fn) {
function _defineProperty (line 45) | function _defineProperty(obj, key, value) {
function _objectSpread (line 60) | function _objectSpread(target) {
function defineIcons (line 86) | function defineIcons(prefix, icons) {
function bunker (line 586) | function bunker(fn) {
function _defineProperty (line 596) | function _defineProperty(obj, key, value) {
function _objectSpread (line 611) | function _objectSpread(target) {
function defineIcons (line 637) | function defineIcons(prefix, icons) {
function bunker (line 862) | function bunker(fn) {
function _defineProperty (line 872) | function _defineProperty(obj, key, value) {
function _objectSpread (line 887) | function _objectSpread(target) {
function defineIcons (line 913) | function defineIcons(prefix, icons) {
function _typeof (line 1896) | function _typeof(obj) {
function _classCallCheck (line 1910) | function _classCallCheck(instance, Constructor) {
function _defineProperties (line 1916) | function _defineProperties(target, props) {
function _createClass (line 1926) | function _createClass(Constructor, protoProps, staticProps) {
function _defineProperty (line 1932) | function _defineProperty(obj, key, value) {
function _objectSpread (line 1947) | function _objectSpread(target) {
function _slicedToArray (line 1966) | function _slicedToArray(arr, i) {
function _toConsumableArray (line 1970) | function _toConsumableArray(arr) {
function _arrayWithoutHoles (line 1974) | function _arrayWithoutHoles(arr) {
function _arrayWithHoles (line 1982) | function _arrayWithHoles(arr) {
function _iterableToArray (line 1986) | function _iterableToArray(iter) {
function _iterableToArrayLimit (line 1990) | function _iterableToArrayLimit(arr, i) {
function _nonIterableSpread (line 2016) | function _nonIterableSpread() {
function _nonIterableRest (line 2020) | function _nonIterableRest() {
function getAttrConfig (line 2104) | function getAttrConfig(attr) {
function coerce (line 2112) | function coerce(val) {
function domready (line 2183) | function domready (fn) {
function asyncFlush (line 2200) | function asyncFlush() {
function asyncCall (line 2211) | function asyncCall(callback, arg) {
function invokeResolver (line 2220) | function invokeResolver(resolver, promise) {
function invokeCallback (line 2236) | function invokeCallback(subscriber) {
function handleThenable (line 2264) | function handleThenable(promise, value) {
function resolve (line 2307) | function resolve(promise, value) {
function fulfill (line 2313) | function fulfill(promise, value) {
function reject (line 2321) | function reject(promise, reason) {
function publish (line 2329) | function publish(promise) {
function publishFulfillment (line 2333) | function publishFulfillment(promise) {
function publishRejection (line 2338) | function publishRejection(promise) {
function notifyRejectionHandled (line 2347) | function notifyRejectionHandled(promise) {
function P (line 2355) | function P(resolver) {
function resolver (line 2414) | function resolver(index) {
function isReserved (line 2487) | function isReserved(name) {
function bunker (line 2491) | function bunker(fn) {
function insertCss (line 2500) | function insertCss(css) {
function nextUniqueId (line 2524) | function nextUniqueId() {
function toArray (line 2534) | function toArray(obj) {
function classArray (line 2543) | function classArray(node) {
function getIconName (line 2552) | function getIconName(familyPrefix, cls) {
function htmlEscape (line 2563) | function htmlEscape(str) {
function joinAttributes (line 2566) | function joinAttributes(attributes) {
function joinStyles (line 2571) | function joinStyles(styles) {
function transformIsMeaningful (line 2576) | function transformIsMeaningful(transform) {
function transformForSvg (line 2579) | function transformForSvg(_ref) {
function transformForCss (line 2601) | function transformForCss(_ref2) {
function makeIconMasking (line 2630) | function makeIconMasking (_ref) {
function makeIconStandard (line 2701) | function makeIconStandard (_ref) {
function asIcon (line 2742) | function asIcon (_ref) {
function asSymbol (line 2769) | function asSymbol (_ref) {
function makeInlineSvgAbstract (line 2791) | function makeInlineSvgAbstract(params) {
function makeLayersTextAbstract (line 2859) | function makeLayersTextAbstract(params) {
function makeLayersCounterAbstract (line 2916) | function makeLayersCounterAbstract(params) {
function defineIcons (line 3026) | function defineIcons(prefix, icons) {
function byUnicode (line 3107) | function byUnicode(prefix, unicode) {
function byLigature (line 3110) | function byLigature(prefix, ligature) {
function byOldName (line 3113) | function byOldName(name) {
function getCanonicalIcon (line 3128) | function getCanonicalIcon(values) {
function iconFromMapping (line 3147) | function iconFromMapping(mapping, prefix, iconName) {
function toHtml (line 3157) | function toHtml(abstractNodes) {
function isWatched (line 3173) | function isWatched(node) {
function getMutator (line 3178) | function getMutator() {
function performOperationSync (line 3236) | function performOperationSync(op) {
function perform (line 3240) | function perform(mutations, callback) {
function disableObservation (line 3262) | function disableObservation() {
function enableObservation (line 3265) | function enableObservation() {
function observe (line 3269) | function observe(options) {
function disconnect (line 3320) | function disconnect() {
function styleParser (line 3325) | function styleParser (node) {
function toHex (line 3346) | function toHex(unicode) {
function classParser (line 3357) | function classParser (node) {
function transformParser (line 3445) | function transformParser (node) {
function symbolParser (line 3449) | function symbolParser (node) {
function attributesParser (line 3454) | function attributesParser (node) {
function maskParser (line 3476) | function maskParser (node) {
function blankMeta (line 3488) | function blankMeta() {
function parseMeta (line 3503) | function parseMeta(node) {
function MissingIcon (line 3529) | function MissingIcon(error) {
function findIcon (line 3608) | function findIcon(iconName, prefix) {
function generateSvgReplacementMutation (line 3647) | function generateSvgReplacementMutation(node, nodeMeta) {
function generateLayersText (line 3679) | function generateLayersText(node, nodeMeta) {
function generateMutation (line 3708) | function generateMutation(node) {
function onTree (line 3718) | function onTree(root) {
function onNode (line 3783) | function onNode(node) {
function replaceForPosition (line 3792) | function replaceForPosition(node, position) {
function replace (line 3865) | function replace(node) {
function processable (line 3869) | function processable(node) {
function searchPseudoElements (line 3873) | function searchPseudoElements (root) {
function css (line 3893) | function css () {
function Library (line 3912) | function Library() {
function prepIcon (line 3960) | function prepIcon(icon) {
function ensureCss (line 3978) | function ensureCss() {
function apiObject (line 3986) | function apiObject(val, abstractCreator) {
function findIconDefinition (line 4008) | function findIconDefinition(iconLookup) {
function resolveIcons (line 4016) | function resolveIcons(next) {
function bootstrap (line 4250) | function bootstrap() {
FILE: modules/ui/ui/assets/fontawesome/js/brands.js
function bunker (line 35) | function bunker(fn) {
function _defineProperty (line 45) | function _defineProperty(obj, key, value) {
function _objectSpread (line 60) | function _objectSpread(target) {
function defineIcons (line 86) | function defineIcons(prefix, icons) {
FILE: modules/ui/ui/assets/fontawesome/js/fontawesome.js
function _typeof (line 8) | function _typeof(obj) {
function _classCallCheck (line 22) | function _classCallCheck(instance, Constructor) {
function _defineProperties (line 28) | function _defineProperties(target, props) {
function _createClass (line 38) | function _createClass(Constructor, protoProps, staticProps) {
function _defineProperty (line 44) | function _defineProperty(obj, key, value) {
function _objectSpread (line 59) | function _objectSpread(target) {
function _slicedToArray (line 78) | function _slicedToArray(arr, i) {
function _toConsumableArray (line 82) | function _toConsumableArray(arr) {
function _arrayWithoutHoles (line 86) | function _arrayWithoutHoles(arr) {
function _arrayWithHoles (line 94) | function _arrayWithHoles(arr) {
function _iterableToArray (line 98) | function _iterableToArray(iter) {
function _iterableToArrayLimit (line 102) | function _iterableToArrayLimit(arr, i) {
function _nonIterableSpread (line 128) | function _nonIterableSpread() {
function _nonIterableRest (line 132) | function _nonIterableRest() {
function getAttrConfig (line 216) | function getAttrConfig(attr) {
function coerce (line 224) | function coerce(val) {
function domready (line 295) | function domready (fn) {
function asyncFlush (line 312) | function asyncFlush() {
function asyncCall (line 323) | function asyncCall(callback, arg) {
function invokeResolver (line 332) | function invokeResolver(resolver, promise) {
function invokeCallback (line 348) | function invokeCallback(subscriber) {
function handleThenable (line 376) | function handleThenable(promise, value) {
function resolve (line 419) | function resolve(promise, value) {
function fulfill (line 425) | function fulfill(promise, value) {
function reject (line 433) | function reject(promise, reason) {
function publish (line 441) | function publish(promise) {
function publishFulfillment (line 445) | function publishFulfillment(promise) {
function publishRejection (line 450) | function publishRejection(promise) {
function notifyRejectionHandled (line 459) | function notifyRejectionHandled(promise) {
function P (line 467) | function P(resolver) {
function resolver (line 526) | function resolver(index) {
function isReserved (line 599) | function isReserved(name) {
function bunker (line 603) | function bunker(fn) {
function insertCss (line 612) | function insertCss(css) {
function nextUniqueId (line 636) | function nextUniqueId() {
function toArray (line 646) | function toArray(obj) {
function classArray (line 655) | function classArray(node) {
function getIconName (line 664) | function getIconName(familyPrefix, cls) {
function htmlEscape (line 675) | function htmlEscape(str) {
function joinAttributes (line 678) | function joinAttributes(attributes) {
function joinStyles (line 683) | function joinStyles(styles) {
function transformIsMeaningful (line 688) | function transformIsMeaningful(transform) {
function transformForSvg (line 691) | function transformForSvg(_ref) {
function transformForCss (line 713) | function transformForCss(_ref2) {
function makeIconMasking (line 742) | function makeIconMasking (_ref) {
function makeIconStandard (line 813) | function makeIconStandard (_ref) {
function asIcon (line 854) | function asIcon (_ref) {
function asSymbol (line 881) | function asSymbol (_ref) {
function makeInlineSvgAbstract (line 903) | function makeInlineSvgAbstract(params) {
function makeLayersTextAbstract (line 971) | function makeLayersTextAbstract(params) {
function makeLayersCounterAbstract (line 1028) | function makeLayersCounterAbstract(params) {
function defineIcons (line 1138) | function defineIcons(prefix, icons) {
function byUnicode (line 1219) | function byUnicode(prefix, unicode) {
function byLigature (line 1222) | function byLigature(prefix, ligature) {
function byOldName (line 1225) | function byOldName(name) {
function getCanonicalIcon (line 1240) | function getCanonicalIcon(values) {
function iconFromMapping (line 1259) | function iconFromMapping(mapping, prefix, iconName) {
function toHtml (line 1269) | function toHtml(abstractNodes) {
function isWatched (line 1285) | function isWatched(node) {
function getMutator (line 1290) | function getMutator() {
function performOperationSync (line 1348) | function performOperationSync(op) {
function perform (line 1352) | function perform(mutations, callback) {
function disableObservation (line 1374) | function disableObservation() {
function enableObservation (line 1377) | function enableObservation() {
function observe (line 1381) | function observe(options) {
function disconnect (line 1432) | function disconnect() {
function styleParser (line 1437) | function styleParser (node) {
function toHex (line 1458) | function toHex(unicode) {
function classParser (line 1469) | function classParser (node) {
function transformParser (line 1557) | function transformParser (node) {
function symbolParser (line 1561) | function symbolParser (node) {
function attributesParser (line 1566) | function attributesParser (node) {
function maskParser (line 1588) | function maskParser (node) {
function blankMeta (line 1600) | function blankMeta() {
function parseMeta (line 1615) | function parseMeta(node) {
function MissingIcon (line 1641) | function MissingIcon(error) {
function findIcon (line 1720) | function findIcon(iconName, prefix) {
function generateSvgReplacementMutation (line 1759) | function generateSvgReplacementMutation(node, nodeMeta) {
function generateLayersText (line 1791) | function generateLayersText(node, nodeMeta) {
function generateMutation (line 1820) | function generateMutation(node) {
function onTree (line 1830) | function onTree(root) {
function onNode (line 1895) | function onNode(node) {
function replaceForPosition (line 1904) | function replaceForPosition(node, position) {
function replace (line 1977) | function replace(node) {
function processable (line 1981) | function processable(node) {
function searchPseudoElements (line 1985) | function searchPseudoElements (root) {
function css (line 2005) | function css () {
function Library (line 2024) | function Library() {
function prepIcon (line 2072) | function prepIcon(icon) {
function ensureCss (line 2090) | function ensureCss() {
function apiObject (line 2098) | function apiObject(val, abstractCreator) {
function findIconDefinition (line 2120) | function findIconDefinition(iconLookup) {
function resolveIcons (line 2128) | function resolveIcons(next) {
function bootstrap (line 2362) | function bootstrap() {
FILE: modules/ui/ui/assets/fontawesome/js/regular.js
function bunker (line 35) | function bunker(fn) {
function _defineProperty (line 45) | function _defineProperty(obj, key, value) {
function _objectSpread (line 60) | function _objectSpread(target) {
function defineIcons (line 86) | function defineIcons(prefix, icons) {
FILE: modules/ui/ui/assets/fontawesome/js/solid.js
function bunker (line 35) | function bunker(fn) {
function _defineProperty (line 45) | function _defineProperty(obj, key, value) {
function _objectSpread (line 60) | function _objectSpread(target) {
function defineIcons (line 86) | function defineIcons(prefix, icons) {
FILE: modules/ui/ui/assets/fontawesome/js/v4-shims.js
function bunker (line 38) | function bunker(fn) {
FILE: modules/ui/ui/assets/openlayers/ol.js
function t (line 14) | function t(a,b){var c=OPENLAYERS;a=a.split(".");c=c||aa;a[0]in c||!c.exe...
function w (line 14) | function w(a,b){a.prototype=Object.create(b.prototype);a.prototype.const...
function ea (line 14) | function ea(){}
function x (line 14) | function x(a){return a.xp||(a.xp=++fa)}
function ha (line 14) | function ha(a){this.message="Assertion failed. See https://openlayers.or...
function ja (line 14) | function ja(a,b,c,d){this.fa=a;this.la=b;this.ea=c;this.ka=d}
function ka (line 14) | function ka(a,b,c,d,e){return void 0!==e?(e.fa=a,e.la=b,e.ea=c,e.ka=d,e)...
function ma (line 14) | function ma(a,b,c){return a.fa<=b&&b<=a.la&&a.ea<=c&&c<=a.ka}
function na (line 14) | function na(a,b){return a.fa==b.fa&&a.ea==b.ea&&a.la==b.la&&a.ka==b.ka}
function oa (line 14) | function oa(a,b){if(!a)throw new ha(b);}
function pa (line 14) | function pa(a,b,c){return Math.min(Math.max(a,b),c)}
function ra (line 14) | function ra(a){oa(0<a,29);return Math.pow(2,Math.ceil(Math.log(a)/Math.L...
function sa (line 14) | function sa(a,b,c,d,e,f){var g=e-c,h=f-d;if(0!==g||0!==h){var l=((a-c)*g...
function ua (line 14) | function ua(a,b,c,d){a=c-a;b=d-b;return a*a+b*b}
function va (line 14) | function va(a){return a*Math.PI/180}
function wa (line 15) | function wa(a,b){a%=b;return 0>a*b?a+b:a}
function ya (line 15) | function ya(a,b,c){return a+c*(b-a)}
function za (line 15) | function za(a,b,c){void 0===c&&(c=[0,0]);c[0]=a[0]+2*b;c[1]=a[1]+2*b;ret...
function Aa (line 15) | function Aa(a,b,c){void 0===c&&(c=[0,0]);c[0]=a[0]*b+.5|0;c[1]=a[1]*b+.5...
function Ba (line 15) | function Ba(a,b){if(Array.isArray(a))return a;void 0===b?b=[a,a]:b[0]=b[...
function Ca (line 15) | function Ca(a){for(var b=Da(),c=0,d=a.length;c<d;++c)Ea(b,a[c]);return b}
function Fa (line 15) | function Fa(a,b,c){return c?(c[0]=a[0]-b,c[1]=a[1]-b,c[2]=a[2]+b,c[3]=a[...
function Ga (line 15) | function Ga(a,b){return b?(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b):a....
function Ha (line 15) | function Ha(a,b,c){b=b<a[0]?a[0]-b:a[2]<b?b-a[2]:0;a=c<a[1]?a[1]-c:a[3]<...
function Ja (line 15) | function Ja(a,b){return Ka(a,b[0],b[1])}
function La (line 15) | function La(a,b){return a[0]<=b[0]&&b[2]<=a[2]&&a[1]<=b[1]&&b[3]<=a[3]}
function Ka (line 16) | function Ka(a,b,c){return a[0]<=b&&b<=a[2]&&a[1]<=c&&c<=a[3]}
function Ma (line 16) | function Ma(a,b){var c=a[1],d=a[2],e=a[3],f=b[0];b=b[1];var g=0;f<a[0]?g...
function Da (line 16) | function Da(){return[Infinity,Infinity,-Infinity,-Infinity]}
function Na (line 16) | function Na(a,b,c,d,e){return e?(e[0]=a,e[1]=b,e[2]=c,e[3]=d,e):[a,b,c,d]}
function Oa (line 16) | function Oa(a){return Na(Infinity,Infinity,-Infinity,-Infinity,a)}
function Pa (line 16) | function Pa(a,b){var c=a[0];a=a[1];return Na(c,a,c,a,b)}
function Qa (line 17) | function Qa(a,b,c,d,e){e=Oa(e);return Ra(e,a,b,c,d)}
function Sa (line 17) | function Sa(a,b){return a[0]==b[0]&&a[2]==b[2]&&a[1]==b[1]&&a[3]==b[3]}
function Ta (line 17) | function Ta(a,b){b[0]<a[0]&&(a[0]=b[0]);b[2]>a[2]&&(a[2]=b[2]);b[1]<a[1]...
function Ea (line 17) | function Ea(a,b){b[0]<a[0]&&(a[0]=b[0]);b[0]>a[2]&&(a[2]=b[0]);b[1]<a[1]...
function Ra (line 18) | function Ra(a,b,c,d,e){for(;c<d;c+=e){var f=a,g=b[c],h=b[c+1];f[0]=Math....
function Ua (line 18) | function Ua(a,b,c){var d;return(d=b.call(c,Wa(a)))||(d=b.call(c,Ya(a)))|...
function ab (line 18) | function ab(a){var b=0;bb(a)||(b=cb(a)*db(a));return b}
function Wa (line 18) | function Wa(a){return[a[0],a[1]]}
function Ya (line 18) | function Ya(a){return[a[2],a[1]]}
function eb (line 18) | function eb(a){return[(a[0]+a[2])/2,(a[1]+a[3])/2]}
function fb (line 19) | function fb(a,b,c,d,e){var f=b*d[0]/2;d=b*d[1]/2;b=Math.cos(c);var g=Mat...
function db (line 19) | function db(a){return a[3]-a[1]}
function gb (line 19) | function gb(a,b,c){c=c?c:Da();hb(a,b)&&(c[0]=a[0]>b[0]?a[0]:b[0],c[1]=a[...
function $a (line 19) | function $a(a){return[a[0],a[3]]}
function Za (line 20) | function Za(a){return[a[2],a[3]]}
function cb (line 20) | function cb(a){return a[2]-a[0]}
function hb (line 20) | function hb(a,b){return a[0]<=b[2]&&a[2]>=b[0]&&a[1]<=b[3]&&a[3]>=b[1]}
function bb (line 20) | function bb(a){return a[2]<a[0]||a[3]<a[1]}
function ib (line 20) | function ib(a,b){var c=(a[2]-a[0])/2*(b-1);b=(a[3]-a[1])/2*(b-1);a[0]-=c...
function jb (line 21) | function jb(a,b,c){a=[a[0],a[1],a[0],a[3],a[2],a[1],a[2],a[3]];b(a,a,2);...
function lb (line 21) | function lb(a){for(var b in a)delete a[b]}
function mb (line 21) | function mb(a){var b=[],c;for(c in a)b.push(a[c]);return b}
function nb (line 21) | function nb(a){for(var b in a)return!1;return!b}
function ob (line 27) | function ob(a){this.radius=a}
function rb (line 28) | function rb(a,b){var c=b||{},d=c.radius||6371008.8;c=c.projection||"EPSG...
function sb (line 29) | function sb(a,b){for(var c=0,d=0,e=a.length;d<e-1;++d)c+=qb(a[d],a[d+1],...
function qb (line 29) | function qb(a,b,c){var d=va(a[1]),e=va(b[1]),f=(e-d)/2;a=va(b[0]-a[0])/2...
function tb (line 30) | function tb(a,b){var c=b||{},d=c.radius||6371008.8;c=c.projection||"EPSG...
function pb (line 31) | function pb(a,b){for(var c=0,d=a.length,e=a[d-1][0],f=a[d-1][1],g=0;g<d;...
function wb (line 31) | function wb(a){this.wb=a.code;this.a=a.units;this.i=void 0!==a.extent?a....
function xb (line 32) | function xb(a){wb.call(this,{code:a,units:"m",extent:yb,global:!0,worldE...
function Cb (line 33) | function Cb(a,b,c){var d=a.length;c=1<c?c:2;void 0===b&&(2<c?b=a.slice()...
function Db (line 33) | function Db(a,b,c){var d=a.length;c=1<c?c:2;void 0===b&&(2<c?b=a.slice()...
function Eb (line 33) | function Eb(a,b){wb.call(this,{code:a,units:"degrees",extent:Fb,axisOrie...
function Kb (line 33) | function Kb(a,b,c){a=a.wb;b=b.wb;a in Jb||(Jb[a]={});Jb[a][b]=c}
function Lb (line 33) | function Lb(a,b){var c;a in Jb&&b in Jb[a]&&(c=Jb[a][b]);return c}
function Nb (line 33) | function Nb(a,b,c,d){a=Ob(a);var e=a.j;e?b=e(b,c):"degrees"==a.a&&!d||"d...
function Qb (line 33) | function Qb(a){a.forEach(Rb);a.forEach(function(b){a.forEach(function(a)...
function Tb (line 34) | function Tb(){Hb.forEach(function(a){Bb.forEach(function(b){Kb(a,b,Cb);K...
function Rb (line 34) | function Rb(a){Ib[a.wb]=a;Kb(a,a,Sb)}
function Ub (line 34) | function Ub(a){return a?"string"===typeof a?Ob(a):a:Ob("EPSG:3857")}
function Vb (line 34) | function Vb(a,b,c,d){a=Ob(a);b=Ob(b);Kb(a,b,Wb(c));Kb(b,a,Wb(d))}
function Wb (line 34) | function Wb(a){return function(b,c,d){var e=b.length;d=void 0!==d?d:2;c=...
function Ob (line 35) | function Ob(a){var b=null;if(a instanceof wb)b=a;else if("string"===type...
function Xb (line 35) | function Xb(a,b){if(a===b)return!0;var c=a.a===b.a;return a.wb===b.wb?c:...
function Yb (line 35) | function Yb(a,b){a=Ob(a);b=Ob(b);return Pb(a,b)}
function Pb (line 36) | function Pb(a,b){var c=a.wb,d=b.wb,e=Lb(c,d);if(!e){var f=vb||window.pro...
function $b (line 36) | function $b(a,b){if(void 0!==b&&a!==b){for(var c=0,d=a.length;c<d;++c)b[...
function Sb (line 36) | function Sb(a,b){if(void 0!==b){for(var c=0,d=a.length;c<d;++c)b[c]=a[c]...
function ac (line 36) | function ac(a,b,c){return Yb(b,c)(a,void 0,a.length)}
function bc (line 37) | function bc(a,b,c){b=Yb(b,c);return jb(a,b)}
function cc (line 37) | function cc(){Qb(Bb);Qb(Hb);Tb()}
function dc (line 37) | function dc(a,b){return a>b?1:a<b?-1:0}
function ec (line 37) | function ec(a,b){return 0<=a.indexOf(b)}
function fc (line 37) | function fc(a,b,c){var d=a.length;if(a[0]<=b)return 0;if(!(b<=a[d-1]))if...
function gc (line 37) | function gc(a,b){var c=Array.isArray(b)?b:[b],d=c.length;for(b=0;b<d;b++...
function hc (line 38) | function hc(a,b){for(var c=a.length>>>0,d,e=0;e<c;e++)if(d=a[e],b(d,e,a)...
function jc (line 38) | function jc(a,b){var c=a.length;if(c!==b.length)return!1;for(var d=0;d<c...
function kc (line 38) | function kc(a){var b=lc,c=a.length,d=Array(a.length),e;for(e=0;e<c;e++)d...
function mc (line 38) | function mc(a,b){var c;return a.every(function(d,e){c=e;return!b(d,e,a)}...
function nc (line 39) | function nc(a,b){var c=b||dc;return a.every(function(b,e){if(0===e)retur...
function oc (line 39) | function oc(a,b,c,d){return void 0!==d?(d[0]=a,d[1]=b,d[2]=c,d):[a,b,c]}
function pc (line 39) | function pc(a){var b=a[0],c=Array(b),d=1<<b-1,e;for(e=0;e<b;++e){var f=4...
function qc (line 39) | function qc(a){this.minZoom=void 0!==a.minZoom?a.minZoom:0;this.b=a.reso...
function uc (line 41) | function uc(a,b,c,d,e){var f=null,g=b[0]-1;if(2===a.l){var h=b[1];var l=...
function vc (line 42) | function vc(a,b,c,d){if(b[0]<a.maxZoom){if(2===a.l)return a=2*b[1],b=2*b...
function wc (line 42) | function wc(a,b,c){var d=a.Ic(b),e=a.Ta(b);a=Ba(a.Za(b),a.f);return Na(d...
function tc (line 42) | function tc(a,b,c,d){xc(a,b[0],b[1],c,!1,sc);var e=sc[1],f=sc[2];xc(a,b[...
function yc (line 43) | function yc(a,b){var c=a.Ic(b[0]),d=a.Ta(b[0]);a=Ba(a.Za(b[0]),a.f);retu...
function xc (line 44) | function xc(a,b,c,d,e,f){var g=a.Ic(d),h=a.Ta(d);a=Ba(a.Za(d),a.f);b=Mat...
function rc (line 45) | function rc(a,b){for(var c=a.b.length,d=Array(c),e=a.minZoom;e<c;++e)d[e...
function zc (line 45) | function zc(a){var b=a.f;b||(b=Ac(a),a.f=b);return b}
function Bc (line 45) | function Bc(a){var b={};kb(b,void 0!==a?a:{});void 0===b.extent&&(b.exte...
function Cc (line 45) | function Cc(a,b,c){b=void 0!==b?b:42;var d=db(a);a=cb(a);c=Ba(void 0!==c...
function Ac (line 46) | function Ac(a,b,c){a=Dc(a);b=Cc(a,b,c);return new qc({extent:a,origin:$a...
function Dc (line 46) | function Dc(a){a=Ob(a);var b=a.G();b||(a=180*ub.degrees/a.Bc(),b=Na(-a,-...
function Ec (line 46) | function Ec(a){this.og=a.html}
function Fc (line 46) | function Fc(a){function b(b){var c=a.listener,e=a.Ch||a.target;a.Eh&&Gc(...
function Hc (line 46) | function Hc(a,b,c,d){for(var e,f=0,g=a.length;f<g;++f)if(e=a[f],e.listen...
function Ic (line 46) | function Ic(a,b){return(a=a.ab)?a[b]:void 0}
function Jc (line 46) | function Jc(a){var b=a.ab;b||(b=a.ab={});return b}
function Kc (line 47) | function Kc(a,b){var c=Ic(a,b);if(c){for(var d=0,e=c.length;d<e;++d)a.re...
function y (line 47) | function y(a,b,c,d,e){var f=Jc(a),g=f[b];g||(g=f[b]=[]);(f=Hc(g,c,d,!1))...
function Lc (line 47) | function Lc(a,b,c,d){return y(a,b,c,d,!0)}
function Mc (line 47) | function Mc(a,b,c,d){(a=Ic(a,b))&&(c=Hc(a,c,d,!0))&&Gc(c)}
function Gc (line 48) | function Gc(a){if(a&&a.target){a.target.removeEventListener(a.type,a.Dh)...
function Nc (line 48) | function Nc(a){var b=Jc(a),c;for(c in b)Kc(a,c)}
function Oc (line 48) | function Oc(){}
function Pc (line 48) | function Pc(a){a.Ub||(a.Ub=!0,a.ia())}
function Qc (line 48) | function Qc(a){this.type=a;this.target=null}
function Rc (line 48) | function Rc(a){a.stopPropagation()}
function Sc (line 48) | function Sc(){this.Wa={};this.qa={};this.oa={}}
function Tc (line 49) | function Tc(a,b){return b?b in a.oa:0<Object.keys(a.oa).length}
function Uc (line 50) | function Uc(){Sc.call(this);this.g=0}
function Vc (line 51) | function Vc(a){Uc.call(this);x(this);this.N={};void 0!==a&&this.H(a)}
function Xc (line 51) | function Xc(a){return Wc.hasOwnProperty(a)?Wc[a]:Wc[a]="change:"+a}
function Yc (line 51) | function Yc(a,b,c){var d=Xc(b);a.b(new Zc(d,b,c));a.b(new Zc("propertych...
function Zc (line 52) | function Zc(a,b,c){Qc.call(this,a);this.key=b;this.oldValue=c}
function B (line 52) | function B(a,b){Vc.call(this);this.c=!!(b||{}).unique;this.a=a?a:[];if(t...
function ad (line 54) | function ad(a){a.set(bd,a.a.length)}
function $c (line 54) | function $c(a,b,c){for(var d=0,e=a.a.length;d<e;++d)if(a.a[d]===b&&d!==c...
function cd (line 54) | function cd(a,b){Qc.call(this,a);this.element=b}
function dd (line 54) | function dd(a,b,c){Qc.call(this,a);this.map=b;this.frameState=void 0!==c...
function ed (line 54) | function ed(a,b,c,d,e){dd.call(this,a,b,e);this.originalEvent=c;this.pix...
function gd (line 54) | function gd(a,b){var c,d,e=fd.length;for(d=0;d<e;++d)try{if(c=a.getConte...
function Ad (line 55) | function Ad(a,b,c,d,e){ed.call(this,a,b,c.b,d,e);this.b=c}
function Bd (line 55) | function Bd(a,b){this.b=a;this.i=b}
function Cd (line 55) | function Cd(a){Bd.call(this,a,{mousedown:this.Jm,mousemove:this.Km,mouse...
function Dd (line 55) | function Dd(a,b){a=a.g;var c=b.clientX;b=b.clientY;for(var d=0,e=a.lengt...
function Ed (line 55) | function Ed(a){var b=Fd(a,a),c=b.preventDefault;b.preventDefault=functio...
function Kd (line 57) | function Kd(a){Bd.call(this,a,{MSPointerDown:this.Sm,MSPointerMove:this....
function Ld (line 57) | function Ld(a,b){var c=b;"number"===typeof b.pointerType&&(c=Fd(b,b),c.p...
function Nd (line 59) | function Nd(a){Bd.call(this,a,{pointerdown:this.Kp,pointermove:this.Lp,p...
function Md (line 59) | function Md(a,b,c){Qc.call(this,a);this.b=b;a=c?c:{};this.buttons=Pd(a);...
function Pd (line 61) | function Pd(a){if(a.buttons||Rd)a=a.buttons;else switch(a.which){case 1:...
function Qd (line 61) | function Qd(a,b){var c=0;a.pressure?c=a.pressure:c=b?.5:0;return c}
function Sd (line 61) | function Sd(a,b){Bd.call(this,a,{touchstart:this.Qq,touchmove:this.Pq,to...
function Td (line 62) | function Td(a,b,c){b=Fd(b,c);b.pointerId=c.identifier+2;b.bubbles=!0;b.c...
function Ud (line 63) | function Ud(a,b,c){function d(){b.preventDefault()}var e=Array.prototype...
function Vd (line 68) | function Vd(a,b){var c=a.j.g;b=b.changedTouches[0];if(a.g===b.identifier...
function Xd (line 68) | function Xd(a){Sc.call(this);this.f=a;this.g={};this.i={};this.a=[];td?Y...
function Yd (line 68) | function Yd(a,b){var c=Object.keys(b.i);c&&(c.forEach(function(a){var c=...
function Zd (line 69) | function Zd(a,b){b.forEach(function(a){y(this.f,a,this.c,this)},a)}
function $d (line 69) | function $d(a,b){b.forEach(function(a){Mc(this.f,a,this.c,this)},a)}
function Fd (line 69) | function Fd(a,b){for(var c={},d,e=0,f=ae.length;e<f;e++)d=ae[e][0],c[d]=...
function Wd (line 69) | function Wd(a,b,c){b.bubbles=!1;Gd(a,"pointerleave",b,c)}
function Jd (line 70) | function Jd(a,b,c){a.out(b,c);var d=b.target,e=b.relatedTarget;d&&e&&d.c...
function Hd (line 70) | function Hd(a,b,c){b.bubbles=!0;Gd(a,"pointerover",b,c);var d=b.target,e...
function Gd (line 70) | function Gd(a,b,c,d){a.b(new Md(b,d,c))}
function Od (line 70) | function Od(a,b){a.b(new Md(b.type,b,b))}
function be (line 71) | function be(a,b){Sc.call(this);this.g=a;this.j=0;this.l=!1;this.i=[];thi...
function ce (line 71) | function ce(a,b){var c=new Ad("click",a.g,b);a.b(c);0!==a.j?(clearTimeou...
function de (line 72) | function de(a,b){"pointerup"==b.type||"pointercancel"==b.type?delete a.o...
function fe (line 74) | function fe(a,b){return Math.abs(b.clientX-a.c.clientX)>a.D||Math.abs(b....
function ge (line 74) | function ge(a,b){this.s=a;this.c=b;this.b=[];this.g=[];this.a={}}
function he (line 74) | function he(a){var b=a.b,c=a.g,d=b[0];1==b.length?(b.length=0,c.length=0...
function ie (line 75) | function ie(a,b){for(var c=a.b,d=a.g,e=c.length,f=c[b],g=d[b],h=b;b<e>>1...
function je (line 75) | function je(a,b,c){var d=a.b;a=a.g;for(var e=d[c],f=a[c];c>b;){var g=c-1...
function ke (line 76) | function ke(a){var b=a.s,c=a.b,d=a.g,e=0,f=c.length,g;for(g=0;g<f;++g){v...
function le (line 76) | function le(a,b){ge.call(this,function(b){return a.apply(null,b)},functi...
function me (line 77) | function me(a,b,c){for(var d=0,e=!1,f,g,h;a.j<b&&d<c&&0<a.b.length;)g=he...
function ne (line 77) | function ne(a){return function(b){if(b)return[pa(b[0],a[0],a[2]),pa(b[1]...
function oe (line 77) | function oe(a){return a}
function pe (line 77) | function pe(a){return function(b,c,d){if(void 0!==b)return b=fc(a,b,d),b...
function qe (line 77) | function qe(a,b,c){return function(d,e,f){if(void 0!==d)return d=Math.ma...
function re (line 77) | function re(a){if(void 0!==a)return 0}
function se (line 77) | function se(a,b){if(void 0!==a)return a+b}
function ue (line 77) | function ue(a){var b=2*Math.PI/a;return function(a,d){if(void 0!==a)retu...
function we (line 77) | function we(){var a=va(5);return function(b,c){if(void 0!==b)return Math...
function xe (line 77) | function xe(a,b){a=void 0!==b?a.toFixed(b):""+a;b=a.indexOf(".");b=-1===...
function ye (line 77) | function ye(a){a=(""+a).split(".");for(var b=["1","3"],c=0;c<Math.max(a....
function ze (line 77) | function ze(a,b){a[0]+=b[0];a[1]+=b[1];return a}
function Ae (line 77) | function Ae(a,b){var c=b.Bd(),d=b.xa();b=d[0];d=d[1];var e=a[0]-b;a=a[1]...
function Be (line 77) | function Be(a,b){var c=a[0];a=a[1];var d=b[0],e=b[1];b=d[0];d=d[1];var f...
function Ce (line 78) | function Ce(a,b,c){b=wa(b+180,360)-180;var d=Math.abs(3600*b);c=c||0;var...
function De (line 78) | function De(a,b,c){return a?b.replace("{x}",a[0].toFixed(c)).replace("{y...
function Ee (line 78) | function Ee(a,b){for(var c=!0,d=a.length-1;0<=d;--d)if(a[d]!=b[d]){c=!1;...
function Fe (line 79) | function Fe(a,b){var c=Math.cos(b);b=Math.sin(b);var d=a[1]*c+a[0]*b;a[0...
function Ge (line 79) | function Ge(a,b){a[0]*=b;a[1]*=b}
function He (line 79) | function He(a,b){var c=a[0]-b[0];a=a[1]-b[1];return c*c+a*a}
function Ie (line 79) | function Ie(a,b){return Math.sqrt(He(a,b))}
function Je (line 79) | function Je(a,b){return He(a,Be(a,b))}
function Ke (line 79) | function Ke(a,b){return De(a,"{x}, {y}",b)}
function Me (line 79) | function Me(a){return Math.pow(a,3)}
function Oe (line 79) | function Oe(a){return 1-Me(1-a)}
function Pe (line 79) | function Pe(a){return 3*a*a-2*a*a*a}
function Qe (line 79) | function Qe(a){return a}
function Re (line 79) | function Re(){return!0}
function Se (line 79) | function Se(){return!1}
function Te (line 79) | function Te(a,b,c,d,e,f){for(var g=f?f:[],h=0;b<c;b+=d){var l=a[b],m=a[b...
function Ue (line 79) | function Ue(a,b,c,d,e,f,g){for(var h=g?g:[],l=0,m;b<c;b+=d)for(h[l++]=a[...
function We (line 79) | function We(){return[1,0,0,1,0,0]}
function Xe (line 79) | function Xe(a){return Ye(a,1,0,0,1,0,0)}
function Ze (line 79) | function Ze(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],l=b[0],m=...
function Ye (line 79) | function Ye(a,b,c,d,e,f,g){a[0]=b;a[1]=c;a[2]=d;a[3]=e;a[4]=f;a[5]=g;ret...
function $e (line 79) | function $e(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=...
function af (line 80) | function af(a,b){var c=b[0],d=b[1];b[0]=a[0]*c+a[2]*d+a[4];b[1]=a[1]*c+a...
function bf (line 80) | function bf(a,b){var c=Math.cos(b);b=Math.sin(b);Ze(a,Ye(Ve,c,b,-b,c,0,0))}
function cf (line 80) | function cf(a,b,c){return Ze(a,Ye(Ve,b,0,0,c,0,0))}
function df (line 80) | function df(a,b,c){Ze(a,Ye(Ve,1,0,0,1,b,c))}
function ef (line 80) | function ef(a,b,c,d,e,f,g,h){var l=Math.sin(f);f=Math.cos(f);a[0]=d*f;a[...
function ff (line 81) | function ff(a){var b=a[0]*a[3]-a[1]*a[2];oa(0!==b,32);var c=a[0],d=a[1],...
function gf (line 81) | function gf(){Vc.call(this);this.s=Da();this.v=-1;this.i={};this.l=this....
function hf (line 82) | function hf(){gf.call(this);this.ja="XY";this.a=2;this.A=null}
function jf (line 82) | function jf(a){var b;"XY"==a?b=2:"XYZ"==a||"XYM"==a?b=3:"XYZM"==a&&(b=4)...
function kf (line 83) | function kf(a,b,c){a.a=jf(b);a.ja=b;a.A=c}
function lf (line 84) | function lf(a,b,c,d){if(b)c=jf(b);else{for(b=0;b<d;++b){if(0===c.length)...
function mf (line 86) | function mf(a,b,c,d){for(var e=0,f=a[c-d],g=a[c-d+1];b<c;b+=d){var h=a[b...
function nf (line 86) | function nf(a,b,c,d){var e=0,f;var g=0;for(f=c.length;g<f;++g){var h=c[g...
function of (line 86) | function of(a,b,c,d,e,f,g){var h=a[b],l=a[b+1],m=a[c]-h,n=a[c+1]-l;if(0!...
function pf (line 86) | function pf(a,b,c,d,e){var f=a[b],g=a[b+1];for(b+=d;b<c;b+=d){var h=a[b]...
function qf (line 86) | function qf(a,b,c,d,e){var f;var g=0;for(f=c.length;g<f;++g){var h=c[g];...
function tf (line 87) | function tf(a,b,c,d,e,f,g,h,l,m,n){if(b==c)return m;if(0===e){var p=ua(g...
function uf (line 88) | function uf(a,b,c,d,e,f,g,h,l,m,n){n=n?n:[NaN,NaN];var p;var q=0;for(p=c...
function vf (line 88) | function vf(a,b){var c=0,d;var e=0;for(d=b.length;e<d;++e)a[c++]=b[e];re...
function wf (line 88) | function wf(a,b,c,d){var e;var f=0;for(e=c.length;f<e;++f){var g=c[f],h;...
function xf (line 88) | function xf(a,b,c,d,e){e=e?e:[];var f=0,g;var h=0;for(g=c.length;h<g;++h...
function yf (line 88) | function yf(a,b,c,d,e){e=void 0!==e?e:[];for(var f=0;b<c;b+=d)e[f++]=a.s...
function zf (line 88) | function zf(a,b,c,d,e){e=void 0!==e?e:[];var f=0,g;var h=0;for(g=c.lengt...
function Af (line 88) | function Af(a,b,c,d,e){e=void 0!==e?e:[];var f=0,g;var h=0;for(g=c.lengt...
function Bf (line 88) | function Bf(a,b,c,d,e,f,g){var h=(c-b)/d;if(3>h){for(;b<c;b+=d)f[g++]=a[...
function Cf (line 89) | function Cf(a,b,c,d,e,f,g,h){var l;var m=0;for(l=c.length;m<l;++m){var n...
function Df (line 90) | function Df(a,b){hf.call(this);this.c=this.j=-1;this.na(a,b)}
function Ef (line 91) | function Ef(a,b,c){kf(a,b,c);a.u()}
function C (line 91) | function C(a,b){hf.call(this);this.na(a,b)}
function Ff (line 92) | function Ff(a,b,c,d,e){return!Ua(e,function(e){return!Gf(a,b,c,d,e[0],e[...
function Gf (line 92) | function Gf(a,b,c,d,e,f){for(var g=0,h=a[c-d],l=a[c-d+1];b<c;b+=d){var m...
function Hf (line 92) | function Hf(a,b,c,d,e,f){if(0===c.length||!Gf(a,b,c[0],d,e,f))return!1;v...
function If (line 92) | function If(a,b,c,d,e,f,g){for(var h,l,m,n,p,q=e[f+1],r=[],u=0,v=c.lengt...
function Jf (line 92) | function Jf(a,b,c,d,e,f){for(var g=[a[b],a[b+1]],h=[],l;b+d<c;b+=d){h[0]...
function Kf (line 92) | function Kf(a,b,c,d,e){var f=Ra(Da(),a,b,c,d);return hb(e,f)?La(e,f)||f[...
function Lf (line 93) | function Lf(a,b,c,d,e){var f=c[0];if(!(Kf(a,b,f,d,e)||Gf(a,b,f,d,e[0],e[...
function Mf (line 93) | function Mf(a,b,c,d){for(var e=0,f=a[c-d],g=a[c-d+1];b<c;b+=d){var h=a[b...
function Nf (line 93) | function Nf(a,b,c,d){var e=0;d=void 0!==d?d:!1;var f;var g=0;for(f=b.len...
function Of (line 94) | function Of(a,b,c,d,e){e=void 0!==e?e:!1;var f;var g=0;for(f=c.length;g<...
function Pf (line 94) | function Pf(a,b,c,d){var e=0,f;var g=0;for(f=b.length;g<f;++g)e=Of(a,e,b...
function D (line 94) | function D(a,b){hf.call(this);this.c=[];this.o=-1;this.D=null;this.T=thi...
function Qf (line 98) | function Qf(a,b,c,d){var e=d?d:32;d=[];var f;for(f=0;f<e;++f)gc(d,a.offs...
function Rf (line 98) | function Rf(a){var b=a[0],c=a[1],d=a[2];a=a[3];b=[b,c,b,a,d,a,d,c,b,c];c...
function Sf (line 99) | function Sf(a,b,c){var d=b?b:32,e=a.pa();b=a.ja;var f=new D(null,b);d=e*...
function Tf (line 99) | function Tf(a,b,c,d){var e=a.da(),f=a.ja,g=a.pa(),h=a.pb(),l=e.length/g-...
function F (line 99) | function F(a){Vc.call(this);a=kb({},a);this.f=[0,0];this.c=[];this.Ff=th...
function Vf (line 100) | function Vf(a,b){var c={};c.center=void 0!==b.center?b.center:null;var d...
function $f (line 102) | function $f(a,b){var c=kb({},a.C);void 0!==c.resolution?c.resolution=a.P...
function dg (line 107) | function dg(a,b,c){var d=a.xa();if(void 0!==d){var e=[d[0]-c[0],d[1]-c[1...
function cg (line 108) | function cg(a,b,c){var d,e=a.xa();a=a.Pa();void 0!==e&&void 0!==a&&(d=[c...
function eg (line 108) | function eg(a){var b=[100,100];a='.ol-viewport[data-view="'+x(a)+'"]';if...
function fg (line 110) | function fg(a){var b=a.a,c=Math.log(b/a.i)/Math.log(2);return function(a...
function gg (line 110) | function gg(a){var b=a.a,c=Math.log(b/a.i)/Math.log(2);return function(a...
function ag (line 114) | function ag(a){return!!a.xa()&&void 0!==a.Pa()}
function bg (line 115) | function bg(a,b,c){a.f[b]+=c;a.u()}
function hg (line 115) | function hg(a,b){var c=document.createElement("CANVAS");a&&(c.width=a);b...
function ig (line 115) | function ig(a,b){var c=b.parentNode;c&&c.replaceChild(a,b)}
function jg (line 115) | function jg(a){a&&a.parentNode&&a.parentNode.removeChild(a)}
function kg (line 115) | function kg(a){Vc.call(this);var b=kb({},a);b.opacity=void 0!==a.opacity...
function lg (line 116) | function lg(a){a.a.opacity=pa(a.nc(),0,1);a.a.Vj=a.hg();a.a.visible=a.Jb...
function mg (line 117) | function mg(a){var b=a||{};a=kb({},b);delete a.layers;b=b.layers;kg.call...
function qg (line 120) | function qg(a,b){switch(a){case "MAP_RENDERER":a=og;a.push(b);break;case...
function rg (line 120) | function rg(a){for(var b=0,c=a.length;b<c;++b)qg("LAYER_RENDERER",a[b])}
function G (line 120) | function G(a){Vc.call(this);var b=sg(a);this.ob=void 0!==a.loadTilesWhil...
function sg (line 138) | function sg(a){var b=null;void 0!==a.keyboardEventTarget&&(b="string"===...
function vg (line 141) | function vg(a){Vc.call(this);this.element=a.element?a.element:null;this....
function xg (line 142) | function xg(a){var b=kb({},a);delete b.source;kg.call(this,b);this.o=thi...
function yg (line 142) | function yg(a,b){return a.visible&&b>=a.minResolution&&b<a.maxResolution}
function zg (line 143) | function zg(a){a=a?a:{};this.v=document.createElement("UL");this.l=docum...
function Ag (line 146) | function Ag(a){if(a=a.frameState){for(var b={},c=[],d=a.layerStatesArray...
function Bg (line 148) | function Bg(a){a.element.classList.toggle("ol-collapsed");a.c?ig(a.o,a.D...
function Cg (line 148) | function Cg(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-rotat...
function Dg (line 150) | function Dg(a){if(a=a.frameState){a=a.viewState.rotation;if(a!=this.o){v...
function Eg (line 150) | function Eg(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-zoom"...
function Fg (line 152) | function Fg(a){a=a?a:{};var b=new B;(void 0!==a.zoom?a.zoom:1)&&b.push(n...
function Gg (line 152) | function Gg(a,b,c){this.i=a;this.c=b;this.f=c;this.b=[];this.a=this.g=0}
function Hg (line 152) | function Hg(a){a.b.length=0;a.g=0;a.a=0}
function Ig (line 152) | function Ig(a){if(6>a.b.length)return!1;var b=Date.now()-a.f,c=a.b.lengt...
function Jg (line 152) | function Jg(a){Vc.call(this);this.v=null;this.Ha(!0);this.handleEvent=a....
function Kg (line 152) | function Kg(a,b,c,d){if(void 0!==b){var e=a.Sa(),f=a.xa();void 0!==e&&f&...
function Lg (line 153) | function Lg(a,b,c,d){var e=a.Pa();b=a.constrainResolution(e,b,0);if(void...
function Tg (line 153) | function Tg(a,b,c,d){if(b){var e=a.Pa(),f=a.xa();void 0!==e&&f&&b!==e&&d...
function Ug (line 153) | function Ug(a){a=a?a:{};this.a=a.delta?a.delta:1;Jg.call(this,{handleEve...
function Vg (line 153) | function Vg(a){var b=!1,c=a.originalEvent;if("dblclick"==a.type){b=a.coo...
function Wg (line 153) | function Wg(a){a=a.originalEvent;return a.altKey&&!(a.metaKey||a.ctrlKey...
function Xg (line 153) | function Xg(a){a=a.originalEvent;return a.altKey&&!(a.metaKey||a.ctrlKey...
function Yg (line 153) | function Yg(a){a=a.originalEvent;return 0==a.button&&!(ld&&md&&a.ctrlKey)}
function Zg (line 153) | function Zg(a){return"pointermove"==a.type}
function $g (line 153) | function $g(a){return"singleclick"==a.type}
function ah (line 153) | function ah(a){a=a.originalEvent;return!a.altKey&&!(a.metaKey||a.ctrlKey...
function bh (line 154) | function bh(a){a=a.originalEvent;return!a.altKey&&!(a.metaKey||a.ctrlKey...
function ch (line 154) | function ch(a){a=a.originalEvent.target.tagName;return"INPUT"!==a&&"SELE...
function dh (line 154) | function dh(a){oa(a.b,56);return"mouse"==a.b.pointerType}
function eh (line 154) | function eh(a){a=a.b;return a.isPrimary&&0===a.button}
function fh (line 154) | function fh(a){a=a?a:{};Jg.call(this,{handleEvent:a.handleEvent?a.handle...
function hh (line 154) | function hh(a){for(var b=a.length,c=0,d=0,e=0;e<b;e++)c+=a[e].clientX,d+...
function gh (line 155) | function gh(a){if(!(a instanceof Ad))return!0;var b=!1,c=a.type;if("poin...
function ih (line 155) | function ih(a){fh.call(this,{handleDownEvent:jh,handleDragEvent:kh,handl...
function kh (line 155) | function kh(a){var b=this.l,c=hh(b);if(b.length==this.s){if(this.a&&this...
function lh (line 156) | function lh(a){var b=a.map;a=b.aa();if(0===this.l.length){if(!this.j&&th...
function jh (line 157) | function jh(a){if(0<this.l.length&&this.o(a)){var b=a.map.aa();this.f=nu...
function mh (line 157) | function mh(a){a=a?a:{};fh.call(this,{handleDownEvent:nh,handleDragEvent...
function oh (line 157) | function oh(a){if(dh(a)){var b=a.map,c=b.aa();if(c.l.rotation!==re){b=b....
function ph (line 158) | function ph(a){if(!dh(a))return!0;a=a.map.aa();bg(a,1,-1);var b=a.Sa(),c...
function nh (line 158) | function nh(a){return dh(a)&&Yg(a)&&this.f(a)?(bg(a.map.aa(),1,1),this.a...
function qh (line 158) | function qh(a){this.Uc=null;this.a=document.createElement("div");this.a....
function rh (line 158) | function rh(a){var b=a.c,c=a.g;a=a.a.style;a.left=Math.min(b[0],c[0])+"p...
function sh (line 159) | function sh(a){var b=a.c,c=a.g;b=[b,[b[0],c[1]],c,[c[0],b[1]]].map(a.b.R...
function th (line 159) | function th(a){fh.call(this,{handleDownEvent:uh,handleDragEvent:vh,handl...
function xh (line 159) | function xh(a,b,c){a=c[0]-b[0];b=c[1]-b[1];return a*a+b*b>=this.o}
function vh (line 159) | function vh(a){if(dh(a)){var b=this.a,c=a.pixel;b.c=this.f;b.g=c;sh(b);r...
function wh (line 160) | function wh(a){if(!dh(a))return!0;this.a.setMap(null);this.s(a,this.f,a....
function uh (line 160) | function uh(a){if(dh(a)&&Yg(a)&&this.C(a)){this.f=a.pixel;this.a.setMap(...
function yh (line 160) | function yh(a,b,c){Qc.call(this,a);this.coordinate=b;this.mapBrowserEven...
function Ch (line 160) | function Ch(a){a=a?a:{};var b=a.condition?a.condition:bh;this.B=void 0!=...
function Dh (line 161) | function Dh(a){Jg.call(this,{handleEvent:Eh});a=a||{};this.a=function(a)...
function Eh (line 162) | function Eh(a){var b=!1;if("keydown"==a.type){var c=a.originalEvent.keyC...
function Fh (line 162) | function Fh(a){Jg.call(this,{handleEvent:Gh});a=a?a:{};this.f=a.conditio...
function Gh (line 162) | function Gh(a){var b=!1;if("keydown"==a.type||"keypress"==a.type){var c=...
function Hh (line 162) | function Hh(a){Jg.call(this,{handleEvent:Ih});a=a||{};this.j=0;this.D=vo...
function Ih (line 163) | function Ih(a){var b=a.type;if("wheel"!==b&&"mousewheel"!==b)return!0;a....
function Rh (line 165) | function Rh(a){fh.call(this,{handleDownEvent:Sh,handleDragEvent:Th,handl...
function Th (line 166) | function Th(a){var b=0,c=this.l[0],d=this.l[1];c=Math.atan2(d.clientY-c....
function Uh (line 167) | function Uh(a){if(2>this.l.length){a=a.map.aa();bg(a,1,-1);if(this.a){va...
function Sh (line 167) | function Sh(a){return 2<=this.l.length?(a=a.map,this.f=null,this.j=void ...
function Vh (line 167) | function Vh(a){fh.call(this,{handleDownEvent:Wh,handleDragEvent:Xh,handl...
function Xh (line 168) | function Xh(a){var b=1,c=this.l[0],d=this.l[1],e=c.clientX-d.clientX;c=c...
function Yh (line 169) | function Yh(a){if(2>this.l.length){a=a.map.aa();bg(a,1,-1);var b=a.Pa();...
function Wh (line 169) | function Wh(a){return 2<=this.l.length?(a=a.map,this.f=null,this.a=void ...
function Zh (line 169) | function Zh(a){a=a?a:{};var b=new B,c=new Gg(-.005,.05,100);(void 0!==a....
function $h (line 170) | function $h(a,b,c,d){Sc.call(this);this.extent=a;this.a=c;this.resolutio...
function ai (line 170) | function ai(a,b,c,d,e){this.c=void 0!==e?e:null;$h.call(this,a,b,c,void ...
function bi (line 170) | function bi(a,b,c,d,e){Qc.call(this,a);this.vectorContext=b;this.frameSt...
function ci (line 170) | function ci(a){Sc.call(this);this.highWaterMark=void 0!==a?a:2048;this.i...
function di (line 170) | function di(a){return a.i>a.highWaterMark}
function a (line 172) | function a(a){var b=mi();b.font="32px monospace";f=b.measureText("wmytzi...
function b (line 172) | function b(){var b=!0,f;for(f in c)60>c[f]&&(a(f)?(c[f]=60,lb(li),ki=nul...
function mi (line 173) | function mi(){var a=ki;a||(a=ki=hg(1,1));return a}
function pi (line 174) | function pi(a,b){var c=mi();a!=c.font&&(c.font=a);return c.measureText(b...
function qi (line 175) | function qi(a,b,c,d){0!==b&&(a.translate(c,d),a.rotate(b),a.translate(-c...
function si (line 175) | function si(a,b,c,d,e,f,g,h,l,m,n){if(1!=c){var p=a.globalAlpha;a.global...
function vi (line 175) | function vi(a){return Array.isArray(a)?a:wi(a)}
function xi (line 175) | function xi(a){if("string"!==typeof a){var b=a[0];b!=(b|0)&&(b=b+.5|0);v...
function yi (line 177) | function yi(a){var b=[];b[0]=pa(a[0]+.5|0,0,255);b[1]=pa(a[1]+.5|0,0,255...
function zi (line 177) | function zi(a){return"string"===typeof a||a instanceof CanvasPattern||a ...
function Ai (line 177) | function Ai(){}
function Bi (line 177) | function Bi(a,b,c,d,e){this.g=a;this.f=b;this.c=c;this.N=d;this.ob=e;thi...
function Ci (line 178) | function Ci(a,b,c){if(a.M){b=Te(b,0,c,2,a.N,a.o);c=a.g;var d=a.bb,e=c.gl...
function Di (line 179) | function Di(a,b,c,d){var e=0;if(a.qa&&""!==a.ta){a.j&&Ei(a,a.j);a.l&&Fi(...
function Gi (line 180) | function Gi(a,b,c,d,e,f){var g=a.g;a=Te(b,c,d,e,a.N,a.o);g.moveTo(a[0],a...
function Hi (line 180) | function Hi(a,b,c,d,e){var f;var g=0;for(f=d.length;g<f;++g)c=Gi(a,b,c,d...
function Ei (line 185) | function Ei(a,b){var c=a.g,d=a.T;d?d.fillStyle!=b.fillStyle&&(d.fillStyl...
function Fi (line 186) | function Fi(a,b){var c=a.g,d=a.O;d?(d.lineCap!=b.lineCap&&(d.lineCap=c.l...
function Ki (line 191) | function Ki(a){Uc.call(this);this.a=a}
function Si (line 191) | function Si(a,b){var c=b.getState();2!=c&&3!=c&&y(b,"change",a.$,a);0==c...
function Mi (line 191) | function Mi(a){var b=a.a;b.Jb()&&"ready"==b.hg()&&a.u()}
function Ti (line 192) | function Ti(a,b){b.cj()&&a.postRenderFunctions.push(function(a,b,e){b=x(...
function Ui (line 192) | function Ui(a,b){b=b.T;void 0!==b&&("string"===typeof b?a.logos[b]="":b&...
function Vi (line 193) | function Vi(a,b,c,d){b=x(b).toString();c=c.toString();b in a?c in a[b]?(...
function Wi (line 194) | function Wi(a,b,c,d,e,f,g,h,l,m){var n=x(b).toString();n in a.wantedTile...
function Xi (line 194) | function Xi(a){Ki.call(this,a);this.V=We()}
function Yi (line 194) | function Yi(a,b,c){var d=b.pixelRatio,e=b.size[0]*d,f=b.size[1]*d,g=b.vi...
function Zi (line 195) | function Zi(a,b,c,d,e){var f=a.a;if(Tc(f,b)){var g=d.size[0]*d.pixelRati...
function $i (line 196) | function $i(a,b,c){var d=b.viewState,e=b.pixelRatio,f=e/d.resolution;ret...
function aj (line 196) | function aj(a){Xi.call(this,a);this.l=We();this.j=null}
function bj (line 198) | function bj(a){aj.call(this,a);this.M=null;this.f=We();this.o=[];this.c=...
function cj (line 200) | function cj(){this.b={};this.a=0;this.g=32}
function dj (line 200) | function dj(a){if(a.a>a.g){var b=0,c;for(c in a.b){var d=a.b[c];0!==(b++...
function fj (line 200) | function fj(a,b){this.l=b;this.c={};this.v={}}
function gj (line 200) | function gj(a){var b=a.viewState,c=a.coordinateToPixelTransform,d=a.pixe...
function hj (line 200) | function hj(){dj(ej)}
function h (line 201) | function h(a,c){var f=x(a).toString(),g=b.layerStates[x(c)].Te;if(!(f in...
function ij (line 202) | function ij(a,b){var c=x(b).toString();if(c in a.c)return a.c[c];for(var...
function tg (line 202) | function tg(a,b){var c=a.c[b];delete a.c[b];Gc(a.v[b]);delete a.v[b];ret...
function jj (line 203) | function jj(a,b){for(var c in a.c)if(!(c in b.layerStates)){b.postRender...
function lc (line 203) | function lc(a,b){return a.zIndex-b.zIndex}
function kj (line 203) | function kj(a,b){fj.call(this,a,b);this.g=hg();this.b=this.g.canvas;this...
function lj (line 204) | function lj(a,b,c){var d=a.l,e=a.g;if(Tc(d,b)){var f=c.extent,g=c.pixelR...
function mj (line 206) | function mj(a){aj.call(this,a);this.context=null===this.context?null:hg(...
function nj (line 206) | function nj(a,b){b=b.getState();a=a.a.i();return 2==b||4==b||3==b&&!a}
function b (line 212) | function b(a,b,d,f,g){c(a,b,d||0,f||a.length-1,g||e)}
function c (line 212) | function c(a,b,e,f,g){for(;f>e;){if(600<f-e){var h=f-e+1,l=b-e+1,m=Math....
function d (line 212) | function d(a,b,c){var d=a[b];
function e (line 213) | function e(a,b){return a<b?-1:a>b?1:0}
function f (line 213) | function f(a,b){if(!(this instanceof f))return new f(a,b);this.Lf=Math.m...
function g (line 213) | function g(a,b){h(a,0,a.children.length,b,a)}
function h (line 213) | function h(a,b,c,d,e){e||(e=v(null));e.fa=Infinity;e.ea=Infinity;e.la=-I...
function l (line 213) | function l(a,b){a.fa=Math.min(a.fa,b.fa);a.ea=Math.min(a.ea,b.ea);a.la=M...
function m (line 214) | function m(a,b){return a.fa-b.fa}
function n (line 214) | function n(a,b){return a.ea-b.ea}
function p (line 214) | function p(a){return(a.la-a.fa)*(a.ka-a.ea)}
function q (line 214) | function q(a){return a.la-a.fa+(a.ka-a.ea)}
function r (line 214) | function r(a,b){return a.fa<=b.fa&&a.ea<=b.ea&&b.la<=a.la&&b.ka<=a.ka}
function u (line 214) | function u(a,b){return b.fa<=a.la&&b.ea<=a.ka&&b.la>=a.fa&&b.ka>=a.ea}
function v (line 214) | function v(a){return{children:a,height:1,fb:!0,fa:Infinity,ea:Infinity,l...
function z (line 214) | function z(a,b,c,d,e){for(var f=[b,c],g;f.length;)c=f.pop(),b=f.pop(),c-...
function sj (line 222) | function sj(){}
function tj (line 222) | function tj(a,b,c,d){var e=a[b],f=a[b+1],g=0;for(b+=d;b<c;b+=d){var h=a[...
function wj (line 222) | function wj(a,b,c,d,e,f){this.ra=f;this.La=Da();this.ob=a;this.Ea=b;this...
function xj (line 222) | function xj(a,b,c,d,e,f,g,h){b.beginPath();b.moveTo.apply(b,c);b.lineTo....
function zj (line 223) | function zj(a,b,c,d,e,f,g,h,l,m,n,p,q,r,u,v,z,A,E){var S=A||E,Ia=a.bb;f*...
function Aj (line 224) | function Aj(a,b){var c=a.pixelRatio;return 1==c?b:b.map(function(a){retu...
function Bj (line 225) | function Bj(a,b,c,d,e,f,g){var h=a.coordinates.length,l=Cj(a);g&&(c+=e);...
function Dj (line 226) | function Dj(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;++g){var l=d[g];c=Bj...
function Ej (line 228) | function Ej(a,b){a.qa=[0,b,0];a.a.push(a.qa);a.T=[0,b,0];a.b.push(a.T)}
function yj (line 228) | function yj(a,b){a.strokeStyle=b[1];a.lineWidth=b[2];a.lineCap=b[3];a.li...
function Gj (line 229) | function Gj(a,b,c){if(b&&5<b.length){var d=b[4];if(1==d||d==b.length-5){...
function Hj (line 230) | function Hj(a,b,c,d,e,f,g){if(a.oa&&jc(c,a.ca))var h=a.oa;else a.oa||(a....
function Ij (line 236) | function Ij(a,b,c,d,e,f,g){a.$=d;return Hj(a,b,c,e,a.b,f,g)}
function Jj (line 237) | function Jj(a){var b=a.b;b.reverse();var c,d=b.length,e=-1;for(c=0;c<d;+...
function Kj (line 239) | function Kj(a,b,c,d){var e=b.fillStyle;if("string"!==typeof e||b.Pk!=e)c...
function Lj (line 240) | function Lj(a,b,c){var d=b.strokeStyle,e=b.lineCap,f=b.lineDash,g=b.line...
function Fj (line 240) | function Fj(a,b){a.qa[2]=a.a.length;a.qa=null;a.T[2]=a.b.length;a.T=null...
function Cj (line 240) | function Cj(a){a.i||(a.i=Ga(a.Ea),0<a.Wa&&Fa(a.i,a.resolution*(a.Wa+1)/2...
function Mj (line 240) | function Mj(a,b,c,d,e,f){wj.call(this,a,b,c,d,e,f);this.M=this.V=this.B=...
function Nj (line 243) | function Nj(a,b,c,d,e,f){wj.call(this,a,b,c,d,e,f)}
function Oj (line 243) | function Oj(a,b,c,d,e){var f=a.coordinates.length;b=Bj(a,b,c,d,e,!1,!1);...
function Pj (line 245) | function Pj(a,b,c,d,e,f){wj.call(this,a,b,c,d,e,f)}
function Qj (line 245) | function Qj(a,b,c,d,e){var f=a.state,g=void 0!==f.fillStyle;f=void 0!=f....
function Rj (line 249) | function Rj(a,b){var c=a.state;void 0!==c.fillStyle&&Kj(a,c,a.Ah,b);void...
function Sj (line 249) | function Sj(a,b,c,d,e,f){wj.call(this,a,b,c,d,e,f);this.ta="";this.l=thi...
function Uj (line 256) | function Uj(a,b,c,d){var e=a.f,f=a.g,g=a.pixelRatio,h=vj[e.textAlign||"c...
function Tj (line 257) | function Tj(a,b,c,d){var e=a.g,f=a.f,g=a.c,h=a.V;e&&(h in a.ab||(a.ab[h]...
function Vj (line 261) | function Vj(a,b,c,d,e,f,g){this.a=f;this.g=null;this.o=a;this.c=b;this.l...
function Xj (line 261) | function Xj(a,b,c){var d,e=Math.floor(a.length/2);if(b>=e)for(d=e;d<b;d+...
function Yj (line 262) | function Yj(a){if(void 0!==Wj[a])return Wj[a];for(var b=2*a+1,c=Array(b)...
function Zj (line 262) | function Zj(a){for(var b in a.b){var c=a.b[b],d;for(d in c)c[d].bf()}}
function h (line 263) | function h(a){for(var b=n.getImageData(0,0,l,l).data,c=0;c<l;c++)for(var...
function ak (line 264) | function ak(a,b){var c=a.c;a=c[0];var d=c[1],e=c[2];c=c[3];a=[a,d,a,c,e,...
function ck (line 267) | function ck(a,b){return x(a)-x(b)}
function dk (line 267) | function dk(a,b){a=.5*a/b;return a*a}
function ek (line 267) | function ek(a,b,c,d,e,f){var g=!1,h;if(h=c.Y()){var l=h.gf();2==l||3==l?...
function fk (line 267) | function fk(a,b,c,d){if("GeometryCollection"==b.S()){b=b.vd();for(var e=...
function hk (line 270) | function hk(a){Xi.call(this,a);this.f=a.D?rj.Jc(9):null;this.i=!1;this.N...
function jk (line 275) | function jk(a){this.context=null;mj.call(this,a);this.N=a.D?rj.Jc(9):nul...
function H (line 284) | function H(a){a=kb({},a);delete a.renderer;a.controls||(a.controls=Fg())...
function pk (line 284) | function pk(a){Vc.call(this);a=a?a:{};this.a=null;y(this,Xc(qk),this.$m,...
function vk (line 286) | function vk(a){this.i=a.opacity;this.s=a.rotateWithView;this.f=a.rotatio...
function wk (line 286) | function wk(a){this.D=this.o=this.c=null;this.Xa=void 0!==a.fill?a.fill:...
function xk (line 289) | function xk(a,b){var c="",d="",e=0,f=null,g=0,h=0;if(a.Ya){var l=a.Ya.a;...
function yk (line 295) | function yk(a){a=a||{};wk.call(this,{points:Infinity,fill:a.fill,radius:...
function zk (line 295) | function zk(a){a=a||{};this.b=void 0!==a.color?a.color:null;this.a=void 0}
function Ak (line 295) | function Ak(a){a=a||{};this.a=void 0!==a.color?a.color:null;this.f=a.lin...
function Bk (line 296) | function Bk(a){a=a||{};this.Uc=null;this.cb=Ck;void 0!==a.geometry&&this...
function Dk (line 299) | function Dk(a){if("function"!==typeof a){if(Array.isArray(a))var b=a;els...
function Fk (line 299) | function Fk(){if(!Ek){var a=new zk({color:"rgba(255,255,255,0.4)"}),b=ne...
function Gk (line 300) | function Gk(){var a={},b=[255,255,255,1],c=[0,153,255,1];a.Polygon=[new ...
function Ck (line 301) | function Ck(a){return a.U()}
function Hk (line 301) | function Hk(a){Vc.call(this);this.c=void 0;this.a="geometry";this.f=null...
function Ik (line 303) | function Ik(a){var b;if("function"===typeof a)2==a.length?b=function(b){...
function Jk (line 303) | function Jk(a){Vc.call(this);a=a||{};this.a=null;this.i=$b;this.f=new ob...
function Kk (line 307) | function Kk(a,b,c,d,e,f){var g=NaN,h=NaN,l=(c-b)/d;if(1===l)g=a[b],h=a[b...
function Sk (line 308) | function Sk(a,b,c,d,e,f){if(c==b)return null;if(e<a[b+d-1])return f?(c=a...
function Tk (line 309) | function Tk(a,b,c,d,e,f){var g=0;if(f)return Sk(a,g,b[b.length-1],c,d,e)...
function I (line 309) | function I(a,b){hf.call(this);this.c=null;this.o=this.D=this.j=-1;this.n...
function Uk (line 311) | function Uk(a,b,c){for(var d=[],e=a(0),f=a(1),g=b(e),h=b(f),l=[f,e],m=[h...
function Vk (line 311) | function Vk(a,b,c,d,e){var f=Ob("EPSG:4326");return Uk(function(d){retur...
function Wk (line 312) | function Wk(a,b,c,d,e){var f=Ob("EPSG:4326");return Uk(function(d){retur...
function J (line 312) | function J(a){a=a||{};this.a=a.font;this.i=a.rotation;this.l=a.rotateWit...
function Xk (line 315) | function Xk(a){a=a||{};this.i=this.v=null;this.j=this.f=Infinity;this.s=...
function $k (line 317) | function $k(a,b,c,d,e,f,g){var h=g;c=Vk(b,c,d,a.i,e);h=void 0!==a.g[h]?a...
function al (line 318) | function al(a,b,c,d,e,f,g){var h=g;c=Wk(b,c,d,a.i,e);h=void 0!==a.c[h]?a...
function bl (line 322) | function bl(a,b,c,d,e,f){$h.call(this,a,b,c,0);this.i=d;this.M=new Image...
function cl (line 323) | function cl(a,b,c){Sc.call(this);c=c?c:{};this.ya=a;this.state=b;this.g=...
function pj (line 323) | function pj(a){if(!a.g)return a;var b=a.g;do{if(2==b.getState())return b...
function dl (line 323) | function dl(a){if(a.g){var b=a.g;do{if(2==b.getState()){b.g=null;break}e...
function oj (line 324) | function oj(a,b){a.state=b;a.u()}
function qj (line 324) | function qj(a,b,c){if(!a.j)return 1;var d=a.s[b];if(!d)d=c,a.s[b]=d;else...
function el (line 324) | function el(a,b,c,d,e,f){cl.call(this,a,b,f);this.f=d;this.l=c;this.M=ne...
function fl (line 325) | function fl(a){a.c.forEach(Gc);a.c=null}
function gl (line 325) | function gl(){var a=hg(1,1);a.fillStyle="rgba(0,0,0,0)";a.fillRect(0,0,1...
function hl (line 325) | function hl(a){this.b=a}
function il (line 325) | function il(a){this.b=a}
function jl (line 325) | function jl(a){this.b=a}
function ml (line 326) | function ml(a,b){this.g=a.getUniformLocation(b,"h");this.i=a.getUniformL...
function nl (line 326) | function nl(){return[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]}
function pl (line 326) | function pl(a,b){a[0]=b[0];a[1]=b[1];a[4]=b[2];a[5]=b[3];a[12]=b[4];a[13...
function ql (line 326) | function ql(a,b){this.origin=eb(b);this.bb=We();this.Ea=We();this.La=We(...
function sl (line 329) | function sl(a,b,c,d){a.drawElements(4,d-c,b.f?5125:5123,c*(b.f?4:2))}
function wl (line 329) | function wl(a,b,c,d,e,f){a=(c-a)*(f-b)-(e-a)*(d-b);return a<=xl&&a>=-xl?...
function yl (line 329) | function yl(a){this.b=void 0!==a?a:[];this.a=zl}
function Al (line 329) | function Al(a,b){ql.call(this,a,b);this.v=null;this.l=[];this.o=[];this....
function Dl (line 335) | function Dl(a,b,c,d){b.uniform4fv(a.v.O,c);b.uniform1f(a.v.oa,d)}
function Gl (line 337) | function Gl(a,b){this.g=a.getUniformLocation(b,"h");this.i=a.getUniformL...
function Hl (line 337) | function Hl(a,b){this.j=a;this.b=b;this.a={};this.c={};this.g={};this.s=...
function rl (line 338) | function rl(a,b,c){var d=a.b,e=c.b,f=String(x(c));if(f in a.a)d.bindBuff...
function Bl (line 338) | function Bl(a,b){var c=a.b;b=String(x(b));var d=a.a[b];c.isContextLost()...
function Il (line 340) | function Il(a){if(!a.i){var b=a.b,c=b.createFramebuffer();b.bindFramebuf...
function Kl (line 341) | function Kl(a,b){var c=String(x(b));if(c in a.c)return a.c[c];var d=a.b,...
function Cl (line 341) | function Cl(a,b,c){var d=x(b)+"/"+x(c);if(d in a.g)return a.g[d];var e=a...
function Ll (line 342) | function Ll(a,b,c){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d)...
function Jl (line 342) | function Jl(a,b,c){var d=Ll(a,void 0,void 0);a.texImage2D(a.TEXTURE_2D,0...
function Ml (line 343) | function Ml(a,b){var c=Ll(a,33071,33071);a.texImage2D(a.TEXTURE_2D,0,a.R...
function Nl (line 343) | function Nl(a,b){ql.call(this,a,b);this.C=this.D=void 0;this.v=[];this.o...
function Ol (line 344) | function Ol(a,b,c,d){var e=a.D,f=a.C,g=a.height,h=a.oa,l=a.qa,m=a.opacit...
function Pl (line 346) | function Pl(a,b,c,d){var e,f=b.length;for(e=0;e<f;++e){var g=b[e];var h=...
function Ql (line 351) | function Ql(a,b){Nl.call(this,a,b);this.l=[];this.c=[];this.B=[];this.N=[]}
function Rl (line 354) | function Rl(a,b,c){var d=b-c;return a[0]===a[d]&&a[1]===a[d+1]&&3<(b-0)/...
function Ul (line 354) | function Ul(a,b){this.g=a.getUniformLocation(b,"h");this.i=a.getUniformL...
function Vl (line 354) | function Vl(a,b){ql.call(this,a,b);this.v=null;this.o=[];this.l=[];this....
function Wl (line 355) | function Wl(a,b,c,d){var e,f=a.a.length,g=a.b.length,h="bevel"===a.c.lin...
function Xl (line 358) | function Xl(a,b,c,d,e,f){a.a[f++]=b[0];a.a[f++]=b[1];a.a[f++]=c[0];a.a[f...
function fm (line 358) | function fm(a,b,c,d){c-=b;return c<2*d?!1:c===2*d?!jc([a[b],a[b+1]],[a[b...
function gm (line 360) | function gm(a,b,c,d){Rl(b,b.length,d)||(b.push(b[0]),b.push(b[1]));Wl(a,...
function hm (line 360) | function hm(a,b,c){c=void 0===c?a.b.length:c;a.g.push(c);a.i.push(b);a.c...
function im (line 366) | function im(a,b,c,d,e){b.uniform4fv(a.v.C,c);b.uniform1f(a.v.oa,d);b.uni...
function lm (line 368) | function lm(a,b){this.g=a.getUniformLocation(b,"b");this.i=a.getUniformL...
function mm (line 368) | function mm(){this.b=this.a=this.g=void 0;this.c=0}
function nm (line 368) | function nm(a){var b=a.b;if(b){var c=b.next,d=b.Eb;c&&(c.Eb=d);d&&(d.nex...
function om (line 368) | function om(a){a.b=a.g;if(a.b)return a.b.data}
function pm (line 368) | function pm(a){if(a.b&&a.b.next)return a.b=a.b.next,a.b.data}
function qm (line 368) | function qm(a){if(a.b&&a.b.next)return a.b.next.data}
function rm (line 368) | function rm(a){if(a.b&&a.b.Eb)return a.b=a.b.Eb,a.b.data}
function sm (line 368) | function sm(a){if(a.b&&a.b.Eb)return a.b.Eb.data}
function tm (line 369) | function tm(a){if(a.b)return a.b.data}
function um (line 369) | function um(){this.a=rj.Jc(void 0);this.b={}}
function vm (line 370) | function vm(a,b,c){var d=a.b[x(c)];Sa([d.fa,d.ea,d.la,d.ka],b)||(a.remov...
function wm (line 370) | function wm(a){return a.a.all().map(function(a){return a.value})}
function xm (line 370) | function xm(a,b){return a.a.search({fa:b[0],ea:b[1],la:b[2],ka:b[3]}).ma...
function zm (line 370) | function zm(a,b,c,d){return ym(xm(a,b),c,d)}
function ym (line 370) | function ym(a,b,c){for(var d,e=0,f=a.length;e<f&&!(d=b.call(c,a[e]));e++...
function Am (line 371) | function Am(a,b){ql.call(this,a,b);this.f=new Vl(a,b);this.v=null;this.o...
function Bm (line 372) | function Bm(a,b,c,d){var e=new mm,f=new um;Cm(a,b,d,e,f,!0);b=Dm(e);if(c...
function Cm (line 374) | function Cm(a,b,c,d,e,f){var g,h=a.a.length/2,l=[],m=[];if(f===Mf(b,0,b....
function Dm (line 375) | function Dm(a){var b=om(a),c=b,d=[c.Z.x,c.Z.y];do c=pm(a),c.Z.x>d[0]&&(d...
function Em (line 375) | function Em(a,b,c){var d=om(a),e=d,f=pm(a),g=!1;do{var h=c?wl(f.X.x,f.X....
function Gm (line 376) | function Gm(a,b,c,d,e){for(var f=om(a);f.X.x!==b;)f=pm(a);b=f.X;d={x:d,y...
function Hm (line 378) | function Hm(a,b,c){for(var d=!1,e=Nm(b,c);3<b.c;)if(e){if(!Om(a,b,c,e,d)...
function Om (line 380) | function Om(a,b,c,d,e){var f=a.b.length,g=om(b),h=sm(b),l=g,m=pm(b),n=qm...
function Pm (line 381) | function Pm(a,b,c,d){var e=om(b);pm(b);var f=e,g=pm(b),h=!1;do{var l=Lm(...
function Nm (line 382) | function Nm(a,b){var c=om(a),d=c;do{if(Fm(d,b).length)return!1;d=pm(a)}w...
function Im (line 382) | function Im(a,b,c,d){var e=a.a.length;a.a[e++]=b;a.a[e++]=c;return{x:b,y...
function Jm (line 383) | function Jm(a,b,c,d){var e={Z:a,X:b},f={Eb:void 0,next:void 0,data:e},g=...
function Km (line 383) | function Km(a,b,c,d){tm(c)===b&&(nm(c),a.X=b.X,d.remove(b),vm(d,[Math.mi...
function Mm (line 384) | function Mm(a,b,c,d,e){var f,g,h=[],l=xm(d,[Math.min(a.x,b.x,c.x),Math.m...
function Fm (line 385) | function Fm(a,b,c){var d=a.Z,e=a.X;b=xm(b,[Math.min(d.x,e.x),Math.min(d....
function Lm (line 386) | function Lm(a,b,c,d,e){var f=(d.y-c.y)*(b.x-a.x)-(d.x-c.x)*(b.y-a.y);if(...
function Qm (line 387) | function Qm(a,b,c,d,e){if(void 0===b.Kb||void 0===d.Kb)return!1;var f=(c...
function Rm (line 394) | function Rm(a,b){this.b=b;this.a=[{x:0,y:0,width:a,height:a}];this.c={};...
function Sm (line 396) | function Sm(a,b,c,d){b=[b,1];0<c.width&&0<c.height&&b.push(c);0<d.width&...
function Tm (line 396) | function Tm(a){a=a||{};this.a=void 0!==a.initialSize?a.initialSize:256;t...
function Um (line 396) | function Um(a,b){var c;var d=0;for(c=a.length;d<c;++d){var e=a[d];if(e=e...
function Vm (line 396) | function Vm(a,b){return{offsetX:a.offsetX,offsetY:a.offsetY,image:a.imag...
function Wm (line 397) | function Wm(a,b,c,d,e,f,g){var h=b?a.i:a.f,l;var m=0;for(l=h.length;m<l;...
function Xm (line 397) | function Xm(a,b){Nl.call(this,a,b);this.c=[];this.ua=[];this.Ub=hg(0,0)....
function Ym (line 400) | function Ym(a,b){var c=a.l,d=b.length*c.height;return[b.map(function(b){...
function Zm (line 401) | function Zm(a,b){if(1===b.length){var c=a.l,d=a.N;a=a.Ub.getContext("2d"...
function $m (line 404) | function $m(a,b,c){this.c=b;this.i=a;this.g=c;this.a={}}
function an (line 404) | function an(a,b){var c=[],d;for(d in a.a){var e=a.a[d],f;for(f in e)c.pu...
function bn (line 404) | function bn(a,b){for(var c in a.a){var d=a.a[c],e;for(e in d)d[e].gb(b)}}
function dn (line 406) | function dn(a,b,c,d,e,f,g,h,l,m,n){var p=en,q=Object.keys(a.a).map(Numbe...
function fn (line 407) | function fn(a,b,c,d,e,f,g,h){var l=c.b;l.bindFramebuffer(l.FRAMEBUFFER,I...
function gn (line 408) | function gn(a,b,c,d,e,f,g){this.b=a;this.g=b;this.c=f;this.i=g;this.l=e;...
function hn (line 408) | function hn(a,b,c){var d=a.b;b=b.Ja(0,"Text");b.nb(a.a);b.Wb(c,null);b.g...
function ln (line 413) | function ln(a,b){this.f=a.getUniformLocation(b,"d");this.c=a.getUniformL...
function mn (line 413) | function mn(a,b){Ki.call(this,b);this.c=a;this.V=new yl([-1,-1,0,0,1,-1,...
function nn (line 414) | function nn(a,b,c){var d=a.c.g;if(void 0===a.j||a.j!=c){b.postRenderFunc...
function on (line 416) | function on(a,b,c,d){a=a.a;if(Tc(a,b)){var e=d.viewState;a.b(new bi(b,ne...
function pn (line 416) | function pn(a,b){mn.call(this,a,b);this.l=this.i=this.M=null}
function qn (line 416) | function qn(a,b){b=b.Y();return Ml(a.c.g,b)}
function rn (line 418) | function rn(a,b,c,d,e,f,g,h){b*=f;c*=f;a=a.N;Xe(a);cf(a,2*d/b,2*d/c);bf(...
function sn (line 420) | function sn(a,b){fj.call(this,a,b);this.b=document.createElement("CANVAS...
function tn (line 422) | function tn(a,b,c,d){var e=a.g,f=b.lb();if(a.a.a.hasOwnProperty(f))a=a.a...
function vn (line 423) | function vn(a,b,c){var d=a.l;if(Tc(d,b)){a=a.i;var e=c.viewState;d.b(new...
function un (line 424) | function un(a){a=a.g;a.activeTexture(33984);a.blendFuncSeparate(770,771,...
function yn (line 428) | function yn(a,b){this.c=a.getUniformLocation(b,"d");this.g=a.getUniformL...
function zn (line 428) | function zn(a,b){mn.call(this,a,b);this.T=wn;this.ca=xn;this.i=null;this...
function An (line 434) | function An(a,b){mn.call(this,a,b);this.s=!1;this.O=-1;this.T=NaN;this.D...
function d (line 437) | function d(a){var b=a.ib();if(b)var c=b.call(a,m);else(b=e.ib())&&(c=b(a...
function K (line 438) | function K(a){a=kb({},a);a.controls||(a.controls=Fg());a.interactions||(...
function Bn (line 438) | function Bn(a){Vc.call(this);this.id=a.id;this.insertFirst=void 0!==a.in...
function In (line 442) | function In(a,b){var c=a.getBoundingClientRect();a=c.left+window.pageXOf...
function Jn (line 443) | function Jn(a,b){a.a.visible!==b&&(a.element.style.display=b?"":"none",a...
function Hn (line 444) | function Hn(a){var b=a.Ve(),c=a.pi();if(b&&b.c&&c){c=b.Ia(c);var d=b.Cb(...
function Kn (line 445) | function Kn(a,b,c,d,e,f){cl.call(this,a,b,f);this.c=0;this.l=null;this.v...
function ok (line 445) | function ok(a,b,c){return a.f[x(b)+","+c]}
function Mn (line 446) | function Mn(a){a=a?a:{};this.c=void 0!==a.className?a.className:"ol-full...
function On (line 450) | function On(){var a=document.body;return!!(a.webkitRequestFullscreen||a....
function Nn (line 450) | function Nn(){return!!(document.webkitIsFullScreen||document.mozFullScre...
function Pn (line 451) | function Pn(a){a.requestFullscreen?a.requestFullscreen():a.msRequestFull...
function Rn (line 451) | function Rn(a){a=a?a:{};var b=document.createElement("DIV");b.className=...
function Sn (line 452) | function Sn(a){a=a.frameState;a?this.c!=a.viewState.projection&&(this.c=...
function Un (line 453) | function Un(a,b){var c=a.o;if(b&&a.c){if(!a.j){var d=a.si();a.j=d?Pb(a.c...
function Wn (line 453) | function Wn(a){function b(a){a=h.Sd(a);l.a.aa().ub(a);window.removeEvent...
function Xn (line 457) | function Xn(){var a=this.a,b=this.c;if(a.c&&b.c){var c=a.Cb();a=a.aa().q...
function Yn (line 458) | function Yn(a){var b=a.a;a=a.c;var c=b.Cb();b=b.aa().qd(c);a=a.aa();ib(b...
function Zn (line 458) | function Zn(a){var b=a.a,c=a.c;if(b.c&&c.c){var d=b.Cb(),e=b.aa(),f=c.aa...
function $n (line 459) | function $n(a){a.element.classList.toggle("ol-collapsed");a.j?ig(a.o,a.D...
function ao (line 459) | function ao(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-scale...
function bo (line 460) | function bo(a){(a=a.frameState)?this.o=a.viewState:this.o=null;fo(this)}
function fo (line 461) | function fo(a){var b=a.o;if(b){var c=b.center,d=b.projection,e=a.C();b=N...
function go (line 462) | function go(a){a=a?a:{};this.c=void 0;this.j=ho;this.D=this.v=0;this.O=n...
function io (line 464) | function io(a){if(a.frameState){if(!this.$){var b=this.element,c=b.offse...
function jo (line 467) | function jo(a,b){b=1-gg(a.a.aa())(b);var c=a.element.firstElementChild;1...
function ko (line 467) | function ko(a,b){return fg(a.a.aa())(1-b)}
function lo (line 467) | function lo(a){a=a?a:{};this.extent=a.extent?a.extent:null;var b=void 0!...
function no (line 468) | function no(a,b){return mo.createElementNS(a,b)}
function oo (line 468) | function oo(a,b){return po(a,b,[]).join("")}
function po (line 468) | function po(a,b,c){if(a.nodeType==Node.CDATA_SECTION_NODE||a.nodeType==N...
function qo (line 468) | function qo(a){return a instanceof Document}
function ro (line 468) | function ro(a){return a instanceof Node}
function so (line 469) | function so(a){return(new DOMParser).parseFromString(a,"application/xml")}
function to (line 469) | function to(a,b){return function(c,d){c=a.call(b,c,d);void 0!==c&&gc(d[d...
function uo (line 469) | function uo(a,b){return function(c,d){c=a.call(void 0!==b?b:this,c,d);vo...
function vo (line 469) | function vo(a,b){return function(c,d){c=a.call(void 0!==b?b:this,c,d);vo...
function wo (line 470) | function wo(a){return function(b,c){var d=a.call(this,b,c);if(void 0!==d...
function L (line 470) | function L(a,b){return function(c,d){var e=a.call(this,c,d);void 0!==e&&...
function M (line 470) | function M(a,b){return function(c,d,e){a.call(void 0!==b?b:this,c,d,e);e...
function xo (line 471) | function xo(a){var b,c;return function(d,e,f){if(void 0===b){b={};var g=...
function yo (line 471) | function yo(a,b){return function(c,d,e){c=d[d.length-1].node;d=a;void 0=...
function Bo (line 471) | function Bo(a,b){for(var c=b.length,d=Array(c),e=0;e<c;++e)d[e]=a[b[e]];...
function N (line 471) | function N(a,b,c){c=void 0!==c?c:{};var d;var e=0;for(d=a.length;e<d;++e...
function Co (line 472) | function Co(a,b,c,d){for(b=b.firstElementChild;b;b=b.nextElementSibling)...
function O (line 472) | function O(a,b,c,d,e){d.push(a);Co(b,c,d,e);return d.pop()}
function zo (line 472) | function zo(a,b,c,d,e,f){for(var g=(void 0!==e?e:c).length,h,l,m=0;m<g;+...
function Do (line 472) | function Do(a,b,c,d,e,f,g){e.push(a);zo(b,c,d,e,f,g);e.pop()}
function Eo (line 472) | function Eo(a,b,c,d){return function(e,f,g){var h=new XMLHttpRequest;h.o...
function Fo (line 473) | function Fo(a,b){return Eo(a,b,function(a){this.Qc(a)},ea)}
function Go (line 473) | function Go(){this.i=this.defaultDataProjection=null}
function Ho (line 473) | function Ho(a,b,c){var d;c&&(d={dataProjection:c.dataProjection?c.dataPr...
function Io (line 473) | function Io(a,b){return kb({dataProjection:a.defaultDataProjection,featu...
function Jo (line 474) | function Jo(a,b,c){var d=c?Ob(c.featureProjection):null,e=c?Ob(c.dataPro...
function Ko (line 474) | function Ko(){Go.call(this)}
function Lo (line 474) | function Lo(a){return"string"===typeof a?(a=JSON.parse(a))?a:null:null!=...
function P (line 475) | function P(a,b){hf.call(this);this.c=[];this.j=this.o=-1;this.na(a,b)}
function Mo (line 479) | function Mo(a,b){var c=a.ja,d=[],e=[],f;var g=0;for(f=b.length;g<f;++g){...
function No (line 479) | function No(a,b){hf.call(this);this.na(a,b)}
function Q (line 481) | function Q(a,b){hf.call(this);this.c=[];this.o=-1;this.D=null;this.T=thi...
function Ji (line 484) | function Ji(a){if(a.o!=a.g){var b=a.A,c=a.c,d=a.a,e=0,f=[],g;var h=0;for...
function Ii (line 485) | function Ii(a){if(a.T!=a.g){var b=a.A;a:{var c=a.c;var d;var e=0;for(d=c...
function Oo (line 489) | function Oo(a,b){var c=a.ja,d=[],e=[],f;var g=0;for(f=b.length;g<f;++g){...
function Po (line 489) | function Po(a){a=a?a:{};Go.call(this);this.b=a.geometryName}
function Qo (line 490) | function Qo(a,b){if(!a)return null;if("number"===typeof a.x&&"number"===...
function Ro (line 491) | function Ro(a){var b="XY";!0===a.hasZ&&!0===a.hasM?b="XYZM":!0===a.hasZ?...
function To (line 491) | function To(a){a=a.ja;return{hasZ:"XYZ"===a||"XYZM"===a,hasM:"XYM"===a||...
function Vo (line 495) | function Vo(a,b){return(0,Uo[a.S()])(Jo(a,!0,b),b)}
function Wo (line 496) | function Wo(){this.g=new XMLSerializer;Go.call(this)}
function Xo (line 496) | function Xo(a,b,c){a=Yo(a,b,c);return 0<a.length?a[0]:null}
function Yo (line 497) | function Yo(a,b,c){var d=[];for(b=b.firstChild;b;b=b.nextSibling)b.nodeT...
function Zo (line 498) | function Zo(a){a=a?a:{};this.featureType=a.featureType;this.featureNS=a....
function ap (line 506) | function ap(a){a=oo(a,!1);return bp(a)}
function bp (line 506) | function bp(a){if(a=/^\s*(true|1)|(false|0)\s*$/.exec(a))return void 0!=...
function cp (line 506) | function cp(a){a=oo(a,!1);a=Date.parse(a);return isNaN(a)?void 0:a/1E3}
function dp (line 506) | function dp(a){a=oo(a,!1);return ep(a)}
function ep (line 506) | function ep(a){if(a=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(a))...
function fp (line 506) | function fp(a){a=oo(a,!1);return gp(a)}
function gp (line 506) | function gp(a){if(a=/^\s*(\d+)\s*$/.exec(a))return parseInt(a[1],10)}
function R (line 506) | function R(a){return oo(a,!1).trim()}
function hp (line 507) | function hp(a,b){ip(a,b?"1":"0")}
function Ip (line 507) | function Ip(a,b){a.appendChild(mo.createTextNode(b.toPrecision()))}
function Jp (line 507) | function Jp(a,b){a.appendChild(mo.createTextNode(b.toString()))}
function ip (line 507) | function ip(a,b){a.appendChild(mo.createTextNode(b))}
function Kp (line 507) | function Kp(a){a=a?a:{};Zo.call(this,a);this.s=void 0!==a.surface?a.surf...
function Lp (line 515) | function Lp(a,b,c){var d=c[c.length-1];c=d.hasZ;a.setAttribute("srsDimen...
function Tp (line 529) | function Tp(a){a=a?a:{};Zo.call(this,a);this.b["http://www.opengis.net/g...
function Vp (line 534) | function Vp(a){a=no(a,"coordinates");a.setAttribute("decimal",".");a.set...
function Wp (line 535) | function Wp(a,b,c){var d=c[c.length-1];c=d.hasZ;d=d.srsName;b=b.W();for(...
function Xp (line 537) | function Xp(a,b,c){var d="enu";b&&(d=Ob(b).b);b="en"===d.substr(0,2)?a[0...
function dq (line 542) | function dq(a){a=a?a:{};Wo.call(this);this.defaultDataProjection=Ob("EPS...
function fq (line 542) | function fq(a,b,c,d){a.push(parseFloat(c.getAttribute("lon")),parseFloat...
function gq (line 543) | function gq(a,b,c){var d="XY",e=2;a.hasZ&&a.hasM?(d="XYZM",e=4):a.hasZ?(...
function hq (line 543) | function hq(a,b){var c=b[b.length-1],d=a.getAttribute("href");null!==d&&...
function jq (line 543) | function jq(a,b){b[b.length-1].extensionsNode_=a}
function kq (line 544) | function kq(a,b){var c=b[0];if(a=O({flatCoordinates:[],layoutOptions:{}}...
function mq (line 545) | function mq(a,b){var c=b[0];if(a=O({flatCoordinates:[],ends:[],layoutOpt...
function oq (line 545) | function oq(a,b){var c=b[0];if(b=O({},pq,a,b)){var d={};a=fq([],d,a,b);d...
function vq (line 548) | function vq(a,b){b||(b=[]);for(var c=0,d=b.length;c<d;++c){var e=b[c];if...
function wq (line 549) | function wq(a,b,c){a.setAttribute("href",b);b=c[c.length-1].properties;D...
function zq (line 549) | function zq(a,b,c){var d=c[c.length-1],e=d.node.namespaceURI,f=d.propert...
function Kq (line 552) | function Kq(a,b){if(a=a.U())if(a=Jq[a.S()])return no(b[b.length-1].node....
function Mq (line 554) | function Mq(a){gf.call(this);this.a=a?a:null;Nq(this)}
function Oq (line 554) | function Oq(a){var b=[],c;var d=0;for(c=a.length;d<c;++d)b.push(a[d].clo...
function Pq (line 554) | function Pq(a){var b;if(a.a){var c=0;for(b=a.a.length;c<b;++c)Mc(a.a[c],...
function Nq (line 554) | function Nq(a){var b;if(a.a){var c=0;for(b=a.a.length;c<b;++c)y(a.a[c],"...
function Qq (line 557) | function Qq(a){a=a?a:{};Go.call(this);this.defaultDataProjection=Ob(a.de...
function Rq (line 557) | function Rq(a,b){return a?Jo((0,Sq[a.type])(a),!1,b):null}
function Tq (line 557) | function Tq(a,b){return(0,Uq[a.S()])(Jo(a,!0,b),b)}
function Vq (line 562) | function Vq(){Go.call(this)}
function Wq (line 562) | function Wq(a){return"string"===typeof a?a:""}
function Xq (line 562) | function Xq(a){a=a?a:{};Go.call(this);this.defaultDataProjection=Ob("EPS...
function br (line 564) | function br(a,b,c,d,e,f){Sc.call(this);this.j=null;this.M=a?a:new Image;...
function cr (line 564) | function cr(a){var b=hg(1,1);try{b.drawImage(a.M,0,0),b.getImageData(0,0...
function dr (line 566) | function dr(a){a=a||{};this.l=void 0!==a.anchor?a.anchor:[.5,.5];this.o=...
function er (line 571) | function er(a){a=a?a:{};Wo.call(this);fr||(gr=[255,255,255,1],hr=new zk(...
function xr (line 574) | function xr(a,b){var c=[0,0],d="start";if(a.Y()){var e=a.Y().He();null==...
function yr (line 575) | function yr(a,b,c,d,e){return function(){var f=e,g="";f&&this.U()&&(f="P...
function zr (line 575) | function zr(a,b,c){return Array.isArray(a)?a:"string"===typeof a?(!(a in...
function Ar (line 576) | function Ar(a){a=oo(a,!1);if(a=/^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(a))r...
function Br (line 576) | function Br(a){a=oo(a,!1);for(var b=[],c=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?...
function Cr (line 577) | function Cr(a){var b=oo(a,!1).trim();a=a.baseURI;a&&"about:blank"!=a||(a...
function Dr (line 577) | function Dr(a){return dp(a)}
function Er (line 577) | function Er(a,b){return O(null,Fr,a,b)}
function Gr (line 577) | function Gr(a,b){if(b=O({A:[],ak:[]},Hr,a,b)){a=b.A;b=b.ak;var c;var d=0...
function Ir (line 577) | function Ir(a,b){var c=O({},Jr,a,b);if(a=O(null,Kr,a,b))return b=new I(n...
function Lr (line 578) | function Lr(a,b){var c=O({},Jr,a,b);if(a=O(null,Kr,a,b))return b=new D(n...
function Mr (line 579) | function Mr(a,b){a=O([],Nr,a,b);if(!a)return null;if(0===a.length)return...
function Pr (line 580) | function Pr(a,b){var c=O({},Jr,a,b);if(a=O(null,Kr,a,b))return b=new C(n...
function Qr (line 580) | function Qr(a,b){var c=O({},Jr,a,b);if((a=O([null],Rr,a,b))&&a[0]){b=new...
function Sr (line 581) | function Sr(a,b){b=O({},Tr,a,b);if(!b)return null;a="fillStyle"in b?b.fi...
function Or (line 582) | function Or(a,b){var c=b.length,d=Array(b.length),e=Array(b.length),f=Ar...
function Ur (line 582) | function Ur(a,b){Co(Vr,a,b)}
function Wr (line 582) | function Wr(a,b){Co(Xr,a,b)}
function os (line 595) | function os(a,b){for(b=b.firstChild;b;b=b.nextSibling)if(b.nodeType==Nod...
function ps (line 595) | function ps(a,b){var c;for(c=b.firstElementChild;c;c=c.nextElementSiblin...
function qs (line 596) | function qs(a,b){var c=[];for(b=b.firstChild;b;b=b.nextSibling)b.nodeTyp...
function rs (line 597) | function rs(a,b){var c,d=[];for(c=b.firstElementChild;c;c=c.nextElementS...
function ss (line 598) | function ss(a,b){var c=[];for(b=b.firstChild;b;b=b.nextSibling)b.nodeTyp...
function ts (line 599) | function ts(a,b){b=vi(b);b=[255*(4==b.length?b[3]:1),b[2],b[1],b[0]];var...
function us (line 599) | function us(a,b,c){a={node:a};var d=b.S();if("GeometryCollection"==d){va...
function As (line 599) | function As(a,b,c){Do({node:a},Bs,Cs,[b],c)}
function Ds (line 600) | function Ds(a,b,c){var d={node:a};b.c&&a.setAttribute("id",b.c);a=b.L();...
function Hs (line 601) | function Hs(a,b,c){var d=b.da();a={node:a};a.layout=b.ja;a.stride=b.pa()...
function Ks (line 601) | function Ks(a,b,c){b=b.Ud();var d=b.shift();a={node:a};Do(a,Ls,Ms,b,c);D...
function Os (line 601) | function Os(a,b){Ip(a,Math.round(1E6*b)/1E6)}
function Ys (line 608) | function Ys(a,b,c){return no(ur[0],"gx:"+c)}
function Rs (line 608) | function Rs(a,b){return no(b[b.length-1].node.nam
Copy disabled (too large)
Download .json
Condensed preview — 445 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (26,265K chars).
[
{
"path": ".gitattributes",
"chars": 109,
"preview": "*.js linguist-vendored\n/Dockerfile linguist-vendored\n/release.py linguist-vendored\n/**/*.js linguist-vendored"
},
{
"path": ".github/FUNDING.yml",
"chars": 614,
"preview": "# These are supported funding model platforms\n\ngithub: evilsocket\npatreon: evilsocket\nopen_collective: # Replace with a "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 177,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Bettercap Documentation\n url: https://www.bettercap.org/\n abo"
},
{
"path": ".github/ISSUE_TEMPLATE/default_issue.md",
"chars": 1240,
"preview": "---\nname: General Issue\nabout: Write a general issue or bug report.\n---\n\n# Prerequisites\n\nPlease, before creating this i"
},
{
"path": ".github/dependabot.yml",
"chars": 130,
"preview": "version: 2\nupdates:\n # GitHub Actions\n - package-ecosystem: github-actions\n directory: /\n schedule:\n interv"
},
{
"path": ".github/workflows/build-and-deploy.yml",
"chars": 3477,
"preview": "name: Build and Deploy\n\non:\n push:\n tags:\n - 'v*.*.*' # Match version tags\n workflow_dispatch: \n\njobs:"
},
{
"path": ".github/workflows/build-and-push-docker.yml",
"chars": 761,
"preview": "name: Build and Push Docker Images\n\non:\n push:\n branches: [ \"master\" ]\n pull_request:\n branches: [ \"master\" ]\n\nj"
},
{
"path": ".github/workflows/test-on-linux.yml",
"chars": 732,
"preview": "name: Linux tests\n\non:\n push:\n branches: [ \"master\" ]\n pull_request:\n branches: [ \"master\" ]\n workflow_dispatch"
},
{
"path": ".github/workflows/test-on-macos.yml",
"chars": 650,
"preview": "name: macOS tests\n\non:\n push:\n branches: [ \"master\" ]\n pull_request:\n branches: [ \"master\" ]\n workflow_dispatch"
},
{
"path": ".github/workflows/test-on-windows.yml",
"chars": 1266,
"preview": "name: Windows tests\n\non:\n push:\n branches: [ \"master\" ]\n pull_request:\n branches: [ \"master\" ]\n workflow_dispat"
},
{
"path": ".gitignore",
"chars": 182,
"preview": "*.sw*\n*.tar.gz\n*.prof*\n_example/config.js\npcaps\nbuild\nbettercap\nbettercap.history\n*.snap\n*.snap.xdelta3\nprime/\nsnap/\nsta"
},
{
"path": "Dockerfile",
"chars": 881,
"preview": "# build stage\nFROM golang:1.24-alpine AS build-env\n\nRUN apk add --no-cache ca-certificates\nRUN apk add --no-cache bash g"
},
{
"path": "Dockerfile.arm64",
"chars": 1283,
"preview": "# syntax=docker/dockerfile:1\n\n# build stage for cross-compiling for arm64 using native Go cross-compilation\nFROM golang:"
},
{
"path": "LICENSE.md",
"chars": 35187,
"preview": "GNU GENERAL PUBLIC LICENSE\n==========================\n\nVersion 3, 29 June 2007\n\nCopyright © 2007 Free Software Foun"
},
{
"path": "Makefile",
"chars": 1105,
"preview": "TARGET ?= bettercap\nPACKAGES ?= core firewall log modules network packets session tls\nPREFIX ?= /usr/local\nGO "
},
{
"path": "README.md",
"chars": 4786,
"preview": "<p align=\"center\">\n <small>Join the project community on our server!</small>\n <br/><br/>\n <a href=\"https://discord.gg"
},
{
"path": "SECURITY.md",
"chars": 417,
"preview": "# Security Policy\n\n## Supported Versions\n\nFeature updates and security fixes are streamlined only to the latest version,"
},
{
"path": "bettercap.service",
"chars": 356,
"preview": "[Unit]\nDescription=bettercap api.rest service.\nDocumentation=https://bettercap.org\nWants=network.target\nAfter=network.ta"
},
{
"path": "caplets/caplet.go",
"chars": 1287,
"preview": "package caplets\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/evilsocket/islazy/fs\"\n)\n\ntype Script struct {"
},
{
"path": "caplets/caplet_test.go",
"chars": 7944,
"preview": "package caplets\n\nimport (\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestNewCaplet(t *testing.T) {\n\tname"
},
{
"path": "caplets/doc.go",
"chars": 94,
"preview": "// Package caplets contains functions to enumerate, load and execute caplets.\npackage caplets\n"
},
{
"path": "caplets/env.go",
"chars": 1368,
"preview": "package caplets\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\n\t\"github.com/evilsocket/islazy/str\"\n\t\"github.com/mitchellh/"
},
{
"path": "caplets/env_test.go",
"chars": 7349,
"preview": "package caplets\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestGetDefaultInstallBase(t *t"
},
{
"path": "caplets/manager.go",
"chars": 2691,
"preview": "package caplets\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/evilsocket"
},
{
"path": "caplets/manager_test.go",
"chars": 11919,
"preview": "package caplets\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n)\n\nfunc creat"
},
{
"path": "core/banner.go",
"chars": 149,
"preview": "package core\n\nconst (\n\tName = \"bettercap\"\n\tVersion = \"2.41.5\"\n\tAuthor = \"Simone 'evilsocket' Margaritelli\"\n\tWebsite "
},
{
"path": "core/banner_test.go",
"chars": 778,
"preview": "package core\n\nimport (\n\t\"regexp\"\n\t\"testing\"\n)\n\nfunc TestBannerName(t *testing.T) {\n\tif Name != \"bettercap\" {\n\t\tt.Fatalf("
},
{
"path": "core/core.go",
"chars": 975,
"preview": "package core\n\nimport (\n\t\"os/exec\"\n\t\"sort\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/evilsocket/islazy/str\"\n"
},
{
"path": "core/core_android.go",
"chars": 147,
"preview": "//go:build android\n// +build android\n\npackage core\n\nfunc Shell(cmd string) (string, error) {\n\treturn Exec(\"/system/bin/s"
},
{
"path": "core/core_test.go",
"chars": 4796,
"preview": "package core\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/evilsocket/islazy/fs\"\n)\n\nfunc hasInt(a []int, v int) bool {\n\tfor _"
},
{
"path": "core/core_unix.go",
"chars": 163,
"preview": "//go:build !windows && !android\n// +build !windows,!android\n\npackage core\n\nfunc Shell(cmd string) (string, error) {\n\tret"
},
{
"path": "core/core_windows.go",
"chars": 102,
"preview": "package core\n\nfunc Shell(cmd string) (string, error) {\n\treturn Exec(\"cmd.exe\", []string{\"/c\", cmd})\n}\n"
},
{
"path": "core/doc.go",
"chars": 63,
"preview": "// Package core contains basic utility functions.\npackage core\n"
},
{
"path": "core/options.go",
"chars": 2167,
"preview": "package core\n\nimport (\n\t\"flag\"\n)\n\ntype Options struct {\n\tInterfaceName string\n\tGateway string\n\tCaplet strin"
},
{
"path": "firewall/doc.go",
"chars": 111,
"preview": "// Package firewall contains the OS specific implementation of the FirewallManager interface.\npackage firewall\n"
},
{
"path": "firewall/firewall.go",
"chars": 185,
"preview": "package firewall\n\ntype FirewallManager interface {\n\tIsForwardingEnabled() bool\n\tEnableForwarding(enabled bool) error\n\tEn"
},
{
"path": "firewall/firewall_darwin.go",
"chars": 3608,
"preview": "package firewall\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/bettercap/better"
},
{
"path": "firewall/firewall_linux.go",
"chars": 3436,
"preview": "package firewall\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/core\"\n\t\"github.com/"
},
{
"path": "firewall/firewall_windows.go",
"chars": 3137,
"preview": "package firewall\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/core\"\n\t\"github.com/bettercap/bettercap"
},
{
"path": "firewall/redirection.go",
"chars": 599,
"preview": "package firewall\n\nimport \"fmt\"\n\ntype Redirection struct {\n\tInterface string\n\tProtocol string\n\tSrcAddress string\n\tSrcP"
},
{
"path": "firewall/redirection_test.go",
"chars": 5568,
"preview": "package firewall\n\nimport (\n\t\"testing\"\n)\n\nfunc TestNewRedirection(t *testing.T) {\n\tiface := \"eth0\"\n\tproto := \"tcp\"\n\tportF"
},
{
"path": "go.mod",
"chars": 2667,
"preview": "module github.com/bettercap/bettercap/v2\n\ngo 1.23.0\n\ntoolchain go1.24.4\n\nrequire (\n\tgithub.com/acarl005/stripansi v0.0.0"
},
{
"path": "go.sum",
"chars": 17961,
"preview": "github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=\ngithub."
},
{
"path": "js/crypto.go",
"chars": 602,
"preview": "package js\n\nimport (\n\t\"crypto/sha1\"\n\n\t\"github.com/robertkrimen/otto\"\n)\n\nfunc cryptoSha1(call otto.FunctionCall) otto.Val"
},
{
"path": "js/data.go",
"chars": 4037,
"preview": "package js\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/base64\"\n\n\t\"github.com/robertkrimen/otto\"\n)\n\nfunc textEncode(ca"
},
{
"path": "js/data_test.go",
"chars": 12065,
"preview": "package js\n\nimport (\n\t\"encoding/base64\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/robertkrimen/otto\"\n)\n\nfunc TestBtoa(t *testi"
},
{
"path": "js/fs.go",
"chars": 2573,
"preview": "package js\n\nimport (\n\t\"os\"\n\n\t\"github.com/robertkrimen/otto\"\n)\n\nfunc mkdirAll(call otto.FunctionCall) otto.Value {\n\targv "
},
{
"path": "js/fs_test.go",
"chars": 29775,
"preview": "package js\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/robertkrimen/otto\"\n)\n\n"
},
{
"path": "js/http.go",
"chars": 3422,
"preview": "package js\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/robertkrimen/otto\"\n)\n\ntype ht"
},
{
"path": "js/init.go",
"chars": 1216,
"preview": "package js\n\nimport (\n\t\"github.com/evilsocket/islazy/log\"\n\t\"github.com/evilsocket/islazy/plugin\"\n\t\"github.com/robertkrime"
},
{
"path": "js/log.go",
"chars": 972,
"preview": "package js\n\nimport (\n\t\"github.com/evilsocket/islazy/log\"\n\t\"github.com/robertkrimen/otto\"\n)\n\nfunc flog(call otto.Function"
},
{
"path": "js/random.go",
"chars": 483,
"preview": "package js\n\nimport (\n\t\"math/rand\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n)\n\ntype randomPackage struct {\n}\n"
},
{
"path": "js/random_test.go",
"chars": 6537,
"preview": "package js\n\nimport (\n\t\"net\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestRandomString(t *testing.T) {\n\tr := randomPackage"
},
{
"path": "log/doc.go",
"chars": 117,
"preview": "// Package log contains a transparent interface for logging which interacts with the system event queue.\npackage log\n"
},
{
"path": "log/log.go",
"chars": 735,
"preview": "package log\n\nimport (\n\t\"github.com/evilsocket/islazy/log\"\n)\n\ntype logFunction func(level log.Verbosity, format string, a"
},
{
"path": "log/log_test.go",
"chars": 2461,
"preview": "package log\n\nimport (\n\t\"testing\"\n\n\t\"github.com/evilsocket/islazy/log\"\n)\n\nvar called bool\nvar calledLevel log.Verbosity\nv"
},
{
"path": "main.go",
"chars": 2772,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"runtime\"\n\n\t\"github.com/bettercap/bettercap/v2/core\"\n\t\"github.com"
},
{
"path": "main_test.go",
"chars": 1964,
"preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestExitPrompt(t *testing.T) {\n\ttests := []struct {\n\t\tname"
},
{
"path": "modules/any_proxy/any_proxy.go",
"chars": 5099,
"preview": "package any_proxy\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/firewall\"\n\t\"github.com/bet"
},
{
"path": "modules/any_proxy/any_proxy_test.go",
"chars": 4954,
"preview": "package any_proxy\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/bettercap/bettercap/v2/session"
},
{
"path": "modules/api_rest/api_rest.go",
"chars": 8773,
"preview": "package api_rest\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\t"
},
{
"path": "modules/api_rest/api_rest_controller.go",
"chars": 11122,
"preview": "package api_rest\n\nimport (\n\t\"crypto/subtle\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strin"
},
{
"path": "modules/api_rest/api_rest_record.go",
"chars": 2273,
"preview": "package api_rest\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/recording\"\n\n\t\"gith"
},
{
"path": "modules/api_rest/api_rest_replay.go",
"chars": 1797,
"preview": "package api_rest\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/recording\"\n\n\t\"github.com/evilsocket/islazy/f"
},
{
"path": "modules/api_rest/api_rest_test.go",
"chars": 14567,
"preview": "package api_rest\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github"
},
{
"path": "modules/api_rest/api_rest_ws.go",
"chars": 2931,
"preview": "package api_rest\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/session\""
},
{
"path": "modules/arp_spoof/arp_spoof.go",
"chars": 9452,
"preview": "package arp_spoof\n\nimport (\n\t\"bytes\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\t\"g"
},
{
"path": "modules/arp_spoof/arp_spoof_test.go",
"chars": 19612,
"preview": "package arp_spoof\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/firew"
},
{
"path": "modules/ble/ble_options_darwin.go",
"chars": 278,
"preview": "package ble\n\nimport (\n\t\"github.com/bettercap/gatt\"\n)\n\nfunc getClientOptions(deviceID int) []gatt.Option {\n\treturn []gatt"
},
{
"path": "modules/ble/ble_options_linux.go",
"chars": 529,
"preview": "package ble\n\nimport (\n\t\"github.com/bettercap/gatt\"\n\t// \"github.com/bettercap/gatt/linux/cmd\"\n)\n\nfunc getClientOptions(de"
},
{
"path": "modules/ble/ble_recon.go",
"chars": 7405,
"preview": "//go:build !windows && !freebsd && !openbsd && !netbsd\n// +build !windows,!freebsd,!openbsd,!netbsd\n\npackage ble\n\nimport"
},
{
"path": "modules/ble/ble_recon_events.go",
"chars": 2046,
"preview": "//go:build !windows && !freebsd && !openbsd && !netbsd\n// +build !windows,!freebsd,!openbsd,!netbsd\n\npackage ble\n\nimport"
},
{
"path": "modules/ble/ble_recon_test.go",
"chars": 7593,
"preview": "//go:build !windows && !freebsd && !openbsd && !netbsd\n// +build !windows,!freebsd,!openbsd,!netbsd\n\npackage ble\n\nimport"
},
{
"path": "modules/ble/ble_show.go",
"chars": 3492,
"preview": "//go:build !windows && !freebsd && !openbsd && !netbsd\n// +build !windows,!freebsd,!openbsd,!netbsd\n\npackage ble\n\nimport"
},
{
"path": "modules/ble/ble_show_services.go",
"chars": 11061,
"preview": "//go:build !windows && !freebsd && !openbsd && !netbsd\n// +build !windows,!freebsd,!openbsd,!netbsd\n\npackage ble\n\nimport"
},
{
"path": "modules/ble/ble_show_sort.go",
"chars": 1027,
"preview": "//go:build !windows && !freebsd && !openbsd && !netbsd\n// +build !windows,!freebsd,!openbsd,!netbsd\n\npackage ble\n\nimport"
},
{
"path": "modules/ble/ble_unsupported.go",
"chars": 1197,
"preview": "//go:build windows || freebsd || netbsd || openbsd\n// +build windows freebsd netbsd openbsd\n\npackage ble\n\nimport (\n\t\"git"
},
{
"path": "modules/c2/c2.go",
"chars": 10013,
"preview": "package c2\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/acarl005/stripansi\"\n\t\"githu"
},
{
"path": "modules/c2/c2_test.go",
"chars": 7891,
"preview": "package c2\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"text/template\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n)\n\nvar (\n\ttestSes"
},
{
"path": "modules/can/can.go",
"chars": 3484,
"preview": "package can\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\t\"github.com/hashicorp/go-be"
},
{
"path": "modules/can/can_dbc.go",
"chars": 3420,
"preview": "package can\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/evilsocket/islazy/str\"\n\t\"go.einride.tech/can/pkg/descriptor\"\n)\n"
},
{
"path": "modules/can/can_dbc_compile.go",
"chars": 6779,
"preview": "package can\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"time\"\n\n\t\"go.einride.tech/can/pkg/dbc\"\n\t\"go.einride.tech/can/pkg/descriptor\"\n)\n\nty"
},
{
"path": "modules/can/can_dbc_load.go",
"chars": 119,
"preview": "package can\n\nfunc (mod *CANModule) dbcLoad(name string) error {\n\t// load as file\n\treturn mod.dbc.LoadFile(mod, name)\n}\n"
},
{
"path": "modules/can/can_dump_reader.go",
"chars": 2480,
"preview": "package can\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/evilsocket/"
},
{
"path": "modules/can/can_fuzz.go",
"chars": 2835,
"preview": "package can\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"g"
},
{
"path": "modules/can/can_inject.go",
"chars": 442,
"preview": "package can\n\nimport (\n\t\"context\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"go.einride.tech/can\"\n)\n\nfunc (mod *CANModule) Injec"
},
{
"path": "modules/can/can_message.go",
"chars": 404,
"preview": "package can\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/network\"\n\t\"go.einride.tech/can\"\n)\n\ntype Message struct {\n\t// t"
},
{
"path": "modules/can/can_obd2.go",
"chars": 1128,
"preview": "package can\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\ntype OBD2 struct {\n\tsync.RWMutex\n\n\tenabled bool\n}\n\nfunc (obd *OBD2) Enabled() bo"
},
{
"path": "modules/can/can_obd2_message.go",
"chars": 1888,
"preview": "package can\n\nimport (\n\t\"fmt\"\n)\n\n// https://en.wikipedia.org/wiki/OBD-II_PIDs\n\n// https://www.csselectronics.com/pages/ob"
},
{
"path": "modules/can/can_obd2_pid_request.go",
"chars": 8330,
"preview": "package can\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\n\t\"go.einride.tech/can\"\n)\n\nvar servicePIDS = map[uint8]map[uint16]string"
},
{
"path": "modules/can/can_obd2_pid_response.go",
"chars": 550,
"preview": "package can\n\nimport (\n\t\"go.einride.tech/can\"\n)\n\nfunc (msg *OBD2Message) ParseResponse(frame can.Frame) bool {\n\tmsgSize :"
},
{
"path": "modules/can/can_recon.go",
"chars": 2873,
"preview": "package can\n\nimport (\n\t\"errors\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\t\"github.com/evilsocket/islazy/tui\"\n\t\"gith"
},
{
"path": "modules/can/can_show.go",
"chars": 1106,
"preview": "package can\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\t\"github.com/dustin/go-humanize\"\n\t\"gi"
},
{
"path": "modules/can/can_test.go",
"chars": 8900,
"preview": "package can\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\t\"go.einride.tech/can\"\n)\n\nvar (\n\t"
},
{
"path": "modules/caplets/caplets.go",
"chars": 3157,
"preview": "package caplets\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"github.com/bettercap/bettercap/v2/caplets\"\n\t\"github.com/bett"
},
{
"path": "modules/dhcp6_spoof/dhcp6_spoof.go",
"chars": 9858,
"preview": "package dhcp6_spoof\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/b"
},
{
"path": "modules/dns_proxy/dns_proxy.go",
"chars": 5299,
"preview": "package dns_proxy\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/session\"\n\t\"github.com/bettercap/bettercap/v2/tls\"\n\n\t\"git"
},
{
"path": "modules/dns_proxy/dns_proxy_base.go",
"chars": 5811,
"preview": "package dns_proxy\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com"
},
{
"path": "modules/dns_proxy/dns_proxy_base_filters.go",
"chars": 2613,
"preview": "package dns_proxy\n\nimport (\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n)\n\nfunc questionsToStrings(qs []dns.Question) []string {"
},
{
"path": "modules/dns_proxy/dns_proxy_js_query.go",
"chars": 9205,
"preview": "package dns_proxy\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/big\"\n\t\"reflect\"\n\n\t\"github.com/bettercap/bettercap/v2/"
},
{
"path": "modules/dns_proxy/dns_proxy_js_record.go",
"chars": 28995,
"preview": "package dns_proxy\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/miekg/dns\"\n)\n\nfunc NewJ"
},
{
"path": "modules/dns_proxy/dns_proxy_js_record_edns0.go",
"chars": 5568,
"preview": "package dns_proxy\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/miekg/dns\"\n)\n\nfunc NewJ"
},
{
"path": "modules/dns_proxy/dns_proxy_js_record_svcb.go",
"chars": 2852,
"preview": "package dns_proxy\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/miekg/dns\"\n)\n\nfunc NewJ"
},
{
"path": "modules/dns_proxy/dns_proxy_script.go",
"chars": 3121,
"preview": "package dns_proxy\n\nimport (\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/bettercap/bettercap/v2/ses"
},
{
"path": "modules/dns_spoof/dns_spoof.go",
"chars": 8113,
"preview": "package dns_spoof\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github"
},
{
"path": "modules/dns_spoof/dns_spoof_hosts.go",
"chars": 1576,
"preview": "package dns_spoof\n\nimport (\n\t\"bufio\"\n\t\"net\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/gobwas/glob\"\n\n\t\"github.com/evilsock"
},
{
"path": "modules/doc.go",
"chars": 61,
"preview": "// Package modules contains session modules.\npackage modules\n"
},
{
"path": "modules/events_stream/events_rotation.go",
"chars": 1482,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"github.com/evilsocket/islazy/zip\"\n\t\"os\"\n\t\"time\"\n)\n\nfunc (mod *EventsStream) doR"
},
{
"path": "modules/events_stream/events_stream.go",
"chars": 9945,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/sessi"
},
{
"path": "modules/events_stream/events_triggers.go",
"chars": 1345,
"preview": "package events_stream\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/session\"\n\n\t\"github.com/evilsocket/islazy/tui\"\n)\n\nfun"
},
{
"path": "modules/events_stream/events_view.go",
"chars": 4259,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\t\"github.com"
},
{
"path": "modules/events_stream/events_view_ble.go",
"chars": 1157,
"preview": "//go:build !windows\n// +build !windows\n\npackage events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/bettercap/bettercap/v"
},
{
"path": "modules/events_stream/events_view_ble_unsupported.go",
"chars": 203,
"preview": "//go:build windows\n// +build windows\n\npackage events_stream\n\nimport (\n\t\"io\"\n\n\t\"github.com/bettercap/bettercap/v2/session"
},
{
"path": "modules/events_stream/events_view_can.go",
"chars": 2586,
"preview": "package events_stream\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/bettercap/bettercap/v2/modules/can\"\n\t\"github."
},
{
"path": "modules/events_stream/events_view_gateway.go",
"chars": 480,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\n\t\"github.com/evilsocket/isla"
},
{
"path": "modules/events_stream/events_view_gps.go",
"chars": 513,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\t\"github.com/evilsocket/islaz"
},
{
"path": "modules/events_stream/events_view_hid.go",
"chars": 680,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\t\"github.com/bettercap/better"
},
{
"path": "modules/events_stream/events_view_http.go",
"chars": 5524,
"preview": "package events_stream\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"reg"
},
{
"path": "modules/events_stream/events_view_wifi.go",
"chars": 4429,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/modules/wifi\"\n\n\t\"github.com"
},
{
"path": "modules/events_stream/events_view_zeroconf.go",
"chars": 1767,
"preview": "package events_stream\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/modules/zerogod\"\n\t\"github.c"
},
{
"path": "modules/events_stream/trigger_list.go",
"chars": 3252,
"preview": "package events_stream\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/bettercap/bettercap/v"
},
{
"path": "modules/gps/gps.go",
"chars": 5563,
"preview": "package gps\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\n\t\"github.com/adrian"
},
{
"path": "modules/graph/create.go",
"chars": 5032,
"preview": "package graph\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n)\n\nfunc (mod *Module) createIPGraph(endpoin"
},
{
"path": "modules/graph/create_ble.go",
"chars": 583,
"preview": "//go:build !windows\n// +build !windows\n\npackage graph\n\nimport \"github.com/bettercap/bettercap/v2/network\"\n\nfunc (mod *Mo"
},
{
"path": "modules/graph/create_ble_unsupported.go",
"chars": 218,
"preview": "//go:build windows\n// +build windows\n\npackage graph\n\nimport \"github.com/bettercap/bettercap/v2/network\"\n\nfunc (mod *Modu"
},
{
"path": "modules/graph/edge.go",
"chars": 775,
"preview": "package graph\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n)\n\ntype EdgeType string\n\nconst (\n\tI"
},
{
"path": "modules/graph/edges.go",
"chars": 2883,
"preview": "package graph\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/evilsocket/islazy/fs\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path\"\n\t\"sort\"\n\t\"sync\"\n\t"
},
{
"path": "modules/graph/graph.go",
"chars": 8977,
"preview": "package graph\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"path\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\t\""
},
{
"path": "modules/graph/js_builtin.go",
"chars": 298,
"preview": "package graph\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/log\"\n)\n\ntype graphPackage struct{}\n\nfunc (g graphPackage) Is"
},
{
"path": "modules/graph/module.go",
"chars": 9042,
"preview": "package graph\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/caplets\"\n\t"
},
{
"path": "modules/graph/node.go",
"chars": 4281,
"preview": "package graph\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode\"\n)\n\ntype NodeType string"
},
{
"path": "modules/graph/stack.go",
"chars": 616,
"preview": "package graph\n\nimport \"sync\"\n\ntype entry struct {\n\tdata interface{}\n\tnext *entry\n}\n\ntype Stack struct {\n\tlock *sync.Mute"
},
{
"path": "modules/graph/to_dot.go",
"chars": 843,
"preview": "package graph\n\nimport (\n\t\"io/ioutil\"\n\t\"os\"\n\t\"time\"\n)\n\nfunc (mod *Module) generateDotGraph(bssid string) error {\n\tmod.wLo"
},
{
"path": "modules/graph/to_json.go",
"chars": 794,
"preview": "package graph\n\nimport (\n\t\"io/ioutil\"\n\t\"os\"\n\t\"time\"\n)\n\nfunc (mod *Module) generateJSONGraph(bssid string) error {\n\tmod.wL"
},
{
"path": "modules/hid/build_amazon.go",
"chars": 851,
"preview": "package hid\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/network\"\n)\n\nconst (\n\tamzFrameDelay = 5\n)\n\ntype AmazonBuilder s"
},
{
"path": "modules/hid/build_logitech.go",
"chars": 1204,
"preview": "package hid\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/network\"\n)\n\nconst (\n\tltFrameDelay = 12\n)\n\nvar (\n\thelloData "
},
{
"path": "modules/hid/build_microsoft.go",
"chars": 1506,
"preview": "package hid\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n)\n\ntype MicrosoftBuilder struct {\n\tseqn uint1"
},
{
"path": "modules/hid/builders.go",
"chars": 639,
"preview": "package hid\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/network\"\n)\n\ntype FrameBuilder interface {\n\tBuildFrames(*networ"
},
{
"path": "modules/hid/command.go",
"chars": 606,
"preview": "package hid\n\nimport (\n\t\"time\"\n)\n\ntype Frame struct {\n\tData []byte\n\tDelay time.Duration\n}\n\nfunc NewFrame(buf []byte, del"
},
{
"path": "modules/hid/duckyparser.go",
"chars": 4458,
"preview": "package hid\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evilsocket/islazy/fs\"\n)\n\ntype DuckyParser struct {\n\tmod"
},
{
"path": "modules/hid/hid.go",
"chars": 6949,
"preview": "package hid\n\nimport (\n\t\"fmt\"\n\tgolog \"log\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/modules/utils\""
},
{
"path": "modules/hid/hid_inject.go",
"chars": 3867,
"preview": "package hid\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\n\t\"github.com/evilsocket/islazy/tui\"\n"
},
{
"path": "modules/hid/hid_recon.go",
"chars": 3335,
"preview": "package hid\n\nimport (\n\t\"time\"\n\n\t\"github.com/bettercap/nrf24\"\n\t\"github.com/google/gousb\"\n)\n\nfunc (mod *HIDRecon) doHoppin"
},
{
"path": "modules/hid/hid_show.go",
"chars": 2636,
"preview": "package hid\n\nimport (\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\n\t\"github.com/dustin/go-humanize\"\n\n\t"
},
{
"path": "modules/hid/hid_show_sort.go",
"chars": 592,
"preview": "package hid\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/network\"\n)\n\ntype ByHIDMacSorter []*network.HIDDevice\n\nfunc (a "
},
{
"path": "modules/hid/hid_sniff.go",
"chars": 2380,
"preview": "package hid\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\n\t\"github.com/betterc"
},
{
"path": "modules/hid/keymaps.go",
"chars": 73047,
"preview": "package hid\n\nimport (\n\t\"sort\"\n)\n\ntype KeyMap map[string]Command\n\nvar BaseMap = KeyMap{\n\t\"\": Command{},\n\t\"CTRL"
},
{
"path": "modules/http_proxy/http_proxy.go",
"chars": 4027,
"preview": "package http_proxy\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/session\"\n\n\t\"github.com/evilsocket/islazy/str\"\n)\n\ntype H"
},
{
"path": "modules/http_proxy/http_proxy_base.go",
"chars": 11735,
"preview": "package http_proxy\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"net/"
},
{
"path": "modules/http_proxy/http_proxy_base_cookietracker.go",
"chars": 1794,
"preview": "package http_proxy\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/elazarl/goproxy\"\n\t\"github.com/jpillora/"
},
{
"path": "modules/http_proxy/http_proxy_base_filters.go",
"chars": 4058,
"preview": "package http_proxy\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/elazarl/goproxy\"\n\n\t\"github.com/evilso"
},
{
"path": "modules/http_proxy/http_proxy_base_hosttracker.go",
"chars": 1228,
"preview": "package http_proxy\n\nimport (\n\t\"net\"\n\t\"sync\"\n)\n\ntype Host struct {\n\tHostname string\n\tAddress net.IP\n\tResolved sync.WaitG"
},
{
"path": "modules/http_proxy/http_proxy_base_sslstriper.go",
"chars": 9540,
"preview": "package http_proxy\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/bettercap/better"
},
{
"path": "modules/http_proxy/http_proxy_cert_cache.go",
"chars": 586,
"preview": "package http_proxy\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"sync\"\n)\n\nvar (\n\tcertCache = make(map[string]*tls.Certificate)\n\tcertL"
},
{
"path": "modules/http_proxy/http_proxy_js_request.go",
"chars": 6573,
"preview": "package http_proxy\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/bettercap/b"
},
{
"path": "modules/http_proxy/http_proxy_js_response.go",
"chars": 5341,
"preview": "package http_proxy\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/elazarl/goproxy\"\n)\n\ntype JSRespo"
},
{
"path": "modules/http_proxy/http_proxy_script.go",
"chars": 3108,
"preview": "package http_proxy\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/bettercap/bet"
},
{
"path": "modules/http_proxy/http_proxy_test.go",
"chars": 17724,
"preview": "package http_proxy\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"t"
},
{
"path": "modules/http_server/http_server.go",
"chars": 2893,
"preview": "package http_server\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/sess"
},
{
"path": "modules/https_proxy/https_proxy.go",
"chars": 5637,
"preview": "package https_proxy\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/modules/http_proxy\"\n\t\"github.com/bettercap/bettercap/v"
},
{
"path": "modules/https_server/https_server.go",
"chars": 4294,
"preview": "package https_server\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/ses"
},
{
"path": "modules/mac_changer/mac_changer.go",
"chars": 3244,
"preview": "package mac_changer\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/core\"\n\t\"github.co"
},
{
"path": "modules/modules.go",
"chars": 3321,
"preview": "package modules\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/modules/any_proxy\"\n\t\"github.com/bettercap/bettercap/v2/mod"
},
{
"path": "modules/modules_test.go",
"chars": 797,
"preview": "package modules\n\nimport (\n\t\"testing\"\n)\n\nfunc TestLoadModulesWithNilSession(t *testing.T) {\n\t// This test verifies that L"
},
{
"path": "modules/mysql_server/mysql_server.go",
"chars": 5334,
"preview": "package mysql_server\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap"
},
{
"path": "modules/ndp_spoof/ndp_spoof.go",
"chars": 5999,
"preview": "package ndp_spoof\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n\t\"github.com/evi"
},
{
"path": "modules/net_probe/net_probe.go",
"chars": 3806,
"preview": "package net_probe\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/network\"\n\t\"github.com/bettercap/betterc"
},
{
"path": "modules/net_probe/net_probe_nbns.go",
"chars": 632,
"preview": "package net_probe\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n)\n\nfunc (mod *Prober) sendProbeN"
},
{
"path": "modules/net_probe/net_probe_test.go",
"chars": 14204,
"preview": "package net_probe\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2"
},
{
"path": "modules/net_probe/net_probe_upnp.go",
"chars": 647,
"preview": "package net_probe\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n)\n\nfunc (mod *Prober) sendProbeU"
},
{
"path": "modules/net_probe/net_probe_wsd.go",
"chars": 643,
"preview": "package net_probe\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n)\n\nfunc (mod *Prober) sendProbeW"
},
{
"path": "modules/net_recon/net_recon.go",
"chars": 3166,
"preview": "package net_recon\n\nimport (\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/modules/utils\"\n\n\t\"github.com/bettercap/betterca"
},
{
"path": "modules/net_recon/net_recon_test.go",
"chars": 15589,
"preview": "package net_recon\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/modules/utils\"\n\t\"gith"
},
{
"path": "modules/net_recon/net_show.go",
"chars": 7938,
"preview": "package net_recon\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/modules/syn_scan\"\n\n\t\""
},
{
"path": "modules/net_recon/net_show_sort.go",
"chars": 2111,
"preview": "package net_recon\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/network\"\n\t\"github.com/bettercap/bettercap/v2/packets\"\n\t\""
},
{
"path": "modules/net_sniff/net_sniff.go",
"chars": 5786,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\n\t\"github.com/gopacket/gopacket"
},
{
"path": "modules/net_sniff/net_sniff_context.go",
"chars": 3467,
"preview": "package net_sniff\n\nimport (\n\t\"os\"\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/bettercap/bet"
},
{
"path": "modules/net_sniff/net_sniff_dns.go",
"chars": 1325,
"preview": "package net_sniff\n\nimport (\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/layers\"\n\t\"net\"\n\t\"strings\"\n\n\t\""
},
{
"path": "modules/net_sniff/net_sniff_dot11.go",
"chars": 527,
"preview": "package net_sniff\n\nimport (\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/layers\"\n)\n\nfunc onDOT11(radio"
},
{
"path": "modules/net_sniff/net_sniff_event.go",
"chars": 819,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n)\n\ntype SniffData map[string]in"
},
{
"path": "modules/net_sniff/net_sniff_ftp.go",
"chars": 846,
"preview": "package net_sniff\n\nimport (\n\t\"net\"\n\t\"regexp\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/layers\"\n\n\t\""
},
{
"path": "modules/net_sniff/net_sniff_fuzz.go",
"chars": 2235,
"preview": "package net_sniff\n\nimport (\n\t\"math/rand\"\n\t\"strings\"\n\n\t\"github.com/gopacket/gopacket\"\n\n\t\"github.com/evilsocket/islazy/str"
},
{
"path": "modules/net_sniff/net_sniff_http.go",
"chars": 4421,
"preview": "package net_sniff\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gopacke"
},
{
"path": "modules/net_sniff/net_sniff_krb5.go",
"chars": 800,
"preview": "package net_sniff\n\nimport (\n\t\"encoding/asn1\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n\n\t\"github.com/gopacket"
},
{
"path": "modules/net_sniff/net_sniff_mdns.go",
"chars": 1917,
"preview": "package net_sniff\n\nimport (\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n\t\"github.com/bettercap/bette"
},
{
"path": "modules/net_sniff/net_sniff_ntlm.go",
"chars": 1573,
"preview": "package net_sniff\n\nimport (\n\t\"net\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n\n\t\"github.com/gopa"
},
{
"path": "modules/net_sniff/net_sniff_parsers.go",
"chars": 2149,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n\t\"github.com/bettercap/bettercap/v2/"
},
{
"path": "modules/net_sniff/net_sniff_sni.go",
"chars": 953,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"regexp\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/lay"
},
{
"path": "modules/net_sniff/net_sniff_stats.go",
"chars": 1037,
"preview": "package net_sniff\n\nimport (\n\t\"time\"\n\n\t\"github.com/bettercap/bettercap/v2/log\"\n)\n\ntype SnifferStats struct {\n\tNumLocal "
},
{
"path": "modules/net_sniff/net_sniff_tcp.go",
"chars": 1005,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/layers\"\n\n\t\"git"
},
{
"path": "modules/net_sniff/net_sniff_teamviewer.go",
"chars": 750,
"preview": "package net_sniff\n\nimport (\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"gith"
},
{
"path": "modules/net_sniff/net_sniff_udp.go",
"chars": 976,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/layers\"\n\n\t\"git"
},
{
"path": "modules/net_sniff/net_sniff_upnp.go",
"chars": 770,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/packets\"\n\n\t\"github.com/gopacket/gopacket\""
},
{
"path": "modules/net_sniff/net_sniff_views.go",
"chars": 969,
"preview": "package net_sniff\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/bettercap/bettercap/v2/session\"\n\n\t\"github.com/evilsocket/islazy/"
},
{
"path": "modules/packet_proxy/packet_proxy_darwin.go",
"chars": 755,
"preview": "package packet_proxy\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/session\"\n)\n\ntype PacketProxy struct {\n\tsession.Sessio"
},
{
"path": "modules/packet_proxy/packet_proxy_freebsd.go",
"chars": 755,
"preview": "package packet_proxy\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/session\"\n)\n\ntype PacketProxy struct {\n\tsession.Sessio"
},
{
"path": "modules/packet_proxy/packet_proxy_linux.go",
"chars": 5780,
"preview": "package packet_proxy\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"plugin\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/bettercap/betterc"
},
{
"path": "modules/packet_proxy/packet_proxy_windows.go",
"chars": 755,
"preview": "package packet_proxy\n\nimport (\n\t\"github.com/bettercap/bettercap/v2/session\"\n)\n\ntype PacketProxy struct {\n\tsession.Sessio"
},
{
"path": "modules/syn_scan/banner_grabbing.go",
"chars": 805,
"preview": "package syn_scan\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/evilsocket/islazy/async\"\n)\n\nconst bannerGrabTimeout = time.Durat"
},
{
"path": "modules/syn_scan/dns_grabber.go",
"chars": 797,
"preview": "package syn_scan\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/miekg/dns\"\n)\n\nvar chaosParser = regexp.MustCompile(`.*\"([^\"]+)"
}
]
// ... and 245 more files (download for full content)
About this extraction
This page contains the full source code of the evilsocket/bettercap-ng GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 445 files (23.9 MB), approximately 6.3M tokens, and a symbol index with 7941 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.