pyntcli 0.1.72__py3-none-any.whl → 0.1.73__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.
pyntcli/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.72"
1
+ __version__ = "0.1.73"
pyntcli/commands/burp.py CHANGED
@@ -18,7 +18,17 @@ from pyntcli.commands import util, sub_command
18
18
  from pyntcli.ui import report as cli_reporter
19
19
  from pyntcli.transport import pynt_requests
20
20
 
21
- methods = ["get", "post", "put", "delete", "patch", "options", "head", "trace", "connect"]
21
+ methods = [
22
+ "get",
23
+ "post",
24
+ "put",
25
+ "delete",
26
+ "patch",
27
+ "options",
28
+ "head",
29
+ "trace",
30
+ "connect",
31
+ ]
22
32
 
23
33
 
24
34
  def is_valid_method(method: str):
@@ -29,7 +39,7 @@ def is_valid_method(method: str):
29
39
 
30
40
  def replay_req(item, proxy_port):
31
41
  url = item["url"]
32
- decoded_req = base64.b64decode(item["request"]["#text"]).decode('utf-8')
42
+ decoded_req = base64.b64decode(item["request"]["#text"]).decode("utf-8")
33
43
  method = decoded_req.split("\r\n")[0].split(" ")[0]
34
44
 
35
45
  if not is_valid_method(method):
@@ -52,7 +62,16 @@ def replay_req(item, proxy_port):
52
62
  headers[key] = value
53
63
 
54
64
  body = decoded_req.split("\r\n\r\n")[1]
55
- pynt_requests.request_from_xml(method=method, url=url, headers=headers, data=body, proxies={'http': '0.0.0.0:{}'.format(proxy_port), 'https': '0.0.0.0:{}'.format(proxy_port)})
65
+ pynt_requests.request_from_xml(
66
+ method=method,
67
+ url=url,
68
+ headers=headers,
69
+ data=body,
70
+ proxies={
71
+ "http": "0.0.0.0:{}".format(proxy_port),
72
+ "https": "0.0.0.0:{}".format(proxy_port),
73
+ },
74
+ )
56
75
 
57
76
 
58
77
  def run_burp_xml(doc, proxy_port):
@@ -76,20 +95,35 @@ def is_valid_xml(doc) -> bool:
76
95
 
77
96
 
78
97
  def burp_usage():
79
- return ui_thread.PrinterText("Burp integration to Pynt. Run a security scan with a given burp xml output file.") \
80
- .with_line("") \
81
- .with_line("Usage:", style=ui_thread.PrinterText.HEADER) \
82
- .with_line("\tpynt burp [OPTIONS]") \
83
- .with_line("") \
84
- .with_line("Options:", style=ui_thread.PrinterText.HEADER) \
85
- .with_line("\t--xml - Path to the xml to run tests on") \
86
- .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)") \
87
- .with_line("\t--ca-path - The path to the CA file in PEM format") \
88
- .with_line("\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)") \
89
- .with_line("\t--report - If present will save the generated report in this path.") \
90
- .with_line("\t--insecure - use when target uses self signed certificates") \
91
- .with_line("\t--host-ca - path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN.") \
92
- .with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), ")
98
+ return (
99
+ ui_thread.PrinterText(
100
+ "Burp integration to Pynt. Run a security scan with a given burp xml output file."
101
+ )
102
+ .with_line("")
103
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER)
104
+ .with_line("\tpynt burp [OPTIONS]")
105
+ .with_line("")
106
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER)
107
+ .with_line("\t--xml - Path to the xml to run tests on")
108
+ .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)")
109
+ .with_line("\t--ca-path - The path to the CA file in PEM format")
110
+ .with_line(
111
+ "\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)"
112
+ )
113
+ .with_line(
114
+ "\t--report - If present will save the generated report in this path."
115
+ )
116
+ .with_line("\t--insecure - Use when target uses self signed certificates")
117
+ .with_line(
118
+ "\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
119
+ )
120
+ .with_line(
121
+ "\t--host-ca - Path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
122
+ )
123
+ .with_line(
124
+ "\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), "
125
+ )
126
+ )
93
127
 
94
128
 
95
129
  class BurpCommand(sub_command.PyntSubCommand):
@@ -110,25 +144,38 @@ class BurpCommand(sub_command.PyntSubCommand):
110
144
  burp_cmd.add_argument("--xml", help="", default="", required=True)
111
145
  burp_cmd.add_argument("--ca-path", type=str, default="")
112
146
  burp_cmd.add_argument("--report", type=str, default="")
113
- burp_cmd.add_argument('--return-error', choices=['all-findings', 'errors-only', 'never'], default='never')
147
+ burp_cmd.add_argument(
148
+ "--return-error",
149
+ choices=["all-findings", "errors-only", "never"],
150
+ default="never",
151
+ )
114
152
  burp_cmd.print_usage = self.print_usage
115
153
  burp_cmd.print_help = self.print_usage
116
154
  return burp_cmd
117
155
 
118
156
  def _updated_environment(self, args):
119
157
  env_copy = deepcopy(os.environ)
120
- return env_copy.update({"HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
121
- "HTTPS_PROXY": "http://localhost:{}".format(args.proxy_port)})
158
+ return env_copy.update(
159
+ {
160
+ "HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
161
+ "HTTPS_PROXY": "http://localhost:{}".format(args.proxy_port),
162
+ }
163
+ )
122
164
 
123
165
  def _start_proxy(self, args):
124
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/start")
166
+ res = pynt_requests.put(
167
+ self.proxy_server_base_url.format(args.port) + "/proxy/start"
168
+ )
125
169
  res.raise_for_status()
126
170
  self.scan_id = res.json()["scanId"]
127
171
 
128
172
  def _stop_proxy(self, args):
129
173
  start = time.time()
130
174
  while start + self.proxy_healthcheck_buffer > time.time():
131
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/stop", json={"scanId": self.scan_id})
175
+ res = pynt_requests.put(
176
+ self.proxy_server_base_url.format(args.port) + "/proxy/stop",
177
+ json={"scanId": self.scan_id},
178
+ )
132
179
  if res.status_code == HTTPStatus.OK:
133
180
  return
134
181
  time.sleep(self.proxy_sleep_interval)
@@ -136,47 +183,86 @@ class BurpCommand(sub_command.PyntSubCommand):
136
183
 
137
184
  def _get_report(self, args, report_format):
138
185
  while True:
139
- res = pynt_requests.get(self.proxy_server_base_url.format(args.port) + "/report?format={}".format(report_format), params={"scanId": self.scan_id})
186
+ res = pynt_requests.get(
187
+ self.proxy_server_base_url.format(args.port)
188
+ + "/report?format={}".format(report_format),
189
+ params={"scanId": self.scan_id},
190
+ )
140
191
  if res.status_code == HTTPStatus.OK:
141
192
  return res.text
142
193
  if res.status_code == HTTPStatus.ACCEPTED:
143
194
  time.sleep(self.proxy_sleep_interval)
144
195
  continue
145
196
  if res.status_code == 517: # pynt did not recieve any requests
146
- ui_thread.print(ui_thread.PrinterText(res.json()["message"], ui_thread.PrinterText.WARNING))
197
+ ui_thread.print(
198
+ ui_thread.PrinterText(
199
+ res.json()["message"], ui_thread.PrinterText.WARNING
200
+ )
201
+ )
147
202
  return
148
203
  ui_thread.print("Error in polling for scan report: {}".format(res.text))
149
204
  return
150
205
 
151
206
  def run_cmd(self, args: argparse.Namespace):
152
- container = pynt_container.get_container_with_arguments(args, pynt_container.PyntDockerPort(args.port, args.port, "--port"),
153
- pynt_container.PyntDockerPort(args.proxy_port, args.proxy_port, "--proxy-port"))
207
+ container = pynt_container.get_container_with_arguments(
208
+ args,
209
+ pynt_container.PyntDockerPort(args.port, args.port, "--port"),
210
+ pynt_container.PyntDockerPort(
211
+ args.proxy_port, args.proxy_port, "--proxy-port"
212
+ ),
213
+ )
154
214
  if "ca_path" in args and args.ca_path:
155
215
  if not os.path.isfile(args.ca_path):
156
- ui_thread.print(ui_thread.PrinterText("Could not find the provided ca path, please provide with a valid path", ui_thread.PrinterText.WARNING))
216
+ ui_thread.print(
217
+ ui_thread.PrinterText(
218
+ "Could not find the provided ca path, please provide with a valid path",
219
+ ui_thread.PrinterText.WARNING,
220
+ )
221
+ )
157
222
  return
158
223
 
159
224
  ca_name = os.path.basename(args.ca_path)
160
225
  container.docker_arguments += ["--ca-path", ca_name]
161
- container.mounts.append(pynt_container.create_mount(os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)))
226
+ container.mounts.append(
227
+ pynt_container.create_mount(
228
+ os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
229
+ )
230
+ )
162
231
 
163
232
  if not os.path.isfile(args.xml):
164
- ui_thread.print(ui_thread.PrinterText("Could not find the provided xml path, please provide with a valid xml path", ui_thread.PrinterText.WARNING))
233
+ ui_thread.print(
234
+ ui_thread.PrinterText(
235
+ "Could not find the provided xml path, please provide with a valid xml path",
236
+ ui_thread.PrinterText.WARNING,
237
+ )
238
+ )
165
239
  return
166
240
 
167
241
  doc = parse_xml(args.xml)
168
242
  if not doc:
169
- ui_thread.print(ui_thread.PrinterText("Invalid file format. please provide a valid xml", ui_thread.PrinterText.WARNING))
243
+ ui_thread.print(
244
+ ui_thread.PrinterText(
245
+ "Invalid file format. please provide a valid xml",
246
+ ui_thread.PrinterText.WARNING,
247
+ )
248
+ )
170
249
  return
171
250
 
172
251
  if not is_valid_xml(doc):
173
- ui_thread.print(ui_thread.PrinterText("Invalid xml file. please provide a valid xml output generated from burp", ui_thread.PrinterText.WARNING))
252
+ ui_thread.print(
253
+ ui_thread.PrinterText(
254
+ "Invalid xml file. please provide a valid xml output generated from burp",
255
+ ui_thread.PrinterText.WARNING,
256
+ )
257
+ )
174
258
  return
175
259
 
176
- proxy_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
177
- tag="proxy-latest",
178
- detach=True,
179
- base_container=container)
260
+ proxy_docker = pynt_container.PyntContainer(
261
+ image_name=pynt_container.PYNT_DOCKER_IMAGE,
262
+ tag="proxy-latest",
263
+ detach=True,
264
+ base_container=container,
265
+ )
180
266
  proxy_docker.run()
181
267
  ui_thread.print_generator(proxy_docker.stdout)
182
268
 
@@ -187,12 +273,21 @@ class BurpCommand(sub_command.PyntSubCommand):
187
273
 
188
274
  self._stop_proxy(args)
189
275
 
190
- with ui_thread.progress("ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id), partial(lambda *args: None), "scan in progress...", 100):
276
+ with ui_thread.progress(
277
+ "ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),
278
+ partial(lambda *args: None),
279
+ "scan in progress...",
280
+ 100,
281
+ ):
191
282
  html_report = self._get_report(args, "html")
192
- html_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time())))
283
+ html_report_path = os.path.join(
284
+ tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time()))
285
+ )
193
286
 
194
287
  json_report = self._get_report(args, "json")
195
- json_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time())))
288
+ json_report_path = os.path.join(
289
+ tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time()))
290
+ )
196
291
 
197
292
  if "report" in args and args.report:
198
293
  full_path = os.path.abspath(args.report)
@@ -17,22 +17,41 @@ from pyntcli.transport import pynt_requests
17
17
 
18
18
 
19
19
  def command_usage():
20
- return ui_thread.PrinterText("Command integration to Pynt. Run a security scan with a given command.") \
21
- .with_line("") \
22
- .with_line("Usage:", style=ui_thread.PrinterText.HEADER) \
23
- .with_line("\tpynt command [OPTIONS]") \
24
- .with_line("") \
25
- .with_line("Options:", style=ui_thread.PrinterText.HEADER) \
26
- .with_line("\t--cmd - The command that runs the functional tests") \
27
- .with_line("\t--captured-domains - Pynt will scan only these domains and subdomains. For all domains write \"*\"") \
28
- .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)") \
29
- .with_line("\t--allow-errors - If present will allow command to fail and continue execution") \
30
- .with_line("\t--ca-path - The path to the CA file in PEM format") \
31
- .with_line("\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)") \
32
- .with_line("\t--report - If present will save the generated report in this path.") \
33
- .with_line("\t--insecure - use when target uses self signed certificates") \
34
- .with_line("\t--host-ca - path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN.") \
35
- .with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), ")
20
+ return (
21
+ ui_thread.PrinterText(
22
+ "Command integration to Pynt. Run a security scan with a given command."
23
+ )
24
+ .with_line("")
25
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER)
26
+ .with_line("\tpynt command [OPTIONS]")
27
+ .with_line("")
28
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER)
29
+ .with_line("\t--cmd - The command that runs the functional tests")
30
+ .with_line(
31
+ '\t--captured-domains - Pynt will scan only these domains and subdomains. For all domains write "*"'
32
+ )
33
+ .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)")
34
+ .with_line(
35
+ "\t--allow-errors - If present will allow command to fail and continue execution"
36
+ )
37
+ .with_line("\t--ca-path - The path to the CA file in PEM format")
38
+ .with_line(
39
+ "\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)"
40
+ )
41
+ .with_line(
42
+ "\t--report - If present will save the generated report in this path."
43
+ )
44
+ .with_line("\t--insecure - Use when target uses self signed certificates")
45
+ .with_line(
46
+ "\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
47
+ )
48
+ .with_line(
49
+ "\t--host-ca - Path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
50
+ )
51
+ .with_line(
52
+ "\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), "
53
+ )
54
+ )
36
55
 
37
56
 
38
57
  class CommandSubCommand(sub_command.PyntSubCommand):
@@ -51,29 +70,44 @@ class CommandSubCommand(sub_command.PyntSubCommand):
51
70
  proxy_cmd.add_argument("--port", "-p", help="", type=int, default=5001)
52
71
  proxy_cmd.add_argument("--proxy-port", help="", type=int, default=6666)
53
72
  proxy_cmd.add_argument("--cmd", help="", default="", required=True)
54
- proxy_cmd.add_argument("--captured-domains", nargs='+', help="", default="", required=False)
73
+ proxy_cmd.add_argument(
74
+ "--captured-domains", nargs="+", help="", default="", required=False
75
+ )
55
76
  proxy_cmd.add_argument("--allow-errors", action="store_true")
56
77
  proxy_cmd.add_argument("--ca-path", type=str, default="")
57
78
  proxy_cmd.add_argument("--report", type=str, default="")
58
- proxy_cmd.add_argument('--return-error', choices=['all-findings', 'errors-only', 'never'], default='never')
79
+ proxy_cmd.add_argument(
80
+ "--return-error",
81
+ choices=["all-findings", "errors-only", "never"],
82
+ default="never",
83
+ )
59
84
  proxy_cmd.print_usage = self.print_usage
60
85
  proxy_cmd.print_help = self.print_usage
61
86
  return proxy_cmd
62
87
 
63
88
  def _updated_environment(self, args):
64
89
  env_copy = deepcopy(os.environ)
65
- return env_copy.update({"HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
66
- "HTTPS_PROXY": "http://localhost:{}".format(args.proxy_port)})
90
+ return env_copy.update(
91
+ {
92
+ "HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
93
+ "HTTPS_PROXY": "http://localhost:{}".format(args.proxy_port),
94
+ }
95
+ )
67
96
 
68
97
  def _start_proxy(self, args):
69
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/start")
98
+ res = pynt_requests.put(
99
+ self.proxy_server_base_url.format(args.port) + "/proxy/start"
100
+ )
70
101
  res.raise_for_status()
71
102
  self.scan_id = res.json()["scanId"]
72
103
 
73
104
  def _stop_proxy(self, args):
74
105
  start = time.time()
75
106
  while start + self.proxy_healthcheck_buffer > time.time():
76
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/stop", json={"scanId": self.scan_id})
107
+ res = pynt_requests.put(
108
+ self.proxy_server_base_url.format(args.port) + "/proxy/stop",
109
+ json={"scanId": self.scan_id},
110
+ )
77
111
  if res.status_code == HTTPStatus.OK:
78
112
  return
79
113
  time.sleep(self.proxy_sleep_interval)
@@ -81,21 +115,34 @@ class CommandSubCommand(sub_command.PyntSubCommand):
81
115
 
82
116
  def _get_report(self, args, report_format):
83
117
  while True:
84
- res = pynt_requests.get(self.proxy_server_base_url.format(args.port) + "/report?format={}".format(report_format), params={"scanId": self.scan_id})
118
+ res = pynt_requests.get(
119
+ self.proxy_server_base_url.format(args.port)
120
+ + "/report?format={}".format(report_format),
121
+ params={"scanId": self.scan_id},
122
+ )
85
123
  if res.status_code == HTTPStatus.OK:
86
124
  return res.text
87
125
  if res.status_code == HTTPStatus.ACCEPTED:
88
126
  time.sleep(self.proxy_sleep_interval)
89
127
  continue
90
128
  if res.status_code == 517: # pynt did not recieve any requests
91
- ui_thread.print(ui_thread.PrinterText(res.json()["message"], ui_thread.PrinterText.WARNING))
129
+ ui_thread.print(
130
+ ui_thread.PrinterText(
131
+ res.json()["message"], ui_thread.PrinterText.WARNING
132
+ )
133
+ )
92
134
  return
93
135
  ui_thread.print("Error in polling for scan report: {}".format(res.text))
94
136
  return
95
137
 
96
138
  def run_cmd(self, args: argparse.Namespace):
97
- container = pynt_container.get_container_with_arguments(args, pynt_container.PyntDockerPort(args.port, args.port, "--port"),
98
- pynt_container.PyntDockerPort(args.proxy_port, args.proxy_port, "--proxy-port"))
139
+ container = pynt_container.get_container_with_arguments(
140
+ args,
141
+ pynt_container.PyntDockerPort(args.port, args.port, "--port"),
142
+ pynt_container.PyntDockerPort(
143
+ args.proxy_port, args.proxy_port, "--proxy-port"
144
+ ),
145
+ )
99
146
 
100
147
  if args.captured_domains:
101
148
  for host in args.captured_domains:
@@ -103,44 +150,80 @@ class CommandSubCommand(sub_command.PyntSubCommand):
103
150
 
104
151
  if "ca_path" in args and args.ca_path:
105
152
  if not os.path.isfile(args.ca_path):
106
- ui_thread.print(ui_thread.PrinterText("Could not find the provided ca path, please provide with a valid path", ui_thread.PrinterText.WARNING))
153
+ ui_thread.print(
154
+ ui_thread.PrinterText(
155
+ "Could not find the provided ca path, please provide with a valid path",
156
+ ui_thread.PrinterText.WARNING,
157
+ )
158
+ )
107
159
  return
108
160
 
109
161
  ca_name = os.path.basename(args.ca_path)
110
162
  container.docker_arguments += ["--ca-path", ca_name]
111
- container.mounts.append(pynt_container.create_mount(os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)))
112
-
113
- proxy_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
114
- tag="proxy-latest",
115
- detach=True,
116
- base_container=container)
163
+ container.mounts.append(
164
+ pynt_container.create_mount(
165
+ os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
166
+ )
167
+ )
168
+
169
+ proxy_docker = pynt_container.PyntContainer(
170
+ image_name=pynt_container.PYNT_DOCKER_IMAGE,
171
+ tag="proxy-latest",
172
+ detach=True,
173
+ base_container=container,
174
+ )
117
175
  proxy_docker.run()
118
176
  ui_thread.print_generator(proxy_docker.stdout)
119
177
 
120
178
  util.wait_for_healthcheck("http://localhost:{}".format(args.port))
121
179
 
122
180
  if args.captured_domains:
123
- ui_thread.print("\nWill scan APIs that belong to {} domains only".format(args.captured_domains))
181
+ ui_thread.print(
182
+ "\nWill scan APIs that belong to {} domains only".format(
183
+ args.captured_domains
184
+ )
185
+ )
124
186
 
125
187
  self._start_proxy(args)
126
188
 
127
- user_process = Popen(args.cmd, shell=True, stdout=PIPE, stderr=PIPE, env=self._updated_environment(args))
189
+ user_process = Popen(
190
+ args.cmd,
191
+ shell=True,
192
+ stdout=PIPE,
193
+ stderr=PIPE,
194
+ env=self._updated_environment(args),
195
+ )
128
196
  ui_thread.print_generator(user_process.stdout)
129
197
  ui_thread.print_generator(user_process.stderr)
130
198
  rc = user_process.wait()
131
199
  if rc != 0 and not args.allow_errors:
132
200
  proxy_docker.stop()
133
- ui_thread.print(ui_thread.PrinterText("Command finished with error return code {}, If you wish Pynt to run anyway, run with --allow-errors".format(rc)))
201
+ ui_thread.print(
202
+ ui_thread.PrinterText(
203
+ "Command finished with error return code {}, If you wish Pynt to run anyway, run with --allow-errors".format(
204
+ rc
205
+ )
206
+ )
207
+ )
134
208
  return
135
209
 
136
210
  self._stop_proxy(args)
137
211
 
138
- with ui_thread.progress("ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id), partial(lambda *args: None), "scan in progress...", 100):
212
+ with ui_thread.progress(
213
+ "ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),
214
+ partial(lambda *args: None),
215
+ "scan in progress...",
216
+ 100,
217
+ ):
139
218
  html_report = self._get_report(args, "html")
140
- html_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time())))
219
+ html_report_path = os.path.join(
220
+ tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time()))
221
+ )
141
222
 
142
223
  json_report = self._get_report(args, "json")
143
- json_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time())))
224
+ json_report_path = os.path.join(
225
+ tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time()))
226
+ )
144
227
 
145
228
  if "report" in args and args.report:
146
229
  full_path = os.path.abspath(args.report)
pyntcli/commands/har.py CHANGED
@@ -10,17 +10,26 @@ from pyntcli.commands import sub_command, util
10
10
 
11
11
 
12
12
  def har_usage():
13
- return ui_thread.PrinterText("Integration with static har file testing") \
14
- .with_line("") \
15
- .with_line("Usage:", style=ui_thread.PrinterText.HEADER) \
16
- .with_line("\tpynt har [OPTIONS]") \
17
- .with_line("") \
18
- .with_line("Options:", style=ui_thread.PrinterText.HEADER) \
19
- .with_line("\t--har - Path to har file") \
20
- .with_line("\t--captured-domains - Pynt will scan only these domains and subdomains. For all domains write \"*\"") \
21
- .with_line("\t--reporters output results to json") \
22
- .with_line("\t--host-ca - path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN.") \
13
+ return (
14
+ ui_thread.PrinterText("Integration with static har file testing")
23
15
  .with_line("")
16
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER)
17
+ .with_line("\tpynt har [OPTIONS]")
18
+ .with_line("")
19
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER)
20
+ .with_line("\t--har - Path to har file")
21
+ .with_line(
22
+ '\t--captured-domains - Pynt will scan only these domains and subdomains. For all domains write "*"'
23
+ )
24
+ .with_line("\t--reporters - Output results to json")
25
+ .with_line(
26
+ "\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
27
+ )
28
+ .with_line(
29
+ "\t--host-ca - Path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
30
+ )
31
+ .with_line("")
32
+ )
24
33
 
25
34
 
26
35
  class HarSubCommand(sub_command.PyntSubCommand):
@@ -33,23 +42,36 @@ class HarSubCommand(sub_command.PyntSubCommand):
33
42
  def add_cmd(self, parent: argparse._SubParsersAction) -> argparse.ArgumentParser:
34
43
  har_cmd = parent.add_parser(self.name)
35
44
  har_cmd.add_argument("--har", type=str, required=True)
36
- har_cmd.add_argument("--captured-domains", nargs='+', help="", default="", required=True)
37
- har_cmd.add_argument("--reporters", action='store_true')
45
+ har_cmd.add_argument(
46
+ "--captured-domains", nargs="+", help="", default="", required=True
47
+ )
48
+ har_cmd.add_argument("--reporters", action="store_true")
38
49
  har_cmd.print_usage = self.usage
39
50
  har_cmd.print_help = self.usage
40
51
  return har_cmd
41
52
 
42
53
  def run_cmd(self, args: argparse.Namespace):
43
54
  port = str(util.find_open_port())
44
- container = pynt_container.get_container_with_arguments(args, pynt_container.PyntDockerPort(src=port, dest=port, name="--port"))
55
+ container = pynt_container.get_container_with_arguments(
56
+ args, pynt_container.PyntDockerPort(src=port, dest=port, name="--port")
57
+ )
45
58
 
46
59
  if not os.path.isfile(args.har):
47
- ui_thread.print(ui_thread.PrinterText("Could not find the provided har path, please provide with a valid har path", ui_thread.PrinterText.WARNING))
60
+ ui_thread.print(
61
+ ui_thread.PrinterText(
62
+ "Could not find the provided har path, please provide with a valid har path",
63
+ ui_thread.PrinterText.WARNING,
64
+ )
65
+ )
48
66
  return
49
67
 
50
68
  har_name = os.path.basename(args.har)
51
69
  container.docker_arguments += ["--har", har_name]
52
- container.mounts.append(pynt_container.create_mount(os.path.abspath(args.har), "/etc/pynt/{}".format(har_name)))
70
+ container.mounts.append(
71
+ pynt_container.create_mount(
72
+ os.path.abspath(args.har), "/etc/pynt/{}".format(har_name)
73
+ )
74
+ )
53
75
 
54
76
  for host in args.captured_domains:
55
77
  container.docker_arguments += ["--host-targets", host]
@@ -58,16 +80,25 @@ class HarSubCommand(sub_command.PyntSubCommand):
58
80
 
59
81
  container.mounts += m
60
82
 
61
- har_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
62
- tag="har-latest",
63
- detach=True,
64
- base_container=container)
83
+ har_docker = pynt_container.PyntContainer(
84
+ image_name=pynt_container.PYNT_DOCKER_IMAGE,
85
+ tag="har-latest",
86
+ detach=True,
87
+ base_container=container,
88
+ )
65
89
 
66
90
  har_docker.run()
67
91
 
68
- healthcheck = partial(util.wait_for_healthcheck, "http://localhost:{}".format(port))
92
+ healthcheck = partial(
93
+ util.wait_for_healthcheck, "http://localhost:{}".format(port)
94
+ )
69
95
  ui_thread.print_generator(ui_thread.AnsiText.wrap_gen(har_docker.stdout))
70
96
 
71
- with ui_thread.progress("ws://localhost:{}/progress".format(port), healthcheck, "scan in progress...", 100):
97
+ with ui_thread.progress(
98
+ "ws://localhost:{}/progress".format(port),
99
+ healthcheck,
100
+ "scan in progress...",
101
+ 100,
102
+ ):
72
103
  while har_docker.is_alive():
73
104
  time.sleep(1)
@@ -17,20 +17,37 @@ from pyntcli.transport import pynt_requests
17
17
 
18
18
 
19
19
  def listen_usage():
20
- return ui_thread.PrinterText("Listen integration to Pynt. Run a security scan with routed traffic.") \
21
- .with_line("") \
22
- .with_line("Usage:", style=ui_thread.PrinterText.HEADER) \
23
- .with_line("\tpynt listen [OPTIONS]") \
24
- .with_line("") \
25
- .with_line("Options:", style=ui_thread.PrinterText.HEADER) \
26
- .with_line("\t--captured-domains - Pynt will scan only these domains and subdomains. For all domains write \"*\"") \
27
- .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)") \
28
- .with_line("\t--ca-path - The path to the CA file in PEM format") \
29
- .with_line("\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)") \
30
- .with_line("\t--report - If present will save the generated report in this path.") \
31
- .with_line("\t--insecure - use when target uses self signed certificates") \
32
- .with_line("\t--host-ca - path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN.") \
33
- .with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), ")
20
+ return (
21
+ ui_thread.PrinterText(
22
+ "Listen integration to Pynt. Run a security scan with routed traffic."
23
+ )
24
+ .with_line("")
25
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER)
26
+ .with_line("\tpynt listen [OPTIONS]")
27
+ .with_line("")
28
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER)
29
+ .with_line(
30
+ '\t--captured-domains - Pynt will scan only these domains and subdomains. For all domains write "*"'
31
+ )
32
+ .with_line("\t--port - Set the port pynt will listen to (DEFAULT: 5001)")
33
+ .with_line("\t--ca-path - The path to the CA file in PEM format")
34
+ .with_line(
35
+ "\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)"
36
+ )
37
+ .with_line(
38
+ "\t--report - If present will save the generated report in this path."
39
+ )
40
+ .with_line(
41
+ "\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
42
+ )
43
+ .with_line("\t--insecure - use when target uses self signed certificates")
44
+ .with_line(
45
+ "\t--host-ca - path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
46
+ )
47
+ .with_line(
48
+ "\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), "
49
+ )
50
+ )
34
51
 
35
52
 
36
53
  class ListenSubCommand(sub_command.PyntSubCommand):
@@ -48,24 +65,35 @@ class ListenSubCommand(sub_command.PyntSubCommand):
48
65
  listen_cmd = parent.add_parser(self.name)
49
66
  listen_cmd.add_argument("--port", "-p", help="", type=int, default=5001)
50
67
  listen_cmd.add_argument("--proxy-port", help="", type=int, default=6666)
51
- listen_cmd.add_argument("--captured-domains", nargs='+', help="", default="", required=True)
68
+ listen_cmd.add_argument(
69
+ "--captured-domains", nargs="+", help="", default="", required=True
70
+ )
52
71
  listen_cmd.add_argument("--allow-errors", action="store_true")
53
72
  listen_cmd.add_argument("--ca-path", type=str, default="")
54
73
  listen_cmd.add_argument("--report", type=str, default="")
55
- listen_cmd.add_argument('--return-error', choices=['all-findings', 'errors-only', 'never'], default='never')
74
+ listen_cmd.add_argument(
75
+ "--return-error",
76
+ choices=["all-findings", "errors-only", "never"],
77
+ default="never",
78
+ )
56
79
  listen_cmd.print_usage = self.print_usage
57
80
  listen_cmd.print_help = self.print_usage
58
81
  return listen_cmd
59
82
 
60
83
  def _start_proxy(self, args):
61
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/start")
84
+ res = pynt_requests.put(
85
+ self.proxy_server_base_url.format(args.port) + "/proxy/start"
86
+ )
62
87
  res.raise_for_status()
63
88
  self.scan_id = res.json()["scanId"]
64
89
 
65
90
  def _stop_proxy(self, args):
66
91
  start = time.time()
67
92
  while start + self.proxy_healthcheck_buffer > time.time():
68
- res = pynt_requests.put(self.proxy_server_base_url.format(args.port) + "/proxy/stop", json={"scanId": self.scan_id})
93
+ res = pynt_requests.put(
94
+ self.proxy_server_base_url.format(args.port) + "/proxy/stop",
95
+ json={"scanId": self.scan_id},
96
+ )
69
97
  if res.status_code == HTTPStatus.OK:
70
98
  return
71
99
  time.sleep(self.proxy_sleep_interval)
@@ -73,38 +101,62 @@ class ListenSubCommand(sub_command.PyntSubCommand):
73
101
 
74
102
  def _get_report(self, args, report_format):
75
103
  while True:
76
- res = pynt_requests.get(self.proxy_server_base_url.format(args.port) + "/report?format={}".format(report_format), params={"scanId": self.scan_id})
104
+ res = pynt_requests.get(
105
+ self.proxy_server_base_url.format(args.port)
106
+ + "/report?format={}".format(report_format),
107
+ params={"scanId": self.scan_id},
108
+ )
77
109
  if res.status_code == HTTPStatus.OK:
78
110
  return res.text
79
111
  if res.status_code == HTTPStatus.ACCEPTED:
80
112
  time.sleep(self.proxy_sleep_interval)
81
113
  continue
82
114
  if res.status_code == 517: # pynt did not recieve any requests
83
- ui_thread.print(ui_thread.PrinterText(res.json()["message"], ui_thread.PrinterText.WARNING))
115
+ ui_thread.print(
116
+ ui_thread.PrinterText(
117
+ res.json()["message"], ui_thread.PrinterText.WARNING
118
+ )
119
+ )
84
120
  return
85
121
  ui_thread.print("Error in polling for scan report: {}".format(res.text))
86
122
  return
87
123
 
88
124
  def run_cmd(self, args: argparse.Namespace):
89
- container = pynt_container.get_container_with_arguments(args, pynt_container.PyntDockerPort(args.port, args.port, "--port"),
90
- pynt_container.PyntDockerPort(args.proxy_port, args.proxy_port, "--proxy-port"))
125
+ container = pynt_container.get_container_with_arguments(
126
+ args,
127
+ pynt_container.PyntDockerPort(args.port, args.port, "--port"),
128
+ pynt_container.PyntDockerPort(
129
+ args.proxy_port, args.proxy_port, "--proxy-port"
130
+ ),
131
+ )
91
132
 
92
133
  for host in args.captured_domains:
93
134
  container.docker_arguments += ["--host-targets", host]
94
135
 
95
136
  if "ca_path" in args and args.ca_path:
96
137
  if not os.path.isfile(args.ca_path):
97
- ui_thread.print(ui_thread.PrinterText("Could not find the provided ca path, please provide with a valid path", ui_thread.PrinterText.WARNING))
138
+ ui_thread.print(
139
+ ui_thread.PrinterText(
140
+ "Could not find the provided ca path, please provide with a valid path",
141
+ ui_thread.PrinterText.WARNING,
142
+ )
143
+ )
98
144
  return
99
145
 
100
146
  ca_name = os.path.basename(args.ca_path)
101
147
  container.docker_arguments += ["--ca-path", ca_name]
102
- container.mounts.append(pynt_container.create_mount(os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)))
103
-
104
- proxy_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
105
- tag="proxy-latest",
106
- detach=True,
107
- base_container=container)
148
+ container.mounts.append(
149
+ pynt_container.create_mount(
150
+ os.path.abspath(args.ca_path), "/etc/pynt/{}".format(ca_name)
151
+ )
152
+ )
153
+
154
+ proxy_docker = pynt_container.PyntContainer(
155
+ image_name=pynt_container.PYNT_DOCKER_IMAGE,
156
+ tag="proxy-latest",
157
+ detach=True,
158
+ base_container=container,
159
+ )
108
160
  proxy_docker.run()
109
161
  ui_thread.print_generator(proxy_docker.stdout)
110
162
 
@@ -112,22 +164,45 @@ class ListenSubCommand(sub_command.PyntSubCommand):
112
164
 
113
165
  self._start_proxy(args)
114
166
 
115
- ui_thread.print(ui_thread.PrinterText("\nListening to traffic on port: {}".format(args.proxy_port), ui_thread.PrinterText.DEFAULT)
116
- .with_line("Will scan APIs that belong to \'{}\' domains only".format(args.captured_domains))
117
- .with_line(""))
118
-
119
- ui_thread.print(ui_thread.PrinterText("Press Enter to stop recording traffic and run security scan...", ui_thread.PrinterText.HEADER))
167
+ ui_thread.print(
168
+ ui_thread.PrinterText(
169
+ "\nListening to traffic on port: {}".format(args.proxy_port),
170
+ ui_thread.PrinterText.DEFAULT,
171
+ )
172
+ .with_line(
173
+ "Will scan APIs that belong to '{}' domains only".format(
174
+ args.captured_domains
175
+ )
176
+ )
177
+ .with_line("")
178
+ )
179
+
180
+ ui_thread.print(
181
+ ui_thread.PrinterText(
182
+ "Press Enter to stop recording traffic and run security scan...",
183
+ ui_thread.PrinterText.HEADER,
184
+ )
185
+ )
120
186
 
121
187
  input()
122
188
 
123
189
  self._stop_proxy(args)
124
190
 
125
- with ui_thread.progress("ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id), partial(lambda *args: None), "scan in progress...", 100):
191
+ with ui_thread.progress(
192
+ "ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),
193
+ partial(lambda *args: None),
194
+ "scan in progress...",
195
+ 100,
196
+ ):
126
197
  html_report = self._get_report(args, "html")
127
- html_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time())))
198
+ html_report_path = os.path.join(
199
+ tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time()))
200
+ )
128
201
 
129
202
  json_report = self._get_report(args, "json")
130
- json_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time())))
203
+ json_report_path = os.path.join(
204
+ tempfile.gettempdir(), "pynt_report_{}.json".format(int(time.time()))
205
+ )
131
206
 
132
207
  if "report" in args and args.report:
133
208
  full_path = os.path.abspath(args.report)
@@ -8,32 +8,51 @@ from pyntcli.commands import sub_command, util
8
8
  from pyntcli.ui import ui_thread
9
9
  from pyntcli.ui.progress import PyntProgress
10
10
 
11
+
11
12
  def newman_usage():
12
- return ui_thread.PrinterText("Integration with newman, run scan using postman collection from the CLI") \
13
- .with_line("") \
14
- .with_line("Usage:", style=ui_thread.PrinterText.HEADER) \
15
- .with_line("\tpynt newman [OPTIONS]") \
16
- .with_line("") \
17
- .with_line("Options:", style=ui_thread.PrinterText.HEADER) \
18
- .with_line("\t--collection - Postman collection file name") \
19
- .with_line("\t--environment - Postman environment file name") \
20
- .with_line("\t--reporters output results to json") \
21
- .with_line("\t--host-ca - path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN.") \
22
- .with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), ")
13
+ return (
14
+ ui_thread.PrinterText(
15
+ "Integration with newman, run scan using postman collection from the CLI"
16
+ )
17
+ .with_line("")
18
+ .with_line("Usage:", style=ui_thread.PrinterText.HEADER)
19
+ .with_line("\tpynt newman [OPTIONS]")
20
+ .with_line("")
21
+ .with_line("Options:", style=ui_thread.PrinterText.HEADER)
22
+ .with_line("\t--collection - Postman collection file name")
23
+ .with_line("\t--environment - Postman environment file name")
24
+ .with_line("\t--reporters Output results to json")
25
+ .with_line(
26
+ "\t--host-ca - Path to the CA file in PEM format to enable SSL certificate verification for pynt when running through a VPN."
27
+ )
28
+ .with_line(
29
+ "\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io"
30
+ )
31
+ .with_line(
32
+ "\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default), "
33
+ )
34
+ )
35
+
23
36
 
24
37
  class NewmanSubCommand(sub_command.PyntSubCommand):
25
38
  def __init__(self, name) -> None:
26
39
  super().__init__(name)
27
40
 
28
- def usage(self, *args):
41
+ def usage(self, *args):
29
42
  ui_thread.print(newman_usage())
30
43
 
31
44
  def add_cmd(self, parent: argparse._SubParsersAction) -> argparse.ArgumentParser:
32
45
  newman_cmd = parent.add_parser(self.name)
33
- newman_cmd.add_argument("--collection", type=str, required=True)
34
- newman_cmd.add_argument("--environment", nargs='+', required=False)
35
- newman_cmd.add_argument("--reporters", action="store_true",default=False, required=False)
36
- newman_cmd.add_argument('--return-error', choices=['all-findings', 'errors-only', 'never'], default='never')
46
+ newman_cmd.add_argument("--collection", type=str, required=True)
47
+ newman_cmd.add_argument("--environment", nargs="+", required=False)
48
+ newman_cmd.add_argument(
49
+ "--reporters", action="store_true", default=False, required=False
50
+ )
51
+ newman_cmd.add_argument(
52
+ "--return-error",
53
+ choices=["all-findings", "errors-only", "never"],
54
+ default="never",
55
+ )
37
56
 
38
57
  newman_cmd.print_usage = self.usage
39
58
  newman_cmd.print_help = self.usage
@@ -41,38 +60,67 @@ class NewmanSubCommand(sub_command.PyntSubCommand):
41
60
 
42
61
  def run_cmd(self, args: argparse.Namespace):
43
62
  port = str(util.find_open_port())
44
- container = pynt_container.get_container_with_arguments(args, pynt_container.PyntDockerPort(src=port, dest=port, name="--port"))
63
+ container = pynt_container.get_container_with_arguments(
64
+ args, pynt_container.PyntDockerPort(src=port, dest=port, name="--port")
65
+ )
45
66
 
46
- if not os.path.isfile(args.collection):
47
- ui_thread.print(ui_thread.PrinterText("Could not find the provided collection path, please provide with a valid collection path", ui_thread.PrinterText.WARNING))
67
+ if not os.path.isfile(args.collection):
68
+ ui_thread.print(
69
+ ui_thread.PrinterText(
70
+ "Could not find the provided collection path, please provide with a valid collection path",
71
+ ui_thread.PrinterText.WARNING,
72
+ )
73
+ )
48
74
  return
49
-
75
+
50
76
  collection_name = os.path.basename(args.collection)
51
77
  container.docker_arguments += ["-c", collection_name]
52
- container.mounts.append(pynt_container.create_mount(os.path.abspath(args.collection), "/etc/pynt/{}".format(collection_name)))
53
-
78
+ container.mounts.append(
79
+ pynt_container.create_mount(
80
+ os.path.abspath(args.collection), "/etc/pynt/{}".format(collection_name)
81
+ )
82
+ )
83
+
54
84
  if "environment" in args and args.environment:
55
85
  env_names = []
56
86
  for environ in args.environment:
57
87
  if not os.path.isfile(environ):
58
- ui_thread.print(ui_thread.PrinterText(f"Could not find the provided environment path: {environ}, please provide with a valid environment path", ui_thread.PrinterText.WARNING))
88
+ ui_thread.print(
89
+ ui_thread.PrinterText(
90
+ f"Could not find the provided environment path: {environ}, please provide with a valid environment path",
91
+ ui_thread.PrinterText.WARNING,
92
+ )
93
+ )
59
94
  return
60
95
  env_name = os.path.basename(environ)
61
96
  env_names.append(env_name)
62
- container.mounts.append(pynt_container.create_mount(os.path.abspath(environ), "/etc/pynt/{}".format(env_name)))
97
+ container.mounts.append(
98
+ pynt_container.create_mount(
99
+ os.path.abspath(environ), "/etc/pynt/{}".format(env_name)
100
+ )
101
+ )
63
102
  container.docker_arguments += ["-e", ",".join(env_names)]
64
-
103
+
65
104
  with util.create_default_file_mounts(args) as m:
66
105
  container.mounts += m
67
- newman_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
68
- tag="latest",
69
- detach=True,
70
- base_container=container)
106
+ newman_docker = pynt_container.PyntContainer(
107
+ image_name=pynt_container.PYNT_DOCKER_IMAGE,
108
+ tag="latest",
109
+ detach=True,
110
+ base_container=container,
111
+ )
71
112
  newman_docker.run()
72
-
73
- healthcheck = partial(util.wait_for_healthcheck, "http://localhost:{}".format(port))
113
+
114
+ healthcheck = partial(
115
+ util.wait_for_healthcheck, "http://localhost:{}".format(port)
116
+ )
74
117
  ui_thread.print_generator(ui_thread.AnsiText.wrap_gen(newman_docker.stdout))
75
-
76
- with ui_thread.progress("ws://localhost:{}/progress".format(port),healthcheck, "scan in progress...",100):
118
+
119
+ with ui_thread.progress(
120
+ "ws://localhost:{}/progress".format(port),
121
+ healthcheck,
122
+ "scan in progress...",
123
+ 100,
124
+ ):
77
125
  while newman_docker.is_alive():
78
126
  time.sleep(1)
@@ -112,7 +112,7 @@ class PostmanSubCommand(sub_command.PyntSubCommand):
112
112
  html_report_path = os.path.join(tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time())))
113
113
 
114
114
  if html_report:
115
- with open(html_report_path, "w") as html_file:
115
+ with open(html_report_path, "w", encoding="utf-8") as html_file:
116
116
  html_file.write(html_report)
117
117
  webbrowser.open("file://{}".format(html_report_path))
118
118
 
pyntcli/commands/root.py CHANGED
@@ -7,33 +7,48 @@ from pyntcli.auth import login
7
7
  from pyntcli.ui import ui_thread
8
8
  from pyntcli.analytics import send as analytics
9
9
 
10
+
10
11
  def root_usage():
11
- return ui_thread.PrinterText("Usage:",style=ui_thread.PrinterText.HEADER) \
12
- .with_line("\tpynt [COMMAND] [OPTIONS]") \
13
- .with_line("") \
14
- .with_line("Commands:",style=ui_thread.PrinterText.HEADER) \
15
- .with_line("\tpostman - integration with postman, run scan from pynt postman collection") \
16
- .with_line("\tnewman - run postman collection from the CLI") \
17
- .with_line("\tpynt-id - view your pynt-id to use when running pynt in CI pipeline") \
18
- .with_line("") \
19
- .with_line("Run pynt [COMMAND] -h to get help on a specific command",style=ui_thread.PrinterText.INFO)
12
+ return (
13
+ ui_thread.PrinterText("Usage:", style=ui_thread.PrinterText.HEADER)
14
+ .with_line("\tpynt [COMMAND] [OPTIONS]")
15
+ .with_line("")
16
+ .with_line("Commands:", style=ui_thread.PrinterText.HEADER)
17
+ .with_line(
18
+ "\tpostman - integration with postman, run scan from pynt postman collection"
19
+ )
20
+ .with_line("\tnewman - run postman collection from the CLI")
21
+ .with_line("\thar - run scan on static har file")
22
+ .with_line("\tcommand - run scan with a given command")
23
+ .with_line("\tlisten - run scan with a routed traffic")
24
+ .with_line("\tburp - run scan on a burp xml output file")
25
+ .with_line(
26
+ "\tpynt-id - view your pynt-id to use when running pynt in CI pipeline"
27
+ )
28
+ .with_line("")
29
+ .with_line(
30
+ "Run pynt [COMMAND] -h to get help on a specific command",
31
+ style=ui_thread.PrinterText.INFO,
32
+ )
33
+ )
34
+
20
35
 
21
36
  def usage(*args):
22
37
  ui_thread.print(root_usage())
23
38
 
24
39
 
25
40
  def check_cicd_context():
26
- if environ.get('GITHUB_ACTION') is not None:
41
+ if environ.get("GITHUB_ACTION") is not None:
27
42
  analytics.emit(analytics.CICD, {"env": "GitHub"})
28
43
  return
29
- if environ.get('GITLAB_USER_ID') is not None:
44
+ if environ.get("GITLAB_USER_ID") is not None:
30
45
  analytics.emit(analytics.CICD, {"env": "GitLab"})
31
46
  return
32
- if environ.get('JENKINS_HOME') is not None:
47
+ if environ.get("JENKINS_HOME") is not None:
33
48
  analytics.emit(analytics.CICD, {"env": "Jenkins"})
34
-
35
49
 
36
- class BaseCommand():
50
+
51
+ class BaseCommand:
37
52
  def __init__(self) -> None:
38
53
  self.base: argparse.ArgumentParser = None
39
54
  self.subparser: argparse._SubParsersAction = None
@@ -41,15 +56,21 @@ class BaseCommand():
41
56
  def cmd(self):
42
57
  if self.base:
43
58
  return self.base
44
-
59
+
45
60
  self.base = argparse.ArgumentParser(prog="pynt")
46
61
  self.base.print_usage = usage
47
62
  self.base.print_help = usage
48
- return self.base
49
-
63
+ return self.base
64
+
50
65
  def add_base_arguments(self, parser):
51
- parser.add_argument("--insecure", default=False, required=False, action='store_true',help="use when target uses self signed certificates")
52
- parser.add_argument("--dev-flags", type=str,default="", help=argparse.SUPPRESS)
66
+ parser.add_argument(
67
+ "--insecure",
68
+ default=False,
69
+ required=False,
70
+ action="store_true",
71
+ help="use when target uses self signed certificates",
72
+ )
73
+ parser.add_argument("--dev-flags", type=str, default="", help=argparse.SUPPRESS)
53
74
  parser.add_argument("--host-ca", type=str, default="")
54
75
  parser.add_argument("--transport-config", type=str, default="")
55
76
  parser.add_argument("--application-id", type=str, default="", required=False)
@@ -58,7 +79,7 @@ class BaseCommand():
58
79
  def get_subparser(self) -> argparse._SubParsersAction:
59
80
  if self.subparser is None:
60
81
  self.subparser = self.base.add_subparsers(help="", dest="command")
61
-
82
+
62
83
  return self.subparser
63
84
 
64
85
  def run_cmd(self, args: argparse.Namespace):
@@ -67,11 +88,11 @@ class BaseCommand():
67
88
  if login.should_login():
68
89
  l = login.Login().login()
69
90
  else:
70
- login.refresh_token()
71
-
91
+ login.refresh_token()
92
+
72
93
  analytics.emit(analytics.LOGIN_DONE)
73
94
  user_id = login.user_id()
74
95
  if user_id:
75
96
  analytics.set_user_id(user_id)
76
97
 
77
- check_cicd_context()
98
+ check_cicd_context()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyntcli
3
- Version: 0.1.72
3
+ Version: 0.1.73
4
4
  Summary: Command line utility to handle all of Pynt's different integrations
5
5
  Author-email: Pynt-io <support@pynt.io>
6
6
  Project-URL: Homepage, https://pynt.io
@@ -1,19 +1,19 @@
1
- pyntcli/__init__.py,sha256=gUdfeW8Q-eHCbw8IWb2lI3qRGa6BpSk5KcikOGNzSdM,23
1
+ pyntcli/__init__.py,sha256=B2xptQoAZtCL_O_fLMSWF71JDtlCZp8jLmdtHyMdosE,23
2
2
  pyntcli/main.py,sha256=cqratxd_ZJXLsP4xRbF2fmwj3Eo4kQ8WlbrwUtfZQ94,4125
3
3
  pyntcli/analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  pyntcli/analytics/send.py,sha256=ewNAKnn3KbKwfDuOasgAsSGbUWILLD8rPaXIAlLucnM,2507
5
5
  pyntcli/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  pyntcli/auth/login.py,sha256=WgF5r00bpM4c1__thzD6zCJ6207qxgtT0ixPvD1cEHA,5109
7
7
  pyntcli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- pyntcli/commands/burp.py,sha256=pD4MK6m596NaefVayAH4iicexoMgCAeADytE0-Ak7D0,9266
9
- pyntcli/commands/command.py,sha256=Gs8PCk85XzDurnCA66dz-KJNttwIQBZSgFUNZsJf94c,8349
10
- pyntcli/commands/har.py,sha256=jpXZzNXX0nNpUXZR8FiXpMuErsLwRQTR1HNi16OL7Nc,3243
8
+ pyntcli/commands/burp.py,sha256=wd-HuNyj6v6IHk6x9-DAaqXcm1cQa-RA5FlxveBd6wA,10427
9
+ pyntcli/commands/command.py,sha256=tSjJj0fhQt2lCvtdu8H3IuiBlAllesx4f6ptNfuinTw,9435
10
+ pyntcli/commands/har.py,sha256=Iq0455umKvlcMxcU4l70-NIZh7Wovry3f76u68drmQ4,3654
11
11
  pyntcli/commands/id_command.py,sha256=2J5oEa39uyBMMSCRHzuKh3_11CeUEYi7YLoBk1yuu_I,942
12
- pyntcli/commands/listen.py,sha256=wVhvrRclpJZ5aRd3CWwnfekRXzozG26Hh8tG9HRC_DE,7578
13
- pyntcli/commands/newman.py,sha256=GfLPgOx7Pmx1S6ZI8wJOiSzhxBFn4WuEjN-MWL3mW0Y,4233
14
- pyntcli/commands/postman.py,sha256=5eF14wjdDwJC8AvXjwyuZnlb6JZsPs_QWh5e77LauGA,4928
12
+ pyntcli/commands/listen.py,sha256=aANo5DwZ6_TAuXdJX3L8eDk9I6ompPAqtaUgxnEbR54,8536
13
+ pyntcli/commands/newman.py,sha256=_AspmTk98nY0Ct26WNK4fFgoYbqzmU90FfkygxJjgjY,4828
14
+ pyntcli/commands/postman.py,sha256=x5sPR-KaawKzAkLRK9vJXDzZ3sx9-6TuH6SNd5tnM4Y,4946
15
15
  pyntcli/commands/pynt_cmd.py,sha256=NkzT8X4mI_fhzui_9KdAQXY5AnMGdoQkzDH6pcreLHU,2453
16
- pyntcli/commands/root.py,sha256=4TLH67_n1S4nxmlB2YzyDLZpx2GJLK2rXMEfD3Wze1M,2839
16
+ pyntcli/commands/root.py,sha256=FEf2gXvFyO_RZi6XzFakSVnOQw_sGBopY5SL5gldudg,3248
17
17
  pyntcli/commands/sub_command.py,sha256=GF3-rE_qk2L4jGPFqHLm9SdGINmu3EakhjJTFyWjRms,374
18
18
  pyntcli/commands/util.py,sha256=IREZvHYJ7wEth8ujOkk5ZXZ4UrUA7jDv134_UueED4s,2995
19
19
  pyntcli/log/__init__.py,sha256=cOGwOYzMoshEbZiiasBGkj6wF0SBu3Jdpl-AuakDesw,19
@@ -34,8 +34,8 @@ pyntcli/ui/ui_thread.py,sha256=OVTbiIFMg2KgxAvHf7yy86xGm4RVS2vj_VYZkMi-SRY,4956
34
34
  tests/conftest.py,sha256=gToq5K74GtgeGQXjFvXSzMaE6axBYxAzcFG5XJPOXjI,427
35
35
  tests/auth/test_login.py,sha256=M6JRFTQRZrL6M2-iph_r-aBSQMMiFDncQbVYeObBFYU,3296
36
36
  tests/store/test_cred_store.py,sha256=_7-917EtNC9eKEumO2_lt-7KuDmCwOZFaowCm7DbA_A,254
37
- pyntcli-0.1.72.dist-info/METADATA,sha256=8ZRMPVKmEOaic-NVq4hAVWZY2MPIQ3DSs_7GZ0B936E,463
38
- pyntcli-0.1.72.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
39
- pyntcli-0.1.72.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
40
- pyntcli-0.1.72.dist-info/top_level.txt,sha256=u9MDStwVHB7UG8PUcODeWCul_NvzL2EzoLvSlgwLHFs,30
41
- pyntcli-0.1.72.dist-info/RECORD,,
37
+ pyntcli-0.1.73.dist-info/METADATA,sha256=YG6eADsoX_vyR3rTTkWvpkrKZeY8okAneTVRDvu3yZU,463
38
+ pyntcli-0.1.73.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
39
+ pyntcli-0.1.73.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
40
+ pyntcli-0.1.73.dist-info/top_level.txt,sha256=u9MDStwVHB7UG8PUcODeWCul_NvzL2EzoLvSlgwLHFs,30
41
+ pyntcli-0.1.73.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5