Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jose/utils.py: 49%

45 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:16 +0000

1import base64 

2import struct 

3 

4# Piggyback of the backends implementation of the function that converts a long 

5# to a bytes stream. Some plumbing is necessary to have the signatures match. 

6try: 

7 from cryptography.utils import int_to_bytes as _long_to_bytes 

8 

9 def long_to_bytes(n, blocksize=0): 

10 return _long_to_bytes(n, blocksize or None) 

11 

12except ImportError: 

13 from ecdsa.ecdsa import int_to_string as _long_to_bytes 

14 

15 def long_to_bytes(n, blocksize=0): 

16 ret = _long_to_bytes(n) 

17 if blocksize == 0: 

18 return ret 

19 else: 

20 assert len(ret) <= blocksize 

21 padding = blocksize - len(ret) 

22 return b"\x00" * padding + ret 

23 

24 

25def long_to_base64(data, size=0): 

26 return base64.urlsafe_b64encode(long_to_bytes(data, size)).strip(b"=") 

27 

28 

29def int_arr_to_long(arr): 

30 return int("".join(["%02x" % byte for byte in arr]), 16) 

31 

32 

33def base64_to_long(data): 

34 if isinstance(data, str): 

35 data = data.encode("ascii") 

36 

37 # urlsafe_b64decode will happily convert b64encoded data 

38 _d = base64.urlsafe_b64decode(bytes(data) + b"==") 

39 return int_arr_to_long(struct.unpack("%sB" % len(_d), _d)) 

40 

41 

42def calculate_at_hash(access_token, hash_alg): 

43 """Helper method for calculating an access token 

44 hash, as described in http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken 

45 

46 Its value is the base64url encoding of the left-most half of the hash of the octets 

47 of the ASCII representation of the access_token value, where the hash algorithm 

48 used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE 

49 Header. For instance, if the alg is RS256, hash the access_token value with SHA-256, 

50 then take the left-most 128 bits and base64url encode them. The at_hash value is a 

51 case sensitive string. 

52 

53 Args: 

54 access_token (str): An access token string. 

55 hash_alg (callable): A callable returning a hash object, e.g. hashlib.sha256 

56 

57 """ 

58 hash_digest = hash_alg(access_token.encode("utf-8")).digest() 

59 cut_at = int(len(hash_digest) / 2) 

60 truncated = hash_digest[:cut_at] 

61 at_hash = base64url_encode(truncated) 

62 return at_hash.decode("utf-8") 

63 

64 

65def base64url_decode(input): 

66 """Helper method to base64url_decode a string. 

67 

68 Args: 

69 input (str): A base64url_encoded string to decode. 

70 

71 """ 

72 rem = len(input) % 4 

73 

74 if rem > 0: 

75 input += b"=" * (4 - rem) 

76 

77 return base64.urlsafe_b64decode(input) 

78 

79 

80def base64url_encode(input): 

81 """Helper method to base64url_encode a string. 

82 

83 Args: 

84 input (str): A base64url_encoded string to encode. 

85 

86 """ 

87 return base64.urlsafe_b64encode(input).replace(b"=", b"") 

88 

89 

90def timedelta_total_seconds(delta): 

91 """Helper method to determine the total number of seconds 

92 from a timedelta. 

93 

94 Args: 

95 delta (timedelta): A timedelta to convert to seconds. 

96 """ 

97 return delta.days * 24 * 60 * 60 + delta.seconds 

98 

99 

100def ensure_binary(s): 

101 """Coerce **s** to bytes.""" 

102 

103 if isinstance(s, bytes): 

104 return s 

105 if isinstance(s, str): 

106 return s.encode("utf-8", "strict") 

107 raise TypeError(f"not expecting type '{type(s)}'")