pywebexec 1.4.9__py3-none-any.whl → 1.4.11__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 +40 -19
- pywebexec/static/js/script.js +3 -1
- pywebexec/version.py +2 -2
- {pywebexec-1.4.9.dist-info → pywebexec-1.4.11.dist-info}/METADATA +14 -2
- {pywebexec-1.4.9.dist-info → pywebexec-1.4.11.dist-info}/RECORD +9 -9
- {pywebexec-1.4.9.dist-info → pywebexec-1.4.11.dist-info}/LICENSE +0 -0
- {pywebexec-1.4.9.dist-info → pywebexec-1.4.11.dist-info}/WHEEL +0 -0
- {pywebexec-1.4.9.dist-info → pywebexec-1.4.11.dist-info}/entry_points.txt +0 -0
- {pywebexec-1.4.9.dist-info → pywebexec-1.4.11.dist-info}/top_level.txt +0 -0
pywebexec/pywebexec.py
CHANGED
@@ -22,6 +22,7 @@ import signal
|
|
22
22
|
import fcntl
|
23
23
|
import termios
|
24
24
|
import struct
|
25
|
+
import subprocess
|
25
26
|
|
26
27
|
|
27
28
|
if os.environ.get('PYWEBEXEC_LDAP_SERVER'):
|
@@ -40,6 +41,7 @@ app.config['LDAP_BIND_DN'] = os.environ.get('PYWEBEXEC_LDAP_BIND_DN')
|
|
40
41
|
app.config['LDAP_BIND_PASSWORD'] = os.environ.get('PYWEBEXEC_LDAP_BIND_PASSWORD')
|
41
42
|
|
42
43
|
# Directory to store the command status and output
|
44
|
+
CWD = os.getcwd()
|
43
45
|
COMMAND_STATUS_DIR = '.web_status'
|
44
46
|
CONFDIR = os.path.expanduser("~/")
|
45
47
|
if os.path.isdir(f"{CONFDIR}/.config"):
|
@@ -216,17 +218,19 @@ def get_last_non_empty_line_of_file(file_path):
|
|
216
218
|
|
217
219
|
|
218
220
|
def start_gunicorn(daemonized=False, baselog=None):
|
221
|
+
pidfile = f"{baselog}.pid"
|
219
222
|
if daemonized:
|
220
|
-
errorlog = f"{baselog}.log"
|
221
|
-
accesslog = None # f"{baselog}.access.log"
|
222
|
-
pidfile = f"{baselog}.pid"
|
223
223
|
if daemon_d('status', pidfilepath=baselog, silent=True):
|
224
224
|
print(f"Error: pywebexec already running on {args.listen}:{args.port}", file=sys.stderr)
|
225
225
|
sys.exit(1)
|
226
|
-
|
226
|
+
|
227
|
+
if sys.stdout.isatty():
|
227
228
|
errorlog = "-"
|
228
229
|
accesslog = None #"-"
|
229
|
-
|
230
|
+
else:
|
231
|
+
errorlog = f"{baselog}.log"
|
232
|
+
accesslog = None # f"{baselog}.access.log"
|
233
|
+
|
230
234
|
options = {
|
231
235
|
'bind': '%s:%s' % (args.listen, args.port),
|
232
236
|
'workers': 4,
|
@@ -280,6 +284,18 @@ def daemon_d(action, pidfilepath, silent=False, hostname=None, args=None):
|
|
280
284
|
except Exception as e:
|
281
285
|
print(e)
|
282
286
|
|
287
|
+
def start_term():
|
288
|
+
os.chdir(CWD)
|
289
|
+
command_id = str(uuid.uuid4())
|
290
|
+
start_time = datetime.now().isoformat()
|
291
|
+
user = pwd.getpwuid(os.getuid())[0]
|
292
|
+
update_command_status(command_id, 'running', command="term", params=[user,os.ttyname(sys.stdout.fileno())], start_time=start_time, user=user)
|
293
|
+
output_file_path = get_output_file_path(command_id)
|
294
|
+
res = script(output_file_path)
|
295
|
+
end_time = datetime.now().isoformat()
|
296
|
+
update_command_status(command_id, status="success", end_time=end_time, exit_code=res)
|
297
|
+
return res
|
298
|
+
|
283
299
|
def parseargs():
|
284
300
|
global app, args, COMMAND_STATUS_DIR
|
285
301
|
|
@@ -306,10 +322,10 @@ def parseargs():
|
|
306
322
|
parser.add_argument("-k", "--key", type=str, help="Path to https certificate key")
|
307
323
|
parser.add_argument("-g", "--gencert", action="store_true", help="https server self signed cert")
|
308
324
|
parser.add_argument("-T", "--tokenurl", action="store_true", help="generate safe url to access")
|
309
|
-
parser.add_argument("action", nargs="?", help="daemon action start/stop/restart/status/term",
|
325
|
+
parser.add_argument("action", nargs="?", help="daemon action start/stop/restart/status/shareterm/term",
|
326
|
+
choices=["start","stop","restart","status","shareterm", "term"])
|
310
327
|
|
311
328
|
args = parser.parse_args()
|
312
|
-
cwd = os.getcwd()
|
313
329
|
if os.path.isdir(args.dir):
|
314
330
|
try:
|
315
331
|
os.chdir(args.dir)
|
@@ -325,21 +341,13 @@ def parseargs():
|
|
325
341
|
os.mkdir(CONFDIR, mode=0o700)
|
326
342
|
if args.action == "term":
|
327
343
|
COMMAND_STATUS_DIR = f"{os.getcwd()}/{COMMAND_STATUS_DIR}"
|
328
|
-
|
329
|
-
command_id = str(uuid.uuid4())
|
330
|
-
start_time = datetime.now().isoformat()
|
331
|
-
user = pwd.getpwuid(os.getuid())[0]
|
332
|
-
update_command_status(command_id, 'running', command="term", params=[user,os.ttyname(sys.stdout.fileno())], start_time=start_time, user=user)
|
333
|
-
output_file_path = get_output_file_path(command_id)
|
334
|
-
res = script(output_file_path)
|
335
|
-
end_time = datetime.now().isoformat()
|
336
|
-
update_command_status(command_id, status="success", end_time=end_time, exit_code=res)
|
337
|
-
sys.exit(res)
|
344
|
+
sys.exit(start_term())
|
338
345
|
(hostname, ip) = resolve(gethostname()) if args.listen == '0.0.0.0' else resolve(args.listen)
|
339
346
|
url_params = ""
|
340
347
|
|
341
348
|
if args.tokenurl:
|
342
|
-
token = token_urlsafe()
|
349
|
+
token = os.environ.get("PYWEBEXEC_TOKEN", token_urlsafe())
|
350
|
+
os.environ["PYWEBEXEC_TOKEN"] = token
|
343
351
|
app.config["TOKEN_URL"] = token
|
344
352
|
url_params = f"?token={token}"
|
345
353
|
|
@@ -688,12 +696,25 @@ def popup(command_id):
|
|
688
696
|
return render_template('popup.html', command_id=command_id)
|
689
697
|
|
690
698
|
def main():
|
699
|
+
global COMMAND_STATUS_DIR
|
691
700
|
basef = f"{CONFDIR}/pywebexec_{args.listen}:{args.port}"
|
701
|
+
if args.action == "shareterm":
|
702
|
+
COMMAND_STATUS_DIR = f"{os.getcwd()}/{COMMAND_STATUS_DIR}"
|
703
|
+
with open(basef + ".log", "ab+") as log:
|
704
|
+
pywebexec = subprocess.Popen([sys.executable] + sys.argv[:-1], stdout=log, stderr=log)
|
705
|
+
start_term()
|
706
|
+
pywebexec.terminate()
|
707
|
+
sys.exit()
|
708
|
+
|
709
|
+
if args.action == "restart":
|
710
|
+
daemon_d('stop', pidfilepath=basef)
|
711
|
+
args.action = "start"
|
692
712
|
if args.action == "start":
|
693
713
|
return start_gunicorn(daemonized=True, baselog=basef)
|
694
714
|
if args.action:
|
695
715
|
return daemon_d(args.action, pidfilepath=basef)
|
696
|
-
return start_gunicorn()
|
716
|
+
return start_gunicorn(baselog=basef)
|
717
|
+
|
697
718
|
|
698
719
|
if __name__ == '__main__':
|
699
720
|
main()
|
pywebexec/static/js/script.js
CHANGED
@@ -190,7 +190,9 @@ async function viewOutput(command_id) {
|
|
190
190
|
}
|
191
191
|
}
|
192
192
|
|
193
|
-
async function openPopup(command_id) {
|
193
|
+
async function openPopup(command_id, event) {
|
194
|
+
event.stopPropagation();
|
195
|
+
event.stopImmediatePropagation();
|
194
196
|
const popupUrl = `/popup/${command_id}${urlToken}`;
|
195
197
|
window.open(popupUrl, '_blank', 'width=1000,height=600');
|
196
198
|
}
|
pywebexec/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pywebexec
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.11
|
4
4
|
Summary: Simple Python HTTP Exec Server
|
5
5
|
Home-page: https://github.com/joknarf/pywebexec
|
6
6
|
Author: Franck Jouvanceau
|
@@ -85,9 +85,9 @@ $ pywebexec -d <dir>
|
|
85
85
|
* Launch commands with params/view live output/Status using browser
|
86
86
|
* Share your terminal output using `pywebexec -d <dir> term`
|
87
87
|
|
88
|
+

|
88
89
|
|
89
90
|
all commands output / statuses are available in the executables directory in subdirectory `.web_status`
|
90
|
-

|
91
91
|
|
92
92
|
## features
|
93
93
|
|
@@ -113,6 +113,18 @@ $ pywebexec --dir ~/myscripts --listen 0.0.0.0 --port 8080 --title myscripts
|
|
113
113
|
$ pywebexec -d ~/myscripts -l 0.0.0.0 -p 8080 -t myscripts
|
114
114
|
```
|
115
115
|
|
116
|
+
## Sharing terminals
|
117
|
+
|
118
|
+
* start server and share tty in one command
|
119
|
+
```shell
|
120
|
+
$ pywebexec -d ~/webshare shareterm
|
121
|
+
```
|
122
|
+
* share tty with an already pywebexec server started
|
123
|
+
```shell
|
124
|
+
$ pywebexec -d ~/webshare term
|
125
|
+
```
|
126
|
+
if another user need to share his terminal, he need to have write permission on `<dir>/.web_status` directory.
|
127
|
+
|
116
128
|
## Safe url token
|
117
129
|
|
118
130
|
* generate safe url, use the url to access the server
|
@@ -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=gZNUbNeFI2TWimUXmHva9ABHv8S4QH_xiUXOWKlswJM,26843
|
3
|
+
pywebexec/version.py,sha256=CiEe7E8jVlrB3YZUumeEso6PXucVNqiDDQfL8kleYok,413
|
4
4
|
pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
|
5
5
|
pywebexec/static/css/style.css,sha256=sDBhZ-csW5THIKfTDsHqxCSg6rIJ91Oh15sjw_HjJo4,5702
|
6
6
|
pywebexec/static/css/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
|
@@ -15,7 +15,7 @@ pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUN
|
|
15
15
|
pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
|
16
16
|
pywebexec/static/js/commands.js,sha256=8JDb3Q55EJOYf2Q9Uy6qEuqAnn1oGjM0RndgQ4aOjqo,7725
|
17
17
|
pywebexec/static/js/popup.js,sha256=VdkDXEIwd4IawhDIWew6poWhpE7sAReVn0MopdSx5wY,4519
|
18
|
-
pywebexec/static/js/script.js,sha256=
|
18
|
+
pywebexec/static/js/script.js,sha256=QlYuIdvolTwxkJtgp7-X1IRM9Hr8D08iQCyCzZjv3hk,12255
|
19
19
|
pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
|
20
20
|
pywebexec/static/js/xterm/ansi_up.min.js,sha256=KNGV0vEr30hNqKQimTAvGVy-icD5A1JqMQTtvYtKR2Y,13203
|
21
21
|
pywebexec/static/js/xterm/xterm-addon-fit.js,sha256=Pprm9pZe4SadVXS5Bc8b9VnC9Ex4QlWwA0pxOH53Gck,1460
|
@@ -23,9 +23,9 @@ pywebexec/static/js/xterm/xterm.js,sha256=Bzka76jZwEhVt_LlS0e0qMw7ryGa1p5qfxFyeo
|
|
23
23
|
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
24
|
pywebexec/templates/index.html,sha256=DYtT555wSNhnFtzzHhPMWJireynCJNnAuTytpoORQeE,2321
|
25
25
|
pywebexec/templates/popup.html,sha256=6kmZKb0tGJ7jsr9DqDEriSMlbkW-PJTtCiUE9U5_FOE,837
|
26
|
-
pywebexec-1.4.
|
27
|
-
pywebexec-1.4.
|
28
|
-
pywebexec-1.4.
|
29
|
-
pywebexec-1.4.
|
30
|
-
pywebexec-1.4.
|
31
|
-
pywebexec-1.4.
|
26
|
+
pywebexec-1.4.11.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
27
|
+
pywebexec-1.4.11.dist-info/METADATA,sha256=g3K50Awl5n3qkU5zltFdfS_d5w7GbV_pRbhrsKO2HPo,7724
|
28
|
+
pywebexec-1.4.11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
29
|
+
pywebexec-1.4.11.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
30
|
+
pywebexec-1.4.11.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
31
|
+
pywebexec-1.4.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|