synapse 2.165.0__py311-none-any.whl → 2.167.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 (77) hide show
  1. synapse/axon.py +4 -10
  2. synapse/cmds/cortex.py +1 -6
  3. synapse/common.py +6 -0
  4. synapse/cortex.py +104 -57
  5. synapse/datamodel.py +32 -0
  6. synapse/exc.py +1 -0
  7. synapse/lib/agenda.py +81 -51
  8. synapse/lib/aha.py +2 -0
  9. synapse/lib/ast.py +21 -23
  10. synapse/lib/base.py +11 -10
  11. synapse/lib/cell.py +24 -24
  12. synapse/lib/hive.py +11 -0
  13. synapse/lib/httpapi.py +1 -0
  14. synapse/lib/nexus.py +3 -2
  15. synapse/lib/node.py +4 -2
  16. synapse/lib/schemas.py +3 -1
  17. synapse/lib/snap.py +50 -0
  18. synapse/lib/storm.py +19 -17
  19. synapse/lib/stormlib/aha.py +370 -17
  20. synapse/lib/stormlib/auth.py +11 -4
  21. synapse/lib/stormlib/cache.py +202 -0
  22. synapse/lib/stormlib/cortex.py +69 -7
  23. synapse/lib/stormlib/macro.py +11 -18
  24. synapse/lib/stormlib/spooled.py +109 -0
  25. synapse/lib/stormlib/stix.py +1 -1
  26. synapse/lib/stormtypes.py +61 -17
  27. synapse/lib/trigger.py +10 -12
  28. synapse/lib/types.py +3 -1
  29. synapse/lib/version.py +2 -2
  30. synapse/lib/view.py +16 -3
  31. synapse/models/base.py +8 -0
  32. synapse/models/files.py +3 -0
  33. synapse/models/inet.py +74 -2
  34. synapse/models/orgs.py +52 -8
  35. synapse/models/person.py +30 -11
  36. synapse/models/risk.py +44 -3
  37. synapse/telepath.py +115 -32
  38. synapse/tests/files/stormpkg/dotstorm/dotstorm.yaml +3 -0
  39. synapse/tests/test_cortex.py +79 -8
  40. synapse/tests/test_datamodel.py +22 -0
  41. synapse/tests/test_lib_agenda.py +8 -1
  42. synapse/tests/test_lib_aha.py +19 -6
  43. synapse/tests/test_lib_cell.py +6 -2
  44. synapse/tests/test_lib_grammar.py +62 -64
  45. synapse/tests/test_lib_httpapi.py +1 -1
  46. synapse/tests/test_lib_rstorm.py +4 -4
  47. synapse/tests/test_lib_storm.py +98 -7
  48. synapse/tests/test_lib_stormlib_aha.py +196 -0
  49. synapse/tests/test_lib_stormlib_cache.py +272 -0
  50. synapse/tests/test_lib_stormlib_compression.py +12 -12
  51. synapse/tests/test_lib_stormlib_cortex.py +71 -0
  52. synapse/tests/test_lib_stormlib_macro.py +94 -0
  53. synapse/tests/test_lib_stormlib_spooled.py +190 -0
  54. synapse/tests/test_lib_stormtypes.py +71 -37
  55. synapse/tests/test_lib_view.py +50 -3
  56. synapse/tests/test_model_files.py +3 -0
  57. synapse/tests/test_model_inet.py +67 -0
  58. synapse/tests/test_model_risk.py +6 -0
  59. synapse/tests/test_telepath.py +30 -7
  60. synapse/tests/test_tools_genpkg.py +26 -0
  61. synapse/tests/test_tools_hiveload.py +1 -0
  62. synapse/tests/test_tools_hivesave.py +1 -0
  63. synapse/tests/test_tools_modrole.py +81 -0
  64. synapse/tests/test_tools_moduser.py +105 -0
  65. synapse/tests/utils.py +22 -3
  66. synapse/tools/autodoc.py +1 -1
  67. synapse/tools/hive/load.py +3 -0
  68. synapse/tools/hive/save.py +3 -0
  69. synapse/tools/modrole.py +59 -7
  70. synapse/tools/moduser.py +78 -10
  71. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/METADATA +3 -3
  72. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/RECORD +75 -72
  73. synapse/lib/provenance.py +0 -111
  74. synapse/tests/test_lib_provenance.py +0 -37
  75. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/LICENSE +0 -0
  76. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/WHEEL +0 -0
  77. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/top_level.txt +0 -0
synapse/lib/stormtypes.py CHANGED
@@ -36,7 +36,6 @@ import synapse.lib.trigger as s_trigger
36
36
  import synapse.lib.urlhelp as s_urlhelp
37
37
  import synapse.lib.version as s_version
38
38
  import synapse.lib.stormctrl as s_stormctrl
39
- import synapse.lib.provenance as s_provenance
40
39
 
41
40
  logger = logging.getLogger(__name__)
42
41
 
@@ -907,6 +906,18 @@ class LibService(Lib):
907
906
  'returns': {'type': 'boolean', 'desc': 'Returns true if the service is available, false on a '
908
907
  'timeout waiting for the service to be ready.', }}},
909
908
  )
909
+ _storm_lib_perms = (
910
+ {'perm': ('service', 'add'), 'gate': 'cortex',
911
+ 'desc': 'Controls the ability to add a Storm Service to the Cortex.'},
912
+ {'perm': ('service', 'del'), 'gate': 'cortex',
913
+ 'desc': 'Controls the ability to delete a Storm Service from the Cortex'},
914
+ {'perm': ('service', 'get'), 'gate': 'cortex',
915
+ 'desc': 'Controls the ability to get the Service object for any Storm Service.'},
916
+ {'perm': ('service', 'get', '<iden>'), 'gate': 'cortex',
917
+ 'desc': 'Controls the ability to get the Service object for a Storm Service by iden.'},
918
+ {'perm': ('service', 'list'), 'gate': 'cortex',
919
+ 'desc': 'Controls the ability to list all available Storm Services and their service definitions.'},
920
+ )
910
921
  _storm_lib_path = ('service',)
911
922
 
912
923
  def getObjLocals(self):
@@ -931,6 +942,7 @@ class LibService(Lib):
931
942
  except s_exc.AuthDeny:
932
943
  raise e from None
933
944
  else:
945
+ # TODO: Remove support for this permission in 3.0.0
934
946
  mesg = 'Use of service.get.<servicename> permissions are deprecated.'
935
947
  await self.runt.warnonce(mesg, svcname=ssvc.name, svciden=ssvc.iden)
936
948
 
@@ -3425,13 +3437,14 @@ class LibFeed(Lib):
3425
3437
  data = await toprim(data)
3426
3438
 
3427
3439
  self.runt.layerConfirm(('feed:data', *name.split('.')))
3428
- with s_provenance.claim('feed:data', name=name):
3429
- # small work around for the feed API consistency
3430
- if name == 'syn.nodes':
3431
- async for node in self.runt.snap.addNodes(data):
3432
- yield node
3433
- return
3434
- await self.runt.snap.addFeedData(name, data)
3440
+
3441
+ # small work around for the feed API consistency
3442
+ if name == 'syn.nodes':
3443
+ async for node in self.runt.snap.addNodes(data):
3444
+ yield node
3445
+ return
3446
+
3447
+ await self.runt.snap.addFeedData(name, data)
3435
3448
 
3436
3449
  @stormfunc(readonly=True)
3437
3450
  async def _libList(self):
@@ -3443,11 +3456,12 @@ class LibFeed(Lib):
3443
3456
  data = await toprim(data)
3444
3457
 
3445
3458
  self.runt.layerConfirm(('feed:data', *name.split('.')))
3446
- with s_provenance.claim('feed:data', name=name):
3447
- strict = self.runt.snap.strict
3448
- self.runt.snap.strict = False
3449
- await self.runt.snap.addFeedData(name, data)
3450
- self.runt.snap.strict = strict
3459
+
3460
+ # TODO this should be a reentrent safe with block
3461
+ strict = self.runt.snap.strict
3462
+ self.runt.snap.strict = False
3463
+ await self.runt.snap.addFeedData(name, data)
3464
+ self.runt.snap.strict = strict
3451
3465
 
3452
3466
  @registry.registerLib
3453
3467
  class LibPipe(Lib):
@@ -3922,7 +3936,13 @@ class LibTelepath(Lib):
3922
3936
  scheme = url.split('://')[0]
3923
3937
  if not self.runt.allowed(('lib', 'telepath', 'open', scheme)):
3924
3938
  self.runt.confirm(('storm', 'lib', 'telepath', 'open', scheme))
3925
- return Proxy(self.runt, await self.runt.getTeleProxy(url))
3939
+ try:
3940
+ return Proxy(self.runt, await self.runt.getTeleProxy(url))
3941
+ except s_exc.SynErr:
3942
+ raise
3943
+ except Exception as e:
3944
+ mesg = f'Failed to connect to Telepath service: "{s_urlhelp.sanitizeUrl(url)}" error: {str(e)}'
3945
+ raise s_exc.StormRuntimeError(mesg=mesg) from e
3926
3946
 
3927
3947
  @registry.registerType
3928
3948
  class Proxy(StormType):
@@ -7368,7 +7388,11 @@ class View(Prim):
7368
7388
  The parent View iden.
7369
7389
 
7370
7390
  nomerge (bool)
7371
- Setting to $lib.true will prevent the layer from being merged.
7391
+ Deprecated - use protected. Updates to this option will be redirected to
7392
+ the protected option (below) until this option is removed.
7393
+
7394
+ protected (bool)
7395
+ Setting to $lib.true will prevent the layer from being merged or deleted.
7372
7396
 
7373
7397
  layers (list(str))
7374
7398
  Set the list of layer idens for a non-forked view. Layers are specified
@@ -7486,7 +7510,7 @@ class View(Prim):
7486
7510
 
7487
7511
  {'name': 'getPropArrayCount',
7488
7512
  'desc': '''
7489
- Get the number of invidivual array property values in the View for the given array property name.
7513
+ Get the number of individual array property values in the View for the given array property name.
7490
7514
 
7491
7515
  Notes:
7492
7516
  This is a fast approximate count calculated by summing the number of
@@ -7580,6 +7604,10 @@ class View(Prim):
7580
7604
  'args': (),
7581
7605
  'returns': {'name': 'Yields', 'type': 'dict',
7582
7606
  'desc': 'Yields previously successful merges into the view.'}}},
7607
+ {'name': 'getMergingViews', 'desc': 'Get a list of idens of Views that have open merge requests to this View.',
7608
+ 'type': {'type': 'function', '_funcname': 'getMergingViews',
7609
+ 'args': (),
7610
+ 'returns': {'name': 'idens', 'type': 'list', 'desc': 'The list of View idens that have an open merge request into this View.'}}},
7583
7611
  {'name': 'setMergeVoteComment', 'desc': 'Set the comment associated with your vote on a merge request.',
7584
7612
  'type': {'type': 'function', '_funcname': 'setMergeVoteComment',
7585
7613
  'args': ({'name': 'comment', 'type': 'str', 'desc': 'The text comment to set for the merge vote'},),
@@ -7634,6 +7662,7 @@ class View(Prim):
7634
7662
  'delMergeRequest': self.delMergeRequest,
7635
7663
  'setMergeRequest': self.setMergeRequest,
7636
7664
  'setMergeComment': self.setMergeComment,
7665
+ 'getMergingViews': self.getMergingViews,
7637
7666
  }
7638
7667
 
7639
7668
  async def addNode(self, form, valu, props=None):
@@ -7762,6 +7791,8 @@ class View(Prim):
7762
7791
 
7763
7792
  @stormfunc(readonly=True)
7764
7793
  async def _methViewGet(self, name, defv=None):
7794
+ if name == 'nomerge':
7795
+ name = 'protected'
7765
7796
  return self.valu.get(name, defv)
7766
7797
 
7767
7798
  def _reqView(self):
@@ -7788,6 +7819,10 @@ class View(Prim):
7788
7819
  valu = await toprim(valu)
7789
7820
 
7790
7821
  elif name == 'nomerge':
7822
+ name = 'protected'
7823
+ valu = await tobool(valu)
7824
+
7825
+ elif name == 'protected':
7791
7826
  valu = await tobool(valu)
7792
7827
 
7793
7828
  elif name == 'layers':
@@ -7951,6 +7986,12 @@ class View(Prim):
7951
7986
 
7952
7987
  return await view.setMergeComment((await tostr(comment)))
7953
7988
 
7989
+ async def getMergingViews(self):
7990
+ view = self._reqView()
7991
+ self.runt.confirm(('view', 'read'), gateiden=view.iden)
7992
+
7993
+ return await view.getMergingViews()
7994
+
7954
7995
  async def setMergeVote(self, approved=True, comment=None):
7955
7996
  view = self._reqView()
7956
7997
  quorum = view.reqParentQuorum()
@@ -8664,7 +8705,7 @@ class LibCron(Lib):
8664
8705
  'returns': {'type': 'str', 'desc': 'The iden of the CronJob which was moved.'}}},
8665
8706
  {'name': 'list', 'desc': 'List CronJobs in the Cortex.',
8666
8707
  'type': {'type': 'function', '_funcname': '_methCronList',
8667
- 'returns': {'type': 'list', 'desc': 'A list of ``cronjob`` objects..', }}},
8708
+ 'returns': {'type': 'list', 'desc': 'A list of ``cronjob`` objects.', }}},
8668
8709
  {'name': 'enable', 'desc': 'Enable a CronJob in the Cortex.',
8669
8710
  'type': {'type': 'function', '_funcname': '_methCronEnable',
8670
8711
  'args': (
@@ -8855,6 +8896,7 @@ class LibCron(Lib):
8855
8896
  incunit = None
8856
8897
  incval = None
8857
8898
  reqdict = {}
8899
+ pool = await tobool(kwargs.get('pool', False))
8858
8900
  valinfo = { # unit: (minval, next largest unit)
8859
8901
  'month': (1, 'year'),
8860
8902
  'dayofmonth': (1, 'month'),
@@ -8960,6 +9002,7 @@ class LibCron(Lib):
8960
9002
 
8961
9003
  cdef = {'storm': query,
8962
9004
  'reqs': reqdict,
9005
+ 'pool': pool,
8963
9006
  'incunit': incunit,
8964
9007
  'incvals': incval,
8965
9008
  'creator': self.runt.user.iden
@@ -9208,6 +9251,7 @@ class CronJob(Prim):
9208
9251
  'view': view,
9209
9252
  'viewshort': view[:8] + '..',
9210
9253
  'query': self.valu.get('query') or '<missing>',
9254
+ 'pool': self.valu.get('pool', False),
9211
9255
  'isrecur': 'Y' if self.valu.get('recur') else 'N',
9212
9256
  'isrunning': 'Y' if self.valu.get('isrunning') else 'N',
9213
9257
  'enabled': 'Y' if self.valu.get('enabled', True) else 'N',
synapse/lib/trigger.py CHANGED
@@ -11,7 +11,6 @@ import synapse.lib.chop as s_chop
11
11
  import synapse.lib.cache as s_cache
12
12
  import synapse.lib.config as s_config
13
13
  import synapse.lib.grammar as s_grammar
14
- import synapse.lib.provenance as s_provenance
15
14
 
16
15
  logger = logging.getLogger(__name__)
17
16
 
@@ -546,20 +545,19 @@ class Trigger:
546
545
 
547
546
  self.startcount += 1
548
547
 
549
- with s_provenance.claim('trig', cond=cond, form=form, tag=tag, prop=prop):
550
- try:
551
- async with self.view.core.getStormRuntime(query, opts=opts) as runt:
548
+ try:
549
+ async with self.view.core.getStormRuntime(query, opts=opts) as runt:
552
550
 
553
- runt.addInput(node)
554
- await s_common.aspin(runt.execute())
551
+ runt.addInput(node)
552
+ await s_common.aspin(runt.execute())
555
553
 
556
- except (asyncio.CancelledError, s_exc.RecursionLimitHit):
557
- raise
554
+ except (asyncio.CancelledError, s_exc.RecursionLimitHit):
555
+ raise
558
556
 
559
- except Exception as e:
560
- self.errcount += 1
561
- self.lasterrs.append(str(e))
562
- logger.exception('Trigger encountered exception running storm query %s', storm)
557
+ except Exception as e:
558
+ self.errcount += 1
559
+ self.lasterrs.append(str(e))
560
+ logger.exception('Trigger encountered exception running storm query %s', storm)
563
561
 
564
562
  def pack(self):
565
563
  tdef = self.tdef.copy()
synapse/lib/types.py CHANGED
@@ -1447,6 +1447,8 @@ class Edge(Type):
1447
1447
 
1448
1448
  def postTypeInit(self):
1449
1449
 
1450
+ self.deprecated = True
1451
+
1450
1452
  self.fieldoffs = {'n1': 0, 'n2': 1}
1451
1453
 
1452
1454
  self.ndeftype = self.modl.types.get('ndef') # type: Ndef
@@ -1850,7 +1852,7 @@ class Tag(Str):
1850
1852
  mesg = f'Tag does not match tagre: [{s_grammar.tagre.pattern}]'
1851
1853
  raise s_exc.BadTypeValu(valu=norm, name=self.name, mesg=mesg)
1852
1854
 
1853
- return norm, {'subs': subs}
1855
+ return norm, {'subs': subs, 'toks': toks}
1854
1856
 
1855
1857
  def _normPyStr(self, text):
1856
1858
  toks = text.strip('#').split('.')
synapse/lib/version.py CHANGED
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
223
223
  ##############################################################################
224
224
  # The following are touched during the release process by bumpversion.
225
225
  # Do not modify these directly.
226
- version = (2, 165, 0)
226
+ version = (2, 167, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = 'bdf3f6320106318fe52f1803e969090d950e0fdf'
228
+ commit = '7b2983533ea27d69e547ac54d9aab953630137c2'
synapse/lib/view.py CHANGED
@@ -167,6 +167,18 @@ class View(s_nexus.Pusher): # type: ignore
167
167
  if byts is not None:
168
168
  return s_msgpack.un(byts)
169
169
 
170
+ async def getMergingViews(self):
171
+ if self.info.get('quorum') is None:
172
+ mesg = f'View ({self.iden}) does not require quorum voting.'
173
+ raise s_exc.BadState(mesg=mesg)
174
+
175
+ idens = []
176
+ for view in list(self.core.views.values()):
177
+ await asyncio.sleep(0)
178
+ if view.parent == self and view.getMergeRequest() is not None:
179
+ idens.append(view.iden)
180
+ return idens
181
+
170
182
  async def setMergeRequest(self, mergeinfo):
171
183
  self.reqParentQuorum()
172
184
  mergeinfo['iden'] = s_common.guid()
@@ -1086,7 +1098,8 @@ class View(s_nexus.Pusher): # type: ignore
1086
1098
  '''
1087
1099
  Set a mutable view property.
1088
1100
  '''
1089
- if name not in ('name', 'desc', 'parent', 'nomerge', 'quorum'):
1101
+ if name not in ('name', 'desc', 'parent', 'nomerge', 'protected', 'quorum'):
1102
+ # TODO: Remove nomerge after Synapse 3.x.x
1090
1103
  mesg = f'{name} is not a valid view info key'
1091
1104
  raise s_exc.BadOptValu(mesg=mesg)
1092
1105
 
@@ -1334,8 +1347,8 @@ class View(s_nexus.Pusher): # type: ignore
1334
1347
  if self.parent is None:
1335
1348
  raise s_exc.CantMergeView(mesg=f'Cannot merge view ({self.iden}) that has not been forked.')
1336
1349
 
1337
- if self.info.get('nomerge'):
1338
- raise s_exc.CantMergeView(mesg=f'Cannot merge view ({self.iden}) that has nomerge set.')
1350
+ if self.info.get('protected'):
1351
+ raise s_exc.CantMergeView(mesg=f'Cannot merge view ({self.iden}) that has protected set.')
1339
1352
 
1340
1353
  if self.parent.info.get('quorum') is not None:
1341
1354
  raise s_exc.CantMergeView(mesg=f'Cannot merge view({self.iden}). Parent view requires quorum voting.')
synapse/models/base.py CHANGED
@@ -63,28 +63,36 @@ class BaseModule(s_module.CoreModule):
63
63
  'doc': 'A generic rule linked to matches with -(matches)> edges.'}),
64
64
 
65
65
  ('graph:cluster', ('guid', {}), {
66
+ 'deprecated': True,
66
67
  'doc': 'A generic node, used in conjunction with Edge types, to cluster arbitrary nodes to a '
67
68
  'single node in the model.'}),
68
69
 
69
70
  ('graph:node', ('guid', {}), {
71
+ 'deprecated': True,
70
72
  'doc': 'A generic node used to represent objects outside the model.'}),
71
73
 
72
74
  ('graph:event', ('guid', {}), {
75
+ 'deprecated': True,
73
76
  'doc': 'A generic event node to represent events outside the model.'}),
74
77
 
75
78
  ('edge:refs', ('edge', {}), {
79
+ 'deprecated': True,
76
80
  'doc': 'A digraph edge which records that N1 refers to or contains N2.'}),
77
81
 
78
82
  ('edge:has', ('edge', {}), {
83
+ 'deprecated': True,
79
84
  'doc': 'A digraph edge which records that N1 has N2.'}),
80
85
 
81
86
  ('edge:wentto', ('timeedge', {}), {
87
+ 'deprecated': True,
82
88
  'doc': 'A digraph edge which records that N1 went to N2 at a specific time.'}),
83
89
 
84
90
  ('graph:edge', ('edge', {}), {
91
+ 'deprecated': True,
85
92
  'doc': 'A generic digraph edge to show relationships outside the model.'}),
86
93
 
87
94
  ('graph:timeedge', ('timeedge', {}), {
95
+ 'deprecated': True,
88
96
  'doc': 'A generic digraph time edge to show relationships outside the model.'}),
89
97
 
90
98
  ('meta:priority', ('int', {'enums': prioenums, 'enums:strict': False}), {
synapse/models/files.py CHANGED
@@ -65,6 +65,9 @@ class FilePath(s_types.Str):
65
65
 
66
66
  path.append(part)
67
67
 
68
+ if len(path) == 0:
69
+ return '', {}
70
+
68
71
  fullpath = lead + '/'.join(path)
69
72
 
70
73
  base = path[-1]
synapse/models/inet.py CHANGED
@@ -1304,8 +1304,8 @@ class InetModule(s_module.CoreModule):
1304
1304
  }),
1305
1305
 
1306
1306
  ('inet:ssl:cert', ('comp', {'fields': (('server', 'inet:server'), ('file', 'file:bytes'))}), {
1307
- 'doc': 'An SSL certificate file served by a server.',
1308
- 'ex': '(1.2.3.4:443, guid:d41d8cd98f00b204e9800998ecf8427e)',
1307
+ 'deprecated': True,
1308
+ 'doc': 'Deprecated. Please use inet:tls:servercert or inet:tls:clientcert',
1309
1309
  }),
1310
1310
 
1311
1311
  ('inet:port', ('int', {'min': 0, 'max': 0xffff}), {
@@ -1489,6 +1489,24 @@ class InetModule(s_module.CoreModule):
1489
1489
  ('inet:ssl:jarmsample', ('comp', {'fields': (('server', 'inet:server'), ('jarmhash', 'inet:ssl:jarmhash'))}), {
1490
1490
  'doc': 'A JARM hash sample taken from a server.'}),
1491
1491
 
1492
+ ('inet:tls:handshake', ('guid', {}), {
1493
+ 'doc': 'An instance of a TLS handshake between a server and client.'}),
1494
+
1495
+ ('inet:tls:ja3s:sample', ('comp', {'fields': (('server', 'inet:server'), ('ja3s', 'hash:md5'))}), {
1496
+ 'doc': 'A JA3 sample taken from a server.'}),
1497
+
1498
+ ('inet:tls:ja3:sample', ('comp', {'fields': (('client', 'inet:client'), ('ja3', 'hash:md5'))}), {
1499
+ 'doc': 'A JA3 sample taken from a client.'}),
1500
+
1501
+ ('inet:tls:servercert', ('comp', {'fields': (('server', 'inet:server'), ('cert', 'crypto:x509:cert'))}), {
1502
+ 'doc': 'An x509 certificate sent by a server for TLS.',
1503
+ 'ex': '(1.2.3.4:443, c7437790af01ae1bb2f8f3b684c70bf8)',
1504
+ }),
1505
+
1506
+ ('inet:tls:clientcert', ('comp', {'fields': (('client', 'inet:client'), ('cert', 'crypto:x509:cert'))}), {
1507
+ 'doc': 'An x509 certificate sent by a client for TLS.',
1508
+ 'ex': '(1.2.3.4:443, 3fdf364e081c14997b291852d1f23868)',
1509
+ }),
1492
1510
  ),
1493
1511
 
1494
1512
  'interfaces': (
@@ -3234,6 +3252,60 @@ class InetModule(s_module.CoreModule):
3234
3252
  'doc': 'The server that was sampled to compute the JARM hash.'}),
3235
3253
  )),
3236
3254
 
3255
+ ('inet:tls:handshake', {}, (
3256
+ ('time', ('time', {}), {
3257
+ 'doc': 'The time the handshake was initiated.'}),
3258
+ ('flow', ('inet:flow', {}), {
3259
+ 'doc': 'The raw inet:flow associated with the handshake.'}),
3260
+ ('server', ('inet:server', {}), {
3261
+ 'doc': 'The TLS server during the handshake.'}),
3262
+ ('server:cert', ('crypto:x509:cert', {}), {
3263
+ 'doc': 'The x509 certificate sent by the server during the handshake.'}),
3264
+ ('server:fingerprint:ja3', ('hash:md5', {}), {
3265
+ 'doc': 'The JA3S finger of the server.'}),
3266
+ ('client', ('inet:client', {}), {
3267
+ 'doc': 'The TLS client during the handshake.'}),
3268
+ ('client:cert', ('crypto:x509:cert', {}), {
3269
+ 'doc': 'The x509 certificate sent by the client during the handshake.'}),
3270
+ ('client:fingerprint:ja3', ('hash:md5', {}), {
3271
+ 'doc': 'The JA3 fingerprint of the client.'}),
3272
+ )),
3273
+
3274
+ ('inet:tls:ja3s:sample', {}, (
3275
+ ('server', ('inet:server', {}), {
3276
+ 'ro': True,
3277
+ 'doc': 'The server that was sampled to produce the JA3S hash.'}),
3278
+ ('ja3s', ('hash:md5', {}), {
3279
+ 'ro': True,
3280
+ 'doc': "The JA3S hash computed from the server's TLS hello packet."})
3281
+ )),
3282
+
3283
+ ('inet:tls:ja3:sample', {}, (
3284
+ ('client', ('inet:client', {}), {
3285
+ 'ro': True,
3286
+ 'doc': 'The client that was sampled to produce the JA3 hash.'}),
3287
+ ('ja3', ('hash:md5', {}), {
3288
+ 'ro': True,
3289
+ 'doc': "The JA3 hash computed from the client's TLS hello packet."})
3290
+ )),
3291
+
3292
+ ('inet:tls:servercert', {}, (
3293
+ ('server', ('inet:server', {}), {
3294
+ 'ro': True,
3295
+ 'doc': 'The server associated with the x509 certificate.'}),
3296
+ ('cert', ('crypto:x509:cert', {}), {
3297
+ 'ro': True,
3298
+ 'doc': 'The x509 certificate sent by the server.'})
3299
+ )),
3300
+
3301
+ ('inet:tls:clientcert', {}, (
3302
+ ('client', ('inet:client', {}), {
3303
+ 'ro': True,
3304
+ 'doc': 'The client associated with the x509 certificate.'}),
3305
+ ('cert', ('crypto:x509:cert', {}), {
3306
+ 'ro': True,
3307
+ 'doc': 'The x509 certificate sent by the client.'})
3308
+ )),
3237
3309
  ),
3238
3310
  }),
3239
3311
  )
synapse/models/orgs.py CHANGED
@@ -24,14 +24,27 @@ class OuModule(s_module.CoreModule):
24
24
  }),
25
25
  ('ou:isic', ('str', {'regex': r'^[A-Z]([0-9]{2}[0-9]{0,2})?$'}), {
26
26
  'doc': 'An International Standard Industrial Classification of All Economic Activities (ISIC) code.',
27
- 'ex': 'C1393',
28
- }),
27
+ 'ex': 'C1393'}),
28
+
29
29
  ('ou:org', ('guid', {}), {
30
30
  'doc': 'A GUID for a human organization such as a company or military unit.',
31
- }),
31
+ 'display': {
32
+ 'columns': (
33
+ {'type': 'prop', 'opts': {'name': 'name'}},
34
+ {'type': 'prop', 'opts': {'name': 'names'}},
35
+ {'type': 'prop', 'opts': {'name': 'country:code'}},
36
+ ),
37
+ }}),
38
+
32
39
  ('ou:team', ('guid', {}), {
33
40
  'doc': 'A GUID for a team within an organization.',
34
- }),
41
+ 'display': {
42
+ 'columns': (
43
+ {'type': 'prop', 'opts': {'name': 'name'}},
44
+ {'type': 'prop', 'opts': {'name': 'org::name'}},
45
+ ),
46
+ }}),
47
+
35
48
  ('ou:orgtype', ('taxonomy', {}), {
36
49
  'doc': 'An org type taxonomy.',
37
50
  'interfaces': ('meta:taxonomy',),
@@ -49,6 +62,11 @@ class OuModule(s_module.CoreModule):
49
62
  }),
50
63
  ('ou:industry', ('guid', {}), {
51
64
  'doc': 'An industry classification type.',
65
+ 'display': {
66
+ 'columns': (
67
+ {'type': 'prop', 'opts': {'name': 'name'}},
68
+ ),
69
+ },
52
70
  }),
53
71
  ('ou:industry:type:taxonomy', ('taxonomy', {}), {
54
72
  'interfaces': ('meta:taxonomy',),
@@ -113,6 +131,12 @@ class OuModule(s_module.CoreModule):
113
131
  }),
114
132
  ('ou:conference', ('guid', {}), {
115
133
  'doc': 'A conference with a name and sponsoring org.',
134
+ 'display': {
135
+ 'columns': (
136
+ {'type': 'prop', 'opts': {'name': 'name'}},
137
+ {'type': 'prop', 'opts': {'name': 'start'}},
138
+ ),
139
+ },
116
140
  }),
117
141
  ('ou:conference:attendee', ('comp', {'fields': (('conference', 'ou:conference'), ('person', 'ps:person'))}), {
118
142
  'deprecated': True,
@@ -133,6 +157,11 @@ class OuModule(s_module.CoreModule):
133
157
  }),
134
158
  ('ou:goal', ('guid', {}), {
135
159
  'doc': 'An assessed or stated goal which may be abstract or org specific.',
160
+ 'display': {
161
+ 'columns': (
162
+ {'type': 'prop', 'opts': {'name': 'name'}},
163
+ ),
164
+ },
136
165
  }),
137
166
  ('ou:goalname', ('str', {'lower': True, 'onespace': True}), {
138
167
  'doc': 'A goal name.',
@@ -154,16 +183,31 @@ class OuModule(s_module.CoreModule):
154
183
 
155
184
  ('ou:campaign', ('guid', {}), {
156
185
  'doc': "Represents an org's activity in pursuit of a goal.",
157
- }),
186
+ 'display': {
187
+ 'columns': (
188
+ {'type': 'prop', 'opts': {'name': 'name'}},
189
+ {'type': 'prop', 'opts': {'name': 'names'}},
190
+ {'type': 'prop', 'opts': {'name': 'reporter:name'}},
191
+ {'type': 'prop', 'opts': {'name': 'tag'}},
192
+ ),
193
+ }}),
194
+
158
195
  ('ou:conflict', ('guid', {}), {
159
196
  'doc': 'Represents a conflict where two or more campaigns have mutually exclusive goals.',
160
197
  }),
161
198
  ('ou:contribution', ('guid', {}), {
162
- 'doc': 'Represents a specific instance of contributing material support to a campaign.',
163
- }),
199
+ 'doc': 'Represents a specific instance of contributing material support to a campaign.'}),
200
+
164
201
  ('ou:technique', ('guid', {}), {
165
202
  'doc': 'A specific technique used to achieve a goal.',
166
- }),
203
+ 'display': {
204
+ 'columns': (
205
+ {'type': 'prop', 'opts': {'name': 'name'}},
206
+ {'type': 'prop', 'opts': {'name': 'reporter:name'}},
207
+ {'type': 'prop', 'opts': {'name': 'tag'}},
208
+ ),
209
+ }}),
210
+
167
211
  ('ou:technique:taxonomy', ('taxonomy', {}), {
168
212
  'interfaces': ('meta:taxonomy',),
169
213
  'doc': 'An analyst defined taxonomy to classify techniques in different disciplines.',
synapse/models/person.py CHANGED
@@ -39,11 +39,19 @@ class PsModule(s_module.CoreModule):
39
39
  ('ps:persona:has', ('comp', {'fields': (('persona', 'ps:persona'), ('node', 'ndef'))}), {
40
40
  'deprecated': True,
41
41
  'doc': 'A persona owns, controls, or has exclusive use of an object or'
42
- ' resource, potentially during a specific period of time.'
43
- }),
42
+ ' resource, potentially during a specific period of time.'}),
43
+
44
44
  ('ps:contact', ('guid', {}), {
45
45
  'doc': 'A GUID for a contact info record.',
46
- }),
46
+ 'display': {
47
+ 'columns': (
48
+ {'type': 'prop', 'opts': {'name': 'name'}},
49
+ {'type': 'prop', 'opts': {'name': 'type'}},
50
+ {'type': 'prop', 'opts': {'name': 'orgname'}},
51
+ {'type': 'prop', 'opts': {'name': 'email'}},
52
+ ),
53
+ }}),
54
+
47
55
  ('ps:contact:type:taxonomy', ('taxonomy', {}), {
48
56
  'interfaces': ('meta:taxonomy',),
49
57
  'doc': 'A taxonomy of contact types.',
@@ -55,18 +63,29 @@ class PsModule(s_module.CoreModule):
55
63
  'doc': "A GUID representing entry in a contact's work history.",
56
64
  }),
57
65
  ('ps:vitals', ('guid', {}), {
58
- 'doc': 'Statistics and demographic data about a person or contact.',
59
- }),
66
+ 'doc': 'Statistics and demographic data about a person or contact.'}),
67
+
60
68
  ('ps:skill', ('guid', {}), {
61
- 'doc': 'A specific skill which a person or organization may have.'
62
- }),
69
+ 'doc': 'A specific skill which a person or organization may have.',
70
+ 'display': {
71
+ 'columns': (
72
+ {'type': 'prop', 'opts': {'name': 'name'}},
73
+ {'type': 'prop', 'opts': {'name': 'type'}},
74
+ ),
75
+ }}),
76
+
63
77
  ('ps:skill:type:taxonomy', ('taxonomy', {}), {
64
78
  'interfaces': ('meta:taxonomy',),
65
- 'doc': 'A taxonomy of skill types.',
66
- }),
79
+ 'doc': 'A taxonomy of skill types.'}),
80
+
67
81
  ('ps:proficiency', ('guid', {}), {
68
- 'doc': 'The assessment that a given contact possesses a specific skill.'
69
- }),
82
+ 'doc': 'The assessment that a given contact possesses a specific skill.',
83
+ 'display': {
84
+ 'columns': (
85
+ {'type': 'prop', 'opts': {'name': 'contact::name'}},
86
+ {'type': 'prop', 'opts': {'name': 'skill::name'}},
87
+ ),
88
+ }}),
70
89
  ),
71
90
  'edges': (
72
91
  (('ps:contact', 'has', None), {