selenium-webdriver 4.1.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +85 -1
  3. data/LICENSE +1 -1
  4. data/NOTICE +1 -1
  5. data/lib/selenium/server.rb +15 -10
  6. data/lib/selenium/webdriver/bidi/session.rb +38 -0
  7. data/lib/selenium/webdriver/bidi.rb +55 -0
  8. data/lib/selenium/webdriver/chrome/features.rb +5 -0
  9. data/lib/selenium/webdriver/chrome/options.rb +33 -19
  10. data/lib/selenium/webdriver/chrome.rb +0 -14
  11. data/lib/selenium/webdriver/common/action_builder.rb +108 -21
  12. data/lib/selenium/webdriver/common/driver.rb +22 -55
  13. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_bidi.rb} +12 -5
  14. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +10 -0
  15. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +1 -2
  16. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +1 -1
  17. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -67
  18. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +1 -1
  19. data/lib/selenium/webdriver/common/element.rb +1 -1
  20. data/lib/selenium/webdriver/common/error.rb +1 -1
  21. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  22. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -25
  23. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  24. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -1
  25. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  26. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  27. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  28. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +59 -70
  29. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  30. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  31. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  32. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  33. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  34. data/lib/selenium/webdriver/common/interactions/scroll.rb +57 -0
  35. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  36. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  37. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  38. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +42 -0
  39. data/lib/selenium/webdriver/common/keys.rb +1 -0
  40. data/lib/selenium/webdriver/common/manager.rb +0 -27
  41. data/lib/selenium/webdriver/common/options.rb +2 -9
  42. data/lib/selenium/webdriver/common/platform.rb +4 -4
  43. data/lib/selenium/webdriver/common/search_context.rb +0 -6
  44. data/lib/selenium/webdriver/common/service_manager.rb +2 -3
  45. data/lib/selenium/webdriver/common/shadow_root.rb +1 -1
  46. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  47. data/lib/selenium/webdriver/common/takes_screenshot.rb +1 -1
  48. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +83 -0
  49. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +73 -0
  50. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  51. data/lib/selenium/webdriver/common/websocket_connection.rb +156 -0
  52. data/lib/selenium/webdriver/common/window.rb +6 -6
  53. data/lib/selenium/webdriver/common/zipper.rb +1 -1
  54. data/lib/selenium/webdriver/common.rb +17 -3
  55. data/lib/selenium/webdriver/devtools/network_interceptor.rb +176 -0
  56. data/lib/selenium/webdriver/devtools/request.rb +1 -1
  57. data/lib/selenium/webdriver/devtools/response.rb +1 -1
  58. data/lib/selenium/webdriver/devtools.rb +6 -112
  59. data/lib/selenium/webdriver/edge/features.rb +1 -0
  60. data/lib/selenium/webdriver/firefox/driver.rb +1 -0
  61. data/lib/selenium/webdriver/firefox/features.rb +2 -5
  62. data/lib/selenium/webdriver/firefox/options.rb +3 -1
  63. data/lib/selenium/webdriver/firefox/profile.rb +1 -5
  64. data/lib/selenium/webdriver/firefox/util.rb +46 -0
  65. data/lib/selenium/webdriver/firefox.rb +1 -14
  66. data/lib/selenium/webdriver/ie.rb +0 -14
  67. data/lib/selenium/webdriver/remote/bridge.rb +54 -19
  68. data/lib/selenium/webdriver/remote/commands.rb +15 -6
  69. data/lib/selenium/webdriver/remote/driver.rb +0 -1
  70. data/lib/selenium/webdriver/remote/http/default.rb +6 -12
  71. data/lib/selenium/webdriver/remote/response.rb +2 -2
  72. data/lib/selenium/webdriver/safari.rb +0 -14
  73. data/lib/selenium/webdriver/support/cdp_client_generator.rb +4 -4
  74. data/lib/selenium/webdriver/support/color.rb +7 -7
  75. data/lib/selenium/webdriver/support/guards/guard_condition.rb +1 -1
  76. data/lib/selenium/webdriver/support/guards.rb +1 -1
  77. data/lib/selenium/webdriver/version.rb +1 -1
  78. data/lib/selenium/webdriver.rb +1 -0
  79. data/selenium-webdriver.gemspec +9 -6
  80. metadata +64 -12
  81. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
@@ -0,0 +1,48 @@
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
+ module WheelActions
23
+ class ScrollOrigin
24
+ class << self
25
+ def element(element, x_offset = 0, y_offset = 0)
26
+ new(element, x_offset, y_offset)
27
+ end
28
+
29
+ def viewport(x_offset = 0, y_offset = 0)
30
+ new(:viewport, x_offset, y_offset)
31
+ end
32
+ end
33
+
34
+ attr_reader :origin, :x_offset, :y_offset
35
+
36
+ #
37
+ # Use a static method to access
38
+ # @api private
39
+ #
40
+ def initialize(origin, x_offset, y_offset)
41
+ @origin = origin
42
+ @x_offset = x_offset
43
+ @y_offset = y_offset
44
+ end
45
+ end # ScrollOrigin
46
+ end # WheelActions
47
+ end # WebDriver
48
+ end # Selenium
@@ -0,0 +1,54 @@
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
+ module Interactions
23
+ #
24
+ # Actions related to pressing keys.
25
+ #
26
+ # @api private
27
+ #
28
+
29
+ class TypingInteraction < Interaction
30
+ attr_reader :type
31
+
32
+ def initialize(source, type, key)
33
+ super(source)
34
+ @type = assert_type(type)
35
+ @key = Keys.encode_key(key)
36
+ end
37
+
38
+ def assert_source(source)
39
+ raise TypeError, "#{source.type} is not a valid input type" unless source.is_a? KeyInput
40
+ end
41
+
42
+ def assert_type(type)
43
+ raise TypeError, "#{type.inspect} is not a valid key subtype" unless KeyInput::SUBTYPES.key? type
44
+
45
+ KeyInput::SUBTYPES[type]
46
+ end
47
+
48
+ def encode
49
+ {type: @type, value: @key}
50
+ end
51
+ end # TypingInteraction
52
+ end # Interactions
53
+ end # WebDriver
54
+ end # Selenium
@@ -0,0 +1,113 @@
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
+ module WheelActions
23
+ attr_writer :default_scroll_duration
24
+
25
+ #
26
+ # By default this is set to 250ms in the ActionBuilder constructor
27
+ # It can be overridden with default_scroll_duration=
28
+ #
29
+
30
+ def default_scroll_duration
31
+ @default_scroll_duration ||= @duration / 1000.0 # convert ms to seconds
32
+ end
33
+
34
+ #
35
+ # If the element is outside the viewport, scrolls the bottom of the element to the bottom of the viewport.
36
+ #
37
+ # @example Scroll to element
38
+ # el = driver.find_element(id: "some_id")
39
+ # driver.action.scroll_to(element).perform
40
+ #
41
+ # @param [Object] Which element to scroll into the viewport.
42
+ # @return [Selenium::WebDriver::WheelActions] A self reference.
43
+ def scroll_to(element, device: nil)
44
+ scroll(origin: element, device: device)
45
+ end
46
+
47
+ #
48
+ # Scrolls by provided amounts with the origin in the top left corner of the viewport.
49
+ #
50
+ # @example Scroll viewport by a specified amount
51
+ # el = driver.find_element(id: "some_id")
52
+ # driver.action.scroll_by(100, 200).perform
53
+ #
54
+ # @param [Integer] delta_x Distance along X axis to scroll using the wheel. A negative value scrolls left.
55
+ # @param [Integer] delta_y Distance along Y axis to scroll using the wheel. A negative value scrolls up.
56
+ # @return [Selenium::WebDriver::WheelActions] A self reference.
57
+ def scroll_by(delta_x, delta_y, device: nil)
58
+ scroll(delta_x: delta_x, delta_y: delta_y, device: device)
59
+ end
60
+
61
+ #
62
+ # Scrolls by provided amount based on a provided origin.
63
+ #
64
+ # The scroll origin is either the center of an element or the upper left of the viewport plus any offsets.
65
+ # If the origin is an element, and the element is not in the viewport, the bottom of the element will first
66
+ # be scrolled to the bottom of the viewport.
67
+ #
68
+ # @example Scroll from element by a specified amount
69
+ # el = driver.find_element(id: "some_id")
70
+ # origin = WheelActions::ScrollOrigin.element(el)
71
+ # driver.action.scroll_from(origin, 0, 200).perform
72
+ #
73
+ # @example Scroll from element by a specified amount with an offset
74
+ # el = driver.find_element(id: "some_id")
75
+ # origin = WheelActions::ScrollOrigin.element(el, 10, 10)
76
+ # driver.action.scroll_from(origin, 100, 200).perform
77
+ #
78
+ # @example Scroll viewport by a specified amount with an offset
79
+ # origin = WheelActions::ScrollOrigin.viewport(10, 10)
80
+ # driver.action.scroll_from(origin, 0, 200).perform
81
+ #
82
+ # @param [ScrollOrigin] scroll_origin Where scroll originates (viewport or element center) plus provided offsets.
83
+ # @param [Integer] delta_x Distance along X axis to scroll using the wheel. A negative value scrolls left.
84
+ # @param [Integer] delta_y Distance along Y axis to scroll using the wheel. A negative value scrolls up.
85
+ # @return [Selenium::WebDriver::WheelActions] A self reference.
86
+ # @raise [Error::MoveTargetOutOfBoundsError] If the origin with offset is outside the viewport.
87
+ def scroll_from(scroll_origin, delta_x, delta_y, device: nil)
88
+ raise TypeError, "#{scroll_origin.inspect} isn't a valid ScrollOrigin" unless scroll_origin.is_a?(ScrollOrigin)
89
+
90
+ scroll(x: scroll_origin.x_offset,
91
+ y: scroll_origin.y_offset,
92
+ delta_x: delta_x,
93
+ delta_y: delta_y,
94
+ origin: scroll_origin.origin,
95
+ device: device)
96
+ end
97
+
98
+ private
99
+
100
+ def scroll(**opts)
101
+ opts[:duration] = default_scroll_duration
102
+ wheel = wheel_input(opts.delete(:device))
103
+ wheel.create_scroll(**opts)
104
+ tick(wheel)
105
+ self
106
+ end
107
+
108
+ def wheel_input(name = nil)
109
+ device(name: name, type: Interactions::WHEEL) || add_wheel_input('wheel')
110
+ end
111
+ end # WheelActions
112
+ end # WebDriver
113
+ end # Selenium
@@ -0,0 +1,42 @@
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
+ module Interactions
23
+ #
24
+ # Creates actions specific to Pointer Input devices
25
+ #
26
+ # @api private
27
+ #
28
+
29
+ class WheelInput < InputDevice
30
+ def initialize(name = nil)
31
+ super(name)
32
+ @type = Interactions::WHEEL
33
+ end
34
+
35
+ def create_scroll(**opts)
36
+ opts[:source] = self
37
+ add_action(Scroll.new(**opts))
38
+ end
39
+ end # PointerInput
40
+ end # Interactions
41
+ end # WebDriver
42
+ end # Selenium
@@ -90,6 +90,7 @@ module Selenium
90
90
  meta: "\ue03D",
91
91
  command: "\ue03D", # alias
92
92
  left_meta: "\ue03D", # alias
93
+ zenkaku_hankaku: "\uE040",
93
94
  right_shift: "\ue050",
94
95
  right_control: "\ue051",
95
96
  right_alt: "\ue052",
@@ -104,33 +104,6 @@ module Selenium
104
104
  @timeouts ||= Timeouts.new(@bridge)
105
105
  end
106
106
 
107
- def logs
108
- WebDriver.logger.deprecate('Manager#logs', 'Chrome::Driver#logs')
109
- @logs ||= Logs.new(@bridge)
110
- end
111
-
112
- #
113
- # @param type [Symbol] Supports two values: :tab and :window.
114
- # @return [String] The value of the window handle
115
- #
116
- def new_window(type = :tab)
117
- WebDriver.logger.deprecate('Manager#new_window', 'TargetLocator#new_window', id: :new_window) do
118
- 'e.g., `driver.switch_to.new_window(:tab)`'
119
- end
120
- case type
121
- when :tab, :window
122
- result = @bridge.new_window(type)
123
- unless result.key?('handle')
124
- raise UnknownError, "the driver did not return a handle. " \
125
- "The returned result: #{result.inspect}"
126
- end
127
- result['handle']
128
- else
129
- raise ArgumentError, "invalid argument for type. Got: '#{type.inspect}'. " \
130
- "Try :tab or :window"
131
- end
132
- end
133
-
134
107
  def window
135
108
  @window ||= Window.new(@bridge)
136
109
  end
@@ -66,17 +66,10 @@ module Selenium
66
66
 
67
67
  attr_accessor :options
68
68
 
69
- def initialize(options: nil, **opts)
69
+ def initialize(**opts)
70
70
  self.class.set_capabilities
71
71
 
72
- @options = if options
73
- WebDriver.logger.deprecate(":options as keyword for initializing #{self.class}",
74
- "custom values directly in #new constructor",
75
- id: :options_options)
76
- opts.merge(options)
77
- else
78
- opts
79
- end
72
+ @options = opts
80
73
  @options[:browser_name] = self.class::BROWSER
81
74
  end
82
75
 
@@ -104,7 +104,7 @@ module Selenium
104
104
  end
105
105
 
106
106
  def cygwin?
107
- RUBY_PLATFORM =~ /cygwin/
107
+ RUBY_PLATFORM.include?('cygwin')
108
108
  !Regexp.last_match.nil?
109
109
  end
110
110
 
@@ -177,9 +177,9 @@ module Selenium
177
177
 
178
178
  def find_in_program_files(*binary_names)
179
179
  paths = [
180
- ENV['PROGRAMFILES'] || '\\Program Files',
181
- ENV['ProgramFiles(x86)'] || '\\Program Files (x86)',
182
- ENV['ProgramW6432'] || '\\Program Files'
180
+ ENV.fetch('PROGRAMFILES', '\\Program Files'),
181
+ ENV.fetch('ProgramFiles(x86)', '\\Program Files (x86)'),
182
+ ENV.fetch('ProgramW6432', '\\Program Files')
183
183
  ]
184
184
 
185
185
  paths.each do |root|
@@ -61,9 +61,6 @@ module Selenium
61
61
  raise ArgumentError, "cannot find element by #{how.inspect}" unless by
62
62
 
63
63
  bridge.find_element_by by, what, ref
64
- rescue Selenium::WebDriver::Error::TimeoutError
65
- # Implicit Wait times out in Edge
66
- raise Selenium::WebDriver::Error::NoSuchElementError
67
64
  end
68
65
 
69
66
  #
@@ -79,9 +76,6 @@ module Selenium
79
76
  raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
80
77
 
81
78
  bridge.find_elements_by by, what, ref
82
- rescue Selenium::WebDriver::Error::TimeoutError
83
- # Implicit Wait times out in Edge
84
- []
85
79
  end
86
80
 
87
81
  private
@@ -49,7 +49,7 @@ module Selenium
49
49
  def start
50
50
  raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
51
51
 
52
- Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running
52
+ Platform.exit_hook { stop } # make sure we don't leave the server running
53
53
 
54
54
  socket_lock.locked do
55
55
  find_free_port
@@ -60,6 +60,7 @@ module Selenium
60
60
 
61
61
  def stop
62
62
  return unless @shutdown_supported
63
+ return if process_exited?
63
64
 
64
65
  stop_server
65
66
  @process.poll_for_exit STOP_TIMEOUT
@@ -116,8 +117,6 @@ module Selenium
116
117
  end
117
118
 
118
119
  def stop_server
119
- return if process_exited?
120
-
121
120
  connect_to_server do |http|
122
121
  headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup
123
122
  http.get('/shutdown', headers)
@@ -45,7 +45,7 @@ module Selenium
45
45
  alias_method :eql?, :==
46
46
 
47
47
  def hash
48
- @id.hash ^ @bridge.hash
48
+ [@id, @bridge].hash
49
49
  end
50
50
 
51
51
  #
@@ -99,7 +99,7 @@ module Selenium
99
99
  end
100
100
 
101
101
  def socket_writable?(sock)
102
- IO.select(nil, [sock], nil, CONNECT_TIMEOUT)
102
+ sock.wait_writable(CONNECT_TIMEOUT)
103
103
  end
104
104
 
105
105
  def conn_completed?(sock)
@@ -32,7 +32,7 @@ module Selenium
32
32
  def save_screenshot(png_path, full_page: false)
33
33
  extension = File.extname(png_path).downcase
34
34
  if extension != '.png'
35
- WebDriver.logger.warn "name used for saved screenshot does not match file type. "\
35
+ WebDriver.logger.warn "name used for saved screenshot does not match file type. " \
36
36
  "It should end with .png extension",
37
37
  id: :screenshot
38
38
  end
@@ -0,0 +1,83 @@
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
+ #
21
+ # A credential stored in a virtual authenticator.
22
+ # @see https://w3c.github.io/webauthn/#credential-parameters
23
+ #
24
+
25
+ module Selenium
26
+ module WebDriver
27
+ class Credential
28
+ class << self
29
+ def resident(**opts)
30
+ Credential.new(resident_credential: true, **opts)
31
+ end
32
+
33
+ def non_resident(**opts)
34
+ Credential.new(resident_credential: false, **opts)
35
+ end
36
+
37
+ def encode(byte_array)
38
+ Base64.urlsafe_encode64(byte_array&.pack('C*'))
39
+ end
40
+
41
+ def decode(base64)
42
+ Base64.urlsafe_decode64(base64).unpack('C*')
43
+ end
44
+
45
+ def from_json(opts)
46
+ user_handle = opts['userHandle'] ? decode(opts['userHandle']) : nil
47
+ new(id: decode(opts["credentialId"]),
48
+ resident_credential: opts["isResidentCredential"],
49
+ rp_id: opts['rpId'],
50
+ private_key: opts['privateKey'],
51
+ sign_count: opts['signCount'],
52
+ user_handle: user_handle)
53
+ end
54
+ end
55
+
56
+ attr_reader :id, :resident_credential, :rp_id, :user_handle, :private_key, :sign_count
57
+ alias_method :resident_credential?, :resident_credential
58
+
59
+ def initialize(id:, resident_credential:, rp_id:, private_key:, user_handle: nil, sign_count: 0)
60
+ @id = id
61
+ @resident_credential = resident_credential
62
+ @rp_id = rp_id
63
+ @user_handle = user_handle
64
+ @private_key = private_key
65
+ @sign_count = sign_count
66
+ end
67
+
68
+ #
69
+ # @api private
70
+ #
71
+
72
+ def as_json(*)
73
+ credential_data = {'credentialId' => Credential.encode(id),
74
+ 'isResidentCredential' => resident_credential?,
75
+ 'rpId' => rp_id,
76
+ 'privateKey' => Credential.encode(private_key),
77
+ 'signCount' => sign_count}
78
+ credential_data['userHandle'] = Credential.encode(user_handle) if user_handle
79
+ credential_data
80
+ end
81
+ end # Credential
82
+ end # WebDriver
83
+ end # Selenium
@@ -0,0 +1,73 @@
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 VirtualAuthenticator
23
+
24
+ attr_reader :options
25
+
26
+ #
27
+ # api private
28
+ # Use `Driver#add_virtual_authenticator`
29
+ #
30
+
31
+ def initialize(bridge, authenticator_id, options)
32
+ @id = authenticator_id
33
+ @bridge = bridge
34
+ @options = options
35
+ @valid = true
36
+ end
37
+
38
+ def add_credential(credential)
39
+ credential = credential.as_json
40
+ @bridge.add_credential credential, @id
41
+ end
42
+
43
+ def credentials
44
+ credential_data = @bridge.credentials @id
45
+ credential_data.map do |cred|
46
+ Credential.from_json(cred)
47
+ end
48
+ end
49
+
50
+ def remove_credential(credential_id)
51
+ credential_id = Credential.encode(credential_id) if credential_id.instance_of?(Array)
52
+ @bridge.remove_credential credential_id, @id
53
+ end
54
+
55
+ def remove_all_credentials
56
+ @bridge.remove_all_credentials @id
57
+ end
58
+
59
+ def user_verified=(verified)
60
+ @bridge.user_verified verified, @id
61
+ end
62
+
63
+ def remove!
64
+ @bridge.remove_virtual_authenticator(@id)
65
+ @valid = false
66
+ end
67
+
68
+ def valid?
69
+ @valid
70
+ end
71
+ end # VirtualAuthenticator
72
+ end # WebDriver
73
+ end # Selenium
@@ -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, 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
+ #
21
+ # Options for the creation of virtual authenticators.
22
+ # @see http://w3c.github.io/webauthn/#sctn-automation
23
+ #
24
+
25
+ module Selenium
26
+ module WebDriver
27
+ class VirtualAuthenticatorOptions
28
+
29
+ PROTOCOL = {ctap2: "ctap2", u2f: "ctap1/u2f"}.freeze
30
+ TRANSPORT = {ble: "ble", usb: "usb", nfc: "nfc", internal: "internal"}.freeze
31
+
32
+ attr_accessor :protocol, :transport, :resident_key, :user_verification, :user_consenting, :user_verified
33
+ alias_method :resident_key?, :resident_key
34
+ alias_method :user_verification?, :user_verification
35
+ alias_method :user_consenting?, :user_consenting
36
+ alias_method :user_verified?, :user_verified
37
+
38
+ def initialize(protocol: :ctap2, transport: :usb, resident_key: false,
39
+ user_verification: false, user_consenting: true, user_verified: false)
40
+ @protocol = protocol
41
+ @transport = transport
42
+ @resident_key = resident_key
43
+ @user_verification = user_verification
44
+ @user_consenting = user_consenting
45
+ @user_verified = user_verified
46
+ end
47
+
48
+ #
49
+ # @api private
50
+ #
51
+
52
+ def as_json(*)
53
+ {'protocol' => PROTOCOL[protocol],
54
+ 'transport' => TRANSPORT[transport],
55
+ 'hasResidentKey' => resident_key?,
56
+ 'hasUserVerification' => user_verification?,
57
+ 'isUserConsenting' => user_consenting?,
58
+ 'isUserVerified' => user_verified?}
59
+ end
60
+ end # VirtualAuthenticatorOptions
61
+ end # WebDriver
62
+ end # Selenium