pywebexec 1.6.11__py3-none-any.whl → 1.6.13__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.
- pywebexec/pywebexec.py +26 -30
- pywebexec/version.py +2 -2
- {pywebexec-1.6.11.dist-info → pywebexec-1.6.13.dist-info}/METADATA +2 -1
- {pywebexec-1.6.11.dist-info → pywebexec-1.6.13.dist-info}/RECORD +8 -8
- {pywebexec-1.6.11.dist-info → pywebexec-1.6.13.dist-info}/LICENSE +0 -0
- {pywebexec-1.6.11.dist-info → pywebexec-1.6.13.dist-info}/WHEEL +0 -0
- {pywebexec-1.6.11.dist-info → pywebexec-1.6.13.dist-info}/entry_points.txt +0 -0
- {pywebexec-1.6.11.dist-info → pywebexec-1.6.13.dist-info}/top_level.txt +0 -0
pywebexec/pywebexec.py
CHANGED
@@ -25,7 +25,7 @@ import termios
|
|
25
25
|
import struct
|
26
26
|
import subprocess
|
27
27
|
import logging
|
28
|
-
|
28
|
+
import pyte
|
29
29
|
|
30
30
|
if os.environ.get('PYWEBEXEC_LDAP_SERVER'):
|
31
31
|
from ldap3 import Server, Connection, ALL, SIMPLE, SUBTREE, Tls
|
@@ -181,8 +181,14 @@ class PyWebExec(Application):
|
|
181
181
|
def load(self):
|
182
182
|
return self.application
|
183
183
|
|
184
|
-
|
185
|
-
|
184
|
+
def get_visible_output(line):
|
185
|
+
screen = pyte.Screen(len(line)+1, 2)
|
186
|
+
stream = pyte.Stream(screen)
|
187
|
+
stream.feed(line)
|
188
|
+
visible_line = screen.display[0]
|
189
|
+
return visible_line
|
190
|
+
#38;2;66;59;165m
|
191
|
+
ANSI_ESCAPE = re.compile(br'(?:\x1B[@-Z\\-_]|\x1B([(]B|>)|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~]|\x1B\[([0-9]{1,2};){0,4}[0-9]{1,3}[m|K]|\x1B\[[0-9;]*[mGKHF]|[\x00-\x1F\x7F])')
|
186
192
|
|
187
193
|
def strip_ansi_control_chars(text):
|
188
194
|
"""Remove ANSI and control characters from the text."""
|
@@ -192,37 +198,27 @@ def strip_ansi_control_chars(text):
|
|
192
198
|
def decode_line(line: bytes) -> str:
|
193
199
|
"""try decode line exception on binary"""
|
194
200
|
try:
|
195
|
-
return
|
201
|
+
return get_visible_output(line.decode()).strip(" ")
|
196
202
|
except UnicodeDecodeError:
|
197
203
|
return ""
|
198
204
|
|
199
205
|
|
200
|
-
def
|
201
|
-
"""last non empty line
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
last_pos = 0
|
206
|
-
while line in ["", "\n", "\r"] and size < maxsize:
|
207
|
-
try: # catch if file empty / only empty lines
|
208
|
-
if last_pos:
|
209
|
-
fd.seek(last_pos-2, os.SEEK_SET)
|
210
|
-
while fd.read(1) not in [b"\n", b"\r"] and size < maxsize:
|
211
|
-
fd.seek(-2, os.SEEK_CUR)
|
212
|
-
size += 1
|
206
|
+
def get_last_line(file_path, maxsize=1024):
|
207
|
+
"""Retrieve last non empty line after vt100 interpretation"""
|
208
|
+
with open(file_path, 'rb') as fd:
|
209
|
+
try:
|
210
|
+
fd.seek(-maxsize, os.SEEK_END)
|
213
211
|
except OSError:
|
214
212
|
fd.seek(0)
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
line =
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
with open(file_path, 'rb') as f:
|
225
|
-
return last_line(f)
|
213
|
+
lines = fd.read().split(b"\n")
|
214
|
+
if len(lines) == 1:
|
215
|
+
return ""
|
216
|
+
line = ""
|
217
|
+
while True:
|
218
|
+
line = decode_line(lines.pop())
|
219
|
+
if line or not lines:
|
220
|
+
break
|
221
|
+
return line
|
226
222
|
|
227
223
|
|
228
224
|
def start_gunicorn(daemonized=False, baselog=None):
|
@@ -435,7 +431,7 @@ def update_command_status(command_id, updates):
|
|
435
431
|
if status_data['status'] != 'running':
|
436
432
|
output_file_path = get_output_file_path(command_id)
|
437
433
|
if os.path.exists(output_file_path):
|
438
|
-
status_data['last_output_line'] =
|
434
|
+
status_data['last_output_line'] = get_last_line(output_file_path)
|
439
435
|
with open(status_file_path, 'w') as f:
|
440
436
|
json.dump(status_data, f)
|
441
437
|
|
@@ -577,7 +573,7 @@ def read_commands():
|
|
577
573
|
if last_line is None:
|
578
574
|
output_file_path = get_output_file_path(command_id)
|
579
575
|
if os.path.exists(output_file_path):
|
580
|
-
last_line =
|
576
|
+
last_line = get_last_line(output_file_path)
|
581
577
|
commands.append({
|
582
578
|
'command_id': command_id,
|
583
579
|
'status': status['status'],
|
pywebexec/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pywebexec
|
3
|
-
Version: 1.6.
|
3
|
+
Version: 1.6.13
|
4
4
|
Summary: Simple Python HTTP Exec Server
|
5
5
|
Home-page: https://github.com/joknarf/pywebexec
|
6
6
|
Author: Franck Jouvanceau
|
@@ -59,6 +59,7 @@ Requires-Dist: Flask-HTTPAuth>=4.8.0
|
|
59
59
|
Requires-Dist: pexpect>=4.9.0
|
60
60
|
Requires-Dist: gunicorn>=21.2.0
|
61
61
|
Requires-Dist: ldap3>=2.9.1
|
62
|
+
Requires-Dist: pyte>=0.8.1
|
62
63
|
|
63
64
|
[](https://pypi.org/project/pywebexec/)
|
64
65
|

|
@@ -1,6 +1,6 @@
|
|
1
1
|
pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
|
2
|
-
pywebexec/pywebexec.py,sha256=
|
3
|
-
pywebexec/version.py,sha256=
|
2
|
+
pywebexec/pywebexec.py,sha256=hE7O0lZgg_nMk1VIFlBUv6lJ6T5sJFFBycnDmVnRQg4,32518
|
3
|
+
pywebexec/version.py,sha256=F6yOQF2i7n8OMZVy5diTWAk2RoBPwyUW2P5AsaXwnHo,413
|
4
4
|
pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
|
5
5
|
pywebexec/static/css/style.css,sha256=MJHUBpjWL4sLxM7a7DxypmPKaFJQbmA_ESNXsbLviNI,8201
|
6
6
|
pywebexec/static/css/xterm.css,sha256=uo5phWaUiJgcz0DAzv46uoByLLbJLeetYosL1xf68rY,5559
|
@@ -33,9 +33,9 @@ pywebexec/static/js/xterm/xterm.js.map,sha256=Y7O2Pb-fIS7Z8AC1D5s04_aiW_Jf1f4mCf
|
|
33
33
|
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
34
|
pywebexec/templates/index.html,sha256=5h8kLyzAhbvUDU9sEwrGIvD6FxAMcDZLXlN-ldlO8KU,2880
|
35
35
|
pywebexec/templates/popup.html,sha256=3ZqQcE9mYs-RXv0Lfb24zntOlvR137ZYI9mtCZNVAo0,1407
|
36
|
-
pywebexec-1.6.
|
37
|
-
pywebexec-1.6.
|
38
|
-
pywebexec-1.6.
|
39
|
-
pywebexec-1.6.
|
40
|
-
pywebexec-1.6.
|
41
|
-
pywebexec-1.6.
|
36
|
+
pywebexec-1.6.13.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
37
|
+
pywebexec-1.6.13.dist-info/METADATA,sha256=zXXihO8zyUycPpw9EBZK_YbKa9-P4PcHR-RPPPSQ-Qc,8001
|
38
|
+
pywebexec-1.6.13.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
39
|
+
pywebexec-1.6.13.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
40
|
+
pywebexec-1.6.13.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
41
|
+
pywebexec-1.6.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|