pywebexec 1.7.3__py3-none-any.whl → 1.7.4__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 +15 -13
- pywebexec/static/js/popup.js +2 -1
- pywebexec/static/js/script.js +1 -1
- pywebexec/version.py +2 -2
- {pywebexec-1.7.3.dist-info → pywebexec-1.7.4.dist-info}/METADATA +3 -2
- {pywebexec-1.7.3.dist-info → pywebexec-1.7.4.dist-info}/RECORD +10 -10
- {pywebexec-1.7.3.dist-info → pywebexec-1.7.4.dist-info}/LICENSE +0 -0
- {pywebexec-1.7.3.dist-info → pywebexec-1.7.4.dist-info}/WHEEL +0 -0
- {pywebexec-1.7.3.dist-info → pywebexec-1.7.4.dist-info}/entry_points.txt +0 -0
- {pywebexec-1.7.3.dist-info → pywebexec-1.7.4.dist-info}/top_level.txt +0 -0
pywebexec/pywebexec.py
CHANGED
@@ -33,6 +33,8 @@ if os.environ.get('PYWEBEXEC_LDAP_SERVER'):
|
|
33
33
|
app = Flask(__name__)
|
34
34
|
app.secret_key = os.urandom(24) # Secret key for session management
|
35
35
|
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' # Add SameSite attribute to session cookies
|
36
|
+
app.config['SESSION_COOKIE_SECURE'] = True
|
37
|
+
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
36
38
|
auth = HTTPBasicAuth()
|
37
39
|
|
38
40
|
app.config['LDAP_SERVER'] = os.environ.get('PYWEBEXEC_LDAP_SERVER')
|
@@ -112,7 +114,7 @@ def generate_selfsigned_cert(hostname, ip_addresses=None, key=None):
|
|
112
114
|
from cryptography.hazmat.backends import default_backend
|
113
115
|
from cryptography.hazmat.primitives import serialization
|
114
116
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
115
|
-
|
117
|
+
|
116
118
|
# Generate our key
|
117
119
|
if key is None:
|
118
120
|
key = rsa.generate_private_key(
|
@@ -120,16 +122,16 @@ def generate_selfsigned_cert(hostname, ip_addresses=None, key=None):
|
|
120
122
|
key_size=2048,
|
121
123
|
backend=default_backend(),
|
122
124
|
)
|
123
|
-
|
125
|
+
|
124
126
|
name = x509.Name([
|
125
127
|
x509.NameAttribute(NameOID.COMMON_NAME, hostname)
|
126
128
|
])
|
127
|
-
|
128
|
-
# best practice seem to be to include the hostname in the SAN, which *SHOULD* mean COMMON_NAME is ignored.
|
129
|
+
|
130
|
+
# best practice seem to be to include the hostname in the SAN, which *SHOULD* mean COMMON_NAME is ignored.
|
129
131
|
alt_names = [x509.DNSName(hostname)]
|
130
132
|
alt_names.append(x509.DNSName("localhost"))
|
131
|
-
|
132
|
-
# allow addressing by IP, for when you don't have real DNS (common in most testing scenarios
|
133
|
+
|
134
|
+
# allow addressing by IP, for when you don't have real DNS (common in most testing scenarios
|
133
135
|
if ip_addresses:
|
134
136
|
for addr in ip_addresses:
|
135
137
|
# openssl wants DNSnames for ips...
|
@@ -138,7 +140,7 @@ def generate_selfsigned_cert(hostname, ip_addresses=None, key=None):
|
|
138
140
|
# note: older versions of cryptography do not understand ip_address objects
|
139
141
|
alt_names.append(x509.IPAddress(ipaddress.ip_address(addr)))
|
140
142
|
san = x509.SubjectAlternativeName(alt_names)
|
141
|
-
|
143
|
+
|
142
144
|
# path_len=0 means this cert can only sign itself, not other certs.
|
143
145
|
basic_contraints = x509.BasicConstraints(ca=True, path_length=0)
|
144
146
|
now = datetime.now(timezone.utc)
|
@@ -225,7 +227,7 @@ def get_last_line(file_path, cols=None, rows=None, maxsize=2048):
|
|
225
227
|
except OSError:
|
226
228
|
fd.seek(0)
|
227
229
|
return get_visible_output(fd.read(), cols, rows)
|
228
|
-
|
230
|
+
|
229
231
|
|
230
232
|
def start_gunicorn(daemonized=False, baselog=None):
|
231
233
|
check_processes()
|
@@ -304,7 +306,7 @@ def daemon_d(action, pidfilepath, silent=False, hostname=None, args=None):
|
|
304
306
|
def start_term():
|
305
307
|
os.environ["PYWEBEXEC"] = " (shared)"
|
306
308
|
os.chdir(CWD)
|
307
|
-
start_time = datetime.now().isoformat()
|
309
|
+
start_time = datetime.now(timezone.utc).isoformat()
|
308
310
|
user = pwd.getpwuid(os.getuid())[0]
|
309
311
|
print(f"Starting terminal session for {user} : {term_command_id}")
|
310
312
|
update_command_status(term_command_id, {
|
@@ -316,7 +318,7 @@ def start_term():
|
|
316
318
|
})
|
317
319
|
output_file_path = get_output_file_path(term_command_id)
|
318
320
|
res = script(output_file_path)
|
319
|
-
end_time = datetime.now().isoformat()
|
321
|
+
end_time = datetime.now(timezone.utc).isoformat()
|
320
322
|
update_command_status(term_command_id, {
|
321
323
|
'status': 'success',
|
322
324
|
'end_time': end_time,
|
@@ -488,7 +490,7 @@ def script(output_file):
|
|
488
490
|
sigwinch_passthrough(None, None)
|
489
491
|
signal.signal(signal.SIGWINCH, sigwinch_passthrough)
|
490
492
|
p.interact()
|
491
|
-
|
493
|
+
|
492
494
|
|
493
495
|
def run_command(fromip, user, command, params, command_id):
|
494
496
|
# app.logger.info(f'{fromip} run_command {command_id} {user}: {command} {params}')
|
@@ -663,7 +665,7 @@ def check_authentication():
|
|
663
665
|
if request.args.get('token') == token:
|
664
666
|
return
|
665
667
|
return jsonify({'error': 'Forbidden'}), 403
|
666
|
-
|
668
|
+
|
667
669
|
if not app.config['USER'] and not app.config['LDAP_SERVER']:
|
668
670
|
return
|
669
671
|
|
@@ -704,7 +706,7 @@ def verify_ldap(username, password):
|
|
704
706
|
user_dn = conn.entries[0].entry_dn
|
705
707
|
finally:
|
706
708
|
conn.unbind()
|
707
|
-
|
709
|
+
|
708
710
|
# Bind with the user DN and password to verify credentials
|
709
711
|
conn = Connection(server, user=user_dn, password=password, authentication=SIMPLE, auto_bind=True, read_only=True)
|
710
712
|
try:
|
pywebexec/static/js/popup.js
CHANGED
@@ -117,7 +117,7 @@ async function fetchOutput(url) {
|
|
117
117
|
try {
|
118
118
|
const response = await fetch(url);
|
119
119
|
if (!response.ok) {
|
120
|
-
document.getElementById('dimmer').style.display = '
|
120
|
+
document.getElementById('dimmer').style.display = 'block';
|
121
121
|
return;
|
122
122
|
}
|
123
123
|
const data = await response.json();
|
@@ -151,6 +151,7 @@ async function fetchOutput(url) {
|
|
151
151
|
toggleButton.style.display = 'block';
|
152
152
|
setCommandStatus(data.status)
|
153
153
|
}
|
154
|
+
document.getElementById('dimmer').style.display = 'none';
|
154
155
|
}
|
155
156
|
} catch (error) {
|
156
157
|
document.getElementById('dimmer').style.display = 'block';
|
pywebexec/static/js/script.js
CHANGED
@@ -361,7 +361,7 @@ async function stopCommand(command_id, event) {
|
|
361
361
|
function formatTime(time) {
|
362
362
|
if (!time || time === 'N/A') return 'N/A';
|
363
363
|
const date = new Date(time);
|
364
|
-
return date.
|
364
|
+
return date.toLocaleString().slice(0, 16).replace('T', ' ');
|
365
365
|
}
|
366
366
|
|
367
367
|
function formatDuration(startTime, endTime) {
|
pywebexec/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pywebexec
|
3
|
-
Version: 1.7.
|
3
|
+
Version: 1.7.4
|
4
4
|
Summary: Simple Python HTTP Exec Server
|
5
5
|
Home-page: https://github.com/joknarf/pywebexec
|
6
6
|
Author: Franck Jouvanceau
|
@@ -153,8 +153,9 @@ $ pywebexec -u myuser [-P mypass]
|
|
153
153
|
Generated password is given if no `--pasword` option
|
154
154
|
|
155
155
|
* ldap(s) password check / group member
|
156
|
+
ldap server must accept memberOf attribute for group members
|
156
157
|
```shell
|
157
|
-
$ export PYWEBEXEC_LDAP_SERVER=
|
158
|
+
$ export PYWEBEXEC_LDAP_SERVER=ldaps://ldap.mydomain.com:389
|
158
159
|
$ export PYWEBEXEC_LDAP_BIND_DN="cn=read-only-admin,dc=example,dc=com"
|
159
160
|
$ export PYWEBEXEC_LDAP_BIND_PASSWORD="password"
|
160
161
|
$ export PYWEBEXEC_LDAP_BASE_DN="dc=example,dc=com"
|
@@ -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=VBR6KmRiHNCd0ZvGEu_5sTqzVrUEPBhM8Hi6knS1QcA,33526
|
3
|
+
pywebexec/version.py,sha256=RXCVfb--6hzsLq9eHm4YOs9d-j0v74-HRGs2DFWnpjQ,411
|
4
4
|
pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
|
5
5
|
pywebexec/static/css/style.css,sha256=3s7QgbCh4wb7kfZ7Pjo-B6o3lDIBogZ-3j6AfaPdpzU,8209
|
6
6
|
pywebexec/static/css/xterm.css,sha256=uo5phWaUiJgcz0DAzv46uoByLLbJLeetYosL1xf68rY,5559
|
@@ -21,8 +21,8 @@ pywebexec/static/images/resume.svg,sha256=99LP1Ya2JXakRCO9kW8JMuT_4a_CannF65Eiuw
|
|
21
21
|
pywebexec/static/images/running.svg,sha256=fBCYwYb2O9K4N3waC2nURP25NRwZlqR4PbDZy6JQMww,610
|
22
22
|
pywebexec/static/images/success.svg,sha256=NVwezvVMplt46ElW798vqGfrL21Mw_DWHUp_qiD_FU8,489
|
23
23
|
pywebexec/static/js/commands.js,sha256=h2fkd9qpypLBxvhEEbay23nwuqUwcKJA0vHugcyL8pU,7961
|
24
|
-
pywebexec/static/js/popup.js,sha256=
|
25
|
-
pywebexec/static/js/script.js,sha256=
|
24
|
+
pywebexec/static/js/popup.js,sha256=oVkwnOKHae11omBiTZs-00NVeS9HGNEiUo71JSwOqn4,9382
|
25
|
+
pywebexec/static/js/script.js,sha256=hT50gLRs-GRQoxDNJN__X3UQxk003M1ZPlvmzj8BZtc,18201
|
26
26
|
pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
|
27
27
|
pywebexec/static/js/xterm/addon-canvas.js,sha256=ez6QTVvsmLVNJmdJlM-ZQ5bErwlxAQ_9DUmDIptl2TM,94607
|
28
28
|
pywebexec/static/js/xterm/addon-canvas.js.map,sha256=ECBA4B-BqUpdFeRzlsEWLSQnudnhLP-yPQJ8_hKquMo,379537
|
@@ -35,9 +35,9 @@ pywebexec/static/js/xterm/xterm.js.map,sha256=Y7O2Pb-fIS7Z8AC1D5s04_aiW_Jf1f4mCf
|
|
35
35
|
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
36
|
pywebexec/templates/index.html,sha256=2fEN8cggHBEd8-RamDFpnekVJtIbRembFSw0-1YEptc,2979
|
37
37
|
pywebexec/templates/popup.html,sha256=GT2jY7oOxpCaBaRl924QJWdFBmfSOP952T13d37R_pY,1506
|
38
|
-
pywebexec-1.7.
|
39
|
-
pywebexec-1.7.
|
40
|
-
pywebexec-1.7.
|
41
|
-
pywebexec-1.7.
|
42
|
-
pywebexec-1.7.
|
43
|
-
pywebexec-1.7.
|
38
|
+
pywebexec-1.7.4.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
39
|
+
pywebexec-1.7.4.dist-info/METADATA,sha256=Cui8J6P2uQXqzD43UuHSypY2oQCrp3palZ34daD_Gfg,8122
|
40
|
+
pywebexec-1.7.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
41
|
+
pywebexec-1.7.4.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
42
|
+
pywebexec-1.7.4.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
43
|
+
pywebexec-1.7.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|