booth 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/app/assets/images/booth/fido/passkey_mark_b_reverse.svg +55 -0
- data/config/locales/de.yml +5 -5
- data/lib/booth/core/sessions/to_passport.rb +11 -1
- data/lib/booth/core/webauth/authentication_verification.rb +5 -5
- data/lib/booth/models/authenticator.rb +11 -0
- data/lib/booth/passport.rb +15 -0
- data/lib/booth/request.rb +15 -0
- data/lib/booth/requests/authentication.rb +1 -1
- data/lib/booth/requests/storages/login.rb +4 -1
- data/lib/booth/requests/sudo.rb +12 -2
- data/lib/booth/test.rb +10 -17
- data/lib/booth/testing/incorporation_test_case.rb +3 -1
- data/lib/booth/testing/shortcuts.rb +8 -17
- data/lib/booth/testing/support/assert_logged_in.rb +26 -27
- data/lib/booth/testing/support/assert_logged_out.rb +15 -11
- data/lib/booth/testing/support/assert_partial.rb +20 -29
- data/lib/booth/testing/support/capybara_step_logger.rb +22 -0
- data/lib/booth/testing/support/{soft_reset_session.rb → clear_cookies.rb} +5 -6
- data/lib/booth/testing/support/cookie_data_from_browser.rb +38 -0
- data/lib/booth/testing/support/shortcuts/create_and_onboard.rb +4 -0
- data/lib/booth/testing/support/shortcuts/login_with_passkey.rb +6 -4
- data/lib/booth/testing/support/shortcuts/register_new_passkey.rb +6 -2
- data/lib/booth/testing/support/virtual_authenticator.rb +196 -0
- data/lib/booth/testing/support/virtual_authenticators/create.rb +22 -7
- data/lib/booth/testing/support/virtual_authenticators/destroy.rb +14 -9
- data/lib/booth/testing/support/virtual_authenticators/enable.rb +14 -2
- data/lib/booth/testing/support/virtual_authenticators/load.rb +7 -19
- data/lib/booth/testing/support/virtual_authenticators.rb +106 -0
- data/lib/booth/testing/support/visit.rb +1 -0
- data/lib/booth/testing/userland/login_remotely.rb +2 -2
- data/lib/booth/testing/userland/onboarding_first_time.rb +5 -4
- data/lib/booth/testing/userland/onboarding_to_reset_passkeys.rb +3 -3
- data/lib/booth/testing/userland/registration_with_passkey.rb +9 -6
- data/lib/booth/testing/userland/registration_without_passkey.rb +11 -7
- data/lib/booth/testing/userland/sessions_manage_behavior.rb +14 -3
- data/lib/booth/testing/userland/sudo_webauth.rb +34 -0
- data/lib/booth/testing/userland.rb +2 -0
- data/lib/booth/userland/webauths/index.rb +9 -3
- data/lib/booth/userland/webauths/new.rb +10 -2
- data/lib/booth/userland/webauths/transitions/create/choose_nickname.rb +1 -1
- data/lib/booth/userland/webauths/transitions/sudo/authentication_initiation.rb +5 -0
- data/lib/booth/userland/webauths/transitions/sudo/authentication_verification.rb +1 -1
- data/lib/booth/version.rb +1 -1
- metadata +10 -5
- data/lib/booth/testing/support/get_session_value.rb +0 -37
- data/lib/booth/testing/support/virtual_authenticators/manager.rb +0 -124
|
@@ -9,10 +9,14 @@ module Booth
|
|
|
9
9
|
|
|
10
10
|
# Register normally
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
begin
|
|
13
|
+
# Non-headless Chrome may cause Exception if HTTP status is 4xx
|
|
14
|
+
visit_namespaced controller: :registrations, action: :new
|
|
15
|
+
rescue Playwright::Error => e
|
|
16
|
+
raise unless e.message.include?('ERR_HTTP_RESPONSE_CODE_FAILURE')
|
|
17
|
+
end
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
return 'Skipping self-registration tests' if page.has_text?('HTTP ERROR 410')
|
|
19
|
+
return log { 'Skipping self-registration tests' } if page.status_code == 410
|
|
16
20
|
|
|
17
21
|
assert_userland_view controller: :registrations, step: :choose_username
|
|
18
22
|
|
|
@@ -53,17 +57,17 @@ module Booth
|
|
|
53
57
|
assert_userland_view controller: :remote_logins, step: :remote_solved
|
|
54
58
|
|
|
55
59
|
using_session(:other_device) do
|
|
56
|
-
|
|
60
|
+
visit current_path
|
|
57
61
|
|
|
58
62
|
# -------------------------- SIGNIFICANT TEST ---------------------------
|
|
59
63
|
# You can remote-login even though you don't have any Authenticators yet.
|
|
60
64
|
# -----------------------------------------------------------------------
|
|
61
|
-
|
|
65
|
+
assert_logged_in username: 'alice'
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
# Try to Login without having any Authenticators
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
clear_cookies
|
|
67
71
|
|
|
68
72
|
visit_namespaced controller: :logins, action: :new
|
|
69
73
|
|
|
@@ -93,7 +97,7 @@ module Booth
|
|
|
93
97
|
# ---------------- SIGNIFICANT TEST -------------------
|
|
94
98
|
# You cannot register a username that is already taken.
|
|
95
99
|
# -----------------------------------------------------
|
|
96
|
-
assert_text '
|
|
100
|
+
assert_text I18n.t('booth.username_already_exists')
|
|
97
101
|
end
|
|
98
102
|
end
|
|
99
103
|
end
|
|
@@ -10,13 +10,19 @@ module Booth
|
|
|
10
10
|
before_test&.call
|
|
11
11
|
|
|
12
12
|
create_and_onboard(username: 'alice')
|
|
13
|
-
virtual_authenticators.create
|
|
13
|
+
latchkey = virtual_authenticators.create
|
|
14
14
|
register_new_passkey(username: 'alice')
|
|
15
15
|
|
|
16
|
+
# Capture credentials after registration
|
|
17
|
+
latchkey.pull
|
|
18
|
+
|
|
16
19
|
using_session(:"second_browser_#{button_name}") do
|
|
17
|
-
virtual_authenticators.
|
|
20
|
+
virtual_authenticators.import(latchkey)
|
|
18
21
|
login_with_passkey(username: 'alice')
|
|
19
22
|
|
|
23
|
+
# Capture updated sign count from second browser
|
|
24
|
+
latchkey.pull
|
|
25
|
+
|
|
20
26
|
visit_namespaced controller: :sessions, action: :index
|
|
21
27
|
|
|
22
28
|
assert_userland_view controller: :sessions, step: :index
|
|
@@ -30,13 +36,18 @@ module Booth
|
|
|
30
36
|
|
|
31
37
|
visit current_path
|
|
32
38
|
|
|
39
|
+
# Refresh to force session validation with server
|
|
40
|
+
page.refresh
|
|
41
|
+
|
|
33
42
|
# ----------- SIGNIFICANT TEST ---------------
|
|
34
43
|
# A revoked session is not logged in any more.
|
|
35
44
|
# --------------------------------------------
|
|
36
45
|
assert_logged_out
|
|
37
46
|
|
|
47
|
+
# Sync sign count from second browser to first browser
|
|
48
|
+
latchkey.push
|
|
49
|
+
|
|
38
50
|
# Login on first device again and revoke all others
|
|
39
|
-
virtual_authenticators.refresh_from_other_session
|
|
40
51
|
login_with_passkey(username: 'alice')
|
|
41
52
|
|
|
42
53
|
visit_namespaced controller: :sessions, action: :index
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booth
|
|
4
|
+
module Testing
|
|
5
|
+
module Userland
|
|
6
|
+
class SudoWebauth < ::Booth::Testing::IncorporationTestCase
|
|
7
|
+
def call
|
|
8
|
+
before_test&.call
|
|
9
|
+
|
|
10
|
+
create_and_onboard(username: 'alice')
|
|
11
|
+
virtual_authenticators.create
|
|
12
|
+
register_new_passkey(username: 'alice')
|
|
13
|
+
|
|
14
|
+
# Visit webauths index with fresh sudo
|
|
15
|
+
visit_namespaced controller: :webauths, action: :index
|
|
16
|
+
assert_userland_view controller: :webauths, step: :index
|
|
17
|
+
|
|
18
|
+
# Time travel to expire sudo (default interaction_timeout is 20 minutes)
|
|
19
|
+
travel 21.minutes
|
|
20
|
+
|
|
21
|
+
# Visit webauths index again - should require sudo
|
|
22
|
+
visit_namespaced controller: :webauths, action: :index
|
|
23
|
+
assert_userland_view controller: :webauths, step: :sudo
|
|
24
|
+
|
|
25
|
+
# Re-authenticate with hardware key to restore sudo
|
|
26
|
+
click_on :authenticate
|
|
27
|
+
|
|
28
|
+
# After successful sudo, user sees the index again
|
|
29
|
+
assert_userland_view controller: :webauths, step: :index
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -12,6 +12,7 @@ require_relative 'userland/registration_without_passkey'
|
|
|
12
12
|
require_relative 'userland/sessions_manage_behavior'
|
|
13
13
|
require_relative 'userland/sessions_revoke_all_others'
|
|
14
14
|
require_relative 'userland/sessions_revoke_one'
|
|
15
|
+
require_relative 'userland/sudo_webauth'
|
|
15
16
|
|
|
16
17
|
module Booth
|
|
17
18
|
module Testing
|
|
@@ -24,6 +25,7 @@ module Booth
|
|
|
24
25
|
::Booth::Testing::Userland::LoginRemotely,
|
|
25
26
|
::Booth::Testing::Userland::SessionsRevokeOne,
|
|
26
27
|
::Booth::Testing::Userland::SessionsRevokeAllOthers,
|
|
28
|
+
::Booth::Testing::Userland::SudoWebauth,
|
|
27
29
|
].freeze
|
|
28
30
|
|
|
29
31
|
def self.scenarios
|
|
@@ -12,7 +12,7 @@ module Booth
|
|
|
12
12
|
request.must_be_html!
|
|
13
13
|
request.must_be_logged_in!
|
|
14
14
|
|
|
15
|
-
::Booth::Userland::Webauths::Guards::Sudo.call(request:, credential:) { return
|
|
15
|
+
::Booth::Userland::Webauths::Guards::Sudo.call(request:, credential:) { return it }
|
|
16
16
|
|
|
17
17
|
do_index
|
|
18
18
|
end
|
|
@@ -23,7 +23,8 @@ module Booth
|
|
|
23
23
|
request.storage.webauth.reset if params[:reset]
|
|
24
24
|
|
|
25
25
|
Tron.success :current_webauth, step: :index,
|
|
26
|
-
authenticators: authenticator_structs
|
|
26
|
+
authenticators: authenticator_structs,
|
|
27
|
+
authenticators?: authenticators?
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def authenticator_structs
|
|
@@ -31,11 +32,16 @@ module Booth
|
|
|
31
32
|
::Booth::ToStruct.call(
|
|
32
33
|
authenticator.attributes
|
|
33
34
|
.symbolize_keys
|
|
34
|
-
.slice(:id, :confirmed_at, :nickname)
|
|
35
|
+
.slice(:id, :confirmed_at, :nickname, :aaguid)
|
|
36
|
+
.merge(authenticator.provider_attributes),
|
|
35
37
|
)
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
|
|
41
|
+
def authenticators?
|
|
42
|
+
credential.registered_authenticators?
|
|
43
|
+
end
|
|
44
|
+
|
|
39
45
|
def credential
|
|
40
46
|
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
41
47
|
end
|
|
@@ -15,7 +15,8 @@ module Booth
|
|
|
15
15
|
if authenticator&.confirmed?
|
|
16
16
|
return Tron.success :completed, step: :completed,
|
|
17
17
|
nickname: authenticator&.nickname,
|
|
18
|
-
|
|
18
|
+
authenticators?: authenticators?,
|
|
19
|
+
should_add_more_authenticators?: should_add_more_authenticators?
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
::Booth::Userland::Webauths::Guards::Sudo.call(request:, credential:) { return it }
|
|
@@ -29,7 +30,10 @@ module Booth
|
|
|
29
30
|
log { "WebAuthn Authenticator registration in step #{step}" }
|
|
30
31
|
# log { authenticator.inspect }
|
|
31
32
|
|
|
32
|
-
Tron.success :add_webauth, step:,
|
|
33
|
+
Tron.success :add_webauth, step:,
|
|
34
|
+
nickname: authenticator&.nickname,
|
|
35
|
+
authenticators?: authenticators?,
|
|
36
|
+
should_add_more_authenticators?: should_add_more_authenticators?
|
|
33
37
|
end
|
|
34
38
|
|
|
35
39
|
def step
|
|
@@ -38,6 +42,10 @@ module Booth
|
|
|
38
42
|
authenticator.step
|
|
39
43
|
end
|
|
40
44
|
|
|
45
|
+
def authenticators?
|
|
46
|
+
credential.registered_authenticators?
|
|
47
|
+
end
|
|
48
|
+
|
|
41
49
|
def should_add_more_authenticators?
|
|
42
50
|
credential.authenticators.registered_scope.count < 2
|
|
43
51
|
end
|
|
@@ -29,7 +29,7 @@ module Booth
|
|
|
29
29
|
|
|
30
30
|
def do_update_authenticator
|
|
31
31
|
if authenticator.update nickname: nickname_param
|
|
32
|
-
log {
|
|
32
|
+
log { "The nickname successfully changed to #{authenticator.nickname}" }
|
|
33
33
|
Tron.success :nickname_saved
|
|
34
34
|
else
|
|
35
35
|
public_message = authenticator.errors.to_a.to_sentence
|
|
@@ -28,9 +28,14 @@ module Booth
|
|
|
28
28
|
|
|
29
29
|
request.sudo.webauthn_challenge = webauth.challenge
|
|
30
30
|
Tron.success :test_challenge_created, public_json: webauth.as_json,
|
|
31
|
+
authenticators?: authenticators?,
|
|
31
32
|
http_status: :created
|
|
32
33
|
end
|
|
33
34
|
|
|
35
|
+
def authenticators?
|
|
36
|
+
credential.registered_authenticators?
|
|
37
|
+
end
|
|
38
|
+
|
|
34
39
|
def credential
|
|
35
40
|
@credential ||= ::Booth::Models::Credential.find(request.authentication.credential_id)
|
|
36
41
|
end
|
data/lib/booth/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: booth
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- halo
|
|
@@ -187,6 +187,7 @@ files:
|
|
|
187
187
|
- app/assets/images/booth/fido/passkey_mark_a_reverse.svg
|
|
188
188
|
- app/assets/images/booth/fido/passkey_mark_a_white.svg
|
|
189
189
|
- app/assets/images/booth/fido/passkey_mark_b_black.svg
|
|
190
|
+
- app/assets/images/booth/fido/passkey_mark_b_reverse.svg
|
|
190
191
|
- app/assets/images/booth/platforms/README.md
|
|
191
192
|
- app/assets/images/booth/platforms/android.svg
|
|
192
193
|
- app/assets/images/booth/platforms/apple.svg
|
|
@@ -292,6 +293,7 @@ files:
|
|
|
292
293
|
- lib/booth/models/remotes/scopes/recently_responded.rb
|
|
293
294
|
- lib/booth/models/session.rb
|
|
294
295
|
- lib/booth/models/user_agent.rb
|
|
296
|
+
- lib/booth/passport.rb
|
|
295
297
|
- lib/booth/request.rb
|
|
296
298
|
- lib/booth/requests/agent.rb
|
|
297
299
|
- lib/booth/requests/authentication.rb
|
|
@@ -319,18 +321,20 @@ files:
|
|
|
319
321
|
- lib/booth/testing/support/assert_logged_in.rb
|
|
320
322
|
- lib/booth/testing/support/assert_logged_out.rb
|
|
321
323
|
- lib/booth/testing/support/assert_partial.rb
|
|
324
|
+
- lib/booth/testing/support/capybara_step_logger.rb
|
|
325
|
+
- lib/booth/testing/support/clear_cookies.rb
|
|
326
|
+
- lib/booth/testing/support/cookie_data_from_browser.rb
|
|
322
327
|
- lib/booth/testing/support/force_login.rb
|
|
323
|
-
- lib/booth/testing/support/get_session_value.rb
|
|
324
328
|
- lib/booth/testing/support/scenario.rb
|
|
325
329
|
- lib/booth/testing/support/shortcuts/create_and_onboard.rb
|
|
326
330
|
- lib/booth/testing/support/shortcuts/login_with_passkey.rb
|
|
327
331
|
- lib/booth/testing/support/shortcuts/register_new_passkey.rb
|
|
328
|
-
- lib/booth/testing/support/
|
|
332
|
+
- lib/booth/testing/support/virtual_authenticator.rb
|
|
333
|
+
- lib/booth/testing/support/virtual_authenticators.rb
|
|
329
334
|
- lib/booth/testing/support/virtual_authenticators/create.rb
|
|
330
335
|
- lib/booth/testing/support/virtual_authenticators/destroy.rb
|
|
331
336
|
- lib/booth/testing/support/virtual_authenticators/enable.rb
|
|
332
337
|
- lib/booth/testing/support/virtual_authenticators/load.rb
|
|
333
|
-
- lib/booth/testing/support/virtual_authenticators/manager.rb
|
|
334
338
|
- lib/booth/testing/support/visit.rb
|
|
335
339
|
- lib/booth/testing/userland.rb
|
|
336
340
|
- lib/booth/testing/userland/login_remotely.rb
|
|
@@ -341,6 +345,7 @@ files:
|
|
|
341
345
|
- lib/booth/testing/userland/sessions_manage_behavior.rb
|
|
342
346
|
- lib/booth/testing/userland/sessions_revoke_all_others.rb
|
|
343
347
|
- lib/booth/testing/userland/sessions_revoke_one.rb
|
|
348
|
+
- lib/booth/testing/userland/sudo_webauth.rb
|
|
344
349
|
- lib/booth/to_struct.rb
|
|
345
350
|
- lib/booth/userland.rb
|
|
346
351
|
- lib/booth/userland/extract_flash_messages.rb
|
|
@@ -409,7 +414,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
409
414
|
- !ruby/object:Gem::Version
|
|
410
415
|
version: '0'
|
|
411
416
|
requirements: []
|
|
412
|
-
rubygems_version:
|
|
417
|
+
rubygems_version: 3.6.9
|
|
413
418
|
specification_version: 4
|
|
414
419
|
summary: Opinionated authentication framework for Rails
|
|
415
420
|
test_files: []
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Booth
|
|
4
|
-
module Testing
|
|
5
|
-
module Support
|
|
6
|
-
class GetSessionValue
|
|
7
|
-
include ::Calls
|
|
8
|
-
include ::Capybara::DSL
|
|
9
|
-
include ::Booth::Logging
|
|
10
|
-
|
|
11
|
-
option :key
|
|
12
|
-
|
|
13
|
-
def call
|
|
14
|
-
::Capybara::Lockstep.synchronize
|
|
15
|
-
|
|
16
|
-
result = nil
|
|
17
|
-
in_new_window do
|
|
18
|
-
result = page.get_rack_session[key]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
log { "session[#{key.inspect}] is: #{result.inspect}" }
|
|
22
|
-
|
|
23
|
-
::Capybara::Lockstep.synchronize
|
|
24
|
-
result
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
def in_new_window(&)
|
|
30
|
-
window = open_new_window
|
|
31
|
-
within_window(window, &)
|
|
32
|
-
window.close
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Booth
|
|
4
|
-
module Testing
|
|
5
|
-
module Support
|
|
6
|
-
module VirtualAuthenticators
|
|
7
|
-
# Capybara handles multiple separate Chrome sessions (like separate browsers).
|
|
8
|
-
# In Chrome each of those sessions is completely distinct and nows nothing about the others.
|
|
9
|
-
# To "simulate" having the *same* passkey in "two browsers", we need to clone and sync it.
|
|
10
|
-
# This means transferring the secret key, and synchronizing the sign count.
|
|
11
|
-
# This class holds a state of all browser sessions to easier facilitate transfer and sync.
|
|
12
|
-
class Manager
|
|
13
|
-
include ::Capybara::DSL
|
|
14
|
-
include ::Booth::Logging
|
|
15
|
-
|
|
16
|
-
# Creates a brand new passkey.
|
|
17
|
-
def create(has_user_verification: true)
|
|
18
|
-
::Booth::Testing::Support::VirtualAuthenticators::Enable.call
|
|
19
|
-
|
|
20
|
-
new_device = ::Booth::Testing::Support::VirtualAuthenticators::Create.call(
|
|
21
|
-
has_user_verification:,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
this_session[new_device.instance_variable_get(:@id)] = new_device
|
|
25
|
-
|
|
26
|
-
nil
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Takes a passkey from (the) other browser and injects it into this browser.
|
|
30
|
-
def clone_from_other_session
|
|
31
|
-
new_device = ::Booth::Testing::Support::VirtualAuthenticators::Create.call(
|
|
32
|
-
has_user_verification: true,
|
|
33
|
-
)
|
|
34
|
-
new_device.add_credential(other_credential)
|
|
35
|
-
|
|
36
|
-
this_session[new_device.instance_variable_get(:@id)] = new_device
|
|
37
|
-
nil
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Inspects a passkey in (the) other browser and syncs the passkey here if needed.
|
|
41
|
-
def refresh_from_other_session
|
|
42
|
-
this_sign_count = this_credential.instance_variable_get(:@sign_count)
|
|
43
|
-
other_sign_count = other_credential.instance_variable_get(:@sign_count)
|
|
44
|
-
|
|
45
|
-
if this_sign_count == other_sign_count
|
|
46
|
-
log { "Sign count of both Virtual Keys is #{this_sign_count}" }
|
|
47
|
-
return
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
log { "Changing Virtual Key sign count from #{this_sign_count} to #{other_sign_count}" }
|
|
51
|
-
|
|
52
|
-
new_credential = this_credential
|
|
53
|
-
# This only affects the Credential here in our Ruby instance.
|
|
54
|
-
new_credential.instance_variable_set(:@sign_count, other_sign_count)
|
|
55
|
-
|
|
56
|
-
# So let us send our Ruby instance to the browser by replacing the key there.
|
|
57
|
-
this_device.remove_all_credentials
|
|
58
|
-
this_device.add_credential(new_credential)
|
|
59
|
-
|
|
60
|
-
nil
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
def this_credential
|
|
66
|
-
these_credentials = this_device.credentials
|
|
67
|
-
|
|
68
|
-
unless these_credentials.size == 1
|
|
69
|
-
raise "Don't know which other Virtual Credential to pick: #{these_credentials}"
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
these_credentials.first
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def other_credential
|
|
76
|
-
other_credentials = other_device.credentials
|
|
77
|
-
|
|
78
|
-
unless other_credentials.size == 1
|
|
79
|
-
raise "Don't know which Virtual Credential of mine to pick: #{other_credentials}"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
other_credentials.first
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def this_device
|
|
86
|
-
unless this_session.size == 1
|
|
87
|
-
raise "Don't know which Virtual Authenticator of mine to pick: #{this_session.keys}"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
this_session.values.first
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def other_device
|
|
94
|
-
unless other_session.size == 1
|
|
95
|
-
raise "Don't know which other Virtual Authenticator to pick: #{other_session.keys}"
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
other_session.values.first
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def this_session
|
|
102
|
-
sessions[Capybara.session_name]
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def other_session
|
|
106
|
-
other_session_keys = sessions.keys.reject { it == Capybara.session_name }
|
|
107
|
-
|
|
108
|
-
unless other_session_keys.size == 1
|
|
109
|
-
raise "Cannot determine #{sessions.keys} as alternative to #{Capybara.session_name}"
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
sessions[other_session_keys.first]
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def sessions
|
|
116
|
-
@sessions ||= {}
|
|
117
|
-
@sessions[Capybara.session_name] ||= {}
|
|
118
|
-
@sessions
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|