• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 13600950642

01 Mar 2025 04:10AM UTC coverage: 74.211% (+3.2%) from 71.055%
13600950642

Pull #2546

github

web-flow
Merge 77df40314 into 60cff2437
Pull Request #2546: ssh: Allow passing `disabled_algorithms` keyword argument from `ssh` to paramiko

3812 of 6380 branches covered (59.75%)

0 of 1 new or added line in 1 file covered. (0.0%)

1243 existing lines in 37 files now uncovered.

13352 of 17992 relevant lines covered (74.21%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.15
/pwnlib/ui.py
1
from __future__ import absolute_import
1✔
2
from __future__ import division
1✔
3

4
import os
1✔
5
import signal
1✔
6
import string
1✔
7
import struct
1✔
8
import subprocess
1✔
9
import sys
1✔
10
import time
1✔
11

12
from pwnlib import term
1✔
13
from pwnlib.log import getLogger
1✔
14
from pwnlib.term.readline import raw_input
1✔
15
from pwnlib.tubes.process import process
1✔
16

17
log = getLogger(__name__)
1✔
18

19
def testpwnproc(cmd):
1✔
20
    import fcntl
1✔
21
    import termios
1✔
22
    env = dict(os.environ)
1✔
23
    env.pop("PWNLIB_NOTERM", None)
1✔
24
    env["TERM"] = "xterm-256color"
1✔
25
    def handleusr1(sig, frame):
1✔
UNCOV
26
        s = p.stderr.read()
×
27
        log.error("child process failed:\n%s", s.decode())
×
28
    signal.signal(signal.SIGUSR1, handleusr1)
1✔
29
    cmd = """\
1✔
30
import os
31
import signal
32
import sys
33
_ehook = sys.excepthook
34
def ehook(*args):
35
    _ehook(*args)
36
    os.kill(os.getppid(), signal.SIGUSR1)
37
sys.excepthook = ehook
38
from pwn import *
39
""" + cmd
40
    if "coverage" in sys.modules:
1!
41
        cmd = "import coverage; coverage.process_startup()\n" + cmd
1✔
42
        env.setdefault("COVERAGE_PROCESS_START", ".coveragerc")
1✔
43
    env['COLUMNS'] = '80'
1✔
44
    env['ROWS'] = '24'
1✔
45
    p = process([sys.executable, "-c", cmd], env=env, stderr=subprocess.PIPE)
1✔
46
    # late initialization can lead to EINTR in many places
47
    fcntl.ioctl(p.stdout.fileno(), termios.TIOCSWINSZ, struct.pack('HH', 24, 80))
1✔
48
    return p
1✔
49

50
def yesno(prompt, default=None):
1✔
51
    r"""Presents the user with prompt (typically in the form of question)
52
    which the user must answer yes or no.
53

54
    Arguments:
55
      prompt (str): The prompt to show
56
      default: The default option;  `True` means "yes"
57

58
    Returns:
59
      `True` if the answer was "yes", `False` if "no"
60

61
    Examples:
62

63
        >>> yesno("A number:", 20)
64
        Traceback (most recent call last):
65
        ...
66
        ValueError: yesno(): default must be a boolean or None
67
        >>> saved_stdin = sys.stdin
68
        >>> try:
69
        ...     sys.stdin = io.TextIOWrapper(io.BytesIO(b"x\nyes\nno\n\n"))
70
        ...     yesno("is it good 1")
71
        ...     yesno("is it good 2", True)
72
        ...     yesno("is it good 3", False)
73
        ... finally:
74
        ...     sys.stdin = saved_stdin
75
         [?] is it good 1 [yes/no] Please answer yes or no
76
         [?] is it good 1 [yes/no] True
77
         [?] is it good 2 [Yes/no] False
78
         [?] is it good 3 [yes/No] False
79

80
    Tests:
81

82
        >>> p = testpwnproc("print(yesno('is it ok??'))")
83
        >>> b"is it ok" in p.recvuntil(b"??")
84
        True
85
        >>> p.sendline(b"x\nny")
86
        >>> b"True" in p.recvall()
87
        True
88
    """
89

90
    if default is not None and not isinstance(default, bool):
1✔
91
        raise ValueError('yesno(): default must be a boolean or None')
1✔
92

93
    if term.term_mode:
1✔
94
        term.output(' [?] %s [' % prompt)
1✔
95
        yesfocus, yes = term.text.bold('Yes'), 'yes'
1✔
96
        nofocus, no = term.text.bold('No'), 'no'
1✔
97
        hy = term.output(yesfocus if default is True else yes)
1✔
98
        hs = term.output('/')
1✔
99
        hn = term.output(nofocus if default is False else no)
1✔
100
        he = term.output(']\n')
1✔
101
        cur = default
1✔
102
        while True:
1✔
103
            k = term.key.get()
1✔
104
            if   k in ('y', 'Y', '<left>') and cur is not True:
1✔
105
                cur = True
1✔
106
                hy.update(yesfocus)
1✔
107
                hn.update(no)
1✔
108
            elif k in ('n', 'N', '<right>') and cur is not False:
1✔
109
                cur = False
1✔
110
                hy.update(yes)
1✔
111
                hn.update(nofocus)
1✔
112
            elif k == '<enter>':
1✔
113
                if cur is not None:
1✔
114
                    return cur
1✔
115
    else:
116
        prompt = ' [?] %s [%s/%s] ' % (prompt,
1✔
117
                                       'Yes' if default is True else 'yes',
118
                                       'No' if default is False else 'no',
119
                                       )
120
        while True:
1✔
121
            opt = raw_input(prompt).strip().lower()
1✔
122
            if not opt and default is not None:
1✔
123
                return default
1✔
124
            elif opt in (b'y', b'yes'):
1✔
125
                return True
1✔
126
            elif opt in (b'n', b'no'):
1✔
127
                return False
1✔
128
            print('Please answer yes or no')
1✔
129

130
def options(prompt, opts, default = None):
1✔
131
    r"""Presents the user with a prompt (typically in the
132
    form of a question) and a number of options.
133

134
    Arguments:
135
      prompt (str): The prompt to show
136
      opts (list): The options to show to the user
137
      default: The default option to choose
138

139
    Returns:
140
      The users choice in the form of an integer.
141

142
    Examples:
143

144
        >>> options("Select a color", ("red", "green", "blue"), "green")
145
        Traceback (most recent call last):
146
        ...
147
        ValueError: options(): default must be a number or None
148

149
    Tests:
150

151
        >>> p = testpwnproc("print(options('select a color', ('red', 'green', 'blue')))")
152
        >>> p.sendline(b"\33[C\33[A\33[A\33[B\33[1;5A\33[1;5B 0310")
153
        >>> _ = p.recvall()
154
        >>> saved_stdin = sys.stdin
155
        >>> try:
156
        ...     sys.stdin = io.TextIOWrapper(io.BytesIO(b"\n4\n\n3\n"))
157
        ...     with context.local(log_level="INFO"):
158
        ...         options("select a color A", ("red", "green", "blue"), 0)
159
        ...         options("select a color B", ("red", "green", "blue"))
160
        ... finally:
161
        ...     sys.stdin = saved_stdin
162
         [?] select a color A
163
               1) red
164
               2) green
165
               3) blue
166
             Choice [1] 0
167
         [?] select a color B
168
               1) red
169
               2) green
170
               3) blue
171
             Choice  [?] select a color B
172
               1) red
173
               2) green
174
               3) blue
175
             Choice  [?] select a color B
176
               1) red
177
               2) green
178
               3) blue
179
             Choice 2
180
    """
181

182
    if default is not None and not isinstance(default, int):
1✔
183
        raise ValueError('options(): default must be a number or None')
1✔
184

185
    if term.term_mode:
1✔
186
        numfmt = '%' + str(len(str(len(opts)))) + 'd) '
1✔
187
        print(' [?] ' + prompt)
1✔
188
        hs = []
1✔
189
        space = '       '
1✔
190
        arrow = term.text.bold_green('    => ')
1✔
191
        cur = default
1✔
192
        for i, opt in enumerate(opts):
1✔
193
            h = term.output(arrow if i == cur else space, frozen = False)
1✔
194
            num = numfmt % (i + 1)
1✔
195
            h1 = term.output(num)
1✔
196
            h2 = term.output(opt + '\n', indent = len(num) + len(space))
1✔
197
            hs.append((h, h1, h2))
1✔
198
        ds = ''
1✔
199
        while True:
1✔
200
            prev = cur
1✔
201
            was_digit = False
1✔
202
            k = term.key.get()
1✔
203
            if   k == '<up>':
1✔
204
                if cur is None:
1✔
205
                    cur = 0
1✔
206
                else:
207
                    cur = max(0, cur - 1)
1✔
208
            elif k == '<down>':
1✔
209
                if cur is None:
1!
UNCOV
210
                    cur = 0
×
211
                else:
212
                    cur = min(len(opts) - 1, cur + 1)
1✔
213
            elif k == 'C-<up>':
1✔
214
                cur = 0
1✔
215
            elif k == 'C-<down>':
1✔
216
                cur = len(opts) - 1
1✔
217
            elif k in ('<enter>', '<right>'):
1✔
218
                if cur is not None:
1✔
219
                    return cur
1✔
220
            elif k in tuple(string.digits):
1✔
221
                was_digit = True
1✔
222
                d = str(k)
1✔
223
                n = int(ds + d)
1✔
224
                if 0 < n <= len(opts):
1✔
225
                    ds += d
1✔
226
                    cur = n - 1
1✔
227
                elif d != '0':
1✔
228
                    ds = d
1✔
229
                    n = int(ds)
1✔
230
                    cur = n - 1
1✔
231

232
            if prev != cur:
1✔
233
                if prev is not None:
1✔
234
                    hs[prev][0].update(space)
1✔
235
                if was_digit:
1✔
236
                    hs[cur][0].update(term.text.bold_green('%5s> ' % ds))
1✔
237
                else:
238
                    hs[cur][0].update(arrow)
1✔
239
    else:
240
        linefmt =       '       %' + str(len(str(len(opts)))) + 'd) %s'
1✔
241
        if default is not None:
1✔
242
            default += 1
1✔
243
        while True:
1✔
244
            print(' [?] ' + prompt)
1✔
245
            for i, opt in enumerate(opts):
1✔
246
                print(linefmt % (i + 1, opt))
1✔
247
            s = '     Choice '
1✔
248
            if default:
1✔
249
                s += '[%s] ' % str(default)
1✔
250
            try:
1✔
251
                x = int(raw_input(s) or default)
1✔
252
            except (ValueError, TypeError):
1✔
253
                continue
1✔
254
            if x >= 1 and x <= len(opts):
1✔
255
                return x - 1
1✔
256

257
def pause(n=None):
1✔
258
    r"""Waits for either user input or a specific number of seconds.
259

260
    Examples:
261

262
        >>> with context.local(log_level="INFO"):
263
        ...     pause(1)
264
        [x] Waiting
265
        [x] Waiting: 1...
266
        [+] Waiting: Done
267
        >>> pause("whatever")
268
        Traceback (most recent call last):
269
        ...
270
        ValueError: pause(): n must be a number or None
271

272
    Tests:
273

274
        >>> saved_stdin = sys.stdin
275
        >>> try:
276
        ...     sys.stdin = io.TextIOWrapper(io.BytesIO(b"\n"))
277
        ...     with context.local(log_level="INFO"):
278
        ...         pause()
279
        ... finally:
280
        ...     sys.stdin = saved_stdin
281
        [*] Paused (press enter to continue)
282
        >>> p = testpwnproc("pause()")
283
        >>> b"Paused" in p.recvuntil(b"press any")
284
        True
285
        >>> p.send(b"x")
286
        >>> _ = p.recvall()
287
    """
288

289
    if n is None:
1✔
290
        if term.term_mode:
1✔
291
            log.info('Paused (press any to continue)')
1✔
292
            term.getkey()
1✔
293
        else:
294
            log.info('Paused (press enter to continue)')
1✔
295
            raw_input('')
1✔
296
    elif isinstance(n, int):
1✔
297
        with log.waitfor("Waiting") as l:
1✔
298
            for i in range(n, 0, -1):
1✔
299
                l.status('%d... ' % i)
1✔
300
                time.sleep(1)
1✔
301
            l.success()
1✔
302
    else:
303
        raise ValueError('pause(): n must be a number or None')
1✔
304

305
def more(text):
1✔
306
    r"""more(text)
307

308
    Shows text like the command line tool ``more``.
309

310
    It not in term_mode, just prints the data to the screen.
311

312
    Arguments:
313
      text(str):  The text to show.
314

315
    Returns:
316
      :const:`None`
317

318
    Tests:      
319
 
320
        >>> more("text")
321
        text
322
        >>> p = testpwnproc("more('text\\n' * (term.height + 2))")
323
        >>> p.send(b"x")
324
        >>> data = p.recvall()
325
        >>> b"text" in data or data
326
        True
327
    """
328
    if term.term_mode:
1✔
329
        lines = text.split('\n')
1✔
330
        h = term.output(term.text.reverse('(more)'), float = True, frozen = False)
1✔
331
        step = term.height - 1
1✔
332
        for i in range(0, len(lines), step):
1✔
333
            for l in lines[i:i + step]:
1✔
334
                print(l)
1✔
335
            if i + step < len(lines):
1✔
336
                term.key.get()
1✔
337
    else:
338
        print(text)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc