Compare commits
23 Commits
red/dev
...
red/workfl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b653a982f | ||
|
|
ddc27c8880 | ||
|
|
ff281344d8 | ||
|
|
5cec161a7b | ||
|
|
75f169e318 | ||
|
|
dadae2a79c | ||
|
|
ccda2a49f3 | ||
|
|
15095d2037 | ||
|
|
7efeef2fb7 | ||
|
|
113b154043 | ||
|
|
fe897906a3 | ||
|
|
065c7adf03 | ||
|
|
53c97721e1 | ||
|
|
721f1e790d | ||
|
|
334b0c7e06 | ||
|
|
9eca144092 | ||
|
|
15d2acf52a | ||
|
|
6d57165f63 | ||
|
|
cbd9292331 | ||
|
|
0680a51ad0 | ||
|
|
ff4c89bf46 | ||
|
|
85d8d78112 | ||
|
|
dca4415fb8 |
18
.github/workflows/github_actions.yml
vendored
18
.github/workflows/github_actions.yml
vendored
@@ -2,18 +2,34 @@ name: 'BrowserStack Test'
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
|
types: [opened, synchronize, reopened, labeled]
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu-job:
|
ubuntu-job:
|
||||||
name: 'BrowserStack Test on Ubuntu'
|
name: 'BrowserStack Test on Ubuntu'
|
||||||
|
if: contains(github.event.pull_request.labels.*.name, 'safe-to-test')
|
||||||
runs-on: ubuntu-latest # Can be self-hosted runner also
|
runs-on: ubuntu-latest # Can be self-hosted runner also
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
environment:
|
environment:
|
||||||
name: Integrate Pull Request
|
name: Integrate Pull Request
|
||||||
env:
|
env:
|
||||||
GITACTIONS: true
|
GITACTIONS: true
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
- name: 'Remove safe-to-test label'
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.issues.removeLabel({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
name: 'safe-to-test'
|
||||||
|
})
|
||||||
|
|
||||||
- name: 'BrowserStack Env Setup' # Invokes the setup-env action
|
- name: 'BrowserStack Env Setup' # Invokes the setup-env action
|
||||||
uses: browserstack/github-actions/setup-env@master
|
uses: browserstack/github-actions/setup-env@master
|
||||||
with:
|
with:
|
||||||
|
|||||||
11
Dockerfile
11
Dockerfile
@@ -78,9 +78,20 @@ RUN adduser --home /beef --gecos beef --disabled-password beef \
|
|||||||
zlib1g \
|
zlib1g \
|
||||||
bison \
|
bison \
|
||||||
nodejs \
|
nodejs \
|
||||||
|
firefox-esr \
|
||||||
&& apt-get -y clean \
|
&& apt-get -y clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& 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
|
# Use gemset created by the builder above
|
||||||
COPY --chown=beef:beef . /beef
|
COPY --chown=beef:beef . /beef
|
||||||
COPY --from=builder /usr/local/bundle /usr/local/bundle
|
COPY --from=builder /usr/local/bundle /usr/local/bundle
|
||||||
|
|||||||
6
Gemfile
6
Gemfile
@@ -63,11 +63,11 @@ end
|
|||||||
group :test do
|
group :test do
|
||||||
gem 'test-unit-full', '~> 0.0.5'
|
gem 'test-unit-full', '~> 0.0.5'
|
||||||
gem 'rspec', '~> 3.13'
|
gem 'rspec', '~> 3.13'
|
||||||
gem 'rdoc', '~> 7.0'
|
gem 'rdoc', '~> 7.1'
|
||||||
gem 'browserstack-local', '~> 1.4'
|
gem 'browserstack-local', '~> 1.4'
|
||||||
|
|
||||||
gem 'irb', '~> 1.16'
|
gem 'irb', '~> 1.16'
|
||||||
gem 'pry-byebug', '~> 3.11'
|
gem 'pry-byebug', '~> 3.12'
|
||||||
|
|
||||||
gem 'rest-client', '~> 2.1.0'
|
gem 'rest-client', '~> 2.1.0'
|
||||||
gem 'websocket-client-simple', '~> 0.6.1'
|
gem 'websocket-client-simple', '~> 0.6.1'
|
||||||
@@ -79,7 +79,7 @@ group :test do
|
|||||||
# Note: selenium-webdriver 3.x is incompatible with Firefox version 48 and prior
|
# 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 'selenium' # Requires old version of selenium which is no longer available
|
||||||
gem 'geckodriver-helper', '~> 0.24.0'
|
gem 'geckodriver-helper', '~> 0.24.0'
|
||||||
gem 'selenium-webdriver', '~> 4.39'
|
gem 'selenium-webdriver', '~> 4.40'
|
||||||
|
|
||||||
# Note: nokogiri is needed by capybara which may require one of the below commands
|
# Note: nokogiri is needed by capybara which may require one of the below commands
|
||||||
# sudo apt-get install libxslt-dev libxml2-dev
|
# sudo apt-get install libxslt-dev libxml2-dev
|
||||||
|
|||||||
47
Gemfile.lock
47
Gemfile.lock
@@ -1,13 +1,13 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
activemodel (8.1.1)
|
activemodel (8.1.2)
|
||||||
activesupport (= 8.1.1)
|
activesupport (= 8.1.2)
|
||||||
activerecord (8.1.1)
|
activerecord (8.1.2)
|
||||||
activemodel (= 8.1.1)
|
activemodel (= 8.1.2)
|
||||||
activesupport (= 8.1.1)
|
activesupport (= 8.1.2)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activesupport (8.1.1)
|
activesupport (8.1.2)
|
||||||
base64
|
base64
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
@@ -34,9 +34,10 @@ GEM
|
|||||||
async
|
async
|
||||||
io-endpoint
|
io-endpoint
|
||||||
base64 (0.3.0)
|
base64 (0.3.0)
|
||||||
bigdecimal (3.3.1)
|
bigdecimal (4.0.1)
|
||||||
browserstack-local (1.4.3)
|
browserstack-local (1.4.3)
|
||||||
byebug (12.0.0)
|
byebug (13.0.0)
|
||||||
|
reline (>= 0.6.0)
|
||||||
capybara (3.40.0)
|
capybara (3.40.0)
|
||||||
addressable
|
addressable
|
||||||
matrix
|
matrix
|
||||||
@@ -47,8 +48,8 @@ GEM
|
|||||||
regexp_parser (>= 1.5, < 3.0)
|
regexp_parser (>= 1.5, < 3.0)
|
||||||
xpath (~> 3.2)
|
xpath (~> 3.2)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
concurrent-ruby (1.3.5)
|
concurrent-ruby (1.3.6)
|
||||||
connection_pool (2.5.4)
|
connection_pool (3.0.2)
|
||||||
console (1.34.0)
|
console (1.34.0)
|
||||||
fiber-annotation
|
fiber-annotation
|
||||||
fiber-local (~> 1.1)
|
fiber-local (~> 1.1)
|
||||||
@@ -78,7 +79,7 @@ GEM
|
|||||||
http-cookie (1.0.8)
|
http-cookie (1.0.8)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
http_parser.rb (0.8.0)
|
http_parser.rb (0.8.0)
|
||||||
i18n (1.14.7)
|
i18n (1.14.8)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
io-console (0.8.2)
|
io-console (0.8.2)
|
||||||
io-endpoint (0.15.2)
|
io-endpoint (0.15.2)
|
||||||
@@ -99,7 +100,8 @@ GEM
|
|||||||
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
||||||
mime-types-data (3.2025.0902)
|
mime-types-data (3.2025.0902)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
minitest (5.26.1)
|
minitest (6.0.1)
|
||||||
|
prism (~> 1.5)
|
||||||
mojo_magick (0.6.8)
|
mojo_magick (0.6.8)
|
||||||
msfrpc-client (1.1.2)
|
msfrpc-client (1.1.2)
|
||||||
msgpack (~> 1)
|
msgpack (~> 1)
|
||||||
@@ -140,12 +142,13 @@ GEM
|
|||||||
prettyprint
|
prettyprint
|
||||||
prettyprint (0.2.0)
|
prettyprint (0.2.0)
|
||||||
prism (1.7.0)
|
prism (1.7.0)
|
||||||
pry (0.15.2)
|
pry (0.16.0)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
method_source (~> 1.0)
|
method_source (~> 1.0)
|
||||||
pry-byebug (3.11.0)
|
reline (>= 0.6.0)
|
||||||
byebug (~> 12.0)
|
pry-byebug (3.12.0)
|
||||||
pry (>= 0.13, < 0.16)
|
byebug (~> 13.0)
|
||||||
|
pry (>= 0.13, < 0.17)
|
||||||
psych (5.3.1)
|
psych (5.3.1)
|
||||||
date
|
date
|
||||||
stringio
|
stringio
|
||||||
@@ -166,7 +169,7 @@ GEM
|
|||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.3.1)
|
rake (13.3.1)
|
||||||
rdoc (7.0.3)
|
rdoc (7.1.0)
|
||||||
erb
|
erb
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
tsort
|
tsort
|
||||||
@@ -215,7 +218,7 @@ GEM
|
|||||||
json
|
json
|
||||||
rest-client
|
rest-client
|
||||||
securerandom (0.4.1)
|
securerandom (0.4.1)
|
||||||
selenium-webdriver (4.39.0)
|
selenium-webdriver (4.40.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
logger (~> 1.4)
|
logger (~> 1.4)
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
@@ -264,7 +267,7 @@ GEM
|
|||||||
logger
|
logger
|
||||||
rack (>= 1, < 4)
|
rack (>= 1, < 4)
|
||||||
tilt (2.6.1)
|
tilt (2.6.1)
|
||||||
timeout (0.4.4)
|
timeout (0.6.0)
|
||||||
timers (4.4.0)
|
timers (4.4.0)
|
||||||
tins (1.43.0)
|
tins (1.43.0)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
@@ -320,18 +323,18 @@ DEPENDENCIES
|
|||||||
net-smtp
|
net-smtp
|
||||||
otr-activerecord (~> 2.6.0)
|
otr-activerecord (~> 2.6.0)
|
||||||
parseconfig (~> 1.1, >= 1.1.2)
|
parseconfig (~> 1.1, >= 1.1.2)
|
||||||
pry-byebug (~> 3.11)
|
pry-byebug (~> 3.12)
|
||||||
qr4r (~> 0.6.1)
|
qr4r (~> 0.6.1)
|
||||||
rack (~> 3.2)
|
rack (~> 3.2)
|
||||||
rack-protection (~> 4.2.1)
|
rack-protection (~> 4.2.1)
|
||||||
rake (~> 13.3)
|
rake (~> 13.3)
|
||||||
rdoc (~> 7.0)
|
rdoc (~> 7.1)
|
||||||
rest-client (~> 2.1.0)
|
rest-client (~> 2.1.0)
|
||||||
rspec (~> 3.13)
|
rspec (~> 3.13)
|
||||||
rubocop (~> 1.82.1)
|
rubocop (~> 1.82.1)
|
||||||
rubyzip (~> 3.2)
|
rubyzip (~> 3.2)
|
||||||
rushover (~> 0.3.0)
|
rushover (~> 0.3.0)
|
||||||
selenium-webdriver (~> 4.39)
|
selenium-webdriver (~> 4.40)
|
||||||
sinatra (~> 4.1)
|
sinatra (~> 4.1)
|
||||||
slack-notifier (~> 2.4)
|
slack-notifier (~> 2.4)
|
||||||
sqlite3 (~> 2.9)
|
sqlite3 (~> 2.9)
|
||||||
|
|||||||
4
beef
4
beef
@@ -39,6 +39,10 @@ $root_dir = File.join(File.expand_path(File.dirname(File.realpath(__FILE__))), '
|
|||||||
$:.unshift($root_dir)
|
$:.unshift($root_dir)
|
||||||
$home_dir = File.expand_path("#{Dir.home}/.beef/", __FILE__).freeze
|
$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
|
# @note Require core loader
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
# Browser Exploitation Framework (BeEF) - https://beefproject.com
|
# Browser Exploitation Framework (BeEF) - https://beefproject.com
|
||||||
# See the file 'doc/COPYING' for copying permission
|
# See the file 'doc/COPYING' for copying permission
|
||||||
#
|
#
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
module BeEF
|
module BeEF
|
||||||
module Core
|
module Core
|
||||||
module Console
|
module Console
|
||||||
@@ -38,7 +40,7 @@ module BeEF
|
|||||||
@options[:verbose] = true
|
@options[:verbose] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('-a', '--ascii_art', 'Prints BeEF ascii art') do
|
opts.on('-a', '--ascii-art', 'Prints BeEF ascii art') do
|
||||||
@options[:ascii_art] = true
|
@options[:ascii_art] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -54,14 +56,19 @@ module BeEF
|
|||||||
@options[:ws_port] = ws_port
|
@options[:ws_port] = ws_port
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('-ud', '--update_disabled', 'Skips update') do
|
opts.on('-d', '--update-disabled', 'Skips update') do
|
||||||
@options[:update_disabled] = true
|
@options[:update_disabled] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('-ua', '--update_auto', 'Automatic update with no prompt') do
|
opts.on('-u', '--update-auto', 'Automatic update with no prompt') do
|
||||||
@options[:update_auto] = true
|
@options[:update_auto] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opts.on('-h', '--help', 'Show this help') do
|
||||||
|
puts opts
|
||||||
|
exit 0
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
optparse.parse!
|
optparse.parse!
|
||||||
|
|||||||
@@ -14,6 +14,19 @@ module BeEF
|
|||||||
|
|
||||||
configure do
|
configure do
|
||||||
set :show_exceptions, false
|
set :show_exceptions, false
|
||||||
|
|
||||||
|
# Configure Rack::Protection::HostAuthorization.
|
||||||
|
# Allow Rack development defaults and dynamically permit the public host
|
||||||
|
# defined by beef.http.public.host to prevent "Host not permitted" errors.
|
||||||
|
permitted = [
|
||||||
|
'.localhost',
|
||||||
|
'.test',
|
||||||
|
IPAddr.new('0.0.0.0/0'),
|
||||||
|
IPAddr.new('::/0')
|
||||||
|
]
|
||||||
|
public_host = config.get('beef.http.public.host').to_s.strip
|
||||||
|
permitted << public_host unless public_host.empty?
|
||||||
|
set :host_authorization, { permitted_hosts: permitted }
|
||||||
end
|
end
|
||||||
|
|
||||||
# @note Override default 404 HTTP response
|
# @note Override default 404 HTTP response
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
9
package-lock.json
generated
9
package-lock.json
generated
@@ -666,10 +666,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.23",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lodash.camelcase": {
|
"node_modules/lodash.camelcase": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
|
|||||||
@@ -229,8 +229,7 @@ require 'socket'
|
|||||||
@host = '127.0.0.1'
|
@host = '127.0.0.1'
|
||||||
|
|
||||||
unless port_available?
|
unless port_available?
|
||||||
print_error "Port #{@port} is already in use. Exiting."
|
raise "Port #{@port} is already in use. Cannot start BeEF server."
|
||||||
exit
|
|
||||||
end
|
end
|
||||||
load_beef_extensions_and_modules
|
load_beef_extensions_and_modules
|
||||||
|
|
||||||
@@ -317,11 +316,9 @@ require 'socket'
|
|||||||
end
|
end
|
||||||
|
|
||||||
def stop_beef_server(pid)
|
def stop_beef_server(pid)
|
||||||
exit if pid.nil?
|
return if pid.nil?
|
||||||
# Shutting down server
|
|
||||||
Process.kill("KILL", pid) unless 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
|
Process.wait(pid) unless pid.nil? # Ensure the process has exited and the port is released
|
||||||
pid = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,29 +10,36 @@ require 'spec/support/constants.rb'
|
|||||||
def start_beef_and_hook_browser()
|
def start_beef_and_hook_browser()
|
||||||
reset_beef_db
|
reset_beef_db
|
||||||
pid = start_beef_server_and_wait
|
pid = start_beef_server_and_wait
|
||||||
beef_session = BeefTest.login
|
|
||||||
hooked_browser = BeefTest.new_victim
|
|
||||||
|
|
||||||
expect(hooked_browser).not_to be_nil
|
begin
|
||||||
expect(hooked_browser).to be_a(Capybara::Session)
|
beef_session = BeefTest.login
|
||||||
expect(hooked_browser).to have_content('BeEF', wait: PAGE_LOAD_TIMEOUT)
|
hooked_browser = BeefTest.new_victim
|
||||||
|
|
||||||
expect(beef_session).not_to be_nil
|
expect(hooked_browser).not_to be_nil
|
||||||
expect(beef_session).to be_a(Capybara::Session)
|
expect(hooked_browser).to be_a(Capybara::Session)
|
||||||
expect(beef_session).to have_content('Hooked Browsers', wait: PAGE_LOAD_TIMEOUT)
|
expect(hooked_browser).to have_content('BeEF', wait: PAGE_LOAD_TIMEOUT)
|
||||||
|
|
||||||
navigate_to_hooked_browser(beef_session)
|
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)
|
||||||
|
|
||||||
expect(beef_session).to have_content('Commands', wait: PAGE_LOAD_TIMEOUT)
|
navigate_to_hooked_browser(beef_session)
|
||||||
beef_session.click_on('Commands')
|
|
||||||
|
|
||||||
return pid, beef_session, hooked_browser
|
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
|
end
|
||||||
|
|
||||||
def stop_beef_and_unhook_browser(pid, beef_session, hooked_browser)
|
def stop_beef_and_unhook_browser(pid, beef_session, hooked_browser)
|
||||||
stop_beef_server(pid)
|
stop_beef_server(pid)
|
||||||
beef_session.driver.browser.close
|
beef_session.driver.browser.close if beef_session
|
||||||
hooked_browser.driver.browser.close
|
hooked_browser.driver.browser.close if hooked_browser
|
||||||
end
|
end
|
||||||
|
|
||||||
def navigate_to_hooked_browser(session, hooked_browser_text = nil)
|
def navigate_to_hooked_browser(session, hooked_browser_text = nil)
|
||||||
|
|||||||
Reference in New Issue
Block a user