secator 0.3.6__py3-none-any.whl → 0.4.0__py3-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 secator might be problematic. Click here for more details.

secator/template.py ADDED
@@ -0,0 +1,137 @@
1
+ import glob
2
+ from pathlib import Path
3
+
4
+ import yaml
5
+ from dotmap import DotMap
6
+
7
+ from secator.rich import console
8
+ from secator.config import CONFIG, CONFIGS_FOLDER
9
+
10
+ TEMPLATES_DIR_KEYS = ['workflow', 'scan', 'profile']
11
+
12
+
13
+ def load_template(name):
14
+ """Load a config by name.
15
+
16
+ Args:
17
+ name: Name of the config, for instances profiles/aggressive or workflows/domain_scan.
18
+
19
+ Returns:
20
+ dict: Loaded config.
21
+ """
22
+ path = CONFIGS_FOLDER / f'{name}.yaml'
23
+ if not path.exists():
24
+ console.log(f'Config "{name}" could not be loaded.')
25
+ return
26
+ with path.open('r') as f:
27
+ return yaml.load(f.read(), Loader=yaml.Loader)
28
+
29
+
30
+ def find_templates():
31
+ results = {'scan': [], 'workflow': [], 'profile': []}
32
+ dirs_type = [CONFIGS_FOLDER]
33
+ if CONFIG.dirs.templates:
34
+ dirs_type.append(CONFIG.dirs.templates)
35
+ paths = []
36
+ for dir in dirs_type:
37
+ dir_paths = [
38
+ Path(path)
39
+ for path in glob.glob(str(dir).rstrip('/') + '/**/*.y*ml', recursive=True)
40
+ ]
41
+ paths.extend(dir_paths)
42
+ for path in paths:
43
+ with path.open('r') as f:
44
+ try:
45
+ config = yaml.load(f.read(), yaml.Loader)
46
+ type = config.get('type')
47
+ if type:
48
+ results[type].append(path)
49
+ except yaml.YAMLError as exc:
50
+ console.log(f'Unable to load config at {path}')
51
+ console.log(str(exc))
52
+ return results
53
+
54
+
55
+ class TemplateLoader(DotMap):
56
+
57
+ def __init__(self, input={}, name=None, **kwargs):
58
+ if name:
59
+ name = name.replace('-', '_') # so that workflows have a nice '-' in CLI
60
+ config = self._load_from_name(name)
61
+ elif isinstance(input, str) or isinstance(input, Path):
62
+ config = self._load_from_file(input)
63
+ else:
64
+ config = input
65
+ super().__init__(config)
66
+
67
+ def _load_from_file(self, path):
68
+ if isinstance(path, str):
69
+ path = Path(path)
70
+ if not path.exists():
71
+ console.log(f'Config path {path} does not exists', style='bold red')
72
+ return
73
+ with path.open('r') as f:
74
+ return yaml.load(f.read(), Loader=yaml.Loader)
75
+
76
+ def _load_from_name(self, name):
77
+ return load_template(name)
78
+
79
+ @classmethod
80
+ def load_all(cls):
81
+ configs = find_templates()
82
+ return TemplateLoader({
83
+ key: [TemplateLoader(path) for path in configs[key]]
84
+ for key in TEMPLATES_DIR_KEYS
85
+ })
86
+
87
+ def get_tasks_class(self):
88
+ from secator.runners import Task
89
+ tasks = []
90
+ for name, conf in self.tasks.items():
91
+ if name == '_group':
92
+ group_conf = TemplateLoader(input={'tasks': conf})
93
+ tasks.extend(group_conf.get_tasks_class())
94
+ else:
95
+ tasks.append(Task.get_task_class(name))
96
+ return tasks
97
+
98
+ def get_workflows(self):
99
+ return [TemplateLoader(name=f'workflows/{name}') for name, _ in self.workflows.items()]
100
+
101
+ def get_workflow_supported_opts(self):
102
+ opts = {}
103
+ tasks = self.get_tasks_class()
104
+ for task_cls in tasks:
105
+ task_opts = task_cls.get_supported_opts()
106
+ for name, conf in task_opts.items():
107
+ supported = opts.get(name, {}).get('supported', False)
108
+ opts[name] = conf
109
+ opts[name]['supported'] = conf['supported'] or supported
110
+ return opts
111
+
112
+ def get_scan_supported_opts(self):
113
+ opts = {}
114
+ workflows = self.get_workflows()
115
+ for workflow in workflows:
116
+ workflow_opts = workflow.get_workflow_supported_opts()
117
+ for name, conf in workflow_opts.items():
118
+ supported = opts.get(name, {}).get('supported', False)
119
+ opts[name] = conf
120
+ opts[name]['supported'] = conf['supported'] or supported
121
+ return opts
122
+
123
+ @property
124
+ def supported_opts(self):
125
+ return self.get_supported_opts()
126
+
127
+ def get_supported_opts(self):
128
+ opts = {}
129
+ if self.type == 'workflow':
130
+ opts = self.get_workflow_supported_opts()
131
+ elif self.type == 'scan':
132
+ opts = self.get_scan_supported_opts()
133
+ elif self.type == 'task':
134
+ tasks = self.get_tasks_class()
135
+ if tasks:
136
+ opts = tasks[0].get_supported_opts()
137
+ return dict(sorted(opts.items()))
secator/utils.py CHANGED
@@ -19,8 +19,8 @@ import ifaddr
19
19
  import yaml
20
20
  from rich.markdown import Markdown
21
21
 
22
- from secator.definitions import (DEBUG, DEBUG_COMPONENT, DEFAULT_STDIN_TIMEOUT, VERSION, DEV_PACKAGE, ROOT_FOLDER,
23
- LIB_FOLDER)
22
+ from secator.definitions import (DEBUG, DEBUG_COMPONENT, VERSION, DEV_PACKAGE)
23
+ from secator.config import CONFIG, ROOT_FOLDER, LIB_FOLDER
24
24
  from secator.rich import console
25
25
 
26
26
  logger = logging.getLogger(__name__)
@@ -65,7 +65,7 @@ def expand_input(input):
65
65
  """
66
66
  if input is None: # read from stdin
67
67
  console.print('Waiting for input on stdin ...', style='bold yellow')
68
- rlist, _, _ = select.select([sys.stdin], [], [], DEFAULT_STDIN_TIMEOUT)
68
+ rlist, _, _ = select.select([sys.stdin], [], [], CONFIG.cli.stdin_timeout)
69
69
  if rlist:
70
70
  data = sys.stdin.read().splitlines()
71
71
  else:
@@ -312,10 +312,6 @@ def detect_host(interface=None):
312
312
  return None
313
313
 
314
314
 
315
- def find_list_item(array, val, key='id', default=None):
316
- return next((item for item in array if item[key] == val), default)
317
-
318
-
319
315
  def print_results_table(results, title=None, exclude_fields=[], log=False):
320
316
  from secator.output_types import OUTPUT_TYPES
321
317
  from secator.rich import build_table
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: secator
3
- Version: 0.3.6
3
+ Version: 0.4.0
4
4
  Summary: The pentester's swiss knife.
5
5
  Project-URL: Homepage, https://github.com/freelabz/secator
6
6
  Project-URL: Issues, https://github.com/freelabz/secator/issues
@@ -29,11 +29,13 @@ Requires-Dist: humanize<5
29
29
  Requires-Dist: ifaddr<1
30
30
  Requires-Dist: jinja2<4
31
31
  Requires-Dist: packaging<25
32
+ Requires-Dist: pydantic<3
32
33
  Requires-Dist: python-dotenv<2
33
34
  Requires-Dist: pyyaml<7
34
35
  Requires-Dist: requests<3
35
36
  Requires-Dist: rich-click<1.7
36
37
  Requires-Dist: rich<14
38
+ Requires-Dist: typing-extensions<5
37
39
  Requires-Dist: validators<1
38
40
  Requires-Dist: xmltodict<1
39
41
  Provides-Extra: build
@@ -90,7 +92,7 @@ and it is designed to improve productivity for pentesters and security researche
90
92
 
91
93
  # Features
92
94
 
93
- ![](images/short_demo.gif)
95
+ ![](images/demo.gif)
94
96
 
95
97
  * **Curated list of commands**
96
98
 
@@ -177,14 +179,18 @@ wget -O - https://raw.githubusercontent.com/freelabz/secator/main/scripts/instal
177
179
  <summary>Docker</summary>
178
180
 
179
181
  ```sh
180
- docker run -it --rm --net=host -v $HOME/.secator:/root/.secator freelabz/secator --help
182
+ docker run -it --rm --net=host -v ~/.secator:/root/.secator freelabz/secator --help
181
183
  ```
182
184
 
183
- The volume mount `-v` is necessary to save all `secator` reports to your host machine.
185
+ The volume mount -v is necessary to save all secator reports to your host machine, and--net=host is recommended to grant full access to the host network.
184
186
 
185
- You can set up an alias to facilitate running `secator` from Docker:
187
+ You can alias this command to run it easier:
186
188
  ```sh
187
- alias secator="docker run -it --rm --net=host -v $HOME/.secator:/root/.secator freelabz/secator"
189
+ alias secator="docker run -it --rm --net=host -v ~/.secator:/root/.secator freelabz/secator"
190
+ ```
191
+
192
+ Now you can run secator like if it was installed on baremetal:
193
+ ```
188
194
  secator --help
189
195
  ```
190
196
 
@@ -1,14 +1,15 @@
1
1
  secator/.gitignore,sha256=da8MUc3hdb6Mo0WjZu2upn5uZMbXcBGvhdhTQ1L89HI,3093
2
2
  secator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- secator/celery.py,sha256=4jryWgB7Ydqtosc1HrE2VkMhWXqdhb-A8wJiUem4Mh4,12266
4
- secator/cli.py,sha256=zwHB7JcWppX38IE39p4eSUUYDP5SdehYOJ-ByKNtVDw,31565
5
- secator/config.py,sha256=iOeRzq7u1rvR1-Oq5v9wGxQYB613X0xKGLIcrfhEGc4,3693
6
- secator/decorators.py,sha256=xH9QzAPd1DspoAzFv54Ss4JhCiZ9dd1zD5cdYGE7WKY,10784
7
- secator/definitions.py,sha256=ZFDPZW5R4CiAMWjyGvWmrePEljiWFyabgoTVM5Zedt4,7599
8
- secator/installer.py,sha256=wa5YFmbqMEpVI0jNiPvNE8-IDvr6vHNcdALV5rFYBr4,9329
3
+ secator/celery.py,sha256=5Raua1rDFJACdmP4b1HLS15kx3ObcUrVConQ0UcopTc,12135
4
+ secator/cli.py,sha256=-B3Hjy8I1z7Jc6fiPYQPCt0DX6TVrNZ98aU-8oN_RQM,34150
5
+ secator/config.py,sha256=-PdJgIesb7T1N2s38iHHeIquxBHoW1Cmd04gQr9PnnY,17403
6
+ secator/decorators.py,sha256=SIS_32SbeN9iTx82mvy9F9vLpjofRYspOOLCXytIO2g,10764
7
+ secator/definitions.py,sha256=lGhuBw2oBvSjtpxCPm0EwoAZLxcf2rwDEpcU8yfxVUA,3689
8
+ secator/installer.py,sha256=fpjf5fbA5M5zDQVP4Fdr51sLoMwtoGZTe3mXh7DvD6s,9466
9
9
  secator/report.py,sha256=g0stVCcx9klbUS01uKvWcxNE9MJfNFMexYA2SoDIWJU,2596
10
10
  secator/rich.py,sha256=W4PipeZfIVnERfW3ySeWSvnZ90jhCFiABBoERYy_6kM,3177
11
- secator/utils.py,sha256=9bfNqwlk55XBfT475rTafIwOwtEDFPIde417gxGTbEg,10945
11
+ secator/template.py,sha256=MRCzvn8FJ7D4n8V4ceBwAjPsdLhTWjDRu5VLefmLb6M,3705
12
+ secator/utils.py,sha256=_npGVl85skBAMdGDzrhvnNwg4-aRhbisl8oxsB9Q1q8,10824
12
13
  secator/utils_test.py,sha256=xVF9RH1-p3X0TdmODJi4k62H7Xth96Ib7qnUZ4vAJs8,5043
13
14
  secator/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
15
  secator/configs/profiles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -37,12 +38,12 @@ secator/configs/workflows/wordpress.yaml,sha256=QgBUNi8Gav_efbmczUGfzlByWsmogTmG
37
38
  secator/exporters/__init__.py,sha256=2nBPOOas9Fp4nmo9pjSw3mvklZNHL8BmH88w_i-eaJc,356
38
39
  secator/exporters/_base.py,sha256=-RrrwO_qp0ETLLHSta4T-zKtMbWdiEmz1Cw5mNo6USU,77
39
40
  secator/exporters/csv.py,sha256=xsPMljzJhoTc8lcfxWBIKH2niK6KeYL7Bx2NzpdsYw0,982
40
- secator/exporters/gdrive.py,sha256=VI6r1vlChz39myaN4sFvOlHO32SAhZS5_mI5EwGUdq8,4056
41
+ secator/exporters/gdrive.py,sha256=hq6PtCVejeqp9cipcAkH5ZsijBWB_SXIcW9uctYJAYM,4143
41
42
  secator/exporters/json.py,sha256=cWkDugUdy-lbcPFKNgBrRFxHspiFhjVbJfdDABjJ9uk,431
42
43
  secator/exporters/table.py,sha256=RHQoaFeeyeoBGNucJgrlk2KtmVqe9BGNtAAYee7xJ8Y,210
43
44
  secator/exporters/txt.py,sha256=QbiwWYGgHpITGw1sL2TX-S3AfmBdJ-VOWkPJzuBvOu4,785
44
45
  secator/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- secator/hooks/mongodb.py,sha256=GTd6BeiGtWUPWjmXKmalZYNoeGNZfNqEJ6BxRJh1Mr8,7149
46
+ secator/hooks/mongodb.py,sha256=PGcM6hkTl4bt46-cPlFgcY-PfNWmHpz_eiv77XeV0-A,7036
46
47
  secator/output_types/__init__.py,sha256=uj6AXDeorECPwhwekNVGjQbGv41jHG_8udkuoc4XzW0,854
47
48
  secator/output_types/_base.py,sha256=bld1ED0pN1hOvwBV2canrlKrfBCgawzWKPDH6F3jVQE,2469
48
49
  secator/output_types/exploit.py,sha256=NIa0mbhm3ZTyV5kyjEvrI5QK2swMpdMCj3f1gIWcsro,1581
@@ -55,46 +56,46 @@ secator/output_types/tag.py,sha256=8AlT0VigsYP04GN8sPCTM07IlL5uMUmFgsNa9IDCoyY,1
55
56
  secator/output_types/target.py,sha256=gJWzzqhal34Cnl9oAKf0m1MSaGxRtUGdA2XbkhD_yd0,848
56
57
  secator/output_types/url.py,sha256=yDozBXCuPfuybH1iX_xGmbCJPXO6Ei14C8Hp5CnzNbE,2535
57
58
  secator/output_types/user_account.py,sha256=EiT2BFl2LTCdqHF1meoMEKVhjKGroyf8-JoWHPuBOTc,1378
58
- secator/output_types/vulnerability.py,sha256=p0DTbr5w7Vv5D3dgbdnvsG5qXzqVVk4YPOPWYS1lxmM,2843
59
+ secator/output_types/vulnerability.py,sha256=hV6gsCFLdZ9IQV1ZSVCnsUms8H3md2_XZqp3wJDYDn4,2896
59
60
  secator/runners/__init__.py,sha256=EBbOk37vkBy9p8Hhrbi-2VtM_rTwQ3b-0ggTyiD22cE,290
60
- secator/runners/_base.py,sha256=jhglHTz1yf-LBdCdTX2YyAt664yBeQkkySQCrJYpjnM,28290
61
- secator/runners/_helpers.py,sha256=7UUboSsr4b6srIOOHtSSYhJ9Jxq_qaMVbbF2gVEBnR4,3703
62
- secator/runners/command.py,sha256=JzdwhbvsDujOyE-i_XgBGH-g6jaEoDNwL7CU2BIZ-Ng,18737
63
- secator/runners/scan.py,sha256=ZRfSgJd0RxtmxWp7cDGZsnmhdo-t1TSBH26XKxvH94k,1675
64
- secator/runners/task.py,sha256=hv9O8yeVBHuznDoNeQuDPxB6Doc2MKV_P838qJdO7b0,2772
65
- secator/runners/workflow.py,sha256=tQD03JqebVve9ncR9gxpzcgTsP6yvAWjUs2YBX80jzc,3717
61
+ secator/runners/_base.py,sha256=RHEQq-OvoC_rnpws30LmXDaO907pcblPe_WbWRcXQqk,28370
62
+ secator/runners/_helpers.py,sha256=kxXfxP4LOCz49p5Y-OKuUqvVAmRPtAoK2O9PHoUxCX0,3947
63
+ secator/runners/command.py,sha256=F6Eg5hLisk6KLXKSBgNIURu2A67heNzmkVF_OYF_Xdo,18688
64
+ secator/runners/scan.py,sha256=ZN6bgb3yqu5wemq_VVqul5VTU64TtYUl_0wkcW1aXRU,1647
65
+ secator/runners/task.py,sha256=c038lkkQ2H1GpLcHp46PEmSSXsIIRA5jnDgw6x8rEAY,2826
66
+ secator/runners/workflow.py,sha256=i2s-lJYIMJfHrxdVwglG9bkCGKu90yUNAM2lfwT6RIA,3689
66
67
  secator/serializers/__init__.py,sha256=OP5cmFl77ovgSCW_IDcZ21St2mUt5UK4QHfrsK2KvH8,248
67
68
  secator/serializers/dataclass.py,sha256=g5gMT4NwndjhGcGbFuYEs07AZW_Q_m9orov_edVEGlI,792
68
69
  secator/serializers/json.py,sha256=XwuSQOBwrOAs16F5HtY-Q-rAGAxfNvlq3z-Nb2gwigE,304
69
70
  secator/serializers/regex.py,sha256=hGJ_1JSOv9xPtfn_umHlsjnR_alnsDFv-UmjYCC3vwU,314
70
71
  secator/tasks/__init__.py,sha256=Wp2QF5QS2e_BlVygsIEFbmYPTfTg7v_Vd3LQJeXTC7I,344
71
- secator/tasks/_categories.py,sha256=w4vxKffTQFJEHNzi6BV5DslGpnSAlKEN0K7H6slG3Vg,9015
72
+ secator/tasks/_categories.py,sha256=2cUsZOdYHA-YXJwryU2FTTT4Y4xXzmDJ92F8ud-MDJQ,10402
72
73
  secator/tasks/cariddi.py,sha256=GKVJ8nWtJu9fB_FhAVYA2TX3fMdKYdbMpH2IhCkj_no,3155
73
74
  secator/tasks/dalfox.py,sha256=nrLkIbTNz_J7LgUy_3kBgzhTUbQi3RmiSJhc9HWa05c,1744
74
75
  secator/tasks/dirsearch.py,sha256=2hJeJZJwaAl3-UAjBwlmjW1w9bxjVWxxwfcaTTxqClc,2387
75
76
  secator/tasks/dnsx.py,sha256=H_3z87KAK-ndAQgCwS8TRWaUX_Hh54qEeuKQCS4rjBw,1771
76
- secator/tasks/dnsxbrute.py,sha256=obr2SsxIJlO2KckxrCOPHvvzyfequFW6-D4ZAUq4Egk,1224
77
+ secator/tasks/dnsxbrute.py,sha256=TT1wEU6BSS0VVwk7c5cFRKEnPji3HeK_tLrWtLJBSvk,1245
77
78
  secator/tasks/feroxbuster.py,sha256=9QQpd8T0CSMfXf_BMmCX4LeIogyvsc_ccXFJnEocxVo,3011
78
- secator/tasks/ffuf.py,sha256=ocmFfJJoV4zF8zkhUxHqUyDuJe9flmuijHCq_xk2pa4,2558
79
+ secator/tasks/ffuf.py,sha256=eJyXY912hg8e_8sibzo7X7704QM4vI4C0o317bcTV-c,2428
79
80
  secator/tasks/fping.py,sha256=P2EAPUGgwEC4Geh2zUbBPKF9bdqrlrdDg-R_TYLTFng,1127
80
81
  secator/tasks/gau.py,sha256=Sq5l277cGxpT2bB5s1RqrggP804RKbC6xxgLDZZzLFs,1391
81
82
  secator/tasks/gf.py,sha256=WlhoEyL6xE79w6nE5XNSXHs-jVeO10njqJxBF8w20sA,945
82
83
  secator/tasks/gospider.py,sha256=_UlTb9G5Ss8D68NT53s0_rI6TnG00Ph0yxWyHic7cKs,2172
83
84
  secator/tasks/grype.py,sha256=n60Zs9d1NWJFHQ0DwIZib5wu3xH-tV2RzgLYwuQSTo4,2413
84
85
  secator/tasks/h8mail.py,sha256=hZBpfV6M1mbpD_PbDHxLI5HMvqAvTeY_W0lbkq3Hugo,2037
85
- secator/tasks/httpx.py,sha256=NuycnbPejEZoUdFYFXyahYiZnzhz1cPJarHdP7WyP6c,3979
86
- secator/tasks/katana.py,sha256=Xa03zP2-78Ns59unUPrR_MHSd1DugTQlThxl8cL6pX4,4370
86
+ secator/tasks/httpx.py,sha256=ugk4AOIqhvT5-HVhlRsQw_oF2BGovgHlS-_D9wav8wo,3972
87
+ secator/tasks/katana.py,sha256=3JHtvxoSxJtju9xqvQptVaYXKnLLlCkOn6oY0A8h7wM,4371
87
88
  secator/tasks/maigret.py,sha256=PZDTICJ4LZF3joKe-dXu2alffakD_1sxBuNEUBtJDm4,2098
88
89
  secator/tasks/mapcidr.py,sha256=7aa2WXQATWgIQo5oA12URjAg80L6MFMGdxScxls8DuA,980
89
- secator/tasks/msfconsole.py,sha256=VlhEzsdYMHb6eJy4HBRdXMtRKhdzf5KtQGh7qZqO9Rs,6073
90
+ secator/tasks/msfconsole.py,sha256=Cm0vzOFff17C4M1YjkgU6T7Jc5-ClBK0Qi_529qVRb0,6065
90
91
  secator/tasks/naabu.py,sha256=RNs4NCZXgKhPqzR78l6l61tau0mGHuj6C3If7fimpgs,1594
91
- secator/tasks/nmap.py,sha256=LS5FBo-vFxbHVK4DxF5x-O2cAvAK3zL1pROT1GddX9E,9459
92
- secator/tasks/nuclei.py,sha256=7MlTygHd4EVz81ndrVwP5y6PZ-4j-Y8Oxuk3G3ayHPI,3343
92
+ secator/tasks/nmap.py,sha256=WS071HX7dnb2bP-M4Ah0yNYWva-WTVaj9oVzMMFUvRY,11239
93
+ secator/tasks/nuclei.py,sha256=lKZYPVcnCYomd830-ZCOz4fyc8xAKjNDuKayyz0BPek,3507
93
94
  secator/tasks/searchsploit.py,sha256=RD2uv3GFI3Eb-DiTzJp59jyXnvAZRACq-WjDI1NgFM0,1664
94
95
  secator/tasks/subfinder.py,sha256=cpFyFCpVaDZ3QAjNId26ezOwntn3CA5Uk-AC2l0mo0E,1087
95
96
  secator/tasks/wpscan.py,sha256=UVWnBPOQ1RDB2wzMswWR6vc6cucYgHtuJ8pLZoqCM40,5434
96
- secator-0.3.6.dist-info/METADATA,sha256=HaAuvqTAtZiaWWcTsn4KcZditRPlRYdE5nZQIboxwbk,13933
97
- secator-0.3.6.dist-info/WHEEL,sha256=K0BPUNF1N3kQ9olb8aVEtkObePEjdr2JOLT1N83EVws,87
98
- secator-0.3.6.dist-info/entry_points.txt,sha256=lPgsqqUXWgiuGSfKy-se5gHdQlAXIwS_A46NYq7Acic,44
99
- secator-0.3.6.dist-info/licenses/LICENSE,sha256=19W5Jsy4WTctNkqmZIqLRV1gTDOp01S3LDj9iSgWaJ0,2867
100
- secator-0.3.6.dist-info/RECORD,,
97
+ secator-0.4.0.dist-info/METADATA,sha256=sG5y-7z5TSaCkO2_BehY8co5v_ieePZfv2EV9k9K8pc,14095
98
+ secator-0.4.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
99
+ secator-0.4.0.dist-info/entry_points.txt,sha256=lPgsqqUXWgiuGSfKy-se5gHdQlAXIwS_A46NYq7Acic,44
100
+ secator-0.4.0.dist-info/licenses/LICENSE,sha256=19W5Jsy4WTctNkqmZIqLRV1gTDOp01S3LDj9iSgWaJ0,2867
101
+ secator-0.4.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.24.0
2
+ Generator: hatchling 1.24.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any