OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 import httplib | |
6 import json | |
7 import logging | |
8 import pprint | |
9 import time | |
10 | |
11 logger = logging.getLogger('proximity_auth.%s' % __name__) | |
12 | |
13 _GOOGLE_APIS_URL = 'www.googleapis.com' | |
14 _REQUEST_PATH = '/cryptauth/v1/%s?alt=JSON' | |
15 | |
16 class CryptAuthClient(object): | |
17 """ A client for making blocking CryptAuth API calls. """ | |
18 | |
19 def __init__(self, access_token, google_apis_url=_GOOGLE_APIS_URL): | |
20 self._access_token = access_token | |
21 self._google_apis_url = google_apis_url | |
22 | |
23 def GetMyDevices(self): | |
24 """ Invokes the GetMyDevices API. | |
25 | |
26 Returns: | |
27 A list of devices or None if the API call fails. | |
28 Each device is a dictionary of the deserialized JSON returned by | |
29 CryptAuth. | |
30 """ | |
31 request_data = { | |
32 'approvedForUnlockRequired': False, | |
33 'allowStaleRead': False, | |
34 'invocationReason': 13 # REASON_MANUAL | |
35 } | |
36 response = self._SendRequest('deviceSync/getmydevices', request_data) | |
37 return response['devices'] if response is not None else None | |
38 | |
39 def GetUnlockKey(self): | |
40 """ | |
41 Returns: | |
42 The unlock key registered with CryptAuth if it exists or None. | |
43 The device is a dictionary of the deserialized JSON returned by CryptAuth. | |
44 """ | |
45 devices = self.GetMyDevices() | |
46 if devices is None: | |
47 return None | |
48 | |
49 for device in devices: | |
50 if device['unlockKey']: | |
51 return device | |
52 return None | |
53 | |
54 def ToggleEasyUnlock(self, enable, public_key=''): | |
55 """ Calls the ToggleEasyUnlock API. | |
56 Args: | |
57 enable: True to designate the device specified by |public_key| as an | |
58 unlock key. | |
59 public_key: The public key of the device to toggle. Ignored if |enable| is | |
60 False, which toggles all unlock keys off. | |
61 Returns: | |
62 True upon success, else False. | |
63 """ | |
64 request_data = { 'enable': enable, } | |
65 if not enable: | |
66 request_data['applyToAll'] = True | |
67 else: | |
68 request_data['publicKey'] = public_key | |
69 response = self._SendRequest('deviceSync/toggleeasyunlock', request_data) | |
70 return response is not None | |
71 | |
72 def FindEligibleUnlockDevices(self, time_delta_millis=None): | |
73 """ Finds devices eligible to be an unlock key. | |
74 Args: | |
75 time_delta_millis: If specified, then only return eligible devices that | |
76 have contacted CryptAuth in the last time delta. | |
77 Returns: | |
78 A tuple containing two lists, one of eligible devices and the other of | |
79 ineligible devices. | |
80 Each device is a dictionary of the deserialized JSON returned by | |
81 CryptAuth. | |
82 """ | |
83 request_data = {} | |
84 if time_delta_millis is not None: | |
85 request_data['maxLastUpdateTimeDeltaMillis'] = time_delta_millis * 1000; | |
86 | |
87 response = self._SendRequest( | |
88 'deviceSync/findeligibleunlockdevices', request_data) | |
89 if response is None: | |
90 return None | |
91 eligibleDevices = response['eligibleDevices'] if \ | |
92 'eligibleDevices' in response else [] | |
Ilya Sherman
2015/03/24 01:25:14
nit: I think this is normally wrapped like so:
Tim Song
2015/03/25 23:08:44
Done.
| |
93 ineligibleDevices = response['ineligibleDevices'] if \ | |
94 'ineligibleDevices' in response else [] | |
95 return eligibleDevices, ineligibleDevices | |
96 | |
97 def PingPhones(self, timeout_secs=10): | |
98 """ Asks CryptAuth to ping registered phones and determine their status. | |
99 Args: | |
100 timeout_secs: The number of seconds to wait for phones to respond. | |
101 Returns: | |
102 A tuple containing two lists, one of eligible devices and the other of | |
103 ineligible devices. | |
104 Each device is a dictionary of the deserialized JSON returned by | |
105 CryptAuth. | |
106 """ | |
107 response = self._SendRequest( | |
108 'deviceSync/senddevicesynctickle', | |
109 { 'tickleType': 'updateEnrollment' }) | |
110 if response is None: | |
111 return None | |
112 # We wait for phones to update their status with CryptAuth. | |
113 logger.info('Waiting for %s seconds for phone status...' % timeout_secs) | |
114 time.sleep(timeout_secs) | |
115 return self.FindEligibleUnlockDevices(time_delta_millis=timeout_secs) | |
116 | |
117 def _SendRequest(self, function_path, request_data): | |
118 """ Sends an HTTP request to CryptAuth and returns the deserialized | |
119 response. | |
120 """ | |
121 conn = httplib.HTTPSConnection(self._google_apis_url) | |
122 path = _REQUEST_PATH % function_path | |
123 | |
124 headers = { | |
125 'authorization': 'Bearer ' + self._access_token, | |
126 'Content-Type': 'application/json' | |
127 } | |
128 body = json.dumps(request_data) | |
129 logger.info('Making request to %s with body:\n%s' % \ | |
130 (path, pprint.pformat(request_data))) | |
131 conn.request('POST', path, body, headers) | |
132 | |
133 response = conn.getresponse() | |
134 if response.status == 204: | |
135 return {} | |
136 if response.status != 200: | |
137 logger.warning('Request to %s failed: %s' % (path, response.status)) | |
138 return None | |
139 return json.loads(response.read()) | |
OLD | NEW |