Skip to content

Commit f8109bd

Browse files
committed
Catch bare exceptions, shorten id, add md5 fallback
1 parent c9c6253 commit f8109bd

2 files changed

Lines changed: 59 additions & 12 deletions

File tree

awscli/telemetry.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
1111
# ANY KIND, either express or implied. See the License for the specific
1212
# language governing permissions and limitations under the License.
13-
import hashlib
1413
import io
1514
import os
1615
import sqlite3
@@ -22,6 +21,8 @@
2221
from functools import cached_property
2322
from pathlib import Path
2423

24+
from botocore.compat import get_md5
25+
from botocore.exceptions import MD5UnavailableError
2526
from botocore.useragent import UserAgentComponent
2627

2728
from awscli.compat import is_windows
@@ -30,10 +31,22 @@
3031
_CACHE_DIR = Path.home() / '.aws' / 'cli' / 'cache'
3132
_DATABASE_FILENAME = 'session.db'
3233
_SESSION_LENGTH_SECONDS = 60 * 30
34+
_SESSION_ID_LENGTH = 12
3335

3436
_CACHE_DIR.mkdir(parents=True, exist_ok=True)
3537

3638

39+
def _get_checksum():
40+
hashlib_params = {"usedforsecurity": False}
41+
try:
42+
checksum = get_md5(**hashlib_params)
43+
except MD5UnavailableError:
44+
import hashlib
45+
46+
checksum = hashlib.sha256(**hashlib_params)
47+
return checksum
48+
49+
3750
@dataclass
3851
class CLISessionData:
3952
key: str
@@ -179,17 +192,19 @@ def sweep(self, timestamp):
179192

180193
class CLISessionGenerator:
181194
def generate_session_id(self, host_id, tty, timestamp):
182-
return self._generate_md5_hash(host_id, tty, timestamp)
195+
return self._generate_checksum(host_id, tty, timestamp)
183196

184197
def generate_cache_key(self, host_id, tty):
185-
return self._generate_md5_hash(host_id, tty)
198+
return self._generate_checksum(host_id, tty)
186199

187-
def _generate_md5_hash(self, *args):
200+
def _generate_checksum(self, *args):
201+
checksum = _get_checksum()
188202
str_to_hash = ""
189203
for arg in args:
190204
if arg is not None:
191205
str_to_hash += str(arg)
192-
return hashlib.md5(str_to_hash.encode('utf-8')).hexdigest()
206+
checksum.update(str_to_hash.encode('utf-8'))
207+
return checksum.hexdigest()[:_SESSION_ID_LENGTH]
193208

194209

195210
class CLISessionOrchestrator:
@@ -273,7 +288,16 @@ def _get_cli_session_orchestrator():
273288

274289

275290
def add_session_id_component_to_user_agent_extra(session, orchestrator=None):
276-
cli_session_orchestrator = orchestrator or _get_cli_session_orchestrator()
277-
add_component_to_user_agent_extra(
278-
session, UserAgentComponent("sid", cli_session_orchestrator.session_id)
279-
)
291+
try:
292+
cli_session_orchestrator = (
293+
orchestrator or _get_cli_session_orchestrator()
294+
)
295+
add_component_to_user_agent_extra(
296+
session,
297+
UserAgentComponent("sid", cli_session_orchestrator.session_id),
298+
)
299+
except Exception:
300+
# Ideally, the AWS CLI should never throw if the session id
301+
# can't be generated since it's not critical for users. Issues
302+
# with session dada should instead be caught server-side.
303+
pass

tests/functional/test_telemetry.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from unittest.mock import MagicMock, patch
1515

1616
import pytest
17+
from botocore.exceptions import MD5UnavailableError
1718
from botocore.session import Session
1819

1920
from awscli.telemetry import (
@@ -182,14 +183,24 @@ def test_generate_session_id(self, session_generator):
182183
'my-tty',
183184
1000000000,
184185
)
185-
assert session_id == 'd949713b13ee3fb52983b04316e8e6b5'
186+
assert session_id == 'd949713b13ee'
186187

187188
def test_generate_cache_key(self, session_generator):
188189
cache_key = session_generator.generate_cache_key(
189190
'my-hostname',
190191
'my-tty',
191192
)
192-
assert cache_key == 'b1ca2be0ffac12f172933b6777e06f2c'
193+
assert cache_key == 'b1ca2be0ffac'
194+
195+
@patch('awscli.telemetry.get_md5')
196+
def test_checksum_fips_fallback(self, patched_get_md5, session_generator):
197+
patched_get_md5.side_effect = MD5UnavailableError()
198+
session_id = session_generator.generate_session_id(
199+
'my-hostname',
200+
'my-tty',
201+
1000000000,
202+
)
203+
assert session_id == '183b154db015'
193204

194205

195206
@skip_if_windows
@@ -211,7 +222,7 @@ def test_session_id_gets_cached(
211222
orchestrator = CLISessionOrchestrator(
212223
session_generator, session_writer, session_reader, session_sweeper
213224
)
214-
assert orchestrator.session_id == '881cea8546fa4888970cce8d133c3bf9'
225+
assert orchestrator.session_id == '881cea8546fa'
215226

216227
session_data = session_reader.read(orchestrator.cache_key)
217228
assert session_data.key == orchestrator.cache_key
@@ -299,3 +310,15 @@ def test_add_session_id_component_to_user_agent_extra():
299310
orchestrator.session_id = 'my-session-id'
300311
add_session_id_component_to_user_agent_extra(session, orchestrator)
301312
assert session.user_agent_extra == 'sid/my-session-id'
313+
314+
315+
def test_entrypoint_catches_bare_exceptions():
316+
class FakeOrchestrator(CLISessionOrchestrator):
317+
def __init__(self):
318+
pass
319+
320+
def session_id(self):
321+
raise Exception()
322+
323+
session = MagicMock(Session)
324+
add_session_id_component_to_user_agent_extra(session, FakeOrchestrator())

0 commit comments

Comments
 (0)