pywebexec 1.4.10__tar.gz → 1.4.12__tar.gz
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-1.4.10/pywebexec.egg-info → pywebexec-1.4.12}/PKG-INFO +13 -1
- {pywebexec-1.4.10 → pywebexec-1.4.12}/README.md +12 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/pywebexec.py +43 -20
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/js/popup.js +2 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/templates/popup.html +3 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/version.py +2 -2
- {pywebexec-1.4.10 → pywebexec-1.4.12/pywebexec.egg-info}/PKG-INFO +13 -1
- {pywebexec-1.4.10 → pywebexec-1.4.12}/.github/workflows/python-publish.yml +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/.gitignore +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/LICENSE +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pyproject.toml +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/__init__.py +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/css/Consolas NF.ttf +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/css/style.css +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/css/xterm.css +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/aborted.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/copy.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/copy_ok.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/down-arrow.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/failed.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/favicon.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/popup.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/running.gif +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/images/success.svg +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/js/commands.js +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/js/script.js +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/js/xterm/LICENSE +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/js/xterm/ansi_up.min.js +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/js/xterm/xterm-addon-fit.js +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/static/js/xterm/xterm.js +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/templates/__init__.py +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec/templates/index.html +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec.egg-info/SOURCES.txt +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec.egg-info/dependency_links.txt +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec.egg-info/entry_points.txt +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec.egg-info/requires.txt +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/pywebexec.egg-info/top_level.txt +0 -0
- {pywebexec-1.4.10 → pywebexec-1.4.12}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pywebexec
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.12
|
4
4
|
Summary: Simple Python HTTP Exec Server
|
5
5
|
Home-page: https://github.com/joknarf/pywebexec
|
6
6
|
Author: Franck Jouvanceau
|
@@ -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
|
@@ -51,6 +51,18 @@ $ pywebexec --dir ~/myscripts --listen 0.0.0.0 --port 8080 --title myscripts
|
|
51
51
|
$ pywebexec -d ~/myscripts -l 0.0.0.0 -p 8080 -t myscripts
|
52
52
|
```
|
53
53
|
|
54
|
+
## Sharing terminals
|
55
|
+
|
56
|
+
* start server and share tty in one command
|
57
|
+
```shell
|
58
|
+
$ pywebexec -d ~/webshare shareterm
|
59
|
+
```
|
60
|
+
* share tty with an already pywebexec server started
|
61
|
+
```shell
|
62
|
+
$ pywebexec -d ~/webshare term
|
63
|
+
```
|
64
|
+
if another user need to share his terminal, he need to have write permission on `<dir>/.web_status` directory.
|
65
|
+
|
54
66
|
## Safe url token
|
55
67
|
|
56
68
|
* generate safe url, use the url to access the server
|
@@ -9,6 +9,7 @@ import argparse
|
|
9
9
|
import random
|
10
10
|
import string
|
11
11
|
from datetime import datetime, timezone, timedelta
|
12
|
+
import time
|
12
13
|
import shlex
|
13
14
|
from gunicorn.app.base import Application
|
14
15
|
import ipaddress
|
@@ -22,6 +23,7 @@ import signal
|
|
22
23
|
import fcntl
|
23
24
|
import termios
|
24
25
|
import struct
|
26
|
+
import subprocess
|
25
27
|
|
26
28
|
|
27
29
|
if os.environ.get('PYWEBEXEC_LDAP_SERVER'):
|
@@ -40,6 +42,7 @@ app.config['LDAP_BIND_DN'] = os.environ.get('PYWEBEXEC_LDAP_BIND_DN')
|
|
40
42
|
app.config['LDAP_BIND_PASSWORD'] = os.environ.get('PYWEBEXEC_LDAP_BIND_PASSWORD')
|
41
43
|
|
42
44
|
# Directory to store the command status and output
|
45
|
+
CWD = os.getcwd()
|
43
46
|
COMMAND_STATUS_DIR = '.web_status'
|
44
47
|
CONFDIR = os.path.expanduser("~/")
|
45
48
|
if os.path.isdir(f"{CONFDIR}/.config"):
|
@@ -216,17 +219,19 @@ def get_last_non_empty_line_of_file(file_path):
|
|
216
219
|
|
217
220
|
|
218
221
|
def start_gunicorn(daemonized=False, baselog=None):
|
222
|
+
pidfile = f"{baselog}.pid"
|
219
223
|
if daemonized:
|
220
|
-
errorlog = f"{baselog}.log"
|
221
|
-
accesslog = None # f"{baselog}.access.log"
|
222
|
-
pidfile = f"{baselog}.pid"
|
223
224
|
if daemon_d('status', pidfilepath=baselog, silent=True):
|
224
225
|
print(f"Error: pywebexec already running on {args.listen}:{args.port}", file=sys.stderr)
|
225
226
|
sys.exit(1)
|
226
|
-
|
227
|
+
|
228
|
+
if sys.stdout.isatty():
|
227
229
|
errorlog = "-"
|
228
230
|
accesslog = None #"-"
|
229
|
-
|
231
|
+
else:
|
232
|
+
errorlog = f"{baselog}.log"
|
233
|
+
accesslog = None # f"{baselog}.access.log"
|
234
|
+
|
230
235
|
options = {
|
231
236
|
'bind': '%s:%s' % (args.listen, args.port),
|
232
237
|
'workers': 4,
|
@@ -280,6 +285,19 @@ def daemon_d(action, pidfilepath, silent=False, hostname=None, args=None):
|
|
280
285
|
except Exception as e:
|
281
286
|
print(e)
|
282
287
|
|
288
|
+
def start_term():
|
289
|
+
os.environ["PYWEBEXEC"] = " (shared)"
|
290
|
+
os.chdir(CWD)
|
291
|
+
command_id = str(uuid.uuid4())
|
292
|
+
start_time = datetime.now().isoformat()
|
293
|
+
user = pwd.getpwuid(os.getuid())[0]
|
294
|
+
update_command_status(command_id, 'running', command="term", params=[user,os.ttyname(sys.stdout.fileno())], start_time=start_time, user=user)
|
295
|
+
output_file_path = get_output_file_path(command_id)
|
296
|
+
res = script(output_file_path)
|
297
|
+
end_time = datetime.now().isoformat()
|
298
|
+
update_command_status(command_id, status="success", end_time=end_time, exit_code=res)
|
299
|
+
return res
|
300
|
+
|
283
301
|
def parseargs():
|
284
302
|
global app, args, COMMAND_STATUS_DIR
|
285
303
|
|
@@ -306,10 +324,10 @@ def parseargs():
|
|
306
324
|
parser.add_argument("-k", "--key", type=str, help="Path to https certificate key")
|
307
325
|
parser.add_argument("-g", "--gencert", action="store_true", help="https server self signed cert")
|
308
326
|
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",
|
327
|
+
parser.add_argument("action", nargs="?", help="daemon action start/stop/restart/status/shareterm/term",
|
328
|
+
choices=["start","stop","restart","status","shareterm", "term"])
|
310
329
|
|
311
330
|
args = parser.parse_args()
|
312
|
-
cwd = os.getcwd()
|
313
331
|
if os.path.isdir(args.dir):
|
314
332
|
try:
|
315
333
|
os.chdir(args.dir)
|
@@ -325,21 +343,13 @@ def parseargs():
|
|
325
343
|
os.mkdir(CONFDIR, mode=0o700)
|
326
344
|
if args.action == "term":
|
327
345
|
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)
|
346
|
+
sys.exit(start_term())
|
338
347
|
(hostname, ip) = resolve(gethostname()) if args.listen == '0.0.0.0' else resolve(args.listen)
|
339
348
|
url_params = ""
|
340
349
|
|
341
350
|
if args.tokenurl:
|
342
|
-
token = token_urlsafe()
|
351
|
+
token = os.environ.get("PYWEBEXEC_TOKEN", token_urlsafe())
|
352
|
+
os.environ["PYWEBEXEC_TOKEN"] = token
|
343
353
|
app.config["TOKEN_URL"] = token
|
344
354
|
url_params = f"?token={token}"
|
345
355
|
|
@@ -446,7 +456,6 @@ def script(output_file):
|
|
446
456
|
sigwinch_passthrough(None, None)
|
447
457
|
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
448
458
|
p.interact()
|
449
|
-
|
450
459
|
|
451
460
|
|
452
461
|
def run_command(command, params, command_id, user):
|
@@ -688,12 +697,26 @@ def popup(command_id):
|
|
688
697
|
return render_template('popup.html', command_id=command_id)
|
689
698
|
|
690
699
|
def main():
|
700
|
+
global COMMAND_STATUS_DIR
|
691
701
|
basef = f"{CONFDIR}/pywebexec_{args.listen}:{args.port}"
|
702
|
+
if args.action == "shareterm":
|
703
|
+
COMMAND_STATUS_DIR = f"{os.getcwd()}/{COMMAND_STATUS_DIR}"
|
704
|
+
with open(basef + ".log", "ab+") as log:
|
705
|
+
pywebexec = subprocess.Popen([sys.executable] + sys.argv[:-1], stdout=log, stderr=log)
|
706
|
+
start_term()
|
707
|
+
time.sleep(1)
|
708
|
+
pywebexec.terminate()
|
709
|
+
sys.exit()
|
710
|
+
|
711
|
+
if args.action == "restart":
|
712
|
+
daemon_d('stop', pidfilepath=basef)
|
713
|
+
args.action = "start"
|
692
714
|
if args.action == "start":
|
693
715
|
return start_gunicorn(daemonized=True, baselog=basef)
|
694
716
|
if args.action:
|
695
717
|
return daemon_d(args.action, pidfilepath=basef)
|
696
|
-
return start_gunicorn()
|
718
|
+
return start_gunicorn(baselog=basef)
|
719
|
+
|
697
720
|
|
698
721
|
if __name__ == '__main__':
|
699
722
|
main()
|
@@ -47,6 +47,7 @@ async function fetchOutput(url) {
|
|
47
47
|
try {
|
48
48
|
const response = await fetch(url);
|
49
49
|
if (!response.ok) {
|
50
|
+
document.getElementById('dimmer').style.display = 'none';
|
50
51
|
return;
|
51
52
|
}
|
52
53
|
const data = await response.json();
|
@@ -72,6 +73,7 @@ async function fetchOutput(url) {
|
|
72
73
|
}
|
73
74
|
}
|
74
75
|
} catch (error) {
|
76
|
+
document.getElementById('dimmer').style.display = 'block';
|
75
77
|
console.log('Error fetching output:', error);
|
76
78
|
}
|
77
79
|
}
|
@@ -8,6 +8,9 @@
|
|
8
8
|
<link rel="stylesheet" href="/static/css/xterm.css">
|
9
9
|
</head>
|
10
10
|
<body>
|
11
|
+
<div id="dimmer" class="dimmer">
|
12
|
+
<div class="dimmer-text">Server not available</div>
|
13
|
+
</div>
|
11
14
|
<div id="output" class="output"></div>
|
12
15
|
<div class="slider-container">
|
13
16
|
<input type="range" id="outputSlider" min="0" max="100" value="100">
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pywebexec
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.12
|
4
4
|
Summary: Simple Python HTTP Exec Server
|
5
5
|
Home-page: https://github.com/joknarf/pywebexec
|
6
6
|
Author: Franck Jouvanceau
|
@@ -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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|