1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """ Script that exercises the Smart Lock setup flow, testing that a nearby phone
6 can be found and used to unlock a Chromebook.
8 Note: This script does not currently automate Android phones, so make sure that
9 a phone is properly configured and online before starting the test.
12 python setup_test.py --remote_address REMOTE_ADDRESS
17 If |--app_path| is provided, then a copy of the Smart Lock app on the local
18 machine will be used instead of the app on the ChromeOS device.
30 logger
= logging
.getLogger('proximity_auth.%s' % __name__
)
32 class SmartLockSetupError(Exception):
35 def pingable_address(address
):
37 subprocess
.check_output(['ping', '-c', '1', '-W', '1', address
])
38 except subprocess
.CalledProcessError
:
39 raise argparse
.ArgumentError('%s cannot be reached.' % address
)
43 tokens
= arg
.lower().split('@')
44 if len(tokens
) != 2 or '.' not in tokens
[1]:
45 raise argparse
.ArgumentError('%s is not a valid email address' % arg
)
47 if domain
== 'gmail.com':
48 name
= name
.replace('.', '')
49 return '@'.join([name
, domain
])
52 if not os
.path
.isdir(path
):
53 raise argparse
.ArgumentError('%s is not a directory' % path
)
57 parser
= argparse
.ArgumentParser(prog
='python setup_test.py')
58 parser
.add_argument('--remote_address', required
=True, type=pingable_address
)
59 parser
.add_argument('--username', required
=True, type=email
)
60 parser
.add_argument('--password', required
=True)
61 parser
.add_argument('--ssh_port', type=int)
62 parser
.add_argument('--app_path', type=directory
)
63 args
= parser
.parse_args()
66 def CheckCryptAuthState(access_token
):
67 cryptauth_client
= cryptauth
.CryptAuthClient(access_token
)
69 # Check if we can make CryptAuth requests.
70 if cryptauth_client
.GetMyDevices() is None:
71 logger
.error('Cannot reach CryptAuth on test machine.')
74 if cryptauth_client
.GetUnlockKey() is not None:
75 logger
.info('Smart Lock currently enabled, turning off on Cryptauth...')
76 if not cryptauth_client
.ToggleEasyUnlock(False):
77 logger
.error('ToggleEasyUnlock request failed.')
80 result
= cryptauth_client
.FindEligibleUnlockDevices()
82 logger
.error('FindEligibleUnlockDevices request failed')
84 eligibleDevices
, _
= result
85 if len(eligibleDevices
) == 0:
86 logger
.warn('No eligible phones found, trying to ping phones...')
87 result
= cryptauth_client
.PingPhones()
88 if result
is None or not len(result
[0]):
89 logger
.error('Pinging phones failed :(')
92 logger
.info('Pinging phones succeeded!')
94 logger
.info('Found eligible device: %s' % (
95 eligibleDevices
[0]['friendlyDeviceName']))
98 def _NavigateSetupDialog(chromeos
, app
):
99 logger
.info('Scanning for nearby phones...')
100 btmon
= chromeos
.RunBtmon()
101 find_phone_success
= app
.FindPhone()
104 if not find_phone_success
:
105 fd
, filepath
= tempfile
.mkstemp(prefix
='btmon-')
106 os
.write(fd
, btmon
.stdout
.read())
108 logger
.info('Logs for btmon can be found at %s' % filepath
)
109 raise SmartLockSetupError("Failed to find nearby phone.")
111 logger
.info('Phone found! Starting pairing...')
112 if not app
.PairPhone():
113 raise SmartLockSetupError("Failed to pair with phone.")
114 logger
.info('Pairing success! Starting trial run...')
117 logger
.info('Unlocking for trial run...')
118 lock_screen
= chromeos
.GetAccountPickerScreen()
119 lock_screen
.WaitForSmartLockState(
120 lock_screen
.SmartLockState
.AUTHENTICATED
)
121 lock_screen
.UnlockWithClick()
123 logger
.info('Trial run success! Dismissing app...')
126 def RunSetupTest(args
):
127 logger
.info('Starting test for %s at %s' % (
128 args
.username
, args
.remote_address
))
129 if args
.app_path
is not None:
130 logger
.info('Replacing Smart Lock app with %s' % args
.app_path
)
132 chromeos
= cros
.ChromeOS(
133 args
.remote_address
, args
.username
, args
.password
, ssh_port
=args
.ssh_port
)
134 with chromeos
.Start(local_app_path
=args
.app_path
):
135 logger
.info('Chrome initialized')
137 # TODO(tengs): The access token is currently fetched from the Smart Lock
138 # app's background page. To be more robust, we should instead mint the
139 # access token ourselves.
140 if not CheckCryptAuthState(chromeos
.cryptauth_access_token
):
141 raise SmartLockSetupError('Failed to check CryptAuth state')
143 logger
.info('Opening Smart Lock settings...')
144 settings
= chromeos
.GetSmartLockSettings()
145 assert(not settings
.is_smart_lock_enabled
)
146 logger
.info('Starting Smart Lock setup flow...')
147 app
= settings
.StartSetupAndReturnApp()
149 _NavigateSetupDialog(chromeos
, app
)
152 logging
.basicConfig()
153 logging
.getLogger('proximity_auth').setLevel(logging
.INFO
)
157 if __name__
== '__main__':