pywebexec 1.3.1__py3-none-any.whl → 1.3.3__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
@@ -17,6 +17,7 @@ from socket import gethostname, gethostbyname_ex, gethostbyaddr, inet_aton, inet
17
17
  import ssl
18
18
  import re
19
19
  import pwd
20
+ import platform
20
21
  from secrets import token_urlsafe
21
22
 
22
23
  if os.environ.get('PYWEBEXEC_LDAP_SERVER'):
@@ -327,7 +328,12 @@ def parseargs():
327
328
  user = pwd.getpwuid(os.getuid())[0]
328
329
  update_command_status(command_id, 'running', command="term", params=[user,os.ttyname(sys.stdout.fileno())], start_time=start_time, user=user)
329
330
  output_file_path = get_output_file_path(command_id)
330
- res = os.system(f"script -f {output_file_path}")
331
+ if platform.system() == 'Darwin':
332
+ script_opt = '-F'
333
+ else:
334
+ script_opt = '-f'
335
+ res = os.system(f"script {script_opt} {output_file_path}")
336
+
331
337
  end_time = datetime.now().isoformat()
332
338
  update_command_status(command_id, status="success", end_time=end_time, exit_code=res)
333
339
  sys.exit(res)
Binary file
@@ -1,3 +1,9 @@
1
+ @font-face {
2
+ font-family: 'Consolas NF';
3
+ src: url('/static/css/Consolas NF.ttf');
4
+ font-weight: 400;
5
+ font-style: normal;
6
+ }
1
7
  body {
2
8
  font-family: Arial, sans-serif;
3
9
  overflow: hidden;
@@ -256,4 +262,13 @@ body.dimmed * {
256
262
  span {
257
263
  letter-spacing: -0.03px !important;
258
264
  }
265
+ .slider-container {
266
+ display: flex;
267
+ align-items: center;
268
+ gap: 10px;
269
+ margin-top: 10px;
270
+ }
271
+ #outputSlider {
272
+ width: 100%;
273
+ }
259
274
 
@@ -1,39 +1,46 @@
1
1
  let currentCommandId = null;
2
2
  let outputInterval = null;
3
3
  let nextOutputLink = null;
4
+ let fullOutput = '';
5
+
6
+
7
+ function initTerminal()
8
+ {
9
+ return new Terminal({
10
+ cursorBlink: false,
11
+ cursorHidden: true,
12
+ disableStdin: true,
13
+ convertEol: true,
14
+ fontFamily: 'Consolas NF, monospace, courier-new, courier',
15
+ scrollback: 999999,
16
+ theme: {
17
+ background: '#111412',
18
+ black: '#111412',
19
+ green: '#088a5b',
20
+ blue: "#2760aa",
21
+ red: '#ba1611',
22
+ yellow: "#cf8700",
23
+ magenta: "#4c3d80",
24
+ cyan: "#00a7aa",
25
+ brightBlack: "#243C4F",
26
+ brightBlue: "#5584b1",
27
+ },
28
+ rescaleOverlappingGlyphs: true,
29
+ });
30
+ }
31
+ let terminal = initTerminal()
4
32
 
5
- const terminal = new Terminal({
6
- cursorBlink: false,
7
- cursorHidden: true,
8
- disableStdin: true,
9
- convertEol: true,
10
- fontFamily: 'Consolas NF, monospace, courier-new, courier',
11
- scrollback: 999999,
12
- theme: {
13
- background: '#111412',
14
- black: '#111412',
15
- green: '#088a5b',
16
- blue: "#2760aa",
17
- red: '#ba1611',
18
- yellow: "#cf8700",
19
- magenta: "#4c3d80",
20
- cyan: "#00a7aa",
21
- brightBlack: "#243C4F",
22
- brightBlue: "#5584b1",
23
- },
24
- rescaleOverlappingGlyphs: true,
25
- });
26
33
  const fitAddon = new FitAddon.FitAddon();
27
34
  terminal.loadAddon(fitAddon);
28
35
  terminal.open(document.getElementById('output'));
29
36
  fitAddon.fit();
37
+
30
38
  function getTokenParam() {
31
39
  const urlParams = new URLSearchParams(window.location.search);
32
40
  return urlParams.get('token') ? `?token=${urlParams.get('token')}` : '';
33
41
  }
34
42
  const urlToken = getTokenParam();
35
43
 
36
-
37
44
  terminal.onSelectionChange(() => {
38
45
  const selectionText = terminal.getSelection();
39
46
  if (selectionText) {
@@ -43,7 +50,6 @@ terminal.onSelectionChange(() => {
43
50
  }
44
51
  });
45
52
 
46
-
47
53
  document.getElementById('launchForm').addEventListener('submit', async (event) => {
48
54
  event.preventDefault();
49
55
  const commandName = document.getElementById('commandName').value;
@@ -122,7 +128,8 @@ async function fetchOutput(url) {
122
128
  terminal.write(data.error);
123
129
  clearInterval(outputInterval);
124
130
  } else {
125
- terminal.write(data.output);
131
+ fullOutput += data.output;
132
+ updateTerminalOutput();
126
133
  nextOutputLink = data.links.next;
127
134
  if (data.status != 'running') {
128
135
  clearInterval(outputInterval);
@@ -134,11 +141,14 @@ async function fetchOutput(url) {
134
141
  }
135
142
 
136
143
  async function viewOutput(command_id) {
144
+ document.getElementById('outputSlider').value = 100;
137
145
  adjustOutputHeight();
138
146
  currentCommandId = command_id;
139
147
  nextOutputLink = `/command_output/${command_id}${urlToken}`;
140
148
  clearInterval(outputInterval);
141
149
  terminal.clear();
150
+ terminal.reset();
151
+ fullOutput = '';
142
152
  try {
143
153
  const response = await fetch(`/command_status/${command_id}${urlToken}`);
144
154
  if (!response.ok) {
@@ -246,7 +256,7 @@ function adjustOutputHeight() {
246
256
  const outputDiv = document.getElementById('output');
247
257
  const windowHeight = window.innerHeight;
248
258
  const outputTop = outputDiv.getBoundingClientRect().top;
249
- const maxHeight = windowHeight - outputTop - 30; // 20px for padding/margin
259
+ const maxHeight = windowHeight - outputTop - 60; // Adjusted for slider height
250
260
  outputDiv.style.height = `${maxHeight}px`;
251
261
  fitAddon.fit();
252
262
  }
@@ -274,6 +284,19 @@ function initResizer() {
274
284
  }
275
285
  }
276
286
 
287
+ function updateTerminalOutput() {
288
+ const slider = document.getElementById('outputSlider');
289
+ const percentage = slider.value;
290
+ const outputLength = Math.floor((fullOutput.length * percentage) / 100);
291
+ const limitedOutput = fullOutput.slice(0, outputLength);
292
+ terminal.clear();
293
+ terminal.reset();
294
+ terminal.write(limitedOutput);
295
+ document.getElementById('outputPercentage').innerText = `${percentage}%`;
296
+ }
297
+
298
+ document.getElementById('outputSlider').addEventListener('input', updateTerminalOutput);
299
+
277
300
  window.addEventListener('resize', adjustOutputHeight);
278
301
  window.addEventListener('load', initResizer);
279
302
 
@@ -44,6 +44,10 @@
44
44
  <div class="resizer" id="resizer"></div>
45
45
  </div>
46
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>
47
51
  <script src="/static/js/xterm/ansi_up.min.js"></script>
48
52
  <script src="/static/js/xterm/xterm.js"></script>
49
53
  <script src="/static/js/xterm/xterm-addon-fit.js"></script>
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.3.1'
16
- __version_tuple__ = version_tuple = (1, 3, 1)
15
+ __version__ = version = '1.3.3'
16
+ __version_tuple__ = version_tuple = (1, 3, 3)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1,7 +1,8 @@
1
1
  pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
2
- pywebexec/pywebexec.py,sha256=ljvGw-inDwsP6KQqYwwfKUeN_q9k7JwyP7PfRacnqFQ,25475
3
- pywebexec/version.py,sha256=cOVPCvD2h2G_2KB6G3ddreYkIQfAnS6WqgAkF_qgGOQ,411
4
- pywebexec/static/css/style.css,sha256=nuJodEFojt_kCLPqbDBQAaBtWcRZ6uLjfI52mSf3EJA,5302
2
+ pywebexec/pywebexec.py,sha256=b-lypYr27O-t-YTUJs0pIWiDPsBE0eSQwSBqfNdkYR4,25618
3
+ pywebexec/version.py,sha256=VriGPi1kVXIBM0YGAuhpE803XR-FNq1JvTW1Kz2us08,411
4
+ pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
5
+ pywebexec/static/css/style.css,sha256=iLX6k1hoWLinZWyqtbH50U-0hND2M-5_Zr1U1UC_gos,5578
5
6
  pywebexec/static/css/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
6
7
  pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
7
8
  pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
@@ -12,16 +13,16 @@ pywebexec/static/images/favicon.svg,sha256=ti80IfuDZwIvQcmJxkOeUaB1iMsiyOPmQmVO-
12
13
  pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUNZa7cpw,25696
13
14
  pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
14
15
  pywebexec/static/js/commands.js,sha256=VdMeCop9V5KwsR2v1J_OY1xFE7tJUYgcMg_lh2VGNjs,7476
15
- pywebexec/static/js/script.js,sha256=WL8wvYjbAQpm_uMrGmuqx6rmHz9V_yMiGZPb1mU8xOU,10103
16
+ pywebexec/static/js/script.js,sha256=NCjnVd-i8zUE3qvu7UqUHBt_IcbnnUUKVGlp7XbFzic,10913
16
17
  pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
17
18
  pywebexec/static/js/xterm/ansi_up.min.js,sha256=KNGV0vEr30hNqKQimTAvGVy-icD5A1JqMQTtvYtKR2Y,13203
18
19
  pywebexec/static/js/xterm/xterm-addon-fit.js,sha256=Pprm9pZe4SadVXS5Bc8b9VnC9Ex4QlWwA0pxOH53Gck,1460
19
20
  pywebexec/static/js/xterm/xterm.js,sha256=Bzka76jZwEhVt_LlS0e0qMw7ryGa1p5qfxFyeohphBo,283371
20
21
  pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- pywebexec/templates/index.html,sha256=LaRXHXsOR2eWkBcLIlPxGKHSLTa8JfDkDCJZWadn_1Q,2116
22
- pywebexec-1.3.1.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
23
- pywebexec-1.3.1.dist-info/METADATA,sha256=lO1a0YsGGQR_yxguJZ5M-lSSETyT4MD8g7nLy_e0cQU,7397
24
- pywebexec-1.3.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
25
- pywebexec-1.3.1.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
26
- pywebexec-1.3.1.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
27
- pywebexec-1.3.1.dist-info/RECORD,,
22
+ pywebexec/templates/index.html,sha256=DYtT555wSNhnFtzzHhPMWJireynCJNnAuTytpoORQeE,2321
23
+ pywebexec-1.3.3.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
24
+ pywebexec-1.3.3.dist-info/METADATA,sha256=A69MhlrTDRfLv8tzyDJSdVFccYSaHNFsE5JHq_Qz8rM,7397
25
+ pywebexec-1.3.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
26
+ pywebexec-1.3.3.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
27
+ pywebexec-1.3.3.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
28
+ pywebexec-1.3.3.dist-info/RECORD,,