pywebexec 1.1.0__py3-none-any.whl → 1.1.2__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 CHANGED
@@ -34,7 +34,6 @@ app.config['LDAP_GROUPS'] = os.environ.get('PYWEBEXEC_LDAP_GROUPS')
34
34
  app.config['LDAP_BASE_DN'] = os.environ.get('PYWEBEXEC_LDAP_BASE_DN')
35
35
  app.config['LDAP_BIND_DN'] = os.environ.get('PYWEBEXEC_LDAP_BIND_DN')
36
36
  app.config['LDAP_BIND_PASSWORD'] = os.environ.get('PYWEBEXEC_LDAP_BIND_PASSWORD')
37
- app.config['LDAP_USE_SSL'] = int(os.environ.get('PYWEBEXEC_LDAP_USE_SSL', False))
38
37
 
39
38
  # Directory to store the command status and output
40
39
  COMMAND_STATUS_DIR = '.web_status'
@@ -401,14 +400,14 @@ def verify_password(username, password):
401
400
  return False
402
401
 
403
402
  def verify_ldap(username, password):
404
- tls_configuration = Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1_2) if app.config['LDAP_USE_SSL'] else None
405
- server = Server(app.config['LDAP_SERVER'], use_ssl=app.config['LDAP_USE_SSL'], tls=tls_configuration, get_info=ALL)
403
+ tls_configuration = Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1_2) if app.config['LDAP_SERVER'].startswith("ldaps:") else None
404
+ server = Server(app.config['LDAP_SERVER'], tls=tls_configuration, get_info=ALL)
406
405
  user_filter = f"({app.config['LDAP_USER_ID']}={username})"
407
406
  try:
408
407
  # Bind with the bind DN and password
409
- conn = Connection(server, user=app.config['LDAP_BIND_DN'], password=app.config['LDAP_BIND_PASSWORD'], authentication=SIMPLE, auto_bind=True)
408
+ conn = Connection(server, user=app.config['LDAP_BIND_DN'], password=app.config['LDAP_BIND_PASSWORD'], authentication=SIMPLE, auto_bind=True, read_only=True)
410
409
  try:
411
- conn.search(search_base=app.config['LDAP_BASE_DN'], search_filter=user_filter)
410
+ conn.search(search_base=app.config['LDAP_BASE_DN'], search_filter=user_filter, search_scope=SUBTREE)
412
411
  if len(conn.entries) == 0:
413
412
  print(f"User {username} not found in LDAP.")
414
413
  return False
@@ -417,13 +416,13 @@ def verify_ldap(username, password):
417
416
  conn.unbind()
418
417
 
419
418
  # Bind with the user DN and password to verify credentials
420
- conn = Connection(server, user=user_dn, password=password, authentication=SIMPLE, auto_bind=True)
419
+ conn = Connection(server, user=user_dn, password=password, authentication=SIMPLE, auto_bind=True, read_only=True)
421
420
  try:
422
421
  if not app.config['LDAP_GROUPS'] and conn.result["result"] == 0:
423
422
  return True
424
- group_filter = "".join([f'(ou={group})' for group in app.config['LDAP_GROUPS'].split(",")])
423
+ group_filter = "".join([f'({group})' for group in app.config['LDAP_GROUPS'].split(",")])
425
424
  group_filter = f"(&{group_filter}(|(member={user_dn})(uniqueMember={user_dn})))"
426
- conn.search(search_base=app.config['LDAP_BASE_DN'], search_filter=group_filter)
425
+ conn.search(search_base=app.config['LDAP_BASE_DN'], search_filter=group_filter, search_scope=SUBTREE)
427
426
  result = len(conn.entries) > 0
428
427
  if not result:
429
428
  print(f"User {username} is not a member of groups {app.config['LDAP_GROUPS']}.")
@@ -40,11 +40,11 @@ async function fetchCommands() {
40
40
  <td>${command.status === 'running' ? formatDuration(command.start_time, new Date().toISOString()) : formatDuration(command.start_time, command.end_time)}</td>
41
41
  <td>${command.exit_code}</td>
42
42
  <td>${command.command.replace(/^\.\//, '')}</td>
43
- <td class="monospace outcol">${command.last_output_line || ''}</td>
44
43
  <td>
45
- <button onclick="relaunchCommand('${command.command_id}')">Relaunch</button>
46
- ${command.status === 'running' ? `<button onclick="stopCommand('${command.command_id}')">Stop</button>` : ''}
44
+ ${command.status === 'running' ? `<button onclick="stopCommand('${command.command_id}')">Stop</button>` : ` <button onclick="relaunchCommand('${command.command_id}')">Run</button>
45
+ `}
47
46
  </td>
47
+ <td class="monospace outcol">${command.last_output_line || ''}</td>
48
48
  `;
49
49
  commandsTbody.appendChild(commandRow);
50
50
  });
@@ -13,7 +13,7 @@
13
13
  <select id="commandName" name="commandName"></select>
14
14
  <label for="params">Params</label>
15
15
  <input type="text" id="params" name="params">
16
- <button type="submit">Launch</button>
16
+ <button type="submit">Run</button>
17
17
  </form>
18
18
  <div class="table-container" id="tableContainer">
19
19
  <table>
@@ -25,8 +25,8 @@
25
25
  <th>Duration</th>
26
26
  <th>Exit</th>
27
27
  <th>Command</th>
28
+ <th>Action</th>
28
29
  <th>Output</th>
29
- <th>Actions</th>
30
30
  </tr>
31
31
  </thead>
32
32
  <tbody id="commands"></tbody>
pywebexec/version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.1.0'
16
- __version_tuple__ = version_tuple = (1, 1, 0)
15
+ __version__ = version = '1.1.2'
16
+ __version_tuple__ = version_tuple = (1, 1, 2)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.1.0
3
+ Version: 1.1.2
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -83,7 +83,9 @@ $ pywebexec
83
83
  ```
84
84
 
85
85
  * Launch commands with params/view live output/Status using browser
86
- ![pywebexec](https://github.com/user-attachments/assets/1bfec34f-8e3b-4ad0-b6c4-c03c957c070a)
86
+ ![pywebexec](https://github.com/user-attachments/assets/d352cc23-1552-4b79-a6ff-f02f05cf328e)
87
+
88
+ all commands output / statuses are available in the executables directory in subdirectory `.web_status`
87
89
 
88
90
  ## features
89
91
 
@@ -102,8 +104,8 @@ $ pywebexec
102
104
 
103
105
  ## Customize server
104
106
  ```shell
105
- $ pywebexec --dir ~/myscripts --listen 0.0.0.0 --port 8080
106
- $ pywebexec -d ~/myscripts -l 0.0.0.0 -p 8080
107
+ $ pywebexec --dir ~/myscripts --listen 0.0.0.0 --port 8080 --title myscripts
108
+ $ pywebexec -d ~/myscripts -l 0.0.0.0 -p 8080 -t myscripts
107
109
  ```
108
110
 
109
111
  ## Basic auth
@@ -117,11 +119,10 @@ Generated password is given if no `--pasword` option
117
119
 
118
120
  * ldap(s) password check / group member
119
121
  ```shell
120
- $ export PYWEBEXEC_LDAP_SERVER=ldap.forumsys.com
121
- $ export PYWEBEXEC_LDAP_USE_SSL=0
122
+ $ export PYWEBEXEC_LDAP_SERVER=ldap://ldap.forumsys.com:389
122
123
  $ export PYWEBEXEC_LDAP_BIND_DN="cn=read-only-admin,dc=example,dc=com"
123
124
  $ export PYWEBEXEC_LDAP_BIND_PASSWORD="password"
124
- $ export PYWEBEXEC_LDAP_GROUPS=mathematicians,scientists
125
+ $ export PYWEBEXEC_LDAP_GROUPS=ou=mathematicians,ou=scientists
125
126
  $ export PYWEBEXEC_LDAP_USER_ID="uid"
126
127
  $ export PYWEBEXEC_LDAP_BASE_DN="dc=example,dc=com"
127
128
  $ pywebexec
@@ -162,7 +163,7 @@ $ curl http://myhost:8080/run_script -H 'Content-Type: application/json' -X POST
162
163
  |-----------|-----------------------------|--------------------|---------------------|
163
164
  | POST | /run_command | command: str<br>params: array[str] | command_id: uuid<br>message: str |
164
165
  | POST | /stop_command/command_id | | message: str |
165
- | 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 |
166
+ | 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 |
166
167
  | GET | /command_output/command_id | | output: str<br>status: str |
167
- | 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 |
168
+ | 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 |
168
169
  | GET | /executables | | array of str |
@@ -1,6 +1,6 @@
1
1
  pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
2
- pywebexec/pywebexec.py,sha256=KyKJcadzuXWh1Im0bkbu0ScEBMwsWTPQg5xPN2jDMdQ,21174
3
- pywebexec/version.py,sha256=CqDGE4B1ZqZ-56mxeOFcXRTmlxrdOh4ayrjbcPjziE4,411
2
+ pywebexec/pywebexec.py,sha256=mRvTAK8O9VtGPqUdQxIeYBzpjLYkYVru1rzWmS3Ui5Q,21149
3
+ pywebexec/version.py,sha256=nmVMEP2kpLDIzjgS-U1taCdJbVrmv_k8ao6RojGcvRg,411
4
4
  pywebexec/static/css/style.css,sha256=NiBoOzZ35eBM1ZP2HFNda-dzOsAv4xRPh3vsvVgLL9c,2513
5
5
  pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
6
6
  pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
@@ -9,12 +9,12 @@ pywebexec/static/images/failed.svg,sha256=ADZ7IKrUyOXtqpivnz3VcH0-Wru-I5MOi3OJAk
9
9
  pywebexec/static/images/favicon.svg,sha256=ti80IfuDZwIvQcmJxkOeUaB1iMsiyOPmQmVO-h0y1IU,1126
10
10
  pywebexec/static/images/running.svg,sha256=vBpiG6ClNUNCArkwsyqK7O-qhIKJX1NI7MSjclNSp_8,1537
11
11
  pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
12
- pywebexec/static/js/script.js,sha256=d16MohpBSvw5evamC4o3_MWayQ1B8Cj9TePNclroUvo,7093
12
+ pywebexec/static/js/script.js,sha256=RrlozMlUx_7MJTf7IG98rzJsLgwEMyEV9bSW6QpQdZw,7088
13
13
  pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- pywebexec/templates/index.html,sha256=70yLF1zTrNG4cVFsi9gvy9WYurLXvvMdeR5EFIDafBA,1306
15
- pywebexec-1.1.0.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
16
- pywebexec-1.1.0.dist-info/METADATA,sha256=yeelN08_hUHw_GyZIb9oGFmfqr8KhSNJS1zEEnDOWGk,6567
17
- pywebexec-1.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
- pywebexec-1.1.0.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
19
- pywebexec-1.1.0.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
20
- pywebexec-1.1.0.dist-info/RECORD,,
14
+ pywebexec/templates/index.html,sha256=Q3tubZjBzq4v1aV_BDFSvAKnoim-wKo3EkE_pkA2jm4,1302
15
+ pywebexec-1.1.2.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
16
+ pywebexec-1.1.2.dist-info/METADATA,sha256=7f5boEeNnoqAijinCKAqx-gPL_tGLOxdLe1Jdp9xYVI,6736
17
+ pywebexec-1.1.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
+ pywebexec-1.1.2.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
19
+ pywebexec-1.1.2.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
20
+ pywebexec-1.1.2.dist-info/RECORD,,