Skip to content

Commit d93248f

Browse files
aguspejkim2492
authored andcommitted
[rb] Add Bidi network commands for authentication and interception (SeleniumHQ#14523)
1 parent a6a405e commit d93248f

File tree

11 files changed

+323
-2
lines changed

11 files changed

+323
-2
lines changed

java/.idea/workspace.xml

+28-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rb/lib/selenium/webdriver/bidi.rb

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class BiDi
2525
autoload :LogHandler, 'selenium/webdriver/bidi/log_handler'
2626
autoload :BrowsingContext, 'selenium/webdriver/bidi/browsing_context'
2727
autoload :Struct, 'selenium/webdriver/bidi/struct'
28+
autoload :Network, 'selenium/webdriver/bidi/network'
2829

2930
def initialize(url:)
3031
@ws = WebSocketConnection.new(url: url)
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
class BiDi
23+
class Network
24+
EVENTS = {
25+
before_request: 'network.beforeRequestSent',
26+
response_started: 'network.responseStarted',
27+
response_completed: 'network.responseCompleted',
28+
auth_required: 'network.authRequired',
29+
FETCH_ERROR: 'network.fetchError'
30+
}.freeze
31+
32+
PHASES = {
33+
before_request: 'beforeRequestSent',
34+
response_started: 'responseStarted',
35+
auth_required: 'authRequired'
36+
}.freeze
37+
38+
def initialize(bidi)
39+
@bidi = bidi
40+
end
41+
42+
def add_intercept(phases: [], contexts: nil, url_patterns: nil)
43+
@bidi.send_cmd('network.addIntercept', phases: phases, contexts: contexts, urlPatterns: url_patterns)
44+
end
45+
46+
def remove_intercept(intercept)
47+
@bidi.send_cmd('network.removeIntercept', intercept: intercept)
48+
end
49+
50+
def continue_with_auth(request_id, username, password)
51+
@bidi.send_cmd(
52+
'network.continueWithAuth',
53+
'request' => request_id,
54+
'action' => 'provideCredentials',
55+
'credentials' => {
56+
'type' => 'password',
57+
'username' => username,
58+
'password' => password
59+
}
60+
)
61+
end
62+
63+
def on(event, &)
64+
event = EVENTS[event] if event.is_a?(Symbol)
65+
@bidi.add_callback(event, &)
66+
end
67+
end # Network
68+
end # BiDi
69+
end # WebDriver
70+
end # Selenium

rb/lib/selenium/webdriver/common.rb

+1
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,4 @@
102102
require 'selenium/webdriver/common/script'
103103
require 'selenium/webdriver/common/fedcm/account'
104104
require 'selenium/webdriver/common/fedcm/dialog'
105+
require 'selenium/webdriver/common/network'

rb/lib/selenium/webdriver/common/driver.rb

+9
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,15 @@ def add_virtual_authenticator(options)
264264
bridge.add_virtual_authenticator(options)
265265
end
266266

267+
#
268+
# @return [Network]
269+
# @see Network
270+
#
271+
272+
def network
273+
@network ||= WebDriver::Network.new(bridge)
274+
end
275+
267276
#-------------------------------- sugar --------------------------------
268277

269278
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
class Network
23+
attr_reader :auth_callbacks
24+
25+
def initialize(bridge)
26+
@network = BiDi::Network.new(bridge.bidi)
27+
@auth_callbacks = {}
28+
end
29+
30+
def add_authentication_handler(username, password)
31+
intercept = @network.add_intercept(phases: [BiDi::Network::PHASES[:auth_required]])
32+
auth_id = @network.on(:auth_required) do |event|
33+
request_id = event['requestId']
34+
@network.continue_with_auth(request_id, username, password)
35+
end
36+
@auth_callbacks[auth_id] = intercept
37+
38+
auth_id
39+
end
40+
41+
def remove_authentication_handler(id)
42+
intercept = @auth_callbacks[id]
43+
@network.remove_intercept(intercept['intercept'])
44+
@auth_callbacks.delete(id)
45+
end
46+
47+
def clear_authentication_handlers
48+
@auth_callbacks.each_key { |id| remove_authentication_handler(id) }
49+
end
50+
end # Network
51+
end # WebDriver
52+
end # Selenium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module Selenium
2+
module WebDriver
3+
class BiDi
4+
class Network
5+
@bidi: BiDi
6+
7+
EVENTS: Hash[Symbol, String]
8+
9+
PHASES: Hash[Symbol, String]
10+
11+
def initialize: (BiDi bidi) -> void
12+
13+
def add_intercept: (?phases: Array[String], ?contexts: BrowsingContext?, ?url_patterns: untyped?) -> Hash[String, String]
14+
15+
def remove_intercept: (String intercept) -> untyped
16+
17+
def continue_with_auth: (String request_id, String username, String password) -> untyped
18+
19+
def on: (Symbol event) { (?) -> untyped } -> untyped
20+
end
21+
end
22+
end
23+
end

rb/sig/lib/selenium/webdriver/common/driver.rbs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ module Selenium
1717

1818
def inspect: () -> String
1919

20+
def network: -> Network
21+
2022
def status: () -> Hash[untyped, untyped]
2123

2224
def navigate: () -> Navigation
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Selenium
2+
module WebDriver
3+
class Network
4+
@network: BiDi::Network
5+
6+
attr_reader auth_callbacks: Hash[String, String]
7+
8+
def initialize: (Remote::Bridge bridge) -> void
9+
10+
def add_authentication_handler: (String username, String password) -> String
11+
12+
def clear_authentication_handlers: -> Hash[nil, nil]
13+
14+
def remove_authentication_handler: (String id) -> nil
15+
end
16+
end
17+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS,
16+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
# KIND, either express or implied. See the License for the
18+
# specific language governing permissions and limitations
19+
# under the License.
20+
21+
require_relative '../spec_helper'
22+
23+
module Selenium
24+
module WebDriver
25+
class BiDi
26+
describe Network, exclusive: {bidi: true, reason: 'only executed when bidi is enabled'},
27+
only: {browser: %i[chrome edge firefox]} do
28+
it 'adds an intercept' do
29+
reset_driver!(web_socket_url: true) do |driver|
30+
network = described_class.new(driver.bidi)
31+
intercept = network.add_intercept(phases: [described_class::PHASES[:before_request]])
32+
expect(intercept).not_to be_nil
33+
end
34+
end
35+
36+
it 'removes an intercept' do
37+
reset_driver!(web_socket_url: true) do |driver|
38+
network = described_class.new(driver.bidi)
39+
intercept = network.add_intercept(phases: [described_class::PHASES[:before_request]])
40+
expect(network.remove_intercept(intercept['intercept'])).to be_empty
41+
end
42+
end
43+
44+
it 'continues with auth' do
45+
username = SpecSupport::RackServer::TestApp::BASIC_AUTH_CREDENTIALS.first
46+
password = SpecSupport::RackServer::TestApp::BASIC_AUTH_CREDENTIALS.last
47+
reset_driver!(web_socket_url: true) do |driver|
48+
network = described_class.new(driver.bidi)
49+
network.add_intercept(phases: [described_class::PHASES[:auth_required]])
50+
network.on(:auth_required) do |event|
51+
request_id = event['requestId']
52+
network.continue_with_auth(request_id, username, password)
53+
end
54+
55+
driver.navigate.to url_for('basicAuth')
56+
expect(driver.find_element(tag_name: 'h1').text).to eq('authorized')
57+
end
58+
end
59+
end
60+
end
61+
end
62+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS,
16+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
# KIND, either express or implied. See the License for the
18+
# specific language governing permissions and limitations
19+
# under the License.
20+
21+
require_relative 'spec_helper'
22+
23+
module Selenium
24+
module WebDriver
25+
describe Network, exclusive: {bidi: true, reason: 'only executed when bidi is enabled'},
26+
only: {browser: %i[chrome edge firefox]} do
27+
let(:username) { SpecSupport::RackServer::TestApp::BASIC_AUTH_CREDENTIALS.first }
28+
let(:password) { SpecSupport::RackServer::TestApp::BASIC_AUTH_CREDENTIALS.last }
29+
30+
it 'adds an auth handler' do
31+
reset_driver!(web_socket_url: true) do |driver|
32+
network = described_class.new(driver)
33+
network.add_authentication_handler(username, password)
34+
expect(network.auth_callbacks.count).to be 1
35+
end
36+
end
37+
38+
it 'removes an auth handler' do
39+
reset_driver!(web_socket_url: true) do |driver|
40+
network = described_class.new(driver)
41+
id = network.add_authentication_handler(username, password)
42+
network.remove_authentication_handler(id)
43+
expect(network.auth_callbacks.count).to be 0
44+
end
45+
end
46+
47+
it 'clears all auth handlers' do
48+
reset_driver!(web_socket_url: true) do |driver|
49+
network = described_class.new(driver)
50+
network.add_authentication_handler(username, password)
51+
network.add_authentication_handler(username, password)
52+
network.clear_authentication_handlers
53+
expect(network.auth_callbacks.count).to be 0
54+
end
55+
end
56+
end
57+
end
58+
end

0 commit comments

Comments
 (0)