sippy 2.3.0__tar.gz → 2.4.1__tar.gz

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.
Files changed (187) hide show
  1. {sippy-2.3.0 → sippy-2.4.1}/MANIFEST.in +1 -0
  2. {sippy-2.3.0/sippy.egg-info → sippy-2.4.1}/PKG-INFO +3 -1
  3. {sippy-2.3.0 → sippy-2.4.1}/requirements.txt +2 -0
  4. {sippy-2.3.0 → sippy-2.4.1}/setup.py +1 -1
  5. {sippy-2.3.0 → sippy-2.4.1}/sippy/B2B/Route.py +75 -22
  6. {sippy-2.3.0 → sippy-2.4.1}/sippy/B2B/SimpleAPI.py +7 -3
  7. {sippy-2.3.0 → sippy-2.4.1}/sippy/MyConfigParser.py +7 -3
  8. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/EPoint.py +38 -8
  9. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/udp.py +2 -5
  10. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Session/side.py +2 -3
  11. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/session.py +18 -10
  12. {sippy-2.3.0 → sippy-2.4.1}/sippy/Security/SipNonce.py +26 -12
  13. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipAuthorization.py +3 -16
  14. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipCallId.py +2 -4
  15. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipCiscoGUID.py +3 -6
  16. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipFrom.py +2 -4
  17. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipVia.py +2 -4
  18. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipWWWAuthenticate.py +2 -9
  19. {sippy-2.3.0 → sippy-2.4.1}/sippy/UA.py +2 -5
  20. sippy-2.4.1/sippy/UI/Auth.py +64 -0
  21. sippy-2.4.1/sippy/UI/Controller.py +380 -0
  22. sippy-2.4.1/sippy/UI/Lib.py +248 -0
  23. sippy-2.4.1/sippy/UI/SystemConfiguration.py +5 -0
  24. sippy-2.4.1/sippy/UI/static/active_calls.js +17 -0
  25. sippy-2.4.1/sippy/UI/static/config_box.css +29 -0
  26. sippy-2.4.1/sippy/UI/static/lib.js +146 -0
  27. sippy-2.4.1/sippy/UI/static/login.css +103 -0
  28. sippy-2.4.1/sippy/UI/static/ui.css +50 -0
  29. sippy-2.4.1/sippy/UI/templates/login.html +81 -0
  30. sippy-2.4.1/sippy/UI/templates/redir2login.html +14 -0
  31. sippy-2.4.1/sippy/UaStateConnected.py +311 -0
  32. {sippy-2.3.0 → sippy-2.4.1}/sippy/UaStateGeneric.py +26 -0
  33. {sippy-2.3.0 → sippy-2.4.1}/sippy/UacStateUpdating.py +32 -25
  34. sippy-2.4.1/sippy/UasStateGeneric.py +79 -0
  35. sippy-2.4.1/sippy/UasStateProgressing.py +84 -0
  36. sippy-2.4.1/sippy/UasStateRinging.py +64 -0
  37. sippy-2.4.1/sippy/UasStateTrying.py +89 -0
  38. sippy-2.4.1/sippy/UasStateUpdating.py +103 -0
  39. {sippy-2.3.0 → sippy-2.4.1}/sippy/b2bua.py +7 -1
  40. {sippy-2.3.0 → sippy-2.4.1/sippy.egg-info}/PKG-INFO +3 -1
  41. {sippy-2.3.0 → sippy-2.4.1}/sippy.egg-info/SOURCES.txt +16 -0
  42. {sippy-2.3.0 → sippy-2.4.1}/sippy.egg-info/requires.txt +2 -0
  43. sippy-2.4.1/tests/__init__.py +0 -0
  44. sippy-2.4.1/tests/test_HashOracle.py +30 -0
  45. sippy-2.4.1/tests/test_RtpEPoint.py +61 -0
  46. sippy-2.3.0/sippy/UaStateConnected.py +0 -296
  47. sippy-2.3.0/sippy/UasStateRinging.py +0 -144
  48. sippy-2.3.0/sippy/UasStateTrying.py +0 -137
  49. sippy-2.3.0/sippy/UasStateUpdating.py +0 -128
  50. {sippy-2.3.0 → sippy-2.4.1}/LICENSE +0 -0
  51. {sippy-2.3.0 → sippy-2.4.1}/README.md +0 -0
  52. {sippy-2.3.0 → sippy-2.4.1}/pyproject.toml +0 -0
  53. {sippy-2.3.0 → sippy-2.4.1}/setup.cfg +0 -0
  54. {sippy-2.3.0 → sippy-2.4.1}/sippy/B2B/States.py +0 -0
  55. {sippy-2.3.0 → sippy-2.4.1}/sippy/B2B/Transforms.py +0 -0
  56. {sippy-2.3.0 → sippy-2.4.1}/sippy/B2B/__init__.py +0 -0
  57. {sippy-2.3.0 → sippy-2.4.1}/sippy/CCEvents.py +0 -0
  58. {sippy-2.3.0 → sippy-2.4.1}/sippy/CLIManager.py +0 -0
  59. {sippy-2.3.0 → sippy-2.4.1}/sippy/Core/EventDispatcher.py +0 -0
  60. {sippy-2.3.0 → sippy-2.4.1}/sippy/Core/Exceptions.py +0 -0
  61. {sippy-2.3.0 → sippy-2.4.1}/sippy/Core/__init__.py +0 -0
  62. {sippy-2.3.0 → sippy-2.4.1}/sippy/ESipHeaderCSV.py +0 -0
  63. {sippy-2.3.0 → sippy-2.4.1}/sippy/ESipHeaderIgnore.py +0 -0
  64. {sippy-2.3.0 → sippy-2.4.1}/sippy/Exceptions/RtpProxyError.py +0 -0
  65. {sippy-2.3.0 → sippy-2.4.1}/sippy/Exceptions/SdpParseError.py +0 -0
  66. {sippy-2.3.0 → sippy-2.4.1}/sippy/Exceptions/SipHandlingError.py +0 -0
  67. {sippy-2.3.0 → sippy-2.4.1}/sippy/Exceptions/SipParseError.py +0 -0
  68. {sippy-2.3.0 → sippy-2.4.1}/sippy/Exceptions/__init__.py +0 -0
  69. {sippy-2.3.0 → sippy-2.4.1}/sippy/External_command.py +0 -0
  70. {sippy-2.3.0 → sippy-2.4.1}/sippy/FakeAccounting.py +0 -0
  71. {sippy-2.3.0 → sippy-2.4.1}/sippy/Math/__init__.py +0 -0
  72. {sippy-2.3.0 → sippy-2.4.1}/sippy/Math/recfilter.py +0 -0
  73. {sippy-2.3.0 → sippy-2.4.1}/sippy/MsgBody.py +0 -0
  74. {sippy-2.3.0 → sippy-2.4.1}/sippy/MultipartMixBody.py +0 -0
  75. {sippy-2.3.0 → sippy-2.4.1}/sippy/Network_server.py +0 -0
  76. {sippy-2.3.0 → sippy-2.4.1}/sippy/RadiusAccounting.py +0 -0
  77. {sippy-2.3.0 → sippy-2.4.1}/sippy/RadiusAuthorisation.py +0 -0
  78. {sippy-2.3.0 → sippy-2.4.1}/sippy/Radius_client.py +0 -0
  79. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Codecs/G711.py +0 -0
  80. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Codecs/G722.py +0 -0
  81. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Codecs/GenCodec.py +0 -0
  82. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Codecs/__init__.py +0 -0
  83. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Conf.py +0 -0
  84. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Core/AudioChunk.py +0 -0
  85. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Core/__init__.py +0 -0
  86. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Handlers.py +0 -0
  87. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Ingest.py +0 -0
  88. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/OutputWorker.py +0 -0
  89. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Params.py +0 -0
  90. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/Singletons.py +0 -0
  91. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp/__init__.py +0 -0
  92. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/Worker/__init__.py +0 -0
  93. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/Worker/external.py +0 -0
  94. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/Worker/internal.py +0 -0
  95. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/__init__.py +0 -0
  96. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/internal.py +0 -0
  97. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/local.py +0 -0
  98. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/net.py +0 -0
  99. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Client/stream.py +0 -0
  100. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Cmd/__init__.py +0 -0
  101. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Cmd/sequencer.py +0 -0
  102. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Session/__init__.py +0 -0
  103. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Session/subcommand.py +0 -0
  104. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Session/subcommand_ice.py +0 -0
  105. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Session/update.py +0 -0
  106. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/Session/webrtc.py +0 -0
  107. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/__init__.py +0 -0
  108. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/client.py +0 -0
  109. {sippy-2.3.0 → sippy-2.4.1}/sippy/Rtp_proxy/cmd.py +0 -0
  110. {sippy-2.3.0 → sippy-2.4.1}/sippy/SdpBody.py +0 -0
  111. {sippy-2.3.0 → sippy-2.4.1}/sippy/SdpConnecton.py +0 -0
  112. {sippy-2.3.0 → sippy-2.4.1}/sippy/SdpGeneric.py +0 -0
  113. {sippy-2.3.0 → sippy-2.4.1}/sippy/SdpMedia.py +0 -0
  114. {sippy-2.3.0 → sippy-2.4.1}/sippy/SdpMediaDescription.py +0 -0
  115. {sippy-2.3.0 → sippy-2.4.1}/sippy/SdpOrigin.py +0 -0
  116. {sippy-2.3.0 → sippy-2.4.1}/sippy/Security/__init__.py +0 -0
  117. {sippy-2.3.0 → sippy-2.4.1}/sippy/Signal.py +0 -0
  118. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipAddress.py +0 -0
  119. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipAddressHF.py +0 -0
  120. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipAllow.py +0 -0
  121. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipAlso.py +0 -0
  122. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipCCDiversion.py +0 -0
  123. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipCSeq.py +0 -0
  124. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipConf.py +0 -0
  125. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipContact.py +0 -0
  126. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipContentLength.py +0 -0
  127. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipContentType.py +0 -0
  128. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipDiversion.py +0 -0
  129. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipExpires.py +0 -0
  130. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipGenericHF.py +0 -0
  131. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipHeader.py +0 -0
  132. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipLogger.py +0 -0
  133. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipMaxForwards.py +0 -0
  134. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipMsg.py +0 -0
  135. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipNumericHF.py +0 -0
  136. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipPAssertedIdentity.py +0 -0
  137. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipPath.py +0 -0
  138. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipProxyAuthenticate.py +0 -0
  139. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipProxyAuthorization.py +0 -0
  140. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipRAck.py +0 -0
  141. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipRSeq.py +0 -0
  142. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipReason.py +0 -0
  143. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipRecordRoute.py +0 -0
  144. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipReferTo.py +0 -0
  145. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipReferredBy.py +0 -0
  146. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipRegistrationAgent.py +0 -0
  147. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipReplaces.py +0 -0
  148. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipRequest.py +0 -0
  149. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipResponse.py +0 -0
  150. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipRoute.py +0 -0
  151. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipServer.py +0 -0
  152. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipSupported.py +0 -0
  153. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipTo.py +0 -0
  154. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipTransactionManager.py +0 -0
  155. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipURL.py +0 -0
  156. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipUserAgent.py +0 -0
  157. {sippy-2.3.0 → sippy-2.4.1}/sippy/SipWarning.py +0 -0
  158. {sippy-2.3.0 → sippy-2.4.1}/sippy/StatefulProxy.py +0 -0
  159. {sippy-2.3.0 → sippy-2.4.1}/sippy/Time/MonoTime.py +0 -0
  160. {sippy-2.3.0 → sippy-2.4.1}/sippy/Time/Timeout.py +0 -0
  161. {sippy-2.3.0 → sippy-2.4.1}/sippy/Time/__init__.py +0 -0
  162. {sippy-2.3.0 → sippy-2.4.1}/sippy/Time/clock_dtime.py +0 -0
  163. {sippy-2.3.0/tests → sippy-2.4.1/sippy/UI}/__init__.py +0 -0
  164. {sippy-2.3.0 → sippy-2.4.1}/sippy/UaStateDead.py +0 -0
  165. {sippy-2.3.0 → sippy-2.4.1}/sippy/UaStateDisconnected.py +0 -0
  166. {sippy-2.3.0 → sippy-2.4.1}/sippy/UaStateFailed.py +0 -0
  167. {sippy-2.3.0 → sippy-2.4.1}/sippy/UacStateCancelling.py +0 -0
  168. {sippy-2.3.0 → sippy-2.4.1}/sippy/UacStateIdle.py +0 -0
  169. {sippy-2.3.0 → sippy-2.4.1}/sippy/UacStateRinging.py +0 -0
  170. {sippy-2.3.0 → sippy-2.4.1}/sippy/UacStateTrying.py +0 -0
  171. {sippy-2.3.0 → sippy-2.4.1}/sippy/UasStateIdle.py +0 -0
  172. {sippy-2.3.0 → sippy-2.4.1}/sippy/Udp_server.py +0 -0
  173. {sippy-2.3.0 → sippy-2.4.1}/sippy/Wss_server.py +0 -0
  174. {sippy-2.3.0 → sippy-2.4.1}/sippy/XMPP_server.py +0 -0
  175. {sippy-2.3.0 → sippy-2.4.1}/sippy/__init__.py +0 -0
  176. {sippy-2.3.0 → sippy-2.4.1}/sippy/b2bua_simple.py +0 -0
  177. {sippy-2.3.0 → sippy-2.4.1}/sippy/dictionary +0 -0
  178. {sippy-2.3.0 → sippy-2.4.1}/sippy/misc.py +0 -0
  179. {sippy-2.3.0 → sippy-2.4.1}/sippy.egg-info/dependency_links.txt +0 -0
  180. {sippy-2.3.0 → sippy-2.4.1}/sippy.egg-info/entry_points.txt +0 -0
  181. {sippy-2.3.0 → sippy-2.4.1}/sippy.egg-info/top_level.txt +0 -0
  182. {sippy-2.3.0 → sippy-2.4.1}/tests/test_B2BRoute.py +0 -0
  183. {sippy-2.3.0 → sippy-2.4.1}/tests/test_B2BTransforms.py +0 -0
  184. {sippy-2.3.0 → sippy-2.4.1}/tests/test_Multipart.py +0 -0
  185. {sippy-2.3.0 → sippy-2.4.1}/tests/test_RtpParams.py +0 -0
  186. {sippy-2.3.0 → sippy-2.4.1}/tests/test_SdbBody.py +0 -0
  187. {sippy-2.3.0 → sippy-2.4.1}/tests/test_Udp_server.py +0 -0
@@ -2,3 +2,4 @@ include README.md
2
2
  include requirements.txt
3
3
  include sippy/dictionary
4
4
  recursive-include sippy/UI/static *
5
+ recursive-include sippy/UI/templates *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sippy
3
- Version: 2.3.0
3
+ Version: 2.4.1
4
4
  Summary: RFC3261 SIP Stack and Back-to-Back User Agent (B2BUA)
5
5
  Home-page: http://www.b2bua.org/
6
6
  Author: Sippy Software, Inc.
@@ -17,6 +17,8 @@ Requires-Dist: rtpsynth>=1.3.0
17
17
  Requires-Dist: g722>=1.2.3
18
18
  Requires-Dist: pycryptodome
19
19
  Requires-Dist: websockets
20
+ Requires-Dist: flask
21
+ Requires-Dist: flask-login
20
22
  Dynamic: author
21
23
  Dynamic: author-email
22
24
  Dynamic: classifier
@@ -3,3 +3,5 @@ rtpsynth>=1.3.0
3
3
  g722>=1.2.3
4
4
  pycryptodome
5
5
  websockets
6
+ flask
7
+ flask-login
@@ -12,7 +12,7 @@ with open("README.md", "r") as fh:
12
12
 
13
13
  setup(
14
14
  name = "sippy",
15
- version = "2.3.0",
15
+ version = "2.4.1",
16
16
  packages = find_packages(),
17
17
 
18
18
  install_requires = requirements,
@@ -40,32 +40,69 @@ DST_SIP_UA = 'sip-ua'
40
40
  DST_WSS_UA = 'wss-ua'
41
41
 
42
42
  class B2BRoute(object):
43
+ crt_set = False
44
+ params = None
45
+ extra_headers = None
43
46
  rnum = None
47
+ _ui_cats = {'auth': 'Outbound Digest Authentication', 'net': 'Network', 'lim': 'Limits',
48
+ 'num': 'Calling / Called Numbers', 'acct': 'Accounting'}
49
+ _ui_hints = {}
50
+ # _ui_hints['rnum'] = {'hidden': True}
44
51
  addrinfo = None
45
- cld = None
46
- cld_set = False
47
- hostport = None
48
- hostonly = None
49
- credit_time = None
50
- crt_set = False
51
- expires = None
52
- no_progress_expires = None
53
- no_reply_expires = None
54
- forward_on_fail = False
55
- user = None
56
- passw = None
52
+ # _ui_hints['addrinfo'] = {'readonly': True, 'category': _ui_cats['net'], 'hidden': True}
53
+ hostonly:str = None
54
+ # _ui_hints['hostonly'] = {'readonly': True, 'category': _ui_cats['net'], 'hidden': True}
55
+ ainfo = None
56
+ # _ui_hints['ainfo'] = {'readonly': True, 'category': _ui_cats['net'], 'hidden': True}
57
+ hostport:str = None
58
+ _ui_hints['hostport'] = {'name': 'Destination', 'description': 'Destination host:port',
59
+ 'category': _ui_cats['net']}
60
+ user:str = None
61
+ _ui_hints['user'] = {'name': 'SIP Username', 'category': _ui_cats['auth'],
62
+ 'active': lambda o: not o.pass_auth}
63
+ passw:str = None
64
+ _ui_hints['passw'] = {'name': 'SIP Password', 'category': _ui_cats['auth'], 'password': True,
65
+ 'active': lambda o: not o.pass_auth}
57
66
  pass_auth = True
58
- cli = None
67
+ _ui_hints['pass_auth'] = {'name': 'Mode', 'category': _ui_cats['auth'],
68
+ 'values': {False: 'Normal ("UAC")', True: 'Pass-through ("Proxy")'},}
69
+ _cld:str = None
70
+ _ui_hints['cld'] = {'name': 'Called Party (CLD)', 'description': 'Called party number',
71
+ 'category': _ui_cats['num'], 'type': str}
72
+ cld_set = False
73
+ _ui_hints['cld_set'] = {'name': 'CLD Mode', 'description': 'Controls outbound CLD',
74
+ 'category': _ui_cats['num'], 'active': lambda o: not o.cld,
75
+ 'values': lambda o: {True: 'Erase', False: 'Pass-through'}
76
+ if not o.cld else {True: 'Replace'}}
77
+ _cli:str = None
78
+ _ui_hints['cli'] = {'name': 'Calling Party (CLI)', 'description': 'Caller number',
79
+ 'category': _ui_cats['num'], 'type': str}
59
80
  cli_set = False
60
- params = None
61
- ainfo = None
62
- extra_headers = None
81
+ _ui_hints['cli_set'] = {'name': 'CLI Mode', 'description': 'Controls outbound CLI', 'category':
82
+ _ui_cats['num'], 'active': lambda o: not o.cli,
83
+ 'values': lambda o: {True: 'Erase', False: 'Pass-through'}
84
+ if not o.cli else {True: 'Replace'}}
85
+ credit_time:float = None
86
+ _ui_hints['credit_time'] = {'name': 'Credit Time', 'description': 'Allowed call duration, in seconds',
87
+ 'category': _ui_cats['lim']}
88
+ expires:float = None
89
+ _ui_hints['expires'] = {'name': 'Route Expiry', 'description': 'Time to expire the route, in seconds',
90
+ 'category': _ui_cats['lim']}
91
+ no_progress_expires:float = None
92
+ _ui_hints['no_progress_expires'] = {'name': 'No Progress Timeout', 'category': _ui_cats['lim'],
93
+ 'description': 'Time to expire the route if no 180 or 183 provisional response received, in seconds'}
94
+ no_reply_expires:float = None
95
+ _ui_hints['no_reply_expires'] = {'name': 'No Reply Timeout', 'category': _ui_cats['lim'],
96
+ 'description': 'Time to expire the route if no provisional response received, in seconds'}
97
+ forward_on_fail = False
98
+ _ui_hints['forward_on_fail'] = {'name': 'Failed Calls', 'category': _ui_cats['acct'],
99
+ 'description': 'Emit accounting on SIP failures'}
63
100
 
64
101
  def __init__(self, sroute = None, cself = None):
65
102
  if cself != None:
66
103
  self.rnum = cself.rnum
67
104
  self.addrinfo = cself.addrinfo
68
- self.cld = cself.cld
105
+ self._cld = cself.cld
69
106
  self.cld_set = cself.cld_set
70
107
  self.hostport = cself.hostport
71
108
  self.hostonly = cself.hostonly
@@ -78,7 +115,7 @@ class B2BRoute(object):
78
115
  self.user = cself.user
79
116
  self.passw = cself.passw
80
117
  self.pass_auth = cself.pass_auth
81
- self.cli = cself.cli
118
+ self._cli = cself.cli
82
119
  self.cli_set = cself.cli_set
83
120
  self.params = dict(cself.params)
84
121
  self.ainfo = cself.ainfo
@@ -93,7 +130,6 @@ class B2BRoute(object):
93
130
  # as opposed to the Routing:host, which means that CLD should be obtained
94
131
  # from the incoming call leg.
95
132
  self.cld = None
96
- self.cld_set = True
97
133
  else:
98
134
  self.hostport = route[0]
99
135
  if not self.hostport.startswith('['):
@@ -147,7 +183,6 @@ class B2BRoute(object):
147
183
  self.cli = v
148
184
  if len(self.cli) == 0:
149
185
  self.cli = None
150
- self.cli_set = True
151
186
  elif a == 'cnam':
152
187
  caller_name = unquote(v)
153
188
  if len(caller_name) == 0:
@@ -175,9 +210,9 @@ class B2BRoute(object):
175
210
  pass_headers, max_credit_time):
176
211
  self.rnum = rnum
177
212
  if not self.cld_set:
178
- self.cld = default_cld
213
+ self._cld = default_cld
179
214
  if not self.cli_set:
180
- self.cli = default_cli
215
+ self._cli = default_cli
181
216
  if not self.crt_set:
182
217
  self.crt_set = default_credit_time
183
218
  if 'gt' in self.params:
@@ -210,3 +245,21 @@ class B2BRoute(object):
210
245
  if af == AF_INET6:
211
246
  return ((('[%s]' % amatch[0], amatch[1]), same_af))
212
247
  return (((amatch[0], amatch[1]), same_af))
248
+
249
+ @property
250
+ def cli(self):
251
+ return self._cli
252
+
253
+ @cli.setter
254
+ def cli(self, value):
255
+ self._cli = value
256
+ self.cli_set = True
257
+
258
+ @property
259
+ def cld(self):
260
+ return self._cld
261
+
262
+ @cld.setter
263
+ def cld(self, value):
264
+ self._cld = value
265
+ self.cld_set = True
@@ -116,10 +116,11 @@ class B2BSimpleAPI(CLIConnectionManager):
116
116
  clim.send('OK\n')
117
117
  return False
118
118
  if cmd == 'r':
119
- if len(args) != 1:
120
- clim.send('ERROR: syntax error: r [<id>]\n')
119
+ if len(args) not in (1, 2):
120
+ clim.send('ERROR: syntax error: r <id> [<media-index>]\n')
121
121
  return False
122
122
  idx = int(args[0])
123
+ media_index = int(args[1]) if len(args) == 2 else 0
123
124
  dlist = [x for x in ccm.ccmap if x.id == idx]
124
125
  if len(dlist) == 0:
125
126
  clim.send('ERROR: no call with id of %d has been found\n' % idx)
@@ -128,9 +129,12 @@ class B2BSimpleAPI(CLIConnectionManager):
128
129
  if not cc.proxied:
129
130
  continue
130
131
  if cc.state == CCStateConnected:
131
- cc.disconnect(MonoTime().getOffsetCopy(-60), origin = 'media_timeout')
132
+ cc.disconnect(MonoTime().getOffsetCopy(-60), origin = 'media_timeout',
133
+ media_index = media_index)
132
134
  continue
133
135
  if cc.state == CCStateARComplete:
136
+ if cc.rtp_proxy_session is not None:
137
+ cc.rtp_proxy_session.media_timeout_index = media_index
134
138
  cc.uaO.disconnect(MonoTime().getOffsetCopy(-60), origin = 'media_timeout')
135
139
  continue
136
140
  clim.send('OK\n')
@@ -104,9 +104,13 @@ SUPPORTED_OPTIONS = { \
104
104
  '"host:port:cert_file:key_file", where "cert_file" ' \
105
105
  '/ "key_file" are paths to the TLS certificate ' \
106
106
  'and key file respectively in the X.509 PEM format'),
107
- 'pre_auth_proc': ('S', 'internal routine to be executed before authentication '\
108
- 'is being processed. E.g. "HDR2Xattrs[X-foo-hdr]."'), \
109
- 'xmpp_b2bua_id': ('I', 'ID passed to the XMPP socket server')}
107
+ 'pre_auth_proc': ('S', 'internal routine to be executed before authentication '\
108
+ 'is being processed. E.g. "HDR2Xattrs[X-foo-hdr]."'), \
109
+ 'xmpp_b2bua_id': ('I', 'ID passed to the XMPP socket server'), \
110
+ 'ui': ('B', 'enable Web management UI'), \
111
+ 'uiparams': ('S', 'Semicolon-separated list of UI parameters corresponding to ' \
112
+ 'the flask\'s run() routine'), \
113
+ }
110
114
 
111
115
  class MyConfigParser(RawConfigParser):
112
116
  _default_section = None
@@ -2,6 +2,7 @@ from typing import Optional, Tuple
2
2
  from uuid import uuid4, UUID
3
3
  from threading import Lock
4
4
  import errno
5
+ import weakref
5
6
 
6
7
  from rtpsynth.RtpServer import RtpQueueFullError, RtpServer
7
8
  from sippy.Time.MonoTime import MonoTime
@@ -14,9 +15,12 @@ from .Singletons import acquire_rtp_server, release_rtp_server
14
15
 
15
16
  class RTPEPoint():
16
17
  debug: bool = False
18
+ rtp_received_lock_timeout = 0.01
17
19
  id: UUID
18
20
  dl_file = None
19
21
  firstframe = True
22
+ writer = None
23
+ rserv = None
20
24
  rtp_params:RTPParams
21
25
  state_lock: Lock
22
26
  handlers: RTPHandlers
@@ -29,7 +33,6 @@ class RTPEPoint():
29
33
  self._palloc = rc.palloc
30
34
  self._rtp_server = None
31
35
  self.state_lock = Lock()
32
- self.writer = None
33
36
  self.rsess = self.make_rtp_instream(rtp_params, audio_in)
34
37
  rserv_opts = self.make_udp_server_opts(rtp_params)
35
38
  self.rserv = self.make_udp_server(rserv_opts)
@@ -46,6 +49,28 @@ class RTPEPoint():
46
49
  palloc = self._palloc if rtp_params.rtp_lport == 0 else rtp_params.rtp_lport
47
50
  return (rtp_params.rtp_laddr, palloc)
48
51
 
52
+ def _make_rtp_received_cb(self):
53
+ self_ref = weakref.ref(self)
54
+
55
+ def rtp_received_cb(data, address, rtime_ns=None):
56
+ self = self_ref()
57
+ if self is None:
58
+ return
59
+ return self.rtp_received(data, address, rtime_ns)
60
+
61
+ return rtp_received_cb
62
+
63
+ def _make_send_pkt_cb(self):
64
+ self_ref = weakref.ref(self)
65
+
66
+ def send_pkt_cb(pkt):
67
+ self = self_ref()
68
+ if self is None:
69
+ return
70
+ return self.send_pkt(pkt)
71
+
72
+ return send_pkt_cb
73
+
49
74
  def make_udp_server(self, rserv_opts):
50
75
  rtp_laddr, palloc = rserv_opts
51
76
  server_cls = self.handlers.rtp_server_cls
@@ -67,7 +92,7 @@ class RTPEPoint():
67
92
 
68
93
  def _create_channel(self, rtp_server:RtpServer, bind_host:str, bind_port:int):
69
94
  bind_family = self.rtp_params.rtp_family
70
- ch_kwargs = dict(pkt_in=self.rtp_received, bind_host=bind_host, bind_port=bind_port)
95
+ ch_kwargs = dict(pkt_in=self._make_rtp_received_cb(), bind_host=bind_host, bind_port=bind_port)
71
96
  ch = rtp_server.create_channel(bind_family=bind_family, **ch_kwargs)
72
97
  self.rtp_params.rtp_lport = bind_port
73
98
  return ch
@@ -113,7 +138,7 @@ class RTPEPoint():
113
138
  def writer_setup(self):
114
139
  assert self.writer is None
115
140
  writer = self.make_writer(self.rtp_params)
116
- writer.set_pkt_send_f(self.send_pkt)
141
+ writer.set_pkt_send_f(self._make_send_pkt_cb())
117
142
  if self.dl_file is not None:
118
143
  writer.enable_datalog(self.dl_file)
119
144
  writer.start()
@@ -134,12 +159,18 @@ class RTPEPoint():
134
159
  rtime = MonoTime().monot
135
160
  else:
136
161
  rtime = rtime_ns / 1_000_000_000.0
137
- with self.state_lock:
162
+ if not self.state_lock.acquire(timeout=self.rtp_received_lock_timeout):
163
+ if self.debug:
164
+ print(f'RTP.EPoint.rtp_received[{str(self.id)[:6]}]: state lock timeout')
165
+ return
166
+ try:
138
167
  target = self.rtp_params.rtp_target
139
168
  if target is not None and address != target:
140
169
  if self.debug:
141
170
  print(f"InfernRTPIngest.rtp_received: address mismatch {address=} {self.rtp_params.rtp_target=}")
142
171
  return
172
+ finally:
173
+ self.state_lock.release()
143
174
  self.rsess.rtp_received(data, address, rtime)
144
175
 
145
176
  def update(self, rtp_params:RTPParams):
@@ -176,7 +207,7 @@ class RTPEPoint():
176
207
  channel.set_target(target[0], target[1])
177
208
  if need_new_writer:
178
209
  new_writer = self.make_writer(rtp_params)
179
- new_writer.set_pkt_send_f(self.send_pkt)
210
+ new_writer.set_pkt_send_f(self._make_send_pkt_cb())
180
211
  if self.dl_file is not None:
181
212
  new_writer.enable_datalog(self.dl_file)
182
213
  new_writer.start()
@@ -195,12 +226,10 @@ class RTPEPoint():
195
226
  def shutdown(self):
196
227
  with self.state_lock:
197
228
  writer, channel, rtp_server = self.writer, self.rserv, self._rtp_server
198
- self.writer, self._rtp_server = (None, None)
229
+ self.writer, self.rserv, self._rtp_server = (None, None, None)
199
230
  if writer is not None:
200
231
  writer.end()
201
232
  writer.join()
202
- with self.state_lock:
203
- self.rserv = None
204
233
  if channel is not None:
205
234
  channel.close()
206
235
  if rtp_server is not None:
@@ -209,6 +238,7 @@ class RTPEPoint():
209
238
  def __del__(self):
210
239
  if self.debug:
211
240
  print('RTP.EPoint.__del__')
241
+ self.shutdown()
212
242
 
213
243
  def soundout(self, chunk:AudioChunk):
214
244
  if self.firstframe:
@@ -34,9 +34,7 @@ from sippy.Rtp_proxy.cmd import Rtp_proxy_cmd
34
34
  from sippy.Rtp_proxy.Client.net import Rtp_proxy_client_net
35
35
 
36
36
  from socket import SOCK_DGRAM, AF_INET
37
- from time import time
38
- from hashlib import md5
39
- from random import random
37
+ from secrets import token_hex
40
38
 
41
39
  def getnretrans(first_rert, timeout):
42
40
  if first_rert <= 0:
@@ -93,8 +91,7 @@ class Rtp_proxy_client_udp(Rtp_proxy_client_net):
93
91
  self.delay_flt = recfilter(0.95, 0.25)
94
92
 
95
93
  def send_command(self, command, result_callback = None, *callback_parameters):
96
- entropy = str(random()) + str(time())
97
- cookie = md5(entropy.encode()).hexdigest()
94
+ cookie = token_hex(16)
98
95
  next_retr = self.delay_flt.lastval * 4.0
99
96
  exp_time = 3.0
100
97
  if isinstance(command, Rtp_proxy_cmd):
@@ -90,9 +90,8 @@ class _rtpps_side(object):
90
90
  command += ' %s %s %d %s %s' % ('%s-%d' % (up.rtpps.call_id, up.index), up.remote_ip, up.remote_port, from_tag, to_tag)
91
91
  else:
92
92
  command += ' %s %s %d %s' % ('%s-%d' % (up.rtpps.call_id, up.index), up.remote_ip, up.remote_port, from_tag)
93
- if up.rtpps.notify_socket != None and up.index == 0 and \
94
- rtpc.tnot_supported:
95
- command += ' %s %s' % (up.rtpps.notify_socket, up.rtpps.notify_tag)
93
+ if up.rtpps.notify_socket is not None and up.rtpps.notify_tag is not None and rtpc.tnot_supported:
94
+ command += ' %s %s' % (up.rtpps.notify_socket, up.rtpps.get_notify_tag(up.index))
96
95
  if len(up.subcommands) > 0:
97
96
  command = ' && '.join([command,] + [sc for subc in up.subcommands for sc in subc.commands])
98
97
  rtpq.send_command(command, self.update_result, up)
@@ -25,9 +25,12 @@
25
25
  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
26
 
27
27
  from functools import partial
28
- from hashlib import md5
29
28
  from random import random
30
- from time import time
29
+ from secrets import token_hex
30
+ try:
31
+ from urllib import quote, unquote
32
+ except ImportError:
33
+ from urllib.parse import quote, unquote
31
34
  try:
32
35
  from _thread import get_ident
33
36
  except ImportError:
@@ -52,6 +55,7 @@ class Rtp_proxy_session(object):
52
55
  max_index = -1
53
56
  notify_socket = None
54
57
  notify_tag = None
58
+ media_timeout_index = None
55
59
  global_config = None
56
60
  my_ident = None
57
61
  insert_nortpp = False
@@ -74,20 +78,18 @@ class Rtp_proxy_session(object):
74
78
  if call_id != None:
75
79
  self.call_id = call_id
76
80
  else:
77
- salt = str(random()) + str(time())
78
- self.call_id = md5(salt.encode()).hexdigest()
81
+ self.call_id = token_hex(16)
79
82
  if from_tag != None:
80
83
  self.from_tag = from_tag
81
84
  else:
82
- salt = str(random()) + str(time())
83
- self.from_tag = md5(salt.encode()).hexdigest()
85
+ self.from_tag = token_hex(16)
84
86
  if to_tag != None:
85
87
  self.to_tag = to_tag
86
88
  else:
87
- salt = str(random()) + str(time())
88
- self.to_tag = md5(salt.encode()).hexdigest()
89
+ self.to_tag = token_hex(16)
89
90
  self.notify_socket = self.rtp_proxy_client.notify_socket
90
91
  self.notify_tag = notify_tag
92
+ self.media_timeout_index = None
91
93
  self.caller = _rtpps_side('caller')
92
94
  self.callee = _rtpps_side('callee')
93
95
 
@@ -147,12 +149,18 @@ class Rtp_proxy_session(object):
147
149
  command = make_command('o')
148
150
  return self.rtpp_seq.send_command(command, result_callback)
149
151
 
152
+ def get_notify_tag(self, index):
153
+ if index == 0:
154
+ return self.notify_tag
155
+ return quote('%s %d' % (unquote(self.notify_tag), index))
156
+
150
157
  def delete(self):
151
158
  if self.rtp_proxy_client == None:
152
159
  return
153
160
  while self.max_index >= 0:
154
- command = 'D %s %s %s' % ('%s-%d' % (self.call_id, self.max_index), self.from_tag, self.to_tag)
155
- self.rtpp_seq.send_command(command)
161
+ if self.media_timeout_index is None or self.max_index != self.media_timeout_index:
162
+ command = 'D %s %s %s' % ('%s-%d' % (self.call_id, self.max_index), self.from_tag, self.to_tag)
163
+ self.rtpp_seq.send_command(command)
156
164
  self.max_index -= 1
157
165
  self.rtp_proxy_client = None
158
166
  self.rtpp_seq.delete()
@@ -27,12 +27,16 @@
27
27
 
28
28
  from functools import partial
29
29
  from base64 import b64encode, b64decode
30
+ from hmac import compare_digest, new as hmac_new
31
+ from secrets import token_bytes
30
32
 
31
- from Crypto import Random
32
33
  from Crypto.Cipher import AES
33
34
 
34
35
  from sippy.Time.clock_dtime import clock_getntime, CLOCK_MONOTONIC
35
36
 
37
+ AES_BLOCK_SIZE = AES.block_size
38
+ MAC_SIZE = 16
39
+
36
40
  to_bytes_be = partial(int.to_bytes, byteorder='big')
37
41
  from_bytes_be = partial(int.from_bytes, byteorder='big')
38
42
 
@@ -43,23 +47,30 @@ def bxor(ba1, ba2):
43
47
  return to_bytes_be(ba1 ^ ba2, olen)
44
48
 
45
49
  class AESCipher(object):
46
- bpad = '='.encode()
47
50
  cipher = None
51
+ mac_key = None
48
52
 
49
53
  def __init__(self, key):
50
- self.cipher = AES.new(key, AES.MODE_ECB)
54
+ self.cipher = AES.new(key[:AES_BLOCK_SIZE * 2], AES.MODE_ECB)
55
+ self.mac_key = key[AES_BLOCK_SIZE * 2:]
51
56
 
52
57
  def encrypt(self, raw):
53
- iv = Random.new().read(AES.block_size)
58
+ iv = token_bytes(AES_BLOCK_SIZE)
54
59
  raw = bxor(raw, iv)
55
60
  eraw = self.cipher.encrypt(iv + raw)
56
- return b64encode(eraw)[:-1]
61
+ eraw += hmac_new(self.mac_key, eraw, 'sha256').digest()[:MAC_SIZE]
62
+ return b64encode(eraw).rstrip(b'=')
57
63
 
58
64
  def decrypt(self, enc):
59
- enc = b64decode(enc + self.bpad)
60
- raw = self.cipher.decrypt(enc)
61
- iv = raw[:AES.block_size]
62
- return bxor(raw[AES.block_size:], iv)
65
+ enc = b64decode(enc + (b'=' * (-len(enc) % 4)))
66
+ data = enc[:-MAC_SIZE]
67
+ tag = enc[-MAC_SIZE:]
68
+ ctag = hmac_new(self.mac_key, data, 'sha256').digest()[:MAC_SIZE]
69
+ if not compare_digest(ctag, tag):
70
+ raise ValueError
71
+ raw = self.cipher.decrypt(data)
72
+ iv = raw[:AES_BLOCK_SIZE]
73
+ return bxor(raw[AES_BLOCK_SIZE:], iv)
63
74
 
64
75
  DGST_MD5 = (1 << 0)
65
76
  DGST_MD5SESS = (1 << 1)
@@ -72,7 +83,7 @@ DGST_PRIOS = (DGST_SHA512, DGST_SHA512SESS, DGST_SHA256, DGST_SHA256SESS, DGST_M
72
83
 
73
84
  class HashOracle(object):
74
85
  try: key # pylint: disable=used-before-assignment
75
- except: key = Random.new().read(AES.block_size * 2)
86
+ except: key = token_bytes(AES_BLOCK_SIZE * 4)
76
87
  ac = None
77
88
  vtime = 32 * 10**9
78
89
 
@@ -83,13 +94,16 @@ class HashOracle(object):
83
94
  ts128 = clock_getntime(CLOCK_MONOTONIC) << len(DGST_PRIOS)
84
95
  for ms in cmask:
85
96
  ts128 |= ms
86
- cryptic = self.ac.encrypt(to_bytes_be(ts128, AES.block_size))
97
+ cryptic = self.ac.encrypt(to_bytes_be(ts128, AES_BLOCK_SIZE))
87
98
  #return cryptic
88
99
  return cryptic.decode()
89
100
 
90
101
  def validate_challenge(self, cryptic, cmask):
91
102
  new_ts = clock_getntime(CLOCK_MONOTONIC)
92
- decryptic = from_bytes_be(self.ac.decrypt(cryptic.encode()))
103
+ try:
104
+ decryptic = from_bytes_be(self.ac.decrypt(cryptic.encode()))
105
+ except ValueError:
106
+ return False
93
107
  for ms in cmask:
94
108
  if (ms & decryptic) == 0:
95
109
  return False
@@ -28,24 +28,11 @@ from sippy.SipGenericHF import SipGenericHF
28
28
  from sippy.Security.SipNonce import HashOracle, DGST_MD5, DGST_MD5SESS, \
29
29
  DGST_SHA256, DGST_SHA256SESS, DGST_SHA512, DGST_SHA512SESS
30
30
 
31
- from hashlib import md5, sha256
31
+ from hashlib import md5, new as hash_new, sha256
32
32
 
33
- from Crypto.Hash import SHA512
34
33
 
35
- class sha512_256(object):
36
- d = None
37
-
38
- def __init__(self):
39
- self.d = SHA512.new(truncate = '256')
40
-
41
- def update(self, arg):
42
- self.d.update(arg)
43
-
44
- def digest(self):
45
- return self.d.digest()
46
-
47
- def hexdigest(self):
48
- return self.d.hexdigest()
34
+ def sha512_256():
35
+ return hash_new('sha512_256')
49
36
 
50
37
  _HASH_FUNC = {None:(md5, DGST_MD5), 'MD5':(md5, DGST_MD5), 'MD5-sess':(md5, DGST_MD5SESS), \
51
38
  'SHA-256':(sha256, DGST_SHA256), 'SHA-256-sess':(sha256, DGST_SHA256SESS), \
@@ -25,9 +25,8 @@
25
25
  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
26
 
27
27
  from random import random
28
- from hashlib import md5
29
- from time import time
30
28
  from math import floor
29
+ from secrets import token_hex
31
30
  from sippy.SipConf import SipConf
32
31
  from sippy.SipGenericHF import SipGenericHF
33
32
 
@@ -58,8 +57,7 @@ class SipCallId(SipGenericHF):
58
57
  return SipCallId(self.body + str(other))
59
58
 
60
59
  def genCallId(self):
61
- salt = str((random() * 1000000000) + time())
62
- self.body = md5(salt.encode()).hexdigest()
60
+ self.body = token_hex(16)
63
61
 
64
62
  def getCanName(self, name, compact = False):
65
63
  if compact:
@@ -24,9 +24,7 @@
24
24
  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
25
  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
26
 
27
- from random import random
28
- from hashlib import md5
29
- from time import time
27
+ from secrets import token_bytes
30
28
  from sippy.SipGenericHF import SipGenericHF
31
29
 
32
30
  class SipCiscoGUID(SipGenericHF):
@@ -41,9 +39,8 @@ class SipCiscoGUID(SipGenericHF):
41
39
  if ciscoGUID != None:
42
40
  self.ciscoGUID = ciscoGUID
43
41
  else:
44
- salt = str((random() * 1000000000) + time())
45
- s = md5(salt.encode()).hexdigest()
46
- self.ciscoGUID = (int(s[0:8], 16), int(s[8:16], 16), int(s[16:24], 16), int(s[24:32], 16))
42
+ s = token_bytes(16)
43
+ self.ciscoGUID = tuple(int.from_bytes(s[i:i + 4], 'big') for i in range(0, 16, 4))
47
44
 
48
45
  def parse(self):
49
46
  self.ciscoGUID = tuple([int(x) for x in self.body.split('-', 3)])
@@ -25,9 +25,8 @@
25
25
  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
26
 
27
27
  from random import random
28
- from hashlib import md5
29
- from time import time
30
28
  from math import floor
29
+ from secrets import token_hex
31
30
  from sippy.SipAddressHF import SipAddressHF
32
31
  from sippy.SipAddress import SipAddress
33
32
  from sippy.SipURL import SipURL
@@ -57,8 +56,7 @@ class SipFrom(SipAddressHF):
57
56
  return self.address.getParam('tag')
58
57
 
59
58
  def genTag(self):
60
- salt = str((random() * 1000000000) + time())
61
- self.address.setParam('tag', md5(salt.encode()).hexdigest())
59
+ self.address.setParam('tag', token_hex(16))
62
60
 
63
61
  def setTag(self, value):
64
62
  self.address.setParam('tag', value)
@@ -25,8 +25,7 @@
25
25
  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
26
 
27
27
  from random import random
28
- from hashlib import md5
29
- from time import time
28
+ from secrets import token_hex
30
29
  from sippy.SipGenericHF import SipGenericHF
31
30
  from sippy.SipConf import SipConf
32
31
  from sippy.ESipHeaderCSV import ESipHeaderCSV
@@ -131,8 +130,7 @@ class SipVia(SipGenericHF):
131
130
  return SipVia(cself=self)
132
131
 
133
132
  def genBranch(self):
134
- salt = str((random() * 1000000000) + time())
135
- self.params['branch'] = 'z9hG4bK' + md5(salt.encode()).hexdigest()
133
+ self.params['branch'] = 'z9hG4bK' + token_hex(16)
136
134
 
137
135
  def getBranch(self):
138
136
  return self.params.get('branch', None)