pywebexec 1.2.0__py3-none-any.whl → 1.4.12__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 +228 -96
- pywebexec/static/css/Consolas NF.ttf +0 -0
- pywebexec/static/css/style.css +121 -8
- pywebexec/static/css/xterm.css +209 -0
- pywebexec/static/images/down-arrow.svg +1 -0
- pywebexec/static/images/favicon.svg +8 -1
- pywebexec/static/images/popup.svg +1 -0
- pywebexec/static/js/commands.js +223 -0
- pywebexec/static/js/popup.js +141 -0
- pywebexec/static/js/script.js +130 -52
- pywebexec/static/js/xterm/LICENSE +21 -0
- pywebexec/static/js/xterm/ansi_up.min.js +7 -0
- pywebexec/static/js/xterm/xterm-addon-fit.js +1 -0
- pywebexec/static/js/xterm/xterm.js +1 -0
- pywebexec/templates/index.html +19 -6
- pywebexec/templates/popup.html +24 -0
- pywebexec/version.py +2 -2
- {pywebexec-1.2.0.dist-info → pywebexec-1.4.12.dist-info}/METADATA +41 -13
- pywebexec-1.4.12.dist-info/RECORD +31 -0
- pywebexec-1.2.0.dist-info/RECORD +0 -20
- {pywebexec-1.2.0.dist-info → pywebexec-1.4.12.dist-info}/LICENSE +0 -0
- {pywebexec-1.2.0.dist-info → pywebexec-1.4.12.dist-info}/WHEEL +0 -0
- {pywebexec-1.2.0.dist-info → pywebexec-1.4.12.dist-info}/entry_points.txt +0 -0
- {pywebexec-1.2.0.dist-info → pywebexec-1.4.12.dist-info}/top_level.txt +0 -0
pywebexec/templates/index.html
CHANGED
@@ -5,17 +5,23 @@
|
|
5
5
|
<link rel="icon" href="/static/images/favicon.svg" type="image/svg+xml">
|
6
6
|
<title>{{ title }}</title>
|
7
7
|
<link rel="stylesheet" href="/static/css/style.css">
|
8
|
+
<link rel="stylesheet" href="/static/css/xterm.css">
|
8
9
|
</head>
|
9
10
|
<body>
|
10
11
|
<div id="dimmer" class="dimmer">
|
11
|
-
<div class="dimmer-text">Server not
|
12
|
+
<div class="dimmer-text">Server not available</div>
|
12
13
|
</div>
|
13
14
|
<h2><span class="status-icon title-icon"></span>{{ title }}</h2>
|
14
|
-
<form id="launchForm">
|
15
|
+
<form id="launchForm" class="form-inline">
|
15
16
|
<label for="commandName">Command</label>
|
16
|
-
<
|
17
|
-
|
18
|
-
|
17
|
+
<div class="input-group">
|
18
|
+
<input type="text" id="commandName" name="commandName" size=5 autocomplete="off" style="width: 100px;" autofocus>
|
19
|
+
<div id="showCommandListButton" class="show-command-list-button">
|
20
|
+
<span class="arrow">▼</span>
|
21
|
+
</div>
|
22
|
+
<select id="commandList" class="command-list" size="20"></select>
|
23
|
+
<input type="text" id="params" name="params" oninput="this.style.width = ((this.value.length + 1) * 8) + 'px';">
|
24
|
+
</div>
|
19
25
|
<button type="submit">Run</button>
|
20
26
|
</form>
|
21
27
|
<div class="table-container" id="tableContainer">
|
@@ -26,7 +32,6 @@
|
|
26
32
|
<th>Start Time</th>
|
27
33
|
<th>Duration</th>
|
28
34
|
<th>Command</th>
|
29
|
-
<th>Exit</th>
|
30
35
|
<th>Status</th>
|
31
36
|
<th>Action</th>
|
32
37
|
<th>Output</th>
|
@@ -39,6 +44,14 @@
|
|
39
44
|
<div class="resizer" id="resizer"></div>
|
40
45
|
</div>
|
41
46
|
<div id="output" class="output"></div>
|
47
|
+
<div class="slider-container">
|
48
|
+
<input type="range" id="outputSlider" min="0" max="100" value="100">
|
49
|
+
<label for="outputSlider"><span id="outputPercentage">100%</span></label>
|
50
|
+
</div>
|
51
|
+
<script src="/static/js/xterm/ansi_up.min.js"></script>
|
52
|
+
<script src="/static/js/xterm/xterm.js"></script>
|
53
|
+
<script src="/static/js/xterm/xterm-addon-fit.js"></script>
|
42
54
|
<script type="text/javascript" src="/static/js/script.js"></script>
|
55
|
+
<script type="text/javascript" src="/static/js/commands.js"></script>
|
43
56
|
</body>
|
44
57
|
</html>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<link rel="icon" href="/static/images/favicon.svg" type="image/svg+xml">
|
6
|
+
<title id="outputTitle">Command Output</title>
|
7
|
+
<link rel="stylesheet" href="/static/css/style.css">
|
8
|
+
<link rel="stylesheet" href="/static/css/xterm.css">
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<div id="dimmer" class="dimmer">
|
12
|
+
<div class="dimmer-text">Server not available</div>
|
13
|
+
</div>
|
14
|
+
<div id="output" class="output"></div>
|
15
|
+
<div class="slider-container">
|
16
|
+
<input type="range" id="outputSlider" min="0" max="100" value="100">
|
17
|
+
<label for="outputSlider"><span id="outputPercentage">100%</span></label>
|
18
|
+
</div>
|
19
|
+
<script src="/static/js/xterm/ansi_up.min.js"></script>
|
20
|
+
<script src="/static/js/xterm/xterm.js"></script>
|
21
|
+
<script src="/static/js/xterm/xterm-addon-fit.js"></script>
|
22
|
+
<script type="text/javascript" src="/static/js/popup.js"></script>
|
23
|
+
</body>
|
24
|
+
</html>
|
pywebexec/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pywebexec
|
3
|
-
Version: 1.
|
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
|
@@ -36,7 +36,6 @@ Classifier: Intended Audience :: System Administrators
|
|
36
36
|
Classifier: License :: OSI Approved :: MIT License
|
37
37
|
Classifier: Operating System :: POSIX
|
38
38
|
Classifier: Operating System :: Unix
|
39
|
-
Classifier: Operating System :: Microsoft :: Windows
|
40
39
|
Classifier: Operating System :: MacOS
|
41
40
|
Classifier: Programming Language :: Python
|
42
41
|
Classifier: Programming Language :: Python :: 3
|
@@ -57,6 +56,7 @@ Requires-Dist: python-daemon>=2.3.2
|
|
57
56
|
Requires-Dist: cryptography>=40.0.2
|
58
57
|
Requires-Dist: Flask>=2.0.3
|
59
58
|
Requires-Dist: Flask-HTTPAuth>=4.8.0
|
59
|
+
Requires-Dist: pexpect>=4.9.0
|
60
60
|
Requires-Dist: gunicorn>=21.2.0
|
61
61
|
Requires-Dist: ldap3>=2.9.1
|
62
62
|
|
@@ -67,7 +67,7 @@ Requires-Dist: ldap3>=2.9.1
|
|
67
67
|
[](https://shields.io/)
|
68
68
|
|
69
69
|
# pywebexec
|
70
|
-
Simple Python HTTP(S) API/Web Command Launcher
|
70
|
+
Simple Python HTTP(S) API/Web Command Launcher and Terminal sharing
|
71
71
|
|
72
72
|
## Install
|
73
73
|
```
|
@@ -79,11 +79,13 @@ $ pip install pywebexec
|
|
79
79
|
* put in a directory the scripts/commands/links to commands you want to expose
|
80
80
|
* start http server serving current directory executables listening on 0.0.0.0 port 8080
|
81
81
|
```shell
|
82
|
-
$ pywebexec
|
82
|
+
$ pywebexec -d <dir>
|
83
83
|
```
|
84
84
|
|
85
85
|
* Launch commands with params/view live output/Status using browser
|
86
|
-
|
86
|
+
* Share your terminal output using `pywebexec -d <dir> term`
|
87
|
+
|
88
|
+

|
87
89
|
|
88
90
|
all commands output / statuses are available in the executables directory in subdirectory `.web_status`
|
89
91
|
|
@@ -91,13 +93,16 @@ all commands output / statuses are available in the executables directory in sub
|
|
91
93
|
|
92
94
|
* Serve executables in a directory
|
93
95
|
* Launch commands with params from web browser or API call
|
96
|
+
* multiple share terminal output
|
94
97
|
* Follow live output
|
98
|
+
* Replay terminal history
|
95
99
|
* Stop command
|
96
100
|
* Relaunch command
|
97
101
|
* HTTPS support
|
98
102
|
* HTTPS self-signed certificate generator
|
99
103
|
* Basic Auth
|
100
|
-
* LDAP(S)
|
104
|
+
* LDAP(S) password check/group member
|
105
|
+
* Safe url token generation
|
101
106
|
* Can be started as a daemon (POSIX)
|
102
107
|
* Uses gunicorn to serve http/https
|
103
108
|
* Linux/MacOS compatible
|
@@ -108,7 +113,30 @@ $ pywebexec --dir ~/myscripts --listen 0.0.0.0 --port 8080 --title myscripts
|
|
108
113
|
$ pywebexec -d ~/myscripts -l 0.0.0.0 -p 8080 -t myscripts
|
109
114
|
```
|
110
115
|
|
111
|
-
##
|
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
|
+
|
128
|
+
## Safe url token
|
129
|
+
|
130
|
+
* generate safe url, use the url to access the server
|
131
|
+
```shell
|
132
|
+
$ pywebexec -T
|
133
|
+
$ pywebexec --tokenurl
|
134
|
+
Starting server:
|
135
|
+
http://<host>:8080?token=jSTWiNgEVkddeEJ7I97x2ekOeaiXs2mErRSKNxm3DP0
|
136
|
+
http://x.x.x.x:8080?token=jSTWiNgEVkddeEJ7I97x2ekOeaiXs2mErRSKNxm3DP0
|
137
|
+
```
|
138
|
+
|
139
|
+
## Basic auth
|
112
140
|
|
113
141
|
* single user/password
|
114
142
|
```shell
|
@@ -131,14 +159,14 @@ $ pywebexec
|
|
131
159
|
|
132
160
|
* Generate auto-signed certificate and start https server
|
133
161
|
```shell
|
134
|
-
$
|
135
|
-
$
|
162
|
+
$ pywebexec --gencert
|
163
|
+
$ pywebexec --g
|
136
164
|
```
|
137
165
|
|
138
166
|
* Start https server using existing certificate
|
139
167
|
```shell
|
140
|
-
$
|
141
|
-
$
|
168
|
+
$ pywebexec --cert /pathto/host.cert --key /pathto/host.key
|
169
|
+
$ pywebexec -c /pathto/host.cert -k /pathto/host.key
|
142
170
|
```
|
143
171
|
|
144
172
|
## Launch server as a daemon
|
@@ -153,7 +181,7 @@ $ pywebexec stop
|
|
153
181
|
## Launch command through API
|
154
182
|
|
155
183
|
```shell
|
156
|
-
$ curl http://myhost:8080/
|
184
|
+
$ curl http://myhost:8080/run_command -H 'Content-Type: application/json' -X POST -d '{ "command":"myscript", "params":["param1", ...]}'
|
157
185
|
$ curl http://myhost:8080/command_status/<command_id>
|
158
186
|
$ curl http://myhost:8080/command_output/<command_id> -H "Accept: text/plain"
|
159
187
|
```
|
@@ -166,6 +194,6 @@ $ curl http://myhost:8080/command_output/<command_id> -H "Accept: text/plain"
|
|
166
194
|
| POST | /run_command | command: str<br>params: array[str] | command_id: uuid<br>message: str |
|
167
195
|
| POST | /stop_command/command_id | | message: str |
|
168
196
|
| GET | /command_status/command_id | | command_id: uuid<br>command: str<br>params: array[str]<br>start_time: isotime<br>end_time: isotime<br>status: str<br>exit_code: int<br>last_output_line: str |
|
169
|
-
| GET | /command_output/command_id |
|
197
|
+
| GET | /command_output/command_id | offset: int | output: str<br>status: str<br>links: { next: str } |
|
170
198
|
| GET | /commands | | array of<br>command_id: uuid<br>command: str<br>start_time: isotime<br>end_time: isotime<br>status: str<br>exit_code: int<br>last_output_line: str |
|
171
199
|
| GET | /executables | | array of str |
|
@@ -0,0 +1,31 @@
|
|
1
|
+
pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
|
2
|
+
pywebexec/pywebexec.py,sha256=bo_rh0wsEkcOXltOZMiZlojqABCAQqDM33cJGUUmnrU,26922
|
3
|
+
pywebexec/version.py,sha256=Zv4TpC5V6FOmlNNowuZivqOrr2E0lJ1Gpdzj7o5gDYw,413
|
4
|
+
pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
|
5
|
+
pywebexec/static/css/style.css,sha256=sDBhZ-csW5THIKfTDsHqxCSg6rIJ91Oh15sjw_HjJo4,5702
|
6
|
+
pywebexec/static/css/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
|
7
|
+
pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
|
8
|
+
pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
|
9
|
+
pywebexec/static/images/copy_ok.svg,sha256=mEqUVUhSq8xaJK2msQkxRawnz_KwlCZ-tok8QS6hJ3g,451
|
10
|
+
pywebexec/static/images/down-arrow.svg,sha256=4TclEmntMvKk_F_ADXgTpGtviYo826EDmmZiGE7HQBI,121
|
11
|
+
pywebexec/static/images/failed.svg,sha256=ADZ7IKrUyOXtqpivnz3VcH0-Wru-I5MOi3OJAkI3hxk,1439
|
12
|
+
pywebexec/static/images/favicon.svg,sha256=9gSN5Oak1zTWhTCyutlupPBKUxcbdoVt7dvhk8xvEug,1224
|
13
|
+
pywebexec/static/images/popup.svg,sha256=0Bl9A_v5cBsMPn6FnOlVWlAQKgd2zqiWQbhjcL9BDzI,559
|
14
|
+
pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUNZa7cpw,25696
|
15
|
+
pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
|
16
|
+
pywebexec/static/js/commands.js,sha256=8JDb3Q55EJOYf2Q9Uy6qEuqAnn1oGjM0RndgQ4aOjqo,7725
|
17
|
+
pywebexec/static/js/popup.js,sha256=i7BPBh6oS0Q6H528DwP6KwJ8CKh7ULwm1rLHSbyvDhk,4656
|
18
|
+
pywebexec/static/js/script.js,sha256=QlYuIdvolTwxkJtgp7-X1IRM9Hr8D08iQCyCzZjv3hk,12255
|
19
|
+
pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
|
20
|
+
pywebexec/static/js/xterm/ansi_up.min.js,sha256=KNGV0vEr30hNqKQimTAvGVy-icD5A1JqMQTtvYtKR2Y,13203
|
21
|
+
pywebexec/static/js/xterm/xterm-addon-fit.js,sha256=Pprm9pZe4SadVXS5Bc8b9VnC9Ex4QlWwA0pxOH53Gck,1460
|
22
|
+
pywebexec/static/js/xterm/xterm.js,sha256=Bzka76jZwEhVt_LlS0e0qMw7ryGa1p5qfxFyeohphBo,283371
|
23
|
+
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
+
pywebexec/templates/index.html,sha256=DYtT555wSNhnFtzzHhPMWJireynCJNnAuTytpoORQeE,2321
|
25
|
+
pywebexec/templates/popup.html,sha256=T6_tAOUoA58sA1oxB5pb8i42RenoMdCsH8T86Gccb6Q,945
|
26
|
+
pywebexec-1.4.12.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
27
|
+
pywebexec-1.4.12.dist-info/METADATA,sha256=cCiJmWvh3DHBVJa0uRdM6-oMEBFyU3g0nSNxrhz5Y1I,7724
|
28
|
+
pywebexec-1.4.12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
29
|
+
pywebexec-1.4.12.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
30
|
+
pywebexec-1.4.12.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
31
|
+
pywebexec-1.4.12.dist-info/RECORD,,
|
pywebexec-1.2.0.dist-info/RECORD
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
|
2
|
-
pywebexec/pywebexec.py,sha256=TTTF2mueOTDEv-FZHoIx5dMbIQyhsafOMQ-YzkDFIXk,22564
|
3
|
-
pywebexec/version.py,sha256=zMnMemknXglcJs59xkicNzeEJTVgYd1omSfLWj76yWw,411
|
4
|
-
pywebexec/static/css/style.css,sha256=rvnWRZQ__-J2EPSKdjPnVaA1oJ7auy0IdsNgxx07WAc,3403
|
5
|
-
pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
|
6
|
-
pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
|
7
|
-
pywebexec/static/images/copy_ok.svg,sha256=mEqUVUhSq8xaJK2msQkxRawnz_KwlCZ-tok8QS6hJ3g,451
|
8
|
-
pywebexec/static/images/failed.svg,sha256=ADZ7IKrUyOXtqpivnz3VcH0-Wru-I5MOi3OJAkI3hxk,1439
|
9
|
-
pywebexec/static/images/favicon.svg,sha256=ti80IfuDZwIvQcmJxkOeUaB1iMsiyOPmQmVO-h0y1IU,1126
|
10
|
-
pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUNZa7cpw,25696
|
11
|
-
pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
|
12
|
-
pywebexec/static/js/script.js,sha256=Vg_UZiiTDi79tke6-EpZGQOxPVxXMaAT6qRMpMHGGNU,9380
|
13
|
-
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
-
pywebexec/templates/index.html,sha256=BzTEL60RhPyKi-EAhr4HFgPfJnBSkdQJNFjdkjetZHs,1454
|
15
|
-
pywebexec-1.2.0.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
16
|
-
pywebexec-1.2.0.dist-info/METADATA,sha256=-V_Ta6Z11TvUc6EVbQ_U1fZ2OnhuJNeoklBU1ynF9R4,6906
|
17
|
-
pywebexec-1.2.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
18
|
-
pywebexec-1.2.0.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
19
|
-
pywebexec-1.2.0.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
20
|
-
pywebexec-1.2.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|