synapse 2.190.0__py311-none-any.whl → 2.192.0__py311-none-any.whl

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.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (49) hide show
  1. synapse/axon.py +54 -23
  2. synapse/common.py +9 -0
  3. synapse/cortex.py +3 -2
  4. synapse/datamodel.py +8 -1
  5. synapse/lib/ast.py +6 -2
  6. synapse/lib/cell.py +55 -7
  7. synapse/lib/msgpack.py +10 -3
  8. synapse/lib/nexus.py +2 -1
  9. synapse/lib/stormhttp.py +32 -35
  10. synapse/lib/stormlib/model.py +37 -0
  11. synapse/lib/stormtypes.py +102 -20
  12. synapse/lib/version.py +2 -2
  13. synapse/models/auth.py +2 -1
  14. synapse/models/base.py +20 -0
  15. synapse/models/crypto.py +5 -2
  16. synapse/models/economic.py +45 -11
  17. synapse/models/inet.py +78 -21
  18. synapse/models/person.py +11 -4
  19. synapse/models/risk.py +6 -0
  20. synapse/models/syn.py +22 -12
  21. synapse/models/telco.py +3 -1
  22. synapse/tests/test_axon.py +10 -0
  23. synapse/tests/test_cortex.py +60 -17
  24. synapse/tests/test_lib_agenda.py +1 -6
  25. synapse/tests/test_lib_ast.py +6 -0
  26. synapse/tests/test_lib_cell.py +63 -4
  27. synapse/tests/test_lib_httpapi.py +11 -6
  28. synapse/tests/test_lib_lmdbslab.py +1 -4
  29. synapse/tests/test_lib_stormhttp.py +57 -12
  30. synapse/tests/test_lib_stormlib_cortex.py +1 -3
  31. synapse/tests/test_lib_stormlib_log.py +1 -6
  32. synapse/tests/test_lib_stormlib_model.py +28 -0
  33. synapse/tests/test_lib_stormtypes.py +1 -2
  34. synapse/tests/test_lib_trigger.py +2 -3
  35. synapse/tests/test_model_base.py +12 -2
  36. synapse/tests/test_model_inet.py +23 -0
  37. synapse/tests/test_model_person.py +2 -0
  38. synapse/tests/test_model_risk.py +5 -0
  39. synapse/tests/test_model_syn.py +198 -0
  40. synapse/tests/test_servers_univ.py +0 -12
  41. synapse/tests/test_tools_apikey.py +227 -0
  42. synapse/tests/test_utils.py +23 -4
  43. synapse/tests/utils.py +39 -5
  44. synapse/tools/apikey.py +93 -0
  45. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/METADATA +4 -4
  46. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/RECORD +49 -47
  47. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/LICENSE +0 -0
  48. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/WHEEL +0 -0
  49. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/top_level.txt +0 -0
synapse/axon.py CHANGED
@@ -594,7 +594,7 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
594
594
  return await self.cell.dels(sha256s)
595
595
 
596
596
  async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
597
- ssl=True, timeout=None, proxy=None, ssl_opts=None):
597
+ ssl=True, timeout=None, proxy=True, ssl_opts=None):
598
598
  '''
599
599
  Stream a file download directly into the Axon.
600
600
 
@@ -607,6 +607,7 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
607
607
  method (str): The HTTP method to use.
608
608
  ssl (bool): Perform SSL verification.
609
609
  timeout (int): The timeout of the request, in seconds.
610
+ proxy (str|bool): The proxy value.
610
611
  ssl_opts (dict): Additional SSL/TLS options.
611
612
 
612
613
  Notes:
@@ -621,6 +622,13 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
621
622
  'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
622
623
  }
623
624
 
625
+ The following proxy arguments are supported::
626
+
627
+ None: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
628
+ True: Use the proxy defined by the http:proxy configuration option if set.
629
+ False: Do not use the proxy defined by the http:proxy configuration option if set.
630
+ <str>: A proxy URL string.
631
+
624
632
  The dictionary returned by this may contain the following values::
625
633
 
626
634
  {
@@ -654,13 +662,13 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
654
662
  ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
655
663
 
656
664
  async def postfiles(self, fields, url, params=None, headers=None, method='POST',
657
- ssl=True, timeout=None, proxy=None, ssl_opts=None):
665
+ ssl=True, timeout=None, proxy=True, ssl_opts=None):
658
666
  await self._reqUserAllowed(('axon', 'wput'))
659
667
  return await self.cell.postfiles(fields, url, params=params, headers=headers, method=method,
660
668
  ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
661
669
 
662
670
  async def wput(self, sha256, url, params=None, headers=None, method='PUT',
663
- ssl=True, timeout=None, proxy=None, ssl_opts=None):
671
+ ssl=True, timeout=None, proxy=True, ssl_opts=None):
664
672
  await self._reqUserAllowed(('axon', 'wput'))
665
673
  return await self.cell.wput(sha256, url, params=params, headers=headers, method=method,
666
674
  ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
@@ -935,6 +943,24 @@ class Axon(s_cell.Cell):
935
943
  self.axonhist.add(item, tick=tick)
936
944
  self.axonseqn.add(item)
937
945
 
946
+ async def _resolveProxyUrl(self, valu):
947
+ match valu:
948
+ case None:
949
+ s_common.deprecated('Setting the Axon HTTP proxy argument to None', curv='2.192.0')
950
+ return await self.getConfOpt('http:proxy')
951
+
952
+ case True:
953
+ return await self.getConfOpt('http:proxy')
954
+
955
+ case False:
956
+ return None
957
+
958
+ case str():
959
+ return valu
960
+
961
+ case _:
962
+ raise s_exc.BadArg(mesg='HTTP proxy argument must be a string or bool.')
963
+
938
964
  async def _reqHas(self, sha256):
939
965
  '''
940
966
  Ensure a file exists; and return its size if so.
@@ -1462,7 +1488,7 @@ class Axon(s_cell.Cell):
1462
1488
  sha256=sha256) from None
1463
1489
 
1464
1490
  async def postfiles(self, fields, url, params=None, headers=None, method='POST',
1465
- ssl=True, timeout=None, proxy=None, ssl_opts=None):
1491
+ ssl=True, timeout=None, proxy=True, ssl_opts=None):
1466
1492
  '''
1467
1493
  Send files from the axon as fields in a multipart/form-data HTTP request.
1468
1494
 
@@ -1474,7 +1500,7 @@ class Axon(s_cell.Cell):
1474
1500
  method (str): The HTTP method to use.
1475
1501
  ssl (bool): Perform SSL verification.
1476
1502
  timeout (int): The timeout of the request, in seconds.
1477
- proxy (bool|str|null): Use a specific proxy or disable proxy use.
1503
+ proxy (str|bool): The proxy value.
1478
1504
  ssl_opts (dict): Additional SSL/TLS options.
1479
1505
 
1480
1506
  Notes:
@@ -1497,6 +1523,13 @@ class Axon(s_cell.Cell):
1497
1523
  'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
1498
1524
  }
1499
1525
 
1526
+ The following proxy arguments are supported::
1527
+
1528
+ None: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
1529
+ True: Use the proxy defined by the http:proxy configuration option if set.
1530
+ False: Do not use the proxy defined by the http:proxy configuration option if set.
1531
+ <str>: A proxy URL string.
1532
+
1500
1533
  The dictionary returned by this may contain the following values::
1501
1534
 
1502
1535
  {
@@ -1512,14 +1545,11 @@ class Axon(s_cell.Cell):
1512
1545
  Returns:
1513
1546
  dict: An information dictionary containing the results of the request.
1514
1547
  '''
1515
- if proxy is None:
1516
- proxy = self.conf.get('http:proxy')
1517
-
1518
1548
  ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
1519
1549
 
1520
1550
  connector = None
1521
- if proxy:
1522
- connector = aiohttp_socks.ProxyConnector.from_url(proxy)
1551
+ if proxyurl := await self._resolveProxyUrl(proxy):
1552
+ connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
1523
1553
 
1524
1554
  atimeout = aiohttp.ClientTimeout(total=timeout)
1525
1555
 
@@ -1583,18 +1613,15 @@ class Axon(s_cell.Cell):
1583
1613
  }
1584
1614
 
1585
1615
  async def wput(self, sha256, url, params=None, headers=None, method='PUT', ssl=True, timeout=None,
1586
- filename=None, filemime=None, proxy=None, ssl_opts=None):
1616
+ filename=None, filemime=None, proxy=True, ssl_opts=None):
1587
1617
  '''
1588
1618
  Stream a blob from the axon as the body of an HTTP request.
1589
1619
  '''
1590
- if proxy is None:
1591
- proxy = self.conf.get('http:proxy')
1592
-
1593
1620
  ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
1594
1621
 
1595
1622
  connector = None
1596
- if proxy:
1597
- connector = aiohttp_socks.ProxyConnector.from_url(proxy)
1623
+ if proxyurl := await self._resolveProxyUrl(proxy):
1624
+ connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
1598
1625
 
1599
1626
  atimeout = aiohttp.ClientTimeout(total=timeout)
1600
1627
 
@@ -1654,7 +1681,7 @@ class Axon(s_cell.Cell):
1654
1681
  return info
1655
1682
 
1656
1683
  async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
1657
- ssl=True, timeout=None, proxy=None, ssl_opts=None):
1684
+ ssl=True, timeout=None, proxy=True, ssl_opts=None):
1658
1685
  '''
1659
1686
  Stream a file download directly into the Axon.
1660
1687
 
@@ -1667,7 +1694,7 @@ class Axon(s_cell.Cell):
1667
1694
  method (str): The HTTP method to use.
1668
1695
  ssl (bool): Perform SSL verification.
1669
1696
  timeout (int): The timeout of the request, in seconds.
1670
- proxy (bool|str|null): Use a specific proxy or disable proxy use.
1697
+ proxy (str|bool): The proxy value.
1671
1698
  ssl_opts (dict): Additional SSL/TLS options.
1672
1699
 
1673
1700
  Notes:
@@ -1682,6 +1709,13 @@ class Axon(s_cell.Cell):
1682
1709
  'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
1683
1710
  }
1684
1711
 
1712
+ The following proxy arguments are supported::
1713
+
1714
+ None: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
1715
+ True: Use the proxy defined by the http:proxy configuration option if set.
1716
+ False: Do not use the proxy defined by the http:proxy configuration option if set.
1717
+ <str>: A proxy URL string.
1718
+
1685
1719
  The dictionary returned by this may contain the following values::
1686
1720
 
1687
1721
  {
@@ -1712,14 +1746,11 @@ class Axon(s_cell.Cell):
1712
1746
  '''
1713
1747
  logger.debug(f'Wget called for [{url}].', extra=await self.getLogExtra(url=s_urlhelp.sanitizeUrl(url)))
1714
1748
 
1715
- if proxy is None:
1716
- proxy = self.conf.get('http:proxy')
1717
-
1718
1749
  ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
1719
1750
 
1720
1751
  connector = None
1721
- if proxy:
1722
- connector = aiohttp_socks.ProxyConnector.from_url(proxy)
1752
+ if proxyurl := await self._resolveProxyUrl(proxy):
1753
+ connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
1723
1754
 
1724
1755
  atimeout = aiohttp.ClientTimeout(total=timeout)
1725
1756
 
synapse/common.py CHANGED
@@ -1368,3 +1368,12 @@ def _timeout(delay):
1368
1368
  """
1369
1369
  loop = asyncio.get_running_loop()
1370
1370
  return _Timeout(loop.time() + delay if delay is not None else None)
1371
+
1372
+ def format(text, **kwargs):
1373
+ '''
1374
+ Similar to python str.format() but treats tokens as opaque.
1375
+ '''
1376
+ for name, valu in kwargs.items():
1377
+ tokn = '{' + name + '}'
1378
+ text = text.replace(tokn, valu)
1379
+ return text
synapse/cortex.py CHANGED
@@ -1739,7 +1739,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1739
1739
  for filt in gdef.get('filters', ()):
1740
1740
  await self.getStormQuery(filt)
1741
1741
 
1742
- for pivo in gdef.get('filters', ()):
1742
+ for pivo in gdef.get('pivots', ()):
1743
1743
  await self.getStormQuery(pivo)
1744
1744
 
1745
1745
  for form, rule in gdef.get('forms', {}).items():
@@ -1749,7 +1749,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1749
1749
  for filt in rule.get('filters', ()):
1750
1750
  await self.getStormQuery(filt)
1751
1751
 
1752
- for pivo in rule.get('filters', ()):
1752
+ for pivo in rule.get('pivots', ()):
1753
1753
  await self.getStormQuery(pivo)
1754
1754
 
1755
1755
  async def addStormGraph(self, gdef, user=None):
@@ -4651,6 +4651,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
4651
4651
  # allow an admin to directly open the cortex hive
4652
4652
  # (perhaps this should be a Cell() level pattern)
4653
4653
  if path[0] == 'hive' and user.isAdmin():
4654
+ s_common.deprecated('Cortex /hive telepath path', curv='2.167.0')
4654
4655
  return await self.hiveapi.anit(self.hive, user)
4655
4656
 
4656
4657
  if path[0] == 'layer':
synapse/datamodel.py CHANGED
@@ -1114,7 +1114,14 @@ class Model:
1114
1114
  if item == '$self':
1115
1115
  return form.name
1116
1116
 
1117
- return item.format(**template)
1117
+ item = s_common.format(item, **template)
1118
+
1119
+ # warn but do not blow up. there may be extended model elements
1120
+ # with {}s which are not used for templates...
1121
+ if item.find('{') != -1: # pragma: no cover
1122
+ logger.warning(f'Missing template specifier in: {item}')
1123
+
1124
+ return item
1118
1125
 
1119
1126
  if isinstance(item, dict):
1120
1127
  return {convert(k): convert(v) for (k, v) in item.items()}
synapse/lib/ast.py CHANGED
@@ -59,7 +59,8 @@ class AstNode:
59
59
  }
60
60
 
61
61
  def addExcInfo(self, exc):
62
- exc.errinfo['highlight'] = self.getPosInfo()
62
+ if 'highlight' not in exc.errinfo:
63
+ exc.errinfo['highlight'] = self.getPosInfo()
63
64
  return exc
64
65
 
65
66
  def repr(self):
@@ -3554,7 +3555,10 @@ class VarDeref(Value):
3554
3555
 
3555
3556
  valu = s_stormtypes.fromprim(base, path=path)
3556
3557
  with s_scope.enter({'runt': runt}):
3557
- return await valu.deref(name)
3558
+ try:
3559
+ return await valu.deref(name)
3560
+ except s_exc.SynErr as e:
3561
+ raise self.kids[1].addExcInfo(e)
3558
3562
 
3559
3563
  class FuncCall(Value):
3560
3564
 
synapse/lib/cell.py CHANGED
@@ -96,16 +96,16 @@ def adminapi(log=False):
96
96
  def decrfunc(func):
97
97
 
98
98
  @functools.wraps(func)
99
- def wrapped(*args, **kwargs):
99
+ def wrapped(self, *args, **kwargs):
100
100
 
101
- if args[0].user is not None and not args[0].user.isAdmin():
102
- raise s_exc.AuthDeny(mesg='User is not an admin.',
103
- user=args[0].user.name)
101
+ if self.user is not None and not self.user.isAdmin():
102
+ raise s_exc.AuthDeny(mesg=f'User is not an admin [{self.user.name}]',
103
+ user=self.user.iden, username=self.user.name)
104
104
  if log:
105
- logger.info('Executing [%s] as [%s] with args [%s][%s]',
106
- func.__qualname__, args[0].user.name, args[1:], kwargs)
105
+ logger.info(f'Executing [{func.__qualname__}] as [{self.user.name}] with args [{args}[{kwargs}]',
106
+ extra={'synapse': {'wrapped_func': func.__qualname__}})
107
107
 
108
- return func(*args, **kwargs)
108
+ return func(self, *args, **kwargs)
109
109
 
110
110
  wrapped.__syn_wrapped__ = 'adminapi'
111
111
 
@@ -459,6 +459,43 @@ class CellApi(s_base.Base):
459
459
  async def delRole(self, iden):
460
460
  return await self.cell.delRole(iden)
461
461
 
462
+ async def addUserApiKey(self, name, duration=None, useriden=None):
463
+ if useriden is None:
464
+ useriden = self.user.iden
465
+
466
+ if self.user.iden == useriden:
467
+ self.user.confirm(('auth', 'self', 'set', 'apikey'), default=True)
468
+ else:
469
+ self.user.confirm(('auth', 'user', 'set', 'apikey'))
470
+
471
+ return await self.cell.addUserApiKey(useriden, name, duration=duration)
472
+
473
+ async def listUserApiKeys(self, useriden=None):
474
+ if useriden is None:
475
+ useriden = self.user.iden
476
+
477
+ if self.user.iden == useriden:
478
+ self.user.confirm(('auth', 'self', 'set', 'apikey'), default=True)
479
+ else:
480
+ self.user.confirm(('auth', 'user', 'set', 'apikey'))
481
+
482
+ return await self.cell.listUserApiKeys(useriden)
483
+
484
+ async def delUserApiKey(self, iden):
485
+ apikey = await self.cell.getUserApiKey(iden)
486
+ if apikey is None:
487
+ mesg = f'User API key with {iden=} does not exist.'
488
+ raise s_exc.NoSuchIden(mesg=mesg, iden=iden)
489
+
490
+ useriden = apikey.get('user')
491
+
492
+ if self.user.iden == useriden:
493
+ self.user.confirm(('auth', 'self', 'set', 'apikey'), default=True)
494
+ else:
495
+ self.user.confirm(('auth', 'user', 'set', 'apikey'))
496
+
497
+ return await self.cell.delUserApiKey(iden)
498
+
462
499
  @adminapi()
463
500
  async def dyncall(self, iden, todo, gatekeys=()):
464
501
  return await self.cell.dyncall(iden, todo, gatekeys=gatekeys)
@@ -1095,6 +1132,8 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
1095
1132
  }
1096
1133
  SYSCTL_CHECK_FREQ = 60.0
1097
1134
 
1135
+ LOGGED_HTTPAPI_HEADERS = ('User-Agent',)
1136
+
1098
1137
  async def __anit__(self, dirn, conf=None, readonly=False, parent=None):
1099
1138
 
1100
1139
  # phase 1
@@ -3248,6 +3287,15 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
3248
3287
  'remoteip': remote_ip,
3249
3288
  }
3250
3289
 
3290
+ headers = {}
3291
+
3292
+ for header in self.LOGGED_HTTPAPI_HEADERS:
3293
+ if (valu := handler.request.headers.get(header)) is not None:
3294
+ headers[header.lower()] = valu
3295
+
3296
+ if headers:
3297
+ enfo['headers'] = headers
3298
+
3251
3299
  extra = {'synapse': enfo}
3252
3300
 
3253
3301
  # It is possible that a Cell implementor may register handlers which
synapse/lib/msgpack.py CHANGED
@@ -26,8 +26,16 @@ def _ext_en(item):
26
26
  return msgpack.ExtType(1, item.to_bytes(size, 'big', signed=True))
27
27
  return item
28
28
 
29
+ _packer_kwargs = {
30
+ 'use_bin_type': True,
31
+ 'unicode_errors': 'surrogatepass',
32
+ 'default': _ext_en,
33
+ }
34
+ if msgpack.version >= (1, 1, 0):
35
+ _packer_kwargs['buf_size'] = 1024 * 1024
36
+
29
37
  # Single Packer object which is reused for performance
30
- pakr = msgpack.Packer(use_bin_type=True, unicode_errors='surrogatepass', default=_ext_en)
38
+ pakr = msgpack.Packer(**_packer_kwargs)
31
39
  if isinstance(pakr, m_fallback.Packer): # pragma: no cover
32
40
  logger.warning('******************************************************************************************************')
33
41
  logger.warning('* msgpack is using the pure python fallback implementation. This will impact performance negatively. *')
@@ -87,8 +95,7 @@ def _fallback_en(item):
87
95
  bytes: The serialized bytes in msgpack format.
88
96
  '''
89
97
  try:
90
- return msgpack.packb(item, use_bin_type=True,
91
- unicode_errors='surrogatepass', default=_ext_en)
98
+ return msgpack.packb(item, **_packer_kwargs)
92
99
  except TypeError as e:
93
100
  mesg = f'{e.args[0]}: {repr(item)[:20]}'
94
101
  raise s_exc.NotMsgpackSafe(mesg=mesg) from e
synapse/lib/nexus.py CHANGED
@@ -505,6 +505,7 @@ class NexsRoot(s_base.Base):
505
505
  if features.get('dynmirror'):
506
506
  await proxy.readyToMirror()
507
507
 
508
+ synvers = cellinfo['synapse']['version']
508
509
  cellvers = cellinfo['cell']['version']
509
510
  if cellvers > self.cell.VERSION:
510
511
  logger.error('Leader is a higher version than we are. Mirrors must be updated first. Entering read-only mode.')
@@ -537,7 +538,7 @@ class NexsRoot(s_base.Base):
537
538
  offs = self.nexslog.index()
538
539
 
539
540
  opts = {}
540
- if cellvers >= (2, 95, 0):
541
+ if synvers >= (2, 95, 0):
541
542
  opts['tellready'] = True
542
543
 
543
544
  genr = proxy.getNexusChanges(offs, **opts)
synapse/lib/stormhttp.py CHANGED
@@ -91,12 +91,19 @@ class LibHttp(s_stormtypes.Lib):
91
91
 
92
92
  For APIs that accept an ssl_opts argument, the dictionary may contain the following values::
93
93
 
94
- {
94
+ ({
95
95
  'verify': <bool> - Perform SSL/TLS verification. Is overridden by the ssl_verify argument.
96
96
  'client_cert': <str> - PEM encoded full chain certificate for use in mTLS.
97
97
  'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
98
98
  'ca_cert': <str> - A PEM encoded full chain CA certificate for use when verifying the request.
99
- }
99
+ })
100
+
101
+ For APIs that accept a proxy argument, the following values are supported::
102
+
103
+ $lib.null: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
104
+ $lib.true: Use the proxy defined by the http:proxy configuration option if set.
105
+ $lib.false: Do not use the proxy defined by the http:proxy configuration option if set.
106
+ <str>: A proxy URL string.
100
107
  '''
101
108
  _storm_locals = (
102
109
  {'name': 'get', 'desc': 'Get the contents of a given URL.',
@@ -113,8 +120,8 @@ class LibHttp(s_stormtypes.Lib):
113
120
  'default': 300},
114
121
  {'name': 'allow_redirects', 'type': 'bool', 'desc': 'If set to false, do not follow redirects.',
115
122
  'default': True},
116
- {'name': 'proxy', 'type': ['bool', 'null', 'str'],
117
- 'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
123
+ {'name': 'proxy', 'type': ['bool', 'str'],
124
+ 'desc': 'Configure proxy usage. See $lib.inet.http help for additional details.', 'default': True},
118
125
  {'name': 'ssl_opts', 'type': 'dict',
119
126
  'desc': 'Optional SSL/TLS options. See $lib.inet.http help for additional details.',
120
127
  'default': None},
@@ -145,8 +152,8 @@ class LibHttp(s_stormtypes.Lib):
145
152
  'and the corresponding file will be uploaded as the value for '
146
153
  'the field.',
147
154
  'default': None},
148
- {'name': 'proxy', 'type': ['bool', 'null', 'str'],
149
- 'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
155
+ {'name': 'proxy', 'type': ['bool', 'str'],
156
+ 'desc': 'Configure proxy usage. See $lib.inet.http help for additional details.', 'default': True},
150
157
  {'name': 'ssl_opts', 'type': 'dict',
151
158
  'desc': 'Optional SSL/TLS options. See $lib.inet.http help for additional details.',
152
159
  'default': None},
@@ -167,8 +174,8 @@ class LibHttp(s_stormtypes.Lib):
167
174
  'default': 300, },
168
175
  {'name': 'allow_redirects', 'type': 'bool', 'desc': 'If set to true, follow redirects.',
169
176
  'default': False},
170
- {'name': 'proxy', 'type': ['bool', 'null', 'str'],
171
- 'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
177
+ {'name': 'proxy', 'type': ['bool', 'str'],
178
+ 'desc': 'Configure proxy usage. See $lib.inet.http help for additional details.', 'default': True},
172
179
  {'name': 'ssl_opts', 'type': 'dict',
173
180
  'desc': 'Optional SSL/TLS options. See $lib.inet.http help for additional details.',
174
181
  'default': None},
@@ -200,8 +207,8 @@ class LibHttp(s_stormtypes.Lib):
200
207
  'and the corresponding file will be uploaded as the value for '
201
208
  'the field.',
202
209
  'default': None},
203
- {'name': 'proxy', 'type': ['bool', 'null', 'str'],
204
- 'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
210
+ {'name': 'proxy', 'type': ['bool', 'str'],
211
+ 'desc': 'Configure proxy usage. See $lib.inet.http help for additional details.', 'default': True},
205
212
  {'name': 'ssl_opts', 'type': 'dict',
206
213
  'desc': 'Optional SSL/TLS options. See $lib.inet.http help for additional details.',
207
214
  'default': None},
@@ -221,8 +228,8 @@ class LibHttp(s_stormtypes.Lib):
221
228
  'default': 300},
222
229
  {'name': 'params', 'type': 'dict', 'desc': 'Optional parameters which may be passed to the connection request.',
223
230
  'default': None},
224
- {'name': 'proxy', 'type': ['bool', 'null', 'str'],
225
- 'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
231
+ {'name': 'proxy', 'type': ['bool', 'str'],
232
+ 'desc': 'Configure proxy usage. See $lib.inet.http help for additional details.', 'default': True},
226
233
  {'name': 'ssl_opts', 'type': 'dict',
227
234
  'desc': 'Optional SSL/TLS options. See $lib.inet.http help for additional details.',
228
235
  'default': None},
@@ -308,23 +315,23 @@ class LibHttp(s_stormtypes.Lib):
308
315
  return s_common.httpcodereason(code)
309
316
 
310
317
  async def _httpEasyHead(self, url, headers=None, ssl_verify=True, params=None, timeout=300,
311
- allow_redirects=False, proxy=None, ssl_opts=None):
318
+ allow_redirects=False, proxy=True, ssl_opts=None):
312
319
  return await self._httpRequest('HEAD', url, headers=headers, ssl_verify=ssl_verify, params=params,
313
320
  timeout=timeout, allow_redirects=allow_redirects, proxy=proxy, ssl_opts=ssl_opts)
314
321
 
315
322
  async def _httpEasyGet(self, url, headers=None, ssl_verify=True, params=None, timeout=300,
316
- allow_redirects=True, proxy=None, ssl_opts=None):
323
+ allow_redirects=True, proxy=True, ssl_opts=None):
317
324
  return await self._httpRequest('GET', url, headers=headers, ssl_verify=ssl_verify, params=params,
318
325
  timeout=timeout, allow_redirects=allow_redirects, proxy=proxy, ssl_opts=ssl_opts)
319
326
 
320
327
  async def _httpPost(self, url, headers=None, json=None, body=None, ssl_verify=True,
321
- params=None, timeout=300, allow_redirects=True, fields=None, proxy=None, ssl_opts=None):
328
+ params=None, timeout=300, allow_redirects=True, fields=None, proxy=True, ssl_opts=None):
322
329
  return await self._httpRequest('POST', url, headers=headers, json=json, body=body,
323
330
  ssl_verify=ssl_verify, params=params, timeout=timeout,
324
331
  allow_redirects=allow_redirects, fields=fields, proxy=proxy, ssl_opts=ssl_opts)
325
332
 
326
333
  async def inetHttpConnect(self, url, headers=None, ssl_verify=True, timeout=300,
327
- params=None, proxy=None, ssl_opts=None):
334
+ params=None, proxy=True, ssl_opts=None):
328
335
 
329
336
  url = await s_stormtypes.tostr(url)
330
337
  headers = await s_stormtypes.toprim(headers)
@@ -338,15 +345,9 @@ class LibHttp(s_stormtypes.Lib):
338
345
 
339
346
  sock = await WebSocket.anit()
340
347
 
341
- if proxy is not None:
342
- self.runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
343
-
344
- if proxy is None:
345
- proxy = await self.runt.snap.core.getConfOpt('http:proxy')
346
-
347
348
  connector = None
348
- if proxy:
349
- connector = aiohttp_socks.ProxyConnector.from_url(proxy)
349
+ if proxyurl := await s_stormtypes.resolveCoreProxyUrl(proxy):
350
+ connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
350
351
 
351
352
  timeout = aiohttp.ClientTimeout(total=timeout)
352
353
  kwargs = {'timeout': timeout}
@@ -387,7 +388,7 @@ class LibHttp(s_stormtypes.Lib):
387
388
 
388
389
  async def _httpRequest(self, meth, url, headers=None, json=None, body=None,
389
390
  ssl_verify=True, params=None, timeout=300, allow_redirects=True,
390
- fields=None, proxy=None, ssl_opts=None):
391
+ fields=None, proxy=True, ssl_opts=None):
391
392
  meth = await s_stormtypes.tostr(meth)
392
393
  url = await s_stormtypes.tostr(url)
393
394
  json = await s_stormtypes.toprim(json)
@@ -407,19 +408,18 @@ class LibHttp(s_stormtypes.Lib):
407
408
 
408
409
  headers = s_stormtypes.strifyHttpArg(headers)
409
410
 
410
- if proxy is not None:
411
- self.runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
412
-
413
411
  if fields:
414
412
  if any(['sha256' in field for field in fields]):
415
413
  self.runt.confirm(('storm', 'lib', 'axon', 'wput'))
416
414
 
417
415
  kwargs = {}
418
- axonvers = self.runt.snap.core.axoninfo['synapse']['version']
419
- if axonvers >= s_stormtypes.AXON_MINVERS_PROXY:
416
+
417
+ ok, proxy = await s_stormtypes.resolveAxonProxyArg(proxy)
418
+ if ok:
420
419
  kwargs['proxy'] = proxy
421
420
 
422
421
  if ssl_opts is not None:
422
+ axonvers = self.runt.snap.core.axoninfo['synapse']['version']
423
423
  mesg = f'The ssl_opts argument requires an Axon Synapse version {s_stormtypes.AXON_MINVERS_SSLOPTS}, ' \
424
424
  f'but the Axon is running {axonvers}'
425
425
  s_version.reqVersion(axonvers, s_stormtypes.AXON_MINVERS_SSLOPTS, mesg=mesg)
@@ -432,12 +432,9 @@ class LibHttp(s_stormtypes.Lib):
432
432
 
433
433
  kwargs['ssl'] = self.runt.snap.core.getCachedSslCtx(opts=ssl_opts, verify=ssl_verify)
434
434
 
435
- if proxy is None:
436
- proxy = await self.runt.snap.core.getConfOpt('http:proxy')
437
-
438
435
  connector = None
439
- if proxy:
440
- connector = aiohttp_socks.ProxyConnector.from_url(proxy)
436
+ if proxyurl := await s_stormtypes.resolveCoreProxyUrl(proxy):
437
+ connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
441
438
 
442
439
  timeout = aiohttp.ClientTimeout(total=timeout)
443
440
 
@@ -916,6 +916,21 @@ class LibModelMigrations(s_stormtypes.Lib, MigrationEditorMixin):
916
916
  'desc': 'Do not copy nodedata to the inet:tls:servercert node.'},
917
917
  ),
918
918
  'returns': {'type': 'node', 'desc': 'The newly created inet:tls:servercert node.'}}},
919
+ {'name': 'inetServiceMessageClientAddress', 'desc': '''
920
+ Migrate the :client:address property to :client on inet:service:message nodes.
921
+
922
+ Edits will be made to the inet:service:message node in the current write layer.
923
+
924
+ If the :client:address property is set and the :client property is not set,
925
+ the :client property will be set with the :client:address value. If both
926
+ properties are set, the value will be moved into nodedata under the key
927
+ 'migration:inet:service:message:address'.
928
+ ''',
929
+ 'type': {'type': 'function', '_funcname': '_storm_query',
930
+ 'args': (
931
+ {'name': 'n', 'type': 'node', 'desc': 'The inet:sevice:message node to migrate.'},
932
+ ),
933
+ 'returns': {'type': 'null'}}},
919
934
 
920
935
  )
921
936
  _storm_lib_path = ('model', 'migration', 's')
@@ -956,6 +971,28 @@ class LibModelMigrations(s_stormtypes.Lib, MigrationEditorMixin):
956
971
 
957
972
  return($node)
958
973
  }
974
+
975
+ function inetServiceMessageClientAddress(n) {
976
+ $form = $n.form()
977
+ if ($form != 'inet:service:message') {
978
+ $mesg = `$lib.model.migration.s.inetServiceMessageClientAddress() only accepts inet:service:message nodes, not {$form}`
979
+ $lib.raise(BadArg, $mesg)
980
+ }
981
+
982
+ if (not $n.props.'client:address') { return() }
983
+
984
+ yield $n
985
+
986
+ if :client {
987
+ $node.data.set(migration:inet:service:message:client:address, :client:address)
988
+ } else {
989
+ [ :client = :client:address ]
990
+ }
991
+
992
+ [ -:client:address ]
993
+
994
+ return()
995
+ }
959
996
  '''
960
997
 
961
998
  def getObjLocals(self):