pyntcli 0.1.85__py3-none-any.whl → 0.1.87__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 +1 -1
- pyntcli/commands/burp.py +4 -1
- pyntcli/commands/command.py +19 -5
- pyntcli/commands/har.py +8 -5
- pyntcli/commands/listen.py +9 -7
- pyntcli/commands/newman.py +3 -1
- pyntcli/commands/postman.py +4 -3
- pyntcli/commands/root.py +8 -1
- pyntcli/main.py +15 -9
- pyntcli/pynt_docker/pynt_container.py +13 -1
- pyntcli/ui/pynt_errors.py +16 -5
- pyntcli/ui/ui_thread.py +50 -32
- {pyntcli-0.1.85.dist-info → pyntcli-0.1.87.dist-info}/METADATA +1 -1
- {pyntcli-0.1.85.dist-info → pyntcli-0.1.87.dist-info}/RECORD +17 -17
- {pyntcli-0.1.85.dist-info → pyntcli-0.1.87.dist-info}/WHEEL +1 -1
- {pyntcli-0.1.85.dist-info → pyntcli-0.1.87.dist-info}/entry_points.txt +0 -0
- {pyntcli-0.1.85.dist-info → pyntcli-0.1.87.dist-info}/top_level.txt +0 -0
pyntcli/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.87"
|
pyntcli/commands/burp.py
CHANGED
|
@@ -144,6 +144,7 @@ def burp_usage():
|
|
|
144
144
|
.with_line("\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io")
|
|
145
145
|
.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.")
|
|
146
146
|
.with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default)")
|
|
147
|
+
.with_line("\t--verbose - Use to get more detailed information about the run")
|
|
147
148
|
)
|
|
148
149
|
|
|
149
150
|
|
|
@@ -261,6 +262,7 @@ class BurpCommand(sub_command.PyntSubCommand):
|
|
|
261
262
|
)
|
|
262
263
|
return
|
|
263
264
|
|
|
265
|
+
ui_thread.print_verbose("Parsing burp xml")
|
|
264
266
|
doc = parse_xml(args.xml)
|
|
265
267
|
if not doc:
|
|
266
268
|
ui_thread.print(
|
|
@@ -290,8 +292,9 @@ class BurpCommand(sub_command.PyntSubCommand):
|
|
|
290
292
|
ui_thread.print_generator(proxy_docker.stdout)
|
|
291
293
|
|
|
292
294
|
util.wait_for_healthcheck("http://localhost:{}".format(args.port))
|
|
295
|
+
ui_thread.print_verbose(util.GOT_INITIAL_HEALTHCHECK_MESSAGE)
|
|
293
296
|
ui_thread.print(ui_thread.PrinterText(
|
|
294
|
-
|
|
297
|
+
"Pynt docker is ready",
|
|
295
298
|
ui_thread.PrinterText.INFO,
|
|
296
299
|
))
|
|
297
300
|
|
pyntcli/commands/command.py
CHANGED
|
@@ -35,9 +35,11 @@ def command_usage():
|
|
|
35
35
|
.with_line("\t--proxy-port - Set the port proxied traffic should be routed to (DEFAULT: 6666)")
|
|
36
36
|
.with_line("\t--report - If present will save the generated report in this path.")
|
|
37
37
|
.with_line("\t--insecure - Use when target uses self signed certificates")
|
|
38
|
+
.with_line("\t--self-signed - Use when the functional test verify SSL")
|
|
38
39
|
.with_line("\t--application-id - Attach the scan to an application, you can find the ID in your applications area at app.pynt.io")
|
|
39
40
|
.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.")
|
|
40
41
|
.with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default) ")
|
|
42
|
+
.with_line("\t--verbose - Use to get more detailed information about the run")
|
|
41
43
|
)
|
|
42
44
|
|
|
43
45
|
|
|
@@ -61,6 +63,7 @@ class CommandSubCommand(sub_command.PyntSubCommand):
|
|
|
61
63
|
proxy_cmd.add_argument("--test-name", help="", default="", required=False)
|
|
62
64
|
proxy_cmd.add_argument("--allow-errors", action="store_true")
|
|
63
65
|
proxy_cmd.add_argument("--ca-path", type=str, default="")
|
|
66
|
+
proxy_cmd.add_argument("--self-signed", action="store_true")
|
|
64
67
|
proxy_cmd.add_argument("--report", type=str, default="")
|
|
65
68
|
proxy_cmd.add_argument("--return-error", choices=["all-findings", "errors-only", "never"], default="never")
|
|
66
69
|
proxy_cmd.print_usage = self.print_usage
|
|
@@ -69,6 +72,16 @@ class CommandSubCommand(sub_command.PyntSubCommand):
|
|
|
69
72
|
|
|
70
73
|
def _updated_environment(self, args):
|
|
71
74
|
env_copy = deepcopy(os.environ)
|
|
75
|
+
if "self_signed" in args and args.self_signed:
|
|
76
|
+
cert_path = os.path.join(os.path.expanduser('~'), '.pynt', 'cert')
|
|
77
|
+
cert_file_path = os.path.join(cert_path, 'mitmproxy-ca-cert.pem')
|
|
78
|
+
env_copy.update(
|
|
79
|
+
{
|
|
80
|
+
"REQUESTS_CA_BUNDLE": cert_file_path,
|
|
81
|
+
"SSL_CERT_FILE": cert_file_path,
|
|
82
|
+
"NODE_EXTRA_CA_CERTS": cert_file_path
|
|
83
|
+
}
|
|
84
|
+
)
|
|
72
85
|
return env_copy.update(
|
|
73
86
|
{
|
|
74
87
|
"HTTP_PROXY": "http://localhost:{}".format(args.proxy_port),
|
|
@@ -161,8 +174,9 @@ class CommandSubCommand(sub_command.PyntSubCommand):
|
|
|
161
174
|
ui_thread.print_generator(proxy_docker.stdout)
|
|
162
175
|
|
|
163
176
|
util.wait_for_healthcheck("http://localhost:{}".format(args.port))
|
|
177
|
+
ui_thread.print_verbose(util.GOT_INITIAL_HEALTHCHECK_MESSAGE)
|
|
164
178
|
ui_thread.print(ui_thread.PrinterText(
|
|
165
|
-
|
|
179
|
+
"Pynt docker is ready",
|
|
166
180
|
ui_thread.PrinterText.INFO,
|
|
167
181
|
))
|
|
168
182
|
|
|
@@ -199,10 +213,10 @@ class CommandSubCommand(sub_command.PyntSubCommand):
|
|
|
199
213
|
self._stop_proxy(args)
|
|
200
214
|
|
|
201
215
|
with ui_thread.progress(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
216
|
+
"ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),
|
|
217
|
+
partial(lambda *args: None),
|
|
218
|
+
"scan in progress...",
|
|
219
|
+
100,
|
|
206
220
|
):
|
|
207
221
|
html_report = self._get_report(args, "html")
|
|
208
222
|
html_report_path = os.path.join(
|
pyntcli/commands/har.py
CHANGED
|
@@ -28,6 +28,7 @@ def har_usage():
|
|
|
28
28
|
.with_line(
|
|
29
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
30
|
)
|
|
31
|
+
.with_line("\t--verbose - Use to get more detailed information about the run")
|
|
31
32
|
.with_line("")
|
|
32
33
|
)
|
|
33
34
|
|
|
@@ -51,6 +52,7 @@ class HarSubCommand(sub_command.PyntSubCommand):
|
|
|
51
52
|
return har_cmd
|
|
52
53
|
|
|
53
54
|
def run_cmd(self, args: argparse.Namespace):
|
|
55
|
+
ui_thread.print_verbose("Building container")
|
|
54
56
|
port = util.find_open_port()
|
|
55
57
|
container = pynt_container.get_container_with_arguments(
|
|
56
58
|
args, pynt_container.PyntDockerPort(src=str(port), dest=port, name="--port")
|
|
@@ -94,18 +96,19 @@ class HarSubCommand(sub_command.PyntSubCommand):
|
|
|
94
96
|
)
|
|
95
97
|
|
|
96
98
|
healthcheck()
|
|
99
|
+
ui_thread.print_verbose(util.GOT_INITIAL_HEALTHCHECK_MESSAGE)
|
|
97
100
|
ui_thread.print(ui_thread.PrinterText(
|
|
98
|
-
|
|
101
|
+
"Pynt docker is ready",
|
|
99
102
|
ui_thread.PrinterText.INFO,
|
|
100
103
|
))
|
|
101
104
|
|
|
102
105
|
ui_thread.print_generator(ui_thread.AnsiText.wrap_gen(har_docker.stdout))
|
|
103
106
|
|
|
104
107
|
with ui_thread.progress(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
"ws://localhost:{}/progress".format(port),
|
|
109
|
+
healthcheck,
|
|
110
|
+
"scan in progress...",
|
|
111
|
+
100,
|
|
109
112
|
):
|
|
110
113
|
while har_docker.is_alive():
|
|
111
114
|
time.sleep(1)
|
pyntcli/commands/listen.py
CHANGED
|
@@ -34,6 +34,7 @@ def listen_usage():
|
|
|
34
34
|
.with_line("\t--insecure - use when target uses self signed certificates")
|
|
35
35
|
.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.")
|
|
36
36
|
.with_line("\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default) ")
|
|
37
|
+
.with_line("\t--verbose - Use to get more detailed information about the run")
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
|
|
@@ -57,7 +58,7 @@ class ListenSubCommand(sub_command.PyntSubCommand):
|
|
|
57
58
|
listen_cmd.add_argument("--allow-errors", action="store_true")
|
|
58
59
|
listen_cmd.add_argument("--ca-path", type=str, default="")
|
|
59
60
|
listen_cmd.add_argument("--report", type=str, default="")
|
|
60
|
-
listen_cmd.add_argument("--return-error", choices=["all-findings", "errors-only", "never"], default="never"
|
|
61
|
+
listen_cmd.add_argument("--return-error", choices=["all-findings", "errors-only", "never"], default="never")
|
|
61
62
|
listen_cmd.print_usage = self.print_usage
|
|
62
63
|
listen_cmd.print_help = self.print_usage
|
|
63
64
|
return listen_cmd
|
|
@@ -140,8 +141,9 @@ class ListenSubCommand(sub_command.PyntSubCommand):
|
|
|
140
141
|
ui_thread.print_generator(proxy_docker.stdout)
|
|
141
142
|
|
|
142
143
|
util.wait_for_healthcheck("http://localhost:{}".format(args.port))
|
|
144
|
+
ui_thread.print_verbose(util.GOT_INITIAL_HEALTHCHECK_MESSAGE)
|
|
143
145
|
ui_thread.print(ui_thread.PrinterText(
|
|
144
|
-
|
|
146
|
+
"Pynt docker is ready",
|
|
145
147
|
ui_thread.PrinterText.INFO,
|
|
146
148
|
))
|
|
147
149
|
|
|
@@ -170,9 +172,9 @@ class ListenSubCommand(sub_command.PyntSubCommand):
|
|
|
170
172
|
self._stop_proxy(args)
|
|
171
173
|
|
|
172
174
|
with ui_thread.progress(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
"ws://localhost:{}/progress?scanId={}".format(args.port, self.scan_id),
|
|
176
|
+
partial(lambda *args: None),
|
|
177
|
+
"scan in progress...", 100):
|
|
176
178
|
html_report = self._get_report(args, "html")
|
|
177
179
|
html_report_path = os.path.join(
|
|
178
180
|
tempfile.gettempdir(), "pynt_report_{}.html".format(int(time.time()))
|
|
@@ -189,12 +191,12 @@ class ListenSubCommand(sub_command.PyntSubCommand):
|
|
|
189
191
|
json_report_path = util.get_user_report_path(full_path, "json")
|
|
190
192
|
|
|
191
193
|
if html_report:
|
|
192
|
-
with open(html_report_path, "w",encoding="utf-8") as html_file:
|
|
194
|
+
with open(html_report_path, "w", encoding="utf-8") as html_file:
|
|
193
195
|
html_file.write(html_report)
|
|
194
196
|
webbrowser.open("file://{}".format(html_report_path))
|
|
195
197
|
|
|
196
198
|
if json_report:
|
|
197
|
-
with open(json_report_path, "w",encoding="utf-8") as json_file:
|
|
199
|
+
with open(json_report_path, "w", encoding="utf-8") as json_file:
|
|
198
200
|
json_file.write(json_report)
|
|
199
201
|
reporter = cli_reporter.PyntReporter(json_report_path)
|
|
200
202
|
reporter.print_summary()
|
pyntcli/commands/newman.py
CHANGED
|
@@ -31,6 +31,7 @@ def newman_usage():
|
|
|
31
31
|
.with_line(
|
|
32
32
|
"\t--return-error - 'all-findings' (warnings, or errors), 'errors-only', 'never' (default) "
|
|
33
33
|
)
|
|
34
|
+
.with_line("\t--verbose - Use to get more detailed information about the run")
|
|
34
35
|
)
|
|
35
36
|
|
|
36
37
|
|
|
@@ -116,8 +117,9 @@ class NewmanSubCommand(sub_command.PyntSubCommand):
|
|
|
116
117
|
)
|
|
117
118
|
|
|
118
119
|
healthcheck()
|
|
120
|
+
ui_thread.print_verbose(util.GOT_INITIAL_HEALTHCHECK_MESSAGE)
|
|
119
121
|
ui_thread.print(ui_thread.PrinterText(
|
|
120
|
-
|
|
122
|
+
"Pynt docker is ready",
|
|
121
123
|
ui_thread.PrinterText.INFO,
|
|
122
124
|
))
|
|
123
125
|
|
pyntcli/commands/postman.py
CHANGED
|
@@ -35,7 +35,8 @@ def postman_usage():
|
|
|
35
35
|
.with_line("Options:", style=ui_thread.PrinterText.HEADER) \
|
|
36
36
|
.with_line("\t--port - set the port pynt will listen to (DEFAULT: 5001)") \
|
|
37
37
|
.with_line("\t--insecure - use when target uses self signed certificates") \
|
|
38
|
-
.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.")
|
|
38
|
+
.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.") \
|
|
39
|
+
.with_line("\t--verbose - Use to get more detailed information about the run")
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class PostmanSubCommand(sub_command.PyntSubCommand):
|
|
@@ -94,7 +95,6 @@ class PostmanSubCommand(sub_command.PyntSubCommand):
|
|
|
94
95
|
|
|
95
96
|
container = pynt_container.get_container_with_arguments(args, pynt_container.PyntDockerPort("5001", args.port, name="--port"))
|
|
96
97
|
|
|
97
|
-
|
|
98
98
|
postman_docker = pynt_container.PyntContainer(image_name=pynt_container.PYNT_DOCKER_IMAGE,
|
|
99
99
|
tag="postman-latest",
|
|
100
100
|
detach=True,
|
|
@@ -104,8 +104,9 @@ class PostmanSubCommand(sub_command.PyntSubCommand):
|
|
|
104
104
|
ui_thread.print_generator(postman_docker.stdout)
|
|
105
105
|
|
|
106
106
|
util.wait_for_healthcheck("http://localhost:{}".format(args.port))
|
|
107
|
+
ui_thread.print_verbose(util.GOT_INITIAL_HEALTHCHECK_MESSAGE)
|
|
107
108
|
ui_thread.print(ui_thread.PrinterText(
|
|
108
|
-
|
|
109
|
+
"Pynt docker is ready",
|
|
109
110
|
ui_thread.PrinterText.INFO,
|
|
110
111
|
))
|
|
111
112
|
|
pyntcli/commands/root.py
CHANGED
|
@@ -22,7 +22,7 @@ def root_usage():
|
|
|
22
22
|
.with_line("\tpynt-id - view your pynt-id to use when running pynt in CI pipeline")
|
|
23
23
|
.with_line("\tlogout - log out from your user")
|
|
24
24
|
.with_line("")
|
|
25
|
-
.with_line("Run pynt [COMMAND] -h to get help on a specific command", style=ui_thread.PrinterText.INFO,)
|
|
25
|
+
.with_line("Run pynt [COMMAND] -h to get help on a specific command", style=ui_thread.PrinterText.INFO, )
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
|
|
@@ -68,6 +68,13 @@ class BaseCommand:
|
|
|
68
68
|
parser.add_argument("--transport-config", type=str, default="")
|
|
69
69
|
parser.add_argument("--application-id", type=str, default="", required=False)
|
|
70
70
|
parser.add_argument("--proxy", type=str, default="", required=False)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--verbose",
|
|
73
|
+
default=False,
|
|
74
|
+
required=False,
|
|
75
|
+
action="store_true",
|
|
76
|
+
help="use to get more detailed execution information",
|
|
77
|
+
)
|
|
71
78
|
|
|
72
79
|
def get_subparser(self) -> argparse._SubParsersAction:
|
|
73
80
|
if self.subparser is None:
|
pyntcli/main.py
CHANGED
|
@@ -33,18 +33,17 @@ def signal_handler(signal_number, frame):
|
|
|
33
33
|
exit(0)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def assert_docker_availability():
|
|
37
37
|
pynt_container.get_docker_type()
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
def print_header():
|
|
41
41
|
ui_thread.print(ui_thread.PrinterText(*ui_thread.pynt_header())
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
.with_line(*ui_thread.pynt_version())
|
|
43
|
+
.with_line(""))
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def start_analytics():
|
|
47
|
-
user_id = login.user_id()
|
|
46
|
+
def start_analytics(user_id: str):
|
|
48
47
|
if user_id:
|
|
49
48
|
analytics.set_user_id(user_id)
|
|
50
49
|
log.add_user_details(user_id)
|
|
@@ -72,9 +71,14 @@ def main():
|
|
|
72
71
|
if argv[1] == "logout":
|
|
73
72
|
logout()
|
|
74
73
|
return
|
|
74
|
+
if [n for n in argv if "--verbose" in n]:
|
|
75
|
+
ui_thread.VERBOSE = True
|
|
75
76
|
log.set_source(__version__)
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
ui_thread.print_verbose("Logging in...")
|
|
78
|
+
user_id = login.user_id()
|
|
79
|
+
start_analytics(user_id)
|
|
80
|
+
ui_thread.print_verbose("Asserting docker is properly installed")
|
|
81
|
+
assert_docker_availability()
|
|
78
82
|
signal.signal(signal.SIGINT, signal_handler)
|
|
79
83
|
cli = pynt_cmd.PyntCommand()
|
|
80
84
|
cli.run_cmd(cli.parse_args(argv[1:]))
|
|
@@ -85,7 +89,8 @@ def main():
|
|
|
85
89
|
ui_thread.print(ui_thread.PrinterText("Docker was unavailable, please make sure docker is installed and running.", ui_thread.PrinterText.WARNING))
|
|
86
90
|
analytics.emit(analytics.ERROR, {"error": "docker unavailable. e: {}".format(e)})
|
|
87
91
|
except SSLError as e:
|
|
88
|
-
ui_thread.print(
|
|
92
|
+
ui_thread.print(
|
|
93
|
+
ui_thread.PrinterText("We encountered SSL issues and could not proceed, this may be the cause of a VPN or a Firewall in place. Run again with --insecure", ui_thread.PrinterText.WARNING))
|
|
89
94
|
analytics.emit(analytics.ERROR, {"error": "ssl error. e: {}".format(e)})
|
|
90
95
|
except login.Timeout as e:
|
|
91
96
|
ui_thread.print(ui_thread.PrinterText("Pynt CLI exited due to incomplete registration, please try again.", ui_thread.PrinterText.WARNING))
|
|
@@ -117,7 +122,8 @@ def main():
|
|
|
117
122
|
exit(1)
|
|
118
123
|
except Exception as e:
|
|
119
124
|
analytics.emit(analytics.ERROR, {"error": "{}".format(e)})
|
|
120
|
-
pynt_errors.unexpected_error()
|
|
125
|
+
pynt_errors.unexpected_error(e)
|
|
126
|
+
|
|
121
127
|
finally:
|
|
122
128
|
log.flush_logger()
|
|
123
129
|
shutdown_cli()
|
|
@@ -106,6 +106,14 @@ def get_container_with_arguments(args: argparse.Namespace, *port_args: PyntDocke
|
|
|
106
106
|
docker_arguments += ["--transport-config", tc_name]
|
|
107
107
|
mounts.append(create_mount(os.path.abspath(args.transport_config), "/etc/pynt/{}".format(tc_name)))
|
|
108
108
|
|
|
109
|
+
if "verbose" in args and args.verbose:
|
|
110
|
+
docker_arguments.append("--verbose")
|
|
111
|
+
|
|
112
|
+
creds_path = os.path.dirname(CredStore().file_location)
|
|
113
|
+
mitm_cert_path = os.path.join(creds_path,"cert")
|
|
114
|
+
os.makedirs(mitm_cert_path,exist_ok=True)
|
|
115
|
+
mounts.append(create_mount(mitm_cert_path, "/root/.mitmproxy"))
|
|
116
|
+
|
|
109
117
|
env = {PYNT_ID: CredStore().get_tokens(), "PYNT_SAAS_URL": PYNT_SAAS}
|
|
110
118
|
if user_set_all_variables():
|
|
111
119
|
add_env_variables(env)
|
|
@@ -184,7 +192,8 @@ class PyntContainer():
|
|
|
184
192
|
return self.docker_client.images.pull(self.image, tag=self.tag)
|
|
185
193
|
except APIError as e:
|
|
186
194
|
analytics.emit(analytics.ERROR, {"error": "Unable to pull image from ghcr: {}".format(e)})
|
|
187
|
-
ui_thread.print(ui_thread.PrinterText("Error: Docker unable to pull latest Pynt image due to VPN/proxy. If using a mirror for Docker images, visit docs.pynt.io for help.",
|
|
195
|
+
ui_thread.print(ui_thread.PrinterText("Error: Docker unable to pull latest Pynt image due to VPN/proxy. If using a mirror for Docker images, visit docs.pynt.io for help.",
|
|
196
|
+
ui_thread.PrinterText.WARNING))
|
|
188
197
|
return None
|
|
189
198
|
|
|
190
199
|
def get_image(self):
|
|
@@ -202,6 +211,8 @@ class PyntContainer():
|
|
|
202
211
|
self._create_docker_client()
|
|
203
212
|
|
|
204
213
|
self.running = True
|
|
214
|
+
|
|
215
|
+
ui_thread.print_verbose("Killing other pynt containers if such exist")
|
|
205
216
|
self.kill_other_instances()
|
|
206
217
|
|
|
207
218
|
ui_thread.print(ui_thread.PrinterText("Pulling latest docker", ui_thread.PrinterText.INFO))
|
|
@@ -222,6 +233,7 @@ class PyntContainer():
|
|
|
222
233
|
|
|
223
234
|
run_arguments.update(self.base_container.docker_type.get_argumets())
|
|
224
235
|
|
|
236
|
+
ui_thread.print_verbose("Running pynt docker with arguments:\n {}".format(" ".join(args)))
|
|
225
237
|
c = self.docker_client.containers.run(**run_arguments)
|
|
226
238
|
self.container_name = c.name
|
|
227
239
|
self.stdout = c.logs(stream=True)
|
pyntcli/ui/pynt_errors.py
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
from pyntcli.ui import ui_thread
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
|
|
4
|
+
def unexpected_error(original):
|
|
5
|
+
printer_text = ui_thread.PrinterText("An Unexpected Error Occurred", style=ui_thread.PrinterText.WARNING) \
|
|
6
|
+
.with_line("")
|
|
7
|
+
|
|
8
|
+
msg = str(original) or repr(original)
|
|
9
|
+
if msg:
|
|
10
|
+
printer_text.with_line(f"e: {msg}")
|
|
11
|
+
|
|
12
|
+
printer_text = printer_text.with_line(
|
|
13
|
+
"Please tell us about it in our community channel and we will help you figure it out:",
|
|
14
|
+
style=ui_thread.PrinterText.HEADER) \
|
|
15
|
+
.with_line("https://join.slack.com/t/pynt-community/shared_invite/zt-1mvacojz5-WNjbH4HN8iksmKpCLTxOiQ",
|
|
16
|
+
style=ui_thread.PrinterText.HEADER)
|
|
17
|
+
|
|
18
|
+
ui_thread.print(printer_text)
|
pyntcli/ui/ui_thread.py
CHANGED
|
@@ -12,13 +12,16 @@ from typing import Tuple
|
|
|
12
12
|
from pyntcli import __version__ as cli_version
|
|
13
13
|
from pyntcli.ui.progress import PyntProgress
|
|
14
14
|
|
|
15
|
+
VERBOSE = False
|
|
16
|
+
|
|
17
|
+
|
|
15
18
|
class PrinterText():
|
|
16
19
|
DEFAULT = 0
|
|
17
20
|
HEADER = 1
|
|
18
21
|
INFO = 2
|
|
19
22
|
WARNING = 3
|
|
20
23
|
|
|
21
|
-
def __init__(self,text,style=DEFAULT):
|
|
24
|
+
def __init__(self, text, style=DEFAULT):
|
|
22
25
|
self.text = Text(text, PrinterText.get_style(style))
|
|
23
26
|
|
|
24
27
|
@staticmethod
|
|
@@ -37,57 +40,67 @@ class PrinterText():
|
|
|
37
40
|
self.text.append(Text(line, PrinterText.get_style(style)))
|
|
38
41
|
return self
|
|
39
42
|
|
|
43
|
+
|
|
40
44
|
class AnsiText():
|
|
41
45
|
def __init__(self, data) -> None:
|
|
42
46
|
self.data = data
|
|
43
|
-
|
|
47
|
+
|
|
44
48
|
@staticmethod
|
|
45
49
|
def wrap_gen(gen):
|
|
46
50
|
for v in gen:
|
|
47
51
|
yield AnsiText(v)
|
|
48
52
|
|
|
53
|
+
|
|
49
54
|
class Spinner():
|
|
50
55
|
def __init__(self, prompt, style) -> None:
|
|
51
56
|
self.prompt = prompt
|
|
52
|
-
self.style = style
|
|
57
|
+
self.style = style
|
|
53
58
|
self.runnning = False
|
|
54
|
-
|
|
59
|
+
|
|
55
60
|
def __enter__(self):
|
|
56
|
-
return self
|
|
61
|
+
return self
|
|
57
62
|
|
|
58
63
|
def __exit__(self, exc_type, exc_value, exc_traceback):
|
|
59
64
|
self.running = False
|
|
60
65
|
|
|
61
|
-
def pynt_version()-> Tuple[str,int]:
|
|
62
|
-
return "Pynt CLI version " + cli_version,PrinterText.DEFAULT
|
|
63
66
|
|
|
64
|
-
def
|
|
65
|
-
return "
|
|
67
|
+
def pynt_version() -> Tuple[str, int]:
|
|
68
|
+
return "Pynt CLI version " + cli_version, PrinterText.DEFAULT
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def pynt_header() -> Tuple[str, int]:
|
|
72
|
+
return "API Security testing autopilot", PrinterText.DEFAULT
|
|
73
|
+
|
|
66
74
|
|
|
67
75
|
def gen_func_loop(gen):
|
|
68
76
|
for l in gen:
|
|
69
77
|
data = l
|
|
70
|
-
if type(data) == bytes:
|
|
78
|
+
if type(data) == bytes:
|
|
71
79
|
data = l.decode("utf-8")
|
|
72
80
|
if not isinstance(data, AnsiText) and data[-1] == "\n":
|
|
73
81
|
data = data[:-1]
|
|
74
82
|
_print(data)
|
|
75
|
-
|
|
83
|
+
|
|
84
|
+
|
|
76
85
|
def print_generator(gen):
|
|
77
|
-
t = Thread(target=gen_func_loop, args=(gen,), daemon=True)
|
|
86
|
+
t = Thread(target=gen_func_loop, args=(gen,), daemon=True)
|
|
78
87
|
t.start()
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
|
|
90
|
+
def _print(s):
|
|
81
91
|
Printer.instance().print(s)
|
|
82
92
|
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
|
|
94
|
+
def print(s):
|
|
95
|
+
if type(s) == bytes:
|
|
85
96
|
s = s.decode("utf-8")
|
|
86
97
|
_print(s)
|
|
87
98
|
|
|
99
|
+
|
|
88
100
|
def stop():
|
|
89
101
|
Printer.instance().stop()
|
|
90
102
|
|
|
103
|
+
|
|
91
104
|
class Printer():
|
|
92
105
|
_instace = None
|
|
93
106
|
|
|
@@ -96,31 +109,31 @@ class Printer():
|
|
|
96
109
|
self.run_thread = Thread(target=self._print_in_loop, daemon=True)
|
|
97
110
|
self.print_queue = queue.Queue()
|
|
98
111
|
self.console = Console(tab_size=4)
|
|
99
|
-
|
|
100
|
-
@staticmethod
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
101
114
|
def instance():
|
|
102
115
|
if not Printer._instace:
|
|
103
|
-
Printer._instace = Printer()
|
|
104
|
-
Printer._instace.start()
|
|
116
|
+
Printer._instace = Printer()
|
|
117
|
+
Printer._instace.start()
|
|
105
118
|
|
|
106
119
|
return Printer._instace
|
|
107
120
|
|
|
108
121
|
def start(self):
|
|
109
122
|
self.running = True
|
|
110
123
|
self.run_thread.start()
|
|
111
|
-
|
|
124
|
+
|
|
112
125
|
def _handle_spinner(self, spinner):
|
|
113
|
-
spinner.running = True
|
|
126
|
+
spinner.running = True
|
|
114
127
|
s = Status(spinner.prompt, spinner=spinner.style, console=self.console)
|
|
115
128
|
s.start()
|
|
116
129
|
while spinner.running and self.running:
|
|
117
130
|
time.sleep(0.5)
|
|
118
131
|
s.stop()
|
|
119
|
-
|
|
132
|
+
|
|
120
133
|
def _handle_progress(self, progress):
|
|
121
134
|
if not progress.trackable:
|
|
122
135
|
return
|
|
123
|
-
progress.running = True
|
|
136
|
+
progress.running = True
|
|
124
137
|
with Progress(console=self.console, transient=True) as p:
|
|
125
138
|
t = p.add_task(description=progress.description, total=progress.total)
|
|
126
139
|
for update in progress.trackable:
|
|
@@ -131,9 +144,9 @@ class Printer():
|
|
|
131
144
|
|
|
132
145
|
def _print_in_loop(self):
|
|
133
146
|
while self.running:
|
|
134
|
-
try:
|
|
147
|
+
try:
|
|
135
148
|
data = self.print_queue.get(timeout=1)
|
|
136
|
-
if isinstance(data, list):
|
|
149
|
+
if isinstance(data, list):
|
|
137
150
|
data = data[0]
|
|
138
151
|
if isinstance(data, Spinner):
|
|
139
152
|
self._handle_spinner(data)
|
|
@@ -148,29 +161,34 @@ class Printer():
|
|
|
148
161
|
self.console.print(data)
|
|
149
162
|
except queue.Empty:
|
|
150
163
|
pass
|
|
151
|
-
|
|
164
|
+
|
|
152
165
|
while not self.print_queue.empty():
|
|
153
166
|
self.console.print(self.print_queue.get())
|
|
154
167
|
|
|
155
|
-
|
|
156
168
|
def print(self, data):
|
|
157
|
-
if isinstance(data,PrinterText):
|
|
169
|
+
if isinstance(data, PrinterText):
|
|
158
170
|
data = data.text
|
|
159
171
|
if isinstance(data, AnsiText):
|
|
160
172
|
data = Text.from_ansi(data.data.decode())
|
|
161
173
|
self.print_queue.put(data)
|
|
162
|
-
|
|
174
|
+
|
|
163
175
|
def stop(self):
|
|
164
176
|
self.running = False
|
|
165
177
|
self.run_thread.join()
|
|
166
178
|
|
|
167
|
-
|
|
179
|
+
|
|
180
|
+
def spinner(prompt, style):
|
|
168
181
|
s = Spinner(prompt, style)
|
|
169
182
|
_print([s])
|
|
170
183
|
return s
|
|
171
184
|
|
|
172
|
-
|
|
173
|
-
|
|
185
|
+
|
|
186
|
+
def progress(what_to_track, healthcheck, description, total=100):
|
|
187
|
+
pointer_to_progress = [PyntProgress(what_to_track, healthcheck, total, description)]
|
|
174
188
|
_print(pointer_to_progress)
|
|
175
189
|
return pointer_to_progress[0]
|
|
176
190
|
|
|
191
|
+
|
|
192
|
+
def print_verbose(text: str):
|
|
193
|
+
if VERBOSE:
|
|
194
|
+
print(PrinterText(text, PrinterText.INFO))
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
pyntcli/__init__.py,sha256=
|
|
2
|
-
pyntcli/main.py,sha256=
|
|
1
|
+
pyntcli/__init__.py,sha256=DqFIxZO1qWYGIooEyrZV7d6zn4AaSeN_vya1dM6dtRc,23
|
|
2
|
+
pyntcli/main.py,sha256=eJFpT-haLVQAYP71_ZHjNaA5iG2wvDXy8km84GU0Mwo,6009
|
|
3
3
|
pyntcli/analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
pyntcli/analytics/send.py,sha256=pJOyOWl3g_Vm9apKK3LzNVqsnC6zsWA1bCK3ZegbLpc,3637
|
|
5
5
|
pyntcli/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
pyntcli/auth/login.py,sha256=TljsRXbEkNI1YUrKm5mlTw4YiecYScYUsit8Z8vstss,5228
|
|
7
7
|
pyntcli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
pyntcli/commands/burp.py,sha256=
|
|
9
|
-
pyntcli/commands/command.py,sha256=
|
|
10
|
-
pyntcli/commands/har.py,sha256=
|
|
8
|
+
pyntcli/commands/burp.py,sha256=O-KKyp6kcbTeHMEKsABlLQfI6rFqz229pef53UkpGlQ,11840
|
|
9
|
+
pyntcli/commands/command.py,sha256=0lCMxXIyj3vAd8NfeQ2Ik1WhV8RHq17cwwaQn2isRzQ,10411
|
|
10
|
+
pyntcli/commands/har.py,sha256=iBFd_Zqjths3JztmHHJBvIbrfT98ANVK180tVXqFXFk,4063
|
|
11
11
|
pyntcli/commands/id_command.py,sha256=UBEgMIpm4vauTCsKyixltiGUolNg_OfHEJvJ_i5BpJY,943
|
|
12
|
-
pyntcli/commands/listen.py,sha256=
|
|
13
|
-
pyntcli/commands/newman.py,sha256=
|
|
14
|
-
pyntcli/commands/postman.py,sha256=
|
|
12
|
+
pyntcli/commands/listen.py,sha256=L8lpa8r-mZor9F_ad9L7KQAznljSEOgn_LPURm4e6dM,8789
|
|
13
|
+
pyntcli/commands/newman.py,sha256=MQ7EG1QTm-Xnb_gfpx_DYo1BeoV_Y5SFIBJrtKCZZB8,5181
|
|
14
|
+
pyntcli/commands/postman.py,sha256=wh0sgJTTkUDY5GFKxCKMrcE9OmSZk6nufltsIlJb6As,5013
|
|
15
15
|
pyntcli/commands/pynt_cmd.py,sha256=KOl9guUtesO2JcMM5nPKKkjnK6F9HV4jHHcoUk4KVhw,2825
|
|
16
|
-
pyntcli/commands/root.py,sha256=
|
|
16
|
+
pyntcli/commands/root.py,sha256=inffMhaMJykoRC0T2f7uF3f5BEdJw_c6Q1e2FTG4bfU,3511
|
|
17
17
|
pyntcli/commands/static_file_extensions.py,sha256=PZJb02BI-64tbU-j3rdCNsXzTh7gkIDGxGKbKNw3h5k,1995
|
|
18
18
|
pyntcli/commands/sub_command.py,sha256=GF3-rE_qk2L4jGPFqHLm9SdGINmu3EakhjJTFyWjRms,374
|
|
19
19
|
pyntcli/commands/util.py,sha256=spTI_3z-fd0q7o1htvl-mw9-yKbO2ZESDAL-AsgWCb0,3217
|
|
@@ -21,7 +21,7 @@ pyntcli/log/__init__.py,sha256=cOGwOYzMoshEbZiiasBGkj6wF0SBu3Jdpl-AuakDesw,19
|
|
|
21
21
|
pyntcli/log/log.py,sha256=cWCdWmUaAwePwdhYDcgNMEG9d9RM34sGahxBCYEdv2Y,1069
|
|
22
22
|
pyntcli/pynt_docker/__init__.py,sha256=PQIOVxc7XXtMLfEX7ojgwf_Z3mmTllO3ZvzUZTPOxQY,30
|
|
23
23
|
pyntcli/pynt_docker/container_utils.py,sha256=_Onn7loInzyJAG2-Uk6CGpsuRyelmUFHOvtJj4Uzi9A,175
|
|
24
|
-
pyntcli/pynt_docker/pynt_container.py,sha256=
|
|
24
|
+
pyntcli/pynt_docker/pynt_container.py,sha256=Lz4WJlzJj3YeRQ6bb9D34oeLGnY1c0UDIugoHu-zBWA,9318
|
|
25
25
|
pyntcli/store/__init__.py,sha256=xuS9OB21F6B1sUx5XPGxz_6WpG6-KTMbuq50RrZS5OY,29
|
|
26
26
|
pyntcli/store/json_connector.py,sha256=UGs3uORw3iyn0YJ8kzab-veEZToA6d-ByXYuqEleWsA,560
|
|
27
27
|
pyntcli/store/store.py,sha256=9KwalOd1EA1VtYwr9oJgBsPgUYakX5uyif_sNXGQ614,1917
|
|
@@ -30,14 +30,14 @@ pyntcli/transport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
30
30
|
pyntcli/transport/pynt_requests.py,sha256=KiEG3hNcwY7DLIJDCq-7LIPq54yYQcDBhHe3KhpqRTc,1563
|
|
31
31
|
pyntcli/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
32
|
pyntcli/ui/progress.py,sha256=RrnO_jJNunoyupylakmWmHOEPw3lh99OHpKBzL6OBiE,1008
|
|
33
|
-
pyntcli/ui/pynt_errors.py,sha256=
|
|
33
|
+
pyntcli/ui/pynt_errors.py,sha256=00UprD4tFViREv7kuXGQ99PAKGTpXYixxi3Ndeoeiew,689
|
|
34
34
|
pyntcli/ui/report.py,sha256=W-icPSZrGLOubXgam0LpOvHLl_aZg9Zx9qIkL8Ym5PE,1930
|
|
35
|
-
pyntcli/ui/ui_thread.py,sha256=
|
|
35
|
+
pyntcli/ui/ui_thread.py,sha256=4YzpO5dDrWpbTovMdHvv9ZQdLFJamZEAKXjF9rIIIoQ,5039
|
|
36
36
|
tests/conftest.py,sha256=gToq5K74GtgeGQXjFvXSzMaE6axBYxAzcFG5XJPOXjI,427
|
|
37
37
|
tests/auth/test_login.py,sha256=KFlzWhXBAuwdi7GXf16gCB3ya94LQG2wjcSChE149rQ,3798
|
|
38
38
|
tests/store/test_cred_store.py,sha256=_7-917EtNC9eKEumO2_lt-7KuDmCwOZFaowCm7DbA_A,254
|
|
39
|
-
pyntcli-0.1.
|
|
40
|
-
pyntcli-0.1.
|
|
41
|
-
pyntcli-0.1.
|
|
42
|
-
pyntcli-0.1.
|
|
43
|
-
pyntcli-0.1.
|
|
39
|
+
pyntcli-0.1.87.dist-info/METADATA,sha256=buf6PtP3EoTWbUyD7cqhPJpPkj_stwuVePNRSfMzoDY,463
|
|
40
|
+
pyntcli-0.1.87.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
|
|
41
|
+
pyntcli-0.1.87.dist-info/entry_points.txt,sha256=kcGmqAxXDttNk2EPRcqunc_LTVp61gzakz0v-GEE2SY,43
|
|
42
|
+
pyntcli-0.1.87.dist-info/top_level.txt,sha256=u9MDStwVHB7UG8PUcODeWCul_NvzL2EzoLvSlgwLHFs,30
|
|
43
|
+
pyntcli-0.1.87.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|