🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
Showing first 47 files as there are too many
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/idna/__init__.py
     1 +from .package_data import __version__
     2 +from .core import (
     3 + IDNABidiError,
     4 + IDNAError,
     5 + InvalidCodepoint,
     6 + InvalidCodepointContext,
     7 + alabel,
     8 + check_bidi,
     9 + check_hyphen_ok,
     10 + check_initial_combiner,
     11 + check_label,
     12 + check_nfc,
     13 + decode,
     14 + encode,
     15 + ulabel,
     16 + uts46_remap,
     17 + valid_contextj,
     18 + valid_contexto,
     19 + valid_label_length,
     20 + valid_string_length,
     21 +)
     22 +from .intranges import intranges_contain
     23 + 
     24 +__all__ = [
     25 + "IDNABidiError",
     26 + "IDNAError",
     27 + "InvalidCodepoint",
     28 + "InvalidCodepointContext",
     29 + "alabel",
     30 + "check_bidi",
     31 + "check_hyphen_ok",
     32 + "check_initial_combiner",
     33 + "check_label",
     34 + "check_nfc",
     35 + "decode",
     36 + "encode",
     37 + "intranges_contain",
     38 + "ulabel",
     39 + "uts46_remap",
     40 + "valid_contextj",
     41 + "valid_contexto",
     42 + "valid_label_length",
     43 + "valid_string_length",
     44 +]
     45 + 
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/__init__.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/codec.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/compat.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/core.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/idnadata.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/intranges.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/package_data.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/idna/__pycache__/uts46data.cpython-311.pyc
    Binary file.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/idna/codec.py
     1 +from .core import encode, decode, alabel, ulabel, IDNAError
     2 +import codecs
     3 +import re
     4 +from typing import Tuple, Optional
     5 + 
     6 +_unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]')
     7 + 
     8 +class Codec(codecs.Codec):
     9 + 
     10 + def encode(self, data: str, errors: str = 'strict') -> Tuple[bytes, int]:
     11 + if errors != 'strict':
     12 + raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
     13 + 
     14 + if not data:
     15 + return b"", 0
     16 + 
     17 + return encode(data), len(data)
     18 + 
     19 + def decode(self, data: bytes, errors: str = 'strict') -> Tuple[str, int]:
     20 + if errors != 'strict':
     21 + raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
     22 + 
     23 + if not data:
     24 + return '', 0
     25 + 
     26 + return decode(data), len(data)
     27 + 
     28 +class IncrementalEncoder(codecs.BufferedIncrementalEncoder):
     29 + def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[str, int]: # type: ignore
     30 + if errors != 'strict':
     31 + raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
     32 + 
     33 + if not data:
     34 + return "", 0
     35 + 
     36 + labels = _unicode_dots_re.split(data)
     37 + trailing_dot = ''
     38 + if labels:
     39 + if not labels[-1]:
     40 + trailing_dot = '.'
     41 + del labels[-1]
     42 + elif not final:
     43 + # Keep potentially unfinished label until the next call
     44 + del labels[-1]
     45 + if labels:
     46 + trailing_dot = '.'
     47 + 
     48 + result = []
     49 + size = 0
     50 + for label in labels:
     51 + result.append(alabel(label))
     52 + if size:
     53 + size += 1
     54 + size += len(label)
     55 + 
     56 + # Join with U+002E
     57 + result_str = '.'.join(result) + trailing_dot # type: ignore
     58 + size += len(trailing_dot)
     59 + return result_str, size
     60 + 
     61 +class IncrementalDecoder(codecs.BufferedIncrementalDecoder):
     62 + def _buffer_decode(self, data: str, errors: str, final: bool) -> Tuple[str, int]: # type: ignore
     63 + if errors != 'strict':
     64 + raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
     65 + 
     66 + if not data:
     67 + return ('', 0)
     68 + 
     69 + labels = _unicode_dots_re.split(data)
     70 + trailing_dot = ''
     71 + if labels:
     72 + if not labels[-1]:
     73 + trailing_dot = '.'
     74 + del labels[-1]
     75 + elif not final:
     76 + # Keep potentially unfinished label until the next call
     77 + del labels[-1]
     78 + if labels:
     79 + trailing_dot = '.'
     80 + 
     81 + result = []
     82 + size = 0
     83 + for label in labels:
     84 + result.append(ulabel(label))
     85 + if size:
     86 + size += 1
     87 + size += len(label)
     88 + 
     89 + result_str = '.'.join(result) + trailing_dot
     90 + size += len(trailing_dot)
     91 + return (result_str, size)
     92 + 
     93 + 
     94 +class StreamWriter(Codec, codecs.StreamWriter):
     95 + pass
     96 + 
     97 + 
     98 +class StreamReader(Codec, codecs.StreamReader):
     99 + pass
     100 + 
     101 + 
     102 +def getregentry() -> codecs.CodecInfo:
     103 + # Compatibility as a search_function for codecs.register()
     104 + return codecs.CodecInfo(
     105 + name='idna',
     106 + encode=Codec().encode, # type: ignore
     107 + decode=Codec().decode, # type: ignore
     108 + incrementalencoder=IncrementalEncoder,
     109 + incrementaldecoder=IncrementalDecoder,
     110 + streamwriter=StreamWriter,
     111 + streamreader=StreamReader,
     112 + )
     113 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/idna/compat.py
     1 +from .core import *
     2 +from .codec import *
     3 +from typing import Any, Union
     4 + 
     5 +def ToASCII(label: str) -> bytes:
     6 + return encode(label)
     7 + 
     8 +def ToUnicode(label: Union[bytes, bytearray]) -> str:
     9 + return decode(label)
     10 + 
     11 +def nameprep(s: Any) -> None:
     12 + raise NotImplementedError('IDNA 2008 does not utilise nameprep protocol')
     13 + 
     14 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/idna/core.py
     1 +from . import idnadata
     2 +import bisect
     3 +import unicodedata
     4 +import re
     5 +from typing import Union, Optional
     6 +from .intranges import intranges_contain
     7 + 
     8 +_virama_combining_class = 9
     9 +_alabel_prefix = b'xn--'
     10 +_unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]')
     11 + 
     12 +class IDNAError(UnicodeError):
     13 + """ Base exception for all IDNA-encoding related problems """
     14 + pass
     15 + 
     16 + 
     17 +class IDNABidiError(IDNAError):
     18 + """ Exception when bidirectional requirements are not satisfied """
     19 + pass
     20 + 
     21 + 
     22 +class InvalidCodepoint(IDNAError):
     23 + """ Exception when a disallowed or unallocated codepoint is used """
     24 + pass
     25 + 
     26 + 
     27 +class InvalidCodepointContext(IDNAError):
     28 + """ Exception when the codepoint is not valid in the context it is used """
     29 + pass
     30 + 
     31 + 
     32 +def _combining_class(cp: int) -> int:
     33 + v = unicodedata.combining(chr(cp))
     34 + if v == 0:
     35 + if not unicodedata.name(chr(cp)):
     36 + raise ValueError('Unknown character in unicodedata')
     37 + return v
     38 + 
     39 +def _is_script(cp: str, script: str) -> bool:
     40 + return intranges_contain(ord(cp), idnadata.scripts[script])
     41 + 
     42 +def _punycode(s: str) -> bytes:
     43 + return s.encode('punycode')
     44 + 
     45 +def _unot(s: int) -> str:
     46 + return 'U+{:04X}'.format(s)
     47 + 
     48 + 
     49 +def valid_label_length(label: Union[bytes, str]) -> bool:
     50 + if len(label) > 63:
     51 + return False
     52 + return True
     53 + 
     54 + 
     55 +def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool:
     56 + if len(label) > (254 if trailing_dot else 253):
     57 + return False
     58 + return True
     59 + 
     60 + 
     61 +def check_bidi(label: str, check_ltr: bool = False) -> bool:
     62 + # Bidi rules should only be applied if string contains RTL characters
     63 + bidi_label = False
     64 + for (idx, cp) in enumerate(label, 1):
     65 + direction = unicodedata.bidirectional(cp)
     66 + if direction == '':
     67 + # String likely comes from a newer version of Unicode
     68 + raise IDNABidiError('Unknown directionality in label {} at position {}'.format(repr(label), idx))
     69 + if direction in ['R', 'AL', 'AN']:
     70 + bidi_label = True
     71 + if not bidi_label and not check_ltr:
     72 + return True
     73 + 
     74 + # Bidi rule 1
     75 + direction = unicodedata.bidirectional(label[0])
     76 + if direction in ['R', 'AL']:
     77 + rtl = True
     78 + elif direction == 'L':
     79 + rtl = False
     80 + else:
     81 + raise IDNABidiError('First codepoint in label {} must be directionality L, R or AL'.format(repr(label)))
     82 + 
     83 + valid_ending = False
     84 + number_type = None # type: Optional[str]
     85 + for (idx, cp) in enumerate(label, 1):
     86 + direction = unicodedata.bidirectional(cp)
     87 + 
     88 + if rtl:
     89 + # Bidi rule 2
     90 + if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
     91 + raise IDNABidiError('Invalid direction for codepoint at position {} in a right-to-left label'.format(idx))
     92 + # Bidi rule 3
     93 + if direction in ['R', 'AL', 'EN', 'AN']:
     94 + valid_ending = True
     95 + elif direction != 'NSM':
     96 + valid_ending = False
     97 + # Bidi rule 4
     98 + if direction in ['AN', 'EN']:
     99 + if not number_type:
     100 + number_type = direction
     101 + else:
     102 + if number_type != direction:
     103 + raise IDNABidiError('Can not mix numeral types in a right-to-left label')
     104 + else:
     105 + # Bidi rule 5
     106 + if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
     107 + raise IDNABidiError('Invalid direction for codepoint at position {} in a left-to-right label'.format(idx))
     108 + # Bidi rule 6
     109 + if direction in ['L', 'EN']:
     110 + valid_ending = True
     111 + elif direction != 'NSM':
     112 + valid_ending = False
     113 + 
     114 + if not valid_ending:
     115 + raise IDNABidiError('Label ends with illegal codepoint directionality')
     116 + 
     117 + return True
     118 + 
     119 + 
     120 +def check_initial_combiner(label: str) -> bool:
     121 + if unicodedata.category(label[0])[0] == 'M':
     122 + raise IDNAError('Label begins with an illegal combining character')
     123 + return True
     124 + 
     125 + 
     126 +def check_hyphen_ok(label: str) -> bool:
     127 + if label[2:4] == '--':
     128 + raise IDNAError('Label has disallowed hyphens in 3rd and 4th position')
     129 + if label[0] == '-' or label[-1] == '-':
     130 + raise IDNAError('Label must not start or end with a hyphen')
     131 + return True
     132 + 
     133 + 
     134 +def check_nfc(label: str) -> None:
     135 + if unicodedata.normalize('NFC', label) != label:
     136 + raise IDNAError('Label must be in Normalization Form C')
     137 + 
     138 + 
     139 +def valid_contextj(label: str, pos: int) -> bool:
     140 + cp_value = ord(label[pos])
     141 + 
     142 + if cp_value == 0x200c:
     143 + 
     144 + if pos > 0:
     145 + if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
     146 + return True
     147 + 
     148 + ok = False
     149 + for i in range(pos-1, -1, -1):
     150 + joining_type = idnadata.joining_types.get(ord(label[i]))
     151 + if joining_type == ord('T'):
     152 + continue
     153 + if joining_type in [ord('L'), ord('D')]:
     154 + ok = True
     155 + break
     156 + 
     157 + if not ok:
     158 + return False
     159 + 
     160 + ok = False
     161 + for i in range(pos+1, len(label)):
     162 + joining_type = idnadata.joining_types.get(ord(label[i]))
     163 + if joining_type == ord('T'):
     164 + continue
     165 + if joining_type in [ord('R'), ord('D')]:
     166 + ok = True
     167 + break
     168 + return ok
     169 + 
     170 + if cp_value == 0x200d:
     171 + 
     172 + if pos > 0:
     173 + if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
     174 + return True
     175 + return False
     176 + 
     177 + else:
     178 + 
     179 + return False
     180 + 
     181 + 
     182 +def valid_contexto(label: str, pos: int, exception: bool = False) -> bool:
     183 + cp_value = ord(label[pos])
     184 + 
     185 + if cp_value == 0x00b7:
     186 + if 0 < pos < len(label)-1:
     187 + if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c:
     188 + return True
     189 + return False
     190 + 
     191 + elif cp_value == 0x0375:
     192 + if pos < len(label)-1 and len(label) > 1:
     193 + return _is_script(label[pos + 1], 'Greek')
     194 + return False
     195 + 
     196 + elif cp_value == 0x05f3 or cp_value == 0x05f4:
     197 + if pos > 0:
     198 + return _is_script(label[pos - 1], 'Hebrew')
     199 + return False
     200 + 
     201 + elif cp_value == 0x30fb:
     202 + for cp in label:
     203 + if cp == '\u30fb':
     204 + continue
     205 + if _is_script(cp, 'Hiragana') or _is_script(cp, 'Katakana') or _is_script(cp, 'Han'):
     206 + return True
     207 + return False
     208 + 
     209 + elif 0x660 <= cp_value <= 0x669:
     210 + for cp in label:
     211 + if 0x6f0 <= ord(cp) <= 0x06f9:
     212 + return False
     213 + return True
     214 + 
     215 + elif 0x6f0 <= cp_value <= 0x6f9:
     216 + for cp in label:
     217 + if 0x660 <= ord(cp) <= 0x0669:
     218 + return False
     219 + return True
     220 + 
     221 + return False
     222 + 
     223 + 
     224 +def check_label(label: Union[str, bytes, bytearray]) -> None:
     225 + if isinstance(label, (bytes, bytearray)):
     226 + label = label.decode('utf-8')
     227 + if len(label) == 0:
     228 + raise IDNAError('Empty Label')
     229 + 
     230 + check_nfc(label)
     231 + check_hyphen_ok(label)
     232 + check_initial_combiner(label)
     233 + 
     234 + for (pos, cp) in enumerate(label):
     235 + cp_value = ord(cp)
     236 + if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']):
     237 + continue
     238 + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']):
     239 + try:
     240 + if not valid_contextj(label, pos):
     241 + raise InvalidCodepointContext('Joiner {} not allowed at position {} in {}'.format(
     242 + _unot(cp_value), pos+1, repr(label)))
     243 + except ValueError:
     244 + raise IDNAError('Unknown codepoint adjacent to joiner {} at position {} in {}'.format(
     245 + _unot(cp_value), pos+1, repr(label)))
     246 + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']):
     247 + if not valid_contexto(label, pos):
     248 + raise InvalidCodepointContext('Codepoint {} not allowed at position {} in {}'.format(_unot(cp_value), pos+1, repr(label)))
     249 + else:
     250 + raise InvalidCodepoint('Codepoint {} at position {} of {} not allowed'.format(_unot(cp_value), pos+1, repr(label)))
     251 + 
     252 + check_bidi(label)
     253 + 
     254 + 
     255 +def alabel(label: str) -> bytes:
     256 + try:
     257 + label_bytes = label.encode('ascii')
     258 + ulabel(label_bytes)
     259 + if not valid_label_length(label_bytes):
     260 + raise IDNAError('Label too long')
     261 + return label_bytes
     262 + except UnicodeEncodeError:
     263 + pass
     264 + 
     265 + if not label:
     266 + raise IDNAError('No Input')
     267 + 
     268 + label = str(label)
     269 + check_label(label)
     270 + label_bytes = _punycode(label)
     271 + label_bytes = _alabel_prefix + label_bytes
     272 + 
     273 + if not valid_label_length(label_bytes):
     274 + raise IDNAError('Label too long')
     275 + 
     276 + return label_bytes
     277 + 
     278 + 
     279 +def ulabel(label: Union[str, bytes, bytearray]) -> str:
     280 + if not isinstance(label, (bytes, bytearray)):
     281 + try:
     282 + label_bytes = label.encode('ascii')
     283 + except UnicodeEncodeError:
     284 + check_label(label)
     285 + return label
     286 + else:
     287 + label_bytes = label
     288 + 
     289 + label_bytes = label_bytes.lower()
     290 + if label_bytes.startswith(_alabel_prefix):
     291 + label_bytes = label_bytes[len(_alabel_prefix):]
     292 + if not label_bytes:
     293 + raise IDNAError('Malformed A-label, no Punycode eligible content found')
     294 + if label_bytes.decode('ascii')[-1] == '-':
     295 + raise IDNAError('A-label must not end with a hyphen')
     296 + else:
     297 + check_label(label_bytes)
     298 + return label_bytes.decode('ascii')
     299 + 
     300 + try:
     301 + label = label_bytes.decode('punycode')
     302 + except UnicodeError:
     303 + raise IDNAError('Invalid A-label')
     304 + check_label(label)
     305 + return label
     306 + 
     307 + 
     308 +def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str:
     309 + """Re-map the characters in the string according to UTS46 processing."""
     310 + from .uts46data import uts46data
     311 + output = ''
     312 + 
     313 + for pos, char in enumerate(domain):
     314 + code_point = ord(char)
     315 + try:
     316 + uts46row = uts46data[code_point if code_point < 256 else
     317 + bisect.bisect_left(uts46data, (code_point, 'Z')) - 1]
     318 + status = uts46row[1]
     319 + replacement = None # type: Optional[str]
     320 + if len(uts46row) == 3:
     321 + replacement = uts46row[2] # type: ignore
     322 + if (status == 'V' or
     323 + (status == 'D' and not transitional) or
     324 + (status == '3' and not std3_rules and replacement is None)):
     325 + output += char
     326 + elif replacement is not None and (status == 'M' or
     327 + (status == '3' and not std3_rules) or
     328 + (status == 'D' and transitional)):
     329 + output += replacement
     330 + elif status != 'I':
     331 + raise IndexError()
     332 + except IndexError:
     333 + raise InvalidCodepoint(
     334 + 'Codepoint {} not allowed at position {} in {}'.format(
     335 + _unot(code_point), pos + 1, repr(domain)))
     336 + 
     337 + return unicodedata.normalize('NFC', output)
     338 + 
     339 + 
     340 +def encode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool = False, std3_rules: bool = False, transitional: bool = False) -> bytes:
     341 + if isinstance(s, (bytes, bytearray)):
     342 + try:
     343 + s = s.decode('ascii')
     344 + except UnicodeDecodeError:
     345 + raise IDNAError('should pass a unicode string to the function rather than a byte string.')
     346 + if uts46:
     347 + s = uts46_remap(s, std3_rules, transitional)
     348 + trailing_dot = False
     349 + result = []
     350 + if strict:
     351 + labels = s.split('.')
     352 + else:
     353 + labels = _unicode_dots_re.split(s)
     354 + if not labels or labels == ['']:
     355 + raise IDNAError('Empty domain')
     356 + if labels[-1] == '':
     357 + del labels[-1]
     358 + trailing_dot = True
     359 + for label in labels:
     360 + s = alabel(label)
     361 + if s:
     362 + result.append(s)
     363 + else:
     364 + raise IDNAError('Empty label')
     365 + if trailing_dot:
     366 + result.append(b'')
     367 + s = b'.'.join(result)
     368 + if not valid_string_length(s, trailing_dot):
     369 + raise IDNAError('Domain too long')
     370 + return s
     371 + 
     372 + 
     373 +def decode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool = False, std3_rules: bool = False) -> str:
     374 + try:
     375 + if isinstance(s, (bytes, bytearray)):
     376 + s = s.decode('ascii')
     377 + except UnicodeDecodeError:
     378 + raise IDNAError('Invalid ASCII in A-label')
     379 + if uts46:
     380 + s = uts46_remap(s, std3_rules, False)
     381 + trailing_dot = False
     382 + result = []
     383 + if not strict:
     384 + labels = _unicode_dots_re.split(s)
     385 + else:
     386 + labels = s.split('.')
     387 + if not labels or labels == ['']:
     388 + raise IDNAError('Empty domain')
     389 + if not labels[-1]:
     390 + del labels[-1]
     391 + trailing_dot = True
     392 + for label in labels:
     393 + s = ulabel(label)
     394 + if s:
     395 + result.append(s)
     396 + else:
     397 + raise IDNAError('Empty label')
     398 + if trailing_dot:
     399 + result.append('')
     400 + return '.'.join(result)
     401 + 
  • vuln_analyzer/lib/python3.11/site-packages/idna/idnadata.py
    Diff is too large to be displayed.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/idna/intranges.py
     1 +"""
     2 +Given a list of integers, made up of (hopefully) a small number of long runs
     3 +of consecutive integers, compute a representation of the form
     4 +((start1, end1), (start2, end2) ...). Then answer the question "was x present
     5 +in the original list?" in time O(log(# runs)).
     6 +"""
     7 + 
     8 +import bisect
     9 +from typing import List, Tuple
     10 + 
     11 +def intranges_from_list(list_: List[int]) -> Tuple[int, ...]:
     12 + """Represent a list of integers as a sequence of ranges:
     13 + ((start_0, end_0), (start_1, end_1), ...), such that the original
     14 + integers are exactly those x such that start_i <= x < end_i for some i.
     15 + 
     16 + Ranges are encoded as single integers (start << 32 | end), not as tuples.
     17 + """
     18 + 
     19 + sorted_list = sorted(list_)
     20 + ranges = []
     21 + last_write = -1
     22 + for i in range(len(sorted_list)):
     23 + if i+1 < len(sorted_list):
     24 + if sorted_list[i] == sorted_list[i+1]-1:
     25 + continue
     26 + current_range = sorted_list[last_write+1:i+1]
     27 + ranges.append(_encode_range(current_range[0], current_range[-1] + 1))
     28 + last_write = i
     29 + 
     30 + return tuple(ranges)
     31 + 
     32 +def _encode_range(start: int, end: int) -> int:
     33 + return (start << 32) | end
     34 + 
     35 +def _decode_range(r: int) -> Tuple[int, int]:
     36 + return (r >> 32), (r & ((1 << 32) - 1))
     37 + 
     38 + 
     39 +def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool:
     40 + """Determine if `int_` falls into one of the ranges in `ranges`."""
     41 + tuple_ = _encode_range(int_, 0)
     42 + pos = bisect.bisect_left(ranges, tuple_)
     43 + # we could be immediately ahead of a tuple (start, end)
     44 + # with start < int_ <= end
     45 + if pos > 0:
     46 + left, right = _decode_range(ranges[pos-1])
     47 + if left <= int_ < right:
     48 + return True
     49 + # or we could be immediately behind a tuple (int_, end)
     50 + if pos < len(ranges):
     51 + left, _ = _decode_range(ranges[pos])
     52 + if left == int_:
     53 + return True
     54 + return False
     55 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/idna/package_data.py
     1 +__version__ = '3.4'
     2 + 
     3 + 
  • ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/idna/py.typed
     1 + 
  • vuln_analyzer/lib/python3.11/site-packages/idna/uts46data.py
    Diff is too large to be displayed.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/multidict/__init__.py
     1 +"""Multidict implementation.
     2 + 
     3 +HTTP Headers and URL query string require specific data structure:
     4 +multidict. It behaves mostly like a dict but it can have
     5 +several values for the same key.
     6 +"""
     7 + 
     8 +from ._abc import MultiMapping, MutableMultiMapping
     9 +from ._compat import USE_EXTENSIONS
     10 + 
     11 +__all__ = (
     12 + "MultiMapping",
     13 + "MutableMultiMapping",
     14 + "MultiDictProxy",
     15 + "CIMultiDictProxy",
     16 + "MultiDict",
     17 + "CIMultiDict",
     18 + "upstr",
     19 + "istr",
     20 + "getversion",
     21 +)
     22 + 
     23 +__version__ = "6.0.4"
     24 + 
     25 + 
     26 +try:
     27 + if not USE_EXTENSIONS:
     28 + raise ImportError
     29 + from ._multidict import (
     30 + CIMultiDict,
     31 + CIMultiDictProxy,
     32 + MultiDict,
     33 + MultiDictProxy,
     34 + getversion,
     35 + istr,
     36 + )
     37 +except ImportError: # pragma: no cover
     38 + from ._multidict_py import (
     39 + CIMultiDict,
     40 + CIMultiDictProxy,
     41 + MultiDict,
     42 + MultiDictProxy,
     43 + getversion,
     44 + istr,
     45 + )
     46 + 
     47 + 
     48 +upstr = istr
     49 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/multidict/__init__.pyi
     1 +import abc
     2 +from typing import (
     3 + Generic,
     4 + Iterable,
     5 + Iterator,
     6 + Mapping,
     7 + MutableMapping,
     8 + TypeVar,
     9 + overload,
     10 +)
     11 + 
     12 +class istr(str): ...
     13 + 
     14 +upstr = istr
     15 + 
     16 +_S = str | istr
     17 + 
     18 +_T = TypeVar("_T")
     19 + 
     20 +_T_co = TypeVar("_T_co", covariant=True)
     21 + 
     22 +_D = TypeVar("_D")
     23 + 
     24 +class MultiMapping(Mapping[_S, _T_co]):
     25 + @overload
     26 + @abc.abstractmethod
     27 + def getall(self, key: _S) -> list[_T_co]: ...
     28 + @overload
     29 + @abc.abstractmethod
     30 + def getall(self, key: _S, default: _D) -> list[_T_co] | _D: ...
     31 + @overload
     32 + @abc.abstractmethod
     33 + def getone(self, key: _S) -> _T_co: ...
     34 + @overload
     35 + @abc.abstractmethod
     36 + def getone(self, key: _S, default: _D) -> _T_co | _D: ...
     37 + 
     38 +_Arg = (Mapping[str, _T] | Mapping[istr, _T] | dict[str, _T]
     39 + | dict[istr, _T] | MultiMapping[_T]
     40 + | Iterable[tuple[str, _T]] | Iterable[tuple[istr, _T]])
     41 + 
     42 +class MutableMultiMapping(MultiMapping[_T], MutableMapping[_S, _T], Generic[_T]):
     43 + @abc.abstractmethod
     44 + def add(self, key: _S, value: _T) -> None: ...
     45 + @abc.abstractmethod
     46 + def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
     47 + @overload
     48 + @abc.abstractmethod
     49 + def popone(self, key: _S) -> _T: ...
     50 + @overload
     51 + @abc.abstractmethod
     52 + def popone(self, key: _S, default: _D) -> _T | _D: ...
     53 + @overload
     54 + @abc.abstractmethod
     55 + def popall(self, key: _S) -> list[_T]: ...
     56 + @overload
     57 + @abc.abstractmethod
     58 + def popall(self, key: _S, default: _D) -> list[_T] | _D: ...
     59 + 
     60 +class MultiDict(MutableMultiMapping[_T], Generic[_T]):
     61 + def __init__(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
     62 + def copy(self) -> MultiDict[_T]: ...
     63 + def __getitem__(self, k: _S) -> _T: ...
     64 + def __setitem__(self, k: _S, v: _T) -> None: ...
     65 + def __delitem__(self, v: _S) -> None: ...
     66 + def __iter__(self) -> Iterator[_S]: ...
     67 + def __len__(self) -> int: ...
     68 + @overload
     69 + def getall(self, key: _S) -> list[_T]: ...
     70 + @overload
     71 + def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
     72 + @overload
     73 + def getone(self, key: _S) -> _T: ...
     74 + @overload
     75 + def getone(self, key: _S, default: _D) -> _T | _D: ...
     76 + def add(self, key: _S, value: _T) -> None: ...
     77 + def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
     78 + @overload
     79 + def popone(self, key: _S) -> _T: ...
     80 + @overload
     81 + def popone(self, key: _S, default: _D) -> _T | _D: ...
     82 + @overload
     83 + def popall(self, key: _S) -> list[_T]: ...
     84 + @overload
     85 + def popall(self, key: _S, default: _D) -> list[_T] | _D: ...
     86 + 
     87 +class CIMultiDict(MutableMultiMapping[_T], Generic[_T]):
     88 + def __init__(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
     89 + def copy(self) -> CIMultiDict[_T]: ...
     90 + def __getitem__(self, k: _S) -> _T: ...
     91 + def __setitem__(self, k: _S, v: _T) -> None: ...
     92 + def __delitem__(self, v: _S) -> None: ...
     93 + def __iter__(self) -> Iterator[_S]: ...
     94 + def __len__(self) -> int: ...
     95 + @overload
     96 + def getall(self, key: _S) -> list[_T]: ...
     97 + @overload
     98 + def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
     99 + @overload
     100 + def getone(self, key: _S) -> _T: ...
     101 + @overload
     102 + def getone(self, key: _S, default: _D) -> _T | _D: ...
     103 + def add(self, key: _S, value: _T) -> None: ...
     104 + def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
     105 + @overload
     106 + def popone(self, key: _S) -> _T: ...
     107 + @overload
     108 + def popone(self, key: _S, default: _D) -> _T | _D: ...
     109 + @overload
     110 + def popall(self, key: _S) -> list[_T]: ...
     111 + @overload
     112 + def popall(self, key: _S, default: _D) -> list[_T] | _D: ...
     113 + 
     114 +class MultiDictProxy(MultiMapping[_T], Generic[_T]):
     115 + def __init__(
     116 + self, arg: MultiMapping[_T] | MutableMultiMapping[_T]
     117 + ) -> None: ...
     118 + def copy(self) -> MultiDict[_T]: ...
     119 + def __getitem__(self, k: _S) -> _T: ...
     120 + def __iter__(self) -> Iterator[_S]: ...
     121 + def __len__(self) -> int: ...
     122 + @overload
     123 + def getall(self, key: _S) -> list[_T]: ...
     124 + @overload
     125 + def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
     126 + @overload
     127 + def getone(self, key: _S) -> _T: ...
     128 + @overload
     129 + def getone(self, key: _S, default: _D) -> _T | _D: ...
     130 + 
     131 +class CIMultiDictProxy(MultiMapping[_T], Generic[_T]):
     132 + def __init__(
     133 + self, arg: MultiMapping[_T] | MutableMultiMapping[_T]
     134 + ) -> None: ...
     135 + def __getitem__(self, k: _S) -> _T: ...
     136 + def __iter__(self) -> Iterator[_S]: ...
     137 + def __len__(self) -> int: ...
     138 + @overload
     139 + def getall(self, key: _S) -> list[_T]: ...
     140 + @overload
     141 + def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
     142 + @overload
     143 + def getone(self, key: _S) -> _T: ...
     144 + @overload
     145 + def getone(self, key: _S, default: _D) -> _T | _D: ...
     146 + def copy(self) -> CIMultiDict[_T]: ...
     147 + 
     148 +def getversion(
     149 + md: MultiDict[_T] | CIMultiDict[_T] | MultiDictProxy[_T] | CIMultiDictProxy[_T]
     150 +) -> int: ...
     151 + 
  • vuln_analyzer/lib/python3.11/site-packages/multidict/__pycache__/__init__.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/multidict/__pycache__/_abc.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/multidict/__pycache__/_compat.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/multidict/__pycache__/_multidict_base.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/multidict/__pycache__/_multidict_py.cpython-311.pyc
    Binary file.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/multidict/_abc.py
     1 +import abc
     2 +import sys
     3 +import types
     4 +from collections.abc import Mapping, MutableMapping
     5 + 
     6 + 
     7 +class _TypingMeta(abc.ABCMeta):
     8 + # A fake metaclass to satisfy typing deps in runtime
     9 + # basically MultiMapping[str] and other generic-like type instantiations
     10 + # are emulated.
     11 + # Note: real type hints are provided by __init__.pyi stub file
     12 + if sys.version_info >= (3, 9):
     13 + 
     14 + def __getitem__(self, key):
     15 + return types.GenericAlias(self, key)
     16 + 
     17 + else:
     18 + 
     19 + def __getitem__(self, key):
     20 + return self
     21 + 
     22 + 
     23 +class MultiMapping(Mapping, metaclass=_TypingMeta):
     24 + @abc.abstractmethod
     25 + def getall(self, key, default=None):
     26 + raise KeyError
     27 + 
     28 + @abc.abstractmethod
     29 + def getone(self, key, default=None):
     30 + raise KeyError
     31 + 
     32 + 
     33 +class MutableMultiMapping(MultiMapping, MutableMapping):
     34 + @abc.abstractmethod
     35 + def add(self, key, value):
     36 + raise NotImplementedError
     37 + 
     38 + @abc.abstractmethod
     39 + def extend(self, *args, **kwargs):
     40 + raise NotImplementedError
     41 + 
     42 + @abc.abstractmethod
     43 + def popone(self, key, default=None):
     44 + raise KeyError
     45 + 
     46 + @abc.abstractmethod
     47 + def popall(self, key, default=None):
     48 + raise KeyError
     49 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/multidict/_compat.py
     1 +import os
     2 +import platform
     3 + 
     4 +NO_EXTENSIONS = bool(os.environ.get("MULTIDICT_NO_EXTENSIONS"))
     5 + 
     6 +PYPY = platform.python_implementation() == "PyPy"
     7 + 
     8 +USE_EXTENSIONS = not NO_EXTENSIONS and not PYPY
     9 + 
     10 +if USE_EXTENSIONS:
     11 + try:
     12 + from . import _multidict # noqa
     13 + except ImportError:
     14 + USE_EXTENSIONS = False
     15 + 
  • vuln_analyzer/lib/python3.11/site-packages/multidict/_multidict.cpython-311-x86_64-linux-gnu.so
    Binary file.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/multidict/_multidict_base.py
     1 +from collections.abc import ItemsView, Iterable, KeysView, Set, ValuesView
     2 + 
     3 + 
     4 +def _abc_itemsview_register(view_cls):
     5 + ItemsView.register(view_cls)
     6 + 
     7 + 
     8 +def _abc_keysview_register(view_cls):
     9 + KeysView.register(view_cls)
     10 + 
     11 + 
     12 +def _abc_valuesview_register(view_cls):
     13 + ValuesView.register(view_cls)
     14 + 
     15 + 
     16 +def _viewbaseset_richcmp(view, other, op):
     17 + if op == 0: # <
     18 + if not isinstance(other, Set):
     19 + return NotImplemented
     20 + return len(view) < len(other) and view <= other
     21 + elif op == 1: # <=
     22 + if not isinstance(other, Set):
     23 + return NotImplemented
     24 + if len(view) > len(other):
     25 + return False
     26 + for elem in view:
     27 + if elem not in other:
     28 + return False
     29 + return True
     30 + elif op == 2: # ==
     31 + if not isinstance(other, Set):
     32 + return NotImplemented
     33 + return len(view) == len(other) and view <= other
     34 + elif op == 3: # !=
     35 + return not view == other
     36 + elif op == 4: # >
     37 + if not isinstance(other, Set):
     38 + return NotImplemented
     39 + return len(view) > len(other) and view >= other
     40 + elif op == 5: # >=
     41 + if not isinstance(other, Set):
     42 + return NotImplemented
     43 + if len(view) < len(other):
     44 + return False
     45 + for elem in other:
     46 + if elem not in view:
     47 + return False
     48 + return True
     49 + 
     50 + 
     51 +def _viewbaseset_and(view, other):
     52 + if not isinstance(other, Iterable):
     53 + return NotImplemented
     54 + if isinstance(view, Set):
     55 + view = set(iter(view))
     56 + if isinstance(other, Set):
     57 + other = set(iter(other))
     58 + if not isinstance(other, Set):
     59 + other = set(iter(other))
     60 + return view & other
     61 + 
     62 + 
     63 +def _viewbaseset_or(view, other):
     64 + if not isinstance(other, Iterable):
     65 + return NotImplemented
     66 + if isinstance(view, Set):
     67 + view = set(iter(view))
     68 + if isinstance(other, Set):
     69 + other = set(iter(other))
     70 + if not isinstance(other, Set):
     71 + other = set(iter(other))
     72 + return view | other
     73 + 
     74 + 
     75 +def _viewbaseset_sub(view, other):
     76 + if not isinstance(other, Iterable):
     77 + return NotImplemented
     78 + if isinstance(view, Set):
     79 + view = set(iter(view))
     80 + if isinstance(other, Set):
     81 + other = set(iter(other))
     82 + if not isinstance(other, Set):
     83 + other = set(iter(other))
     84 + return view - other
     85 + 
     86 + 
     87 +def _viewbaseset_xor(view, other):
     88 + if not isinstance(other, Iterable):
     89 + return NotImplemented
     90 + if isinstance(view, Set):
     91 + view = set(iter(view))
     92 + if isinstance(other, Set):
     93 + other = set(iter(other))
     94 + if not isinstance(other, Set):
     95 + other = set(iter(other))
     96 + return view ^ other
     97 + 
     98 + 
     99 +def _itemsview_isdisjoint(view, other):
     100 + "Return True if two sets have a null intersection."
     101 + for v in other:
     102 + if v in view:
     103 + return False
     104 + return True
     105 + 
     106 + 
     107 +def _itemsview_repr(view):
     108 + lst = []
     109 + for k, v in view:
     110 + lst.append("{!r}: {!r}".format(k, v))
     111 + body = ", ".join(lst)
     112 + return "{}({})".format(view.__class__.__name__, body)
     113 + 
     114 + 
     115 +def _keysview_isdisjoint(view, other):
     116 + "Return True if two sets have a null intersection."
     117 + for k in other:
     118 + if k in view:
     119 + return False
     120 + return True
     121 + 
     122 + 
     123 +def _keysview_repr(view):
     124 + lst = []
     125 + for k in view:
     126 + lst.append("{!r}".format(k))
     127 + body = ", ".join(lst)
     128 + return "{}({})".format(view.__class__.__name__, body)
     129 + 
     130 + 
     131 +def _valuesview_repr(view):
     132 + lst = []
     133 + for v in view:
     134 + lst.append("{!r}".format(v))
     135 + body = ", ".join(lst)
     136 + return "{}({})".format(view.__class__.__name__, body)
     137 + 
     138 + 
     139 +def _mdrepr(md):
     140 + lst = []
     141 + for k, v in md.items():
     142 + lst.append("'{}': {!r}".format(k, v))
     143 + body = ", ".join(lst)
     144 + return "<{}({})>".format(md.__class__.__name__, body)
     145 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/multidict/_multidict_py.py
     1 +import sys
     2 +import types
     3 +from array import array
     4 +from collections import abc
     5 + 
     6 +from ._abc import MultiMapping, MutableMultiMapping
     7 + 
     8 +_marker = object()
     9 + 
     10 +if sys.version_info >= (3, 9):
     11 + GenericAlias = types.GenericAlias
     12 +else:
     13 + def GenericAlias(cls):
     14 + return cls
     15 + 
     16 + 
     17 +class istr(str):
     18 + 
     19 + """Case insensitive str."""
     20 + 
     21 + __is_istr__ = True
     22 + 
     23 + 
     24 +upstr = istr # for relaxing backward compatibility problems
     25 + 
     26 + 
     27 +def getversion(md):
     28 + if not isinstance(md, _Base):
     29 + raise TypeError("Parameter should be multidict or proxy")
     30 + return md._impl._version
     31 + 
     32 + 
     33 +_version = array("Q", [0])
     34 + 
     35 + 
     36 +class _Impl:
     37 + __slots__ = ("_items", "_version")
     38 + 
     39 + def __init__(self):
     40 + self._items = []
     41 + self.incr_version()
     42 + 
     43 + def incr_version(self):
     44 + global _version
     45 + v = _version
     46 + v[0] += 1
     47 + self._version = v[0]
     48 + 
     49 + if sys.implementation.name != "pypy":
     50 + 
     51 + def __sizeof__(self):
     52 + return object.__sizeof__(self) + sys.getsizeof(self._items)
     53 + 
     54 + 
     55 +class _Base:
     56 + def _title(self, key):
     57 + return key
     58 + 
     59 + def getall(self, key, default=_marker):
     60 + """Return a list of all values matching the key."""
     61 + identity = self._title(key)
     62 + res = [v for i, k, v in self._impl._items if i == identity]
     63 + if res:
     64 + return res
     65 + if not res and default is not _marker:
     66 + return default
     67 + raise KeyError("Key not found: %r" % key)
     68 + 
     69 + def getone(self, key, default=_marker):
     70 + """Get first value matching the key.
     71 + 
     72 + Raises KeyError if the key is not found and no default is provided.
     73 + """
     74 + identity = self._title(key)
     75 + for i, k, v in self._impl._items:
     76 + if i == identity:
     77 + return v
     78 + if default is not _marker:
     79 + return default
     80 + raise KeyError("Key not found: %r" % key)
     81 + 
     82 + # Mapping interface #
     83 + 
     84 + def __getitem__(self, key):
     85 + return self.getone(key)
     86 + 
     87 + def get(self, key, default=None):
     88 + """Get first value matching the key.
     89 + 
     90 + If the key is not found, returns the default (or None if no default is provided)
     91 + """
     92 + return self.getone(key, default)
     93 + 
     94 + def __iter__(self):
     95 + return iter(self.keys())
     96 + 
     97 + def __len__(self):
     98 + return len(self._impl._items)
     99 + 
     100 + def keys(self):
     101 + """Return a new view of the dictionary's keys."""
     102 + return _KeysView(self._impl)
     103 + 
     104 + def items(self):
     105 + """Return a new view of the dictionary's items *(key, value) pairs)."""
     106 + return _ItemsView(self._impl)
     107 + 
     108 + def values(self):
     109 + """Return a new view of the dictionary's values."""
     110 + return _ValuesView(self._impl)
     111 + 
     112 + def __eq__(self, other):
     113 + if not isinstance(other, abc.Mapping):
     114 + return NotImplemented
     115 + if isinstance(other, _Base):
     116 + lft = self._impl._items
     117 + rht = other._impl._items
     118 + if len(lft) != len(rht):
     119 + return False
     120 + for (i1, k2, v1), (i2, k2, v2) in zip(lft, rht):
     121 + if i1 != i2 or v1 != v2:
     122 + return False
     123 + return True
     124 + if len(self._impl._items) != len(other):
     125 + return False
     126 + for k, v in self.items():
     127 + nv = other.get(k, _marker)
     128 + if v != nv:
     129 + return False
     130 + return True
     131 + 
     132 + def __contains__(self, key):
     133 + identity = self._title(key)
     134 + for i, k, v in self._impl._items:
     135 + if i == identity:
     136 + return True
     137 + return False
     138 + 
     139 + def __repr__(self):
     140 + body = ", ".join("'{}': {!r}".format(k, v) for k, v in self.items())
     141 + return "<{}({})>".format(self.__class__.__name__, body)
     142 + 
     143 + __class_getitem__ = classmethod(GenericAlias)
     144 + 
     145 + 
     146 +class MultiDictProxy(_Base, MultiMapping):
     147 + """Read-only proxy for MultiDict instance."""
     148 + 
     149 + def __init__(self, arg):
     150 + if not isinstance(arg, (MultiDict, MultiDictProxy)):
     151 + raise TypeError(
     152 + "ctor requires MultiDict or MultiDictProxy instance"
     153 + ", not {}".format(type(arg))
     154 + )
     155 + 
     156 + self._impl = arg._impl
     157 + 
     158 + def __reduce__(self):
     159 + raise TypeError("can't pickle {} objects".format(self.__class__.__name__))
     160 + 
     161 + def copy(self):
     162 + """Return a copy of itself."""
     163 + return MultiDict(self.items())
     164 + 
     165 + 
     166 +class CIMultiDictProxy(MultiDictProxy):
     167 + """Read-only proxy for CIMultiDict instance."""
     168 + 
     169 + def __init__(self, arg):
     170 + if not isinstance(arg, (CIMultiDict, CIMultiDictProxy)):
     171 + raise TypeError(
     172 + "ctor requires CIMultiDict or CIMultiDictProxy instance"
     173 + ", not {}".format(type(arg))
     174 + )
     175 + 
     176 + self._impl = arg._impl
     177 + 
     178 + def _title(self, key):
     179 + return key.title()
     180 + 
     181 + def copy(self):
     182 + """Return a copy of itself."""
     183 + return CIMultiDict(self.items())
     184 + 
     185 + 
     186 +class MultiDict(_Base, MutableMultiMapping):
     187 + """Dictionary with the support for duplicate keys."""
     188 + 
     189 + def __init__(self, *args, **kwargs):
     190 + self._impl = _Impl()
     191 + 
     192 + self._extend(args, kwargs, self.__class__.__name__, self._extend_items)
     193 + 
     194 + if sys.implementation.name != "pypy":
     195 + 
     196 + def __sizeof__(self):
     197 + return object.__sizeof__(self) + sys.getsizeof(self._impl)
     198 + 
     199 + def __reduce__(self):
     200 + return (self.__class__, (list(self.items()),))
     201 + 
     202 + def _title(self, key):
     203 + return key
     204 + 
     205 + def _key(self, key):
     206 + if isinstance(key, str):
     207 + return key
     208 + else:
     209 + raise TypeError(
     210 + "MultiDict keys should be either str " "or subclasses of str"
     211 + )
     212 + 
     213 + def add(self, key, value):
     214 + identity = self._title(key)
     215 + self._impl._items.append((identity, self._key(key), value))
     216 + self._impl.incr_version()
     217 + 
     218 + def copy(self):
     219 + """Return a copy of itself."""
     220 + cls = self.__class__
     221 + return cls(self.items())
     222 + 
     223 + __copy__ = copy
     224 + 
     225 + def extend(self, *args, **kwargs):
     226 + """Extend current MultiDict with more values.
     227 + 
     228 + This method must be used instead of update.
     229 + """
     230 + self._extend(args, kwargs, "extend", self._extend_items)
     231 + 
     232 + def _extend(self, args, kwargs, name, method):
     233 + if len(args) > 1:
     234 + raise TypeError(
     235 + "{} takes at most 1 positional argument"
     236 + " ({} given)".format(name, len(args))
     237 + )
     238 + if args:
     239 + arg = args[0]
     240 + if isinstance(args[0], (MultiDict, MultiDictProxy)) and not kwargs:
     241 + items = arg._impl._items
     242 + else:
     243 + if hasattr(arg, "items"):
     244 + arg = arg.items()
     245 + if kwargs:
     246 + arg = list(arg)
     247 + arg.extend(list(kwargs.items()))
     248 + items = []
     249 + for item in arg:
     250 + if not len(item) == 2:
     251 + raise TypeError(
     252 + "{} takes either dict or list of (key, value) "
     253 + "tuples".format(name)
     254 + )
     255 + items.append((self._title(item[0]), self._key(item[0]), item[1]))
     256 + 
     257 + method(items)
     258 + else:
     259 + method(
     260 + [
     261 + (self._title(key), self._key(key), value)
     262 + for key, value in kwargs.items()
     263 + ]
     264 + )
     265 + 
     266 + def _extend_items(self, items):
     267 + for identity, key, value in items:
     268 + self.add(key, value)
     269 + 
     270 + def clear(self):
     271 + """Remove all items from MultiDict."""
     272 + self._impl._items.clear()
     273 + self._impl.incr_version()
     274 + 
     275 + # Mapping interface #
     276 + 
     277 + def __setitem__(self, key, value):
     278 + self._replace(key, value)
     279 + 
     280 + def __delitem__(self, key):
     281 + identity = self._title(key)
     282 + items = self._impl._items
     283 + found = False
     284 + for i in range(len(items) - 1, -1, -1):
     285 + if items[i][0] == identity:
     286 + del items[i]
     287 + found = True
     288 + if not found:
     289 + raise KeyError(key)
     290 + else:
     291 + self._impl.incr_version()
     292 + 
     293 + def setdefault(self, key, default=None):
     294 + """Return value for key, set value to default if key is not present."""
     295 + identity = self._title(key)
     296 + for i, k, v in self._impl._items:
     297 + if i == identity:
     298 + return v
     299 + self.add(key, default)
     300 + return default
     301 + 
     302 + def popone(self, key, default=_marker):
     303 + """Remove specified key and return the corresponding value.
     304 + 
     305 + If key is not found, d is returned if given, otherwise
     306 + KeyError is raised.
     307 + 
     308 + """
     309 + identity = self._title(key)
     310 + for i in range(len(self._impl._items)):
     311 + if self._impl._items[i][0] == identity:
     312 + value = self._impl._items[i][2]
     313 + del self._impl._items[i]
     314 + self._impl.incr_version()
     315 + return value
     316 + if default is _marker:
     317 + raise KeyError(key)
     318 + else:
     319 + return default
     320 + 
     321 + pop = popone # type: ignore
     322 + 
     323 + def popall(self, key, default=_marker):
     324 + """Remove all occurrences of key and return the list of corresponding
     325 + values.
     326 + 
     327 + If key is not found, default is returned if given, otherwise
     328 + KeyError is raised.
     329 + 
     330 + """
     331 + found = False
     332 + identity = self._title(key)
     333 + ret = []
     334 + for i in range(len(self._impl._items) - 1, -1, -1):
     335 + item = self._impl._items[i]
     336 + if item[0] == identity:
     337 + ret.append(item[2])
     338 + del self._impl._items[i]
     339 + self._impl.incr_version()
     340 + found = True
     341 + if not found:
     342 + if default is _marker:
     343 + raise KeyError(key)
     344 + else:
     345 + return default
     346 + else:
     347 + ret.reverse()
     348 + return ret
     349 + 
     350 + def popitem(self):
     351 + """Remove and return an arbitrary (key, value) pair."""
     352 + if self._impl._items:
     353 + i = self._impl._items.pop(0)
     354 + self._impl.incr_version()
     355 + return i[1], i[2]
     356 + else:
     357 + raise KeyError("empty multidict")
     358 + 
     359 + def update(self, *args, **kwargs):
     360 + """Update the dictionary from *other*, overwriting existing keys."""
     361 + self._extend(args, kwargs, "update", self._update_items)
     362 + 
     363 + def _update_items(self, items):
     364 + if not items:
     365 + return
     366 + used_keys = {}
     367 + for identity, key, value in items:
     368 + start = used_keys.get(identity, 0)
     369 + for i in range(start, len(self._impl._items)):
     370 + item = self._impl._items[i]
     371 + if item[0] == identity:
     372 + used_keys[identity] = i + 1
     373 + self._impl._items[i] = (identity, key, value)
     374 + break
     375 + else:
     376 + self._impl._items.append((identity, key, value))
     377 + used_keys[identity] = len(self._impl._items)
     378 + 
     379 + # drop tails
     380 + i = 0
     381 + while i < len(self._impl._items):
     382 + item = self._impl._items[i]
     383 + identity = item[0]
     384 + pos = used_keys.get(identity)
     385 + if pos is None:
     386 + i += 1
     387 + continue
     388 + if i >= pos:
     389 + del self._impl._items[i]
     390 + else:
     391 + i += 1
     392 + 
     393 + self._impl.incr_version()
     394 + 
     395 + def _replace(self, key, value):
     396 + key = self._key(key)
     397 + identity = self._title(key)
     398 + items = self._impl._items
     399 + 
     400 + for i in range(len(items)):
     401 + item = items[i]
     402 + if item[0] == identity:
     403 + items[i] = (identity, key, value)
     404 + # i points to last found item
     405 + rgt = i
     406 + self._impl.incr_version()
     407 + break
     408 + else:
     409 + self._impl._items.append((identity, key, value))
     410 + self._impl.incr_version()
     411 + return
     412 + 
     413 + # remove all tail items
     414 + i = rgt + 1
     415 + while i < len(items):
     416 + item = items[i]
     417 + if item[0] == identity:
     418 + del items[i]
     419 + else:
     420 + i += 1
     421 + 
     422 + 
     423 +class CIMultiDict(MultiDict):
     424 + """Dictionary with the support for duplicate case-insensitive keys."""
     425 + 
     426 + def _title(self, key):
     427 + return key.title()
     428 + 
     429 + 
     430 +class _Iter:
     431 + __slots__ = ("_size", "_iter")
     432 + 
     433 + def __init__(self, size, iterator):
     434 + self._size = size
     435 + self._iter = iterator
     436 + 
     437 + def __iter__(self):
     438 + return self
     439 + 
     440 + def __next__(self):
     441 + return next(self._iter)
     442 + 
     443 + def __length_hint__(self):
     444 + return self._size
     445 + 
     446 + 
     447 +class _ViewBase:
     448 + def __init__(self, impl):
     449 + self._impl = impl
     450 + 
     451 + def __len__(self):
     452 + return len(self._impl._items)
     453 + 
     454 + 
     455 +class _ItemsView(_ViewBase, abc.ItemsView):
     456 + def __contains__(self, item):
     457 + assert isinstance(item, tuple) or isinstance(item, list)
     458 + assert len(item) == 2
     459 + for i, k, v in self._impl._items:
     460 + if item[0] == k and item[1] == v:
     461 + return True
     462 + return False
     463 + 
     464 + def __iter__(self):
     465 + return _Iter(len(self), self._iter(self._impl._version))
     466 + 
     467 + def _iter(self, version):
     468 + for i, k, v in self._impl._items:
     469 + if version != self._impl._version:
     470 + raise RuntimeError("Dictionary changed during iteration")
     471 + yield k, v
     472 + 
     473 + def __repr__(self):
     474 + lst = []
     475 + for item in self._impl._items:
     476 + lst.append("{!r}: {!r}".format(item[1], item[2]))
     477 + body = ", ".join(lst)
     478 + return "{}({})".format(self.__class__.__name__, body)
     479 + 
     480 + 
     481 +class _ValuesView(_ViewBase, abc.ValuesView):
     482 + def __contains__(self, value):
     483 + for item in self._impl._items:
     484 + if item[2] == value:
     485 + return True
     486 + return False
     487 + 
     488 + def __iter__(self):
     489 + return _Iter(len(self), self._iter(self._impl._version))
     490 + 
     491 + def _iter(self, version):
     492 + for item in self._impl._items:
     493 + if version != self._impl._version:
     494 + raise RuntimeError("Dictionary changed during iteration")
     495 + yield item[2]
     496 + 
     497 + def __repr__(self):
     498 + lst = []
     499 + for item in self._impl._items:
     500 + lst.append("{!r}".format(item[2]))
     501 + body = ", ".join(lst)
     502 + return "{}({})".format(self.__class__.__name__, body)
     503 + 
     504 + 
     505 +class _KeysView(_ViewBase, abc.KeysView):
     506 + def __contains__(self, key):
     507 + for item in self._impl._items:
     508 + if item[1] == key:
     509 + return True
     510 + return False
     511 + 
     512 + def __iter__(self):
     513 + return _Iter(len(self), self._iter(self._impl._version))
     514 + 
     515 + def _iter(self, version):
     516 + for item in self._impl._items:
     517 + if version != self._impl._version:
     518 + raise RuntimeError("Dictionary changed during iteration")
     519 + yield item[1]
     520 + 
     521 + def __repr__(self):
     522 + lst = []
     523 + for item in self._impl._items:
     524 + lst.append("{!r}".format(item[1]))
     525 + body = ", ".join(lst)
     526 + return "{}({})".format(self.__class__.__name__, body)
     527 + 
  • ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/multidict/py.typed
     1 +PEP-561 marker.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/nmap/__init__.py
     1 +# -*- coding: latin-1 -*-
     2 + 
     3 +"""
     4 +python-nmap - 2010.12.17
     5 + 
     6 +python-nmap is a python library which helps in using nmap port scanner.
     7 +It allows to easilly manipulate nmap scan results and will be a perfect
     8 +tool for systems administrators who want to automatize scanning task
     9 +and reports. It also supports nmap script outputs.
     10 + 
     11 + 
     12 +Author :
     13 + 
     14 +* Alexandre Norman - [email protected]
     15 + 
     16 +Contributors:
     17 + 
     18 +* Steve 'Ashcrow' Milner - [email protected]
     19 +* Brian Bustin - brian at bustin.us
     20 +* old.schepperhand
     21 +* Johan Lundberg
     22 +* Thomas D. maaaaz
     23 + 
     24 +Licence : GPL v3 or any later version
     25 + 
     26 + 
     27 +This program is free software: you can redistribute it and/or modify
     28 +it under the terms of the GNU General Public License as published by
     29 +the Free Software Foundation, either version 3 of the License, or
     30 +any later version.
     31 + 
     32 +This program is distributed in the hope that it will be useful,
     33 +but WITHOUT ANY WARRANTY; without even the implied warranty of
     34 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     35 +GNU General Public License for more details.
     36 + 
     37 +You should have received a copy of the GNU General Public License
     38 +along with this program. If not, see <http://www.gnu.org/licenses/>.
     39 +"""
     40 + 
     41 +from .nmap import * # noqa
     42 +from .nmap import __author__ # noqa
     43 +from .nmap import __version__ # noqa
     44 +from .nmap import __last_modification__ # noqa
     45 + 
  • vuln_analyzer/lib/python3.11/site-packages/nmap/__pycache__/__init__.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/nmap/__pycache__/nmap.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/nmap/__pycache__/test_nmap.cpython-311.pyc
    Binary file.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/nmap/nmap.py
     1 +#!/usr/bin/env python
     2 +# -*- coding: utf-8 -*-
     3 + 
     4 +"""
     5 +nmap.py - version and date, see below
     6 + 
     7 +Source code : https://bitbucket.org/xael/python-nmap
     8 + 
     9 +Author :
     10 + 
     11 +* Alexandre Norman - norman at xael.org
     12 + 
     13 +Contributors:
     14 + 
     15 +* Steve 'Ashcrow' Milner - steve at gnulinux.net
     16 +* Brian Bustin - brian at bustin.us
     17 +* old.schepperhand
     18 +* Johan Lundberg
     19 +* Thomas D. maaaaz
     20 +* Robert Bost
     21 +* David Peltier
     22 +* Ed Jones
     23 + 
     24 +Licence: GPL v3 or any later version for python-nmap
     25 + 
     26 + 
     27 +This program is free software: you can redistribute it and/or modify
     28 +it under the terms of the GNU General Public License as published by
     29 +the Free Software Foundation, either version 3 of the License, or
     30 +any later version.
     31 + 
     32 +This program is distributed in the hope that it will be useful,
     33 +but WITHOUT ANY WARRANTY; without even the implied warranty of
     34 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     35 +GNU General Public License for more details.
     36 + 
     37 +You should have received a copy of the GNU General Public License
     38 +along with this program. If not, see <http://www.gnu.org/licenses/>.
     39 + 
     40 + 
     41 +**************
     42 +IMPORTANT NOTE
     43 +**************
     44 + 
     45 +The Nmap Security Scanner used by python-nmap is distributed
     46 +under it's own licence that you can find at https://svn.nmap.org/nmap/COPYING
     47 + 
     48 +Any redistribution of python-nmap along with the Nmap Security Scanner
     49 +must conform to the Nmap Security Scanner licence
     50 + 
     51 +"""
     52 +import csv
     53 +import io
     54 +import os
     55 +import re
     56 +import shlex
     57 +import subprocess
     58 +import sys
     59 +from multiprocessing import Process
     60 +from xml.etree import ElementTree as ET
     61 + 
     62 + 
     63 +__author__ = "Alexandre Norman ([email protected])"
     64 +__version__ = "0.7.1"
     65 +__last_modification__ = "2021.10.26"
     66 + 
     67 + 
     68 +############################################################################
     69 + 
     70 + 
     71 +class PortScanner(object):
     72 + """
     73 + PortScanner class allows to use nmap from python
     74 + 
     75 + """
     76 + 
     77 + def __init__(
     78 + self,
     79 + nmap_search_path=(
     80 + "nmap",
     81 + "/usr/bin/nmap",
     82 + "/usr/local/bin/nmap",
     83 + "/sw/bin/nmap",
     84 + "/opt/local/bin/nmap",
     85 + ),
     86 + ):
     87 + """
     88 + Initialize PortScanner module
     89 + 
     90 + * detects nmap on the system and nmap version
     91 + * may raise PortScannerError exception if nmap is not found in the path
     92 + 
     93 + :param nmap_search_path: tupple of string where to search for nmap executable.
     94 + Change this if you want to use a specific version of nmap.
     95 + :returns: nothing
     96 + 
     97 + """
     98 + self._nmap_path = "" # nmap path
     99 + self._scan_result = {}
     100 + self._nmap_version_number = 0 # nmap version number
     101 + self._nmap_subversion_number = 0 # nmap subversion number
     102 + self._nmap_last_output = "" # last full ascii nmap output
     103 + is_nmap_found = False # true if we have found nmap
     104 + 
     105 + self.__process = None
     106 + 
     107 + # regex used to detect nmap (http or https)
     108 + regex = re.compile(r"Nmap version [0-9]*\.[0-9]*[^ ]* \( http(|s)://.* \)")
     109 + # launch 'nmap -V', we wait after
     110 + # > 'Nmap version 5.0 ( http://nmap.org )'
     111 + # This is for Mac OSX. When idle3 is launched from the finder, PATH is not set so nmap was not found
     112 + for nmap_path in nmap_search_path:
     113 + try:
     114 + if (
     115 + sys.platform.startswith("freebsd")
     116 + or sys.platform.startswith("linux")
     117 + or sys.platform.startswith("darwin")
     118 + ):
     119 + p = subprocess.Popen(
     120 + [nmap_path, "-V"],
     121 + bufsize=10000,
     122 + stdout=subprocess.PIPE,
     123 + close_fds=True,
     124 + )
     125 + else:
     126 + p = subprocess.Popen(
     127 + [nmap_path, "-V"], bufsize=10000, stdout=subprocess.PIPE
     128 + )
     129 + 
     130 + except OSError:
     131 + pass
     132 + else:
     133 + self._nmap_path = nmap_path # save path
     134 + break
     135 + else:
     136 + raise PortScannerError(
     137 + f"nmap program was not found in path. PATH is : {os.getenv('PATH')}"
     138 + )
     139 + 
     140 + self._nmap_last_output = bytes.decode(p.communicate()[0]) # sav stdout
     141 + for line in self._nmap_last_output.split(os.linesep):
     142 + if regex.match(line) is not None:
     143 + is_nmap_found = True
     144 + # Search for version number
     145 + regex_version = re.compile("[0-9]+")
     146 + regex_subversion = re.compile(r"\.[0-9]+")
     147 + 
     148 + rv = regex_version.search(line)
     149 + rsv = regex_subversion.search(line)
     150 + 
     151 + if rv is not None and rsv is not None:
     152 + # extract version/subversion
     153 + self._nmap_version_number = int(line[rv.start() : rv.end()])
     154 + self._nmap_subversion_number = int(
     155 + line[rsv.start() + 1 : rsv.end()]
     156 + )
     157 + break
     158 + 
     159 + if not is_nmap_found:
     160 + raise PortScannerError("nmap program was not found in path")
     161 + 
     162 + return
     163 + 
     164 + def get_nmap_last_output(self):
     165 + """
     166 + Returns the last text output of nmap in raw text
     167 + this may be used for debugging purpose
     168 + 
     169 + :returns: string containing the last text output of nmap in raw text
     170 + """
     171 + return self._nmap_last_output
     172 + 
     173 + def nmap_version(self):
     174 + """
     175 + returns nmap version if detected (int version, int subversion)
     176 + or (0, 0) if unknown
     177 + :returns: (nmap_version_number, nmap_subversion_number)
     178 + """
     179 + return (self._nmap_version_number, self._nmap_subversion_number)
     180 + 
     181 + def listscan(self, hosts="127.0.0.1"):
     182 + """
     183 + do not scan but interpret target hosts and return a list a hosts
     184 + """
     185 + assert (
     186 + type(hosts) is str
     187 + ), f"Wrong type for [hosts], should be a string [was {type(hosts)}]"
     188 + output = self.scan(hosts, arguments="-sL")
     189 + # Test if host was IPV6
     190 + if (
     191 + "scaninfo" in output["nmap"]
     192 + and "error" in output["nmap"]["scaninfo"]
     193 + and len(output["nmap"]["scaninfo"]["error"]) > 0
     194 + and "looks like an IPv6 target specification"
     195 + in output["nmap"]["scaninfo"]["error"][0]
     196 + ): # noqa
     197 + self.scan(hosts, arguments="-sL -6")
     198 + 
     199 + return self.all_hosts()
     200 + 
     201 + def scan( # NOQA: CFQ001, C901
     202 + self, hosts="127.0.0.1", ports=None, arguments="-sV", sudo=False, timeout=0
     203 + ):
     204 + """
     205 + Scan given hosts
     206 + 
     207 + May raise PortScannerError exception if nmap output was not xml
     208 + 
     209 + Test existance of the following key to know
     210 + if something went wrong : ['nmap']['scaninfo']['error']
     211 + If not present, everything was ok.
     212 + 
     213 + :param hosts: string for hosts as nmap use it 'scanme.nmap.org' or '198.116.0-255.1-127' or '216.163.128.20/20'
     214 + :param ports: string for ports as nmap use it '22,53,110,143-4564'
     215 + :param arguments: string of arguments for nmap '-sU -sX -sC'
     216 + :param sudo: launch nmap with sudo if True
     217 + :param timeout: int, if > zero, will terminate scan after seconds, otherwise will wait indefintely
     218 + 
     219 + :returns: scan_result as dictionnary
     220 + """
     221 + if sys.version_info[0] == 2:
     222 + assert type(hosts) in (
     223 + str,
     224 + ), f"Wrong type for [hosts], should be a string [was {type(hosts)}]"
     225 + 
     226 + assert type(ports) in (
     227 + str,
     228 + type(None),
     229 + ), f"Wrong type for [ports], should be a string [was {type(ports)}]"
     230 + assert type(arguments) in (
     231 + str,
     232 + ), f"Wrong type for [arguments], should be a string [was {type(arguments)}]"
     233 + else:
     234 + assert (
     235 + type(hosts) is str
     236 + ), f"Wrong type for [hosts], should be a string [was {type(hosts)}]"
     237 + assert type(ports) in (
     238 + str,
     239 + type(None),
     240 + ), f"Wrong type for [ports], should be a string [was {type(ports)}]"
     241 + assert (
     242 + type(arguments) is str
     243 + ), f"Wrong type for [arguments], should be a string [was {type(arguments)}]"
     244 + 
     245 + for redirecting_output in ["-oX", "-oA"]:
     246 + assert (
     247 + redirecting_output not in arguments
     248 + ), "Xml output can't be redirected from command line.\nYou can access it after a scan using:\nnmap.nm.get_nmap_last_output()" # noqa
     249 + 
     250 + h_args = shlex.split(hosts)
     251 + f_args = shlex.split(arguments)
     252 + 
     253 + # Launch scan
     254 + args = (
     255 + [self._nmap_path, "-oX", "-"]
     256 + + h_args
     257 + + ["-p", ports] * (ports is not None)
     258 + + f_args
     259 + )
     260 + if sudo:
     261 + args = ["sudo"] + args
     262 + 
     263 + p = subprocess.Popen(
     264 + args,
     265 + bufsize=100000,
     266 + stdin=subprocess.PIPE,
     267 + stdout=subprocess.PIPE,
     268 + stderr=subprocess.PIPE,
     269 + )
     270 + 
     271 + # wait until finished
     272 + # get output
     273 + # Terminate after user timeout
     274 + if timeout == 0:
     275 + (self._nmap_last_output, nmap_err) = p.communicate()
     276 + else:
     277 + try:
     278 + (self._nmap_last_output, nmap_err) = p.communicate(timeout=timeout)
     279 + except subprocess.TimeoutExpired:
     280 + p.kill()
     281 + raise PortScannerTimeout("Timeout from nmap process")
     282 + 
     283 + nmap_err = bytes.decode(nmap_err)
     284 + 
     285 + # If there was something on stderr, there was a problem so abort... in
     286 + # fact not always. As stated by AlenLPeacock :
     287 + # This actually makes python-nmap mostly unusable on most real-life
     288 + # networks -- a particular subnet might have dozens of scannable hosts,
     289 + # but if a single one is unreachable or unroutable during the scan,
     290 + # nmap.scan() returns nothing. This behavior also diverges significantly
     291 + # from commandline nmap, which simply stderrs individual problems but
     292 + # keeps on trucking.
     293 + 
     294 + nmap_err_keep_trace = []
     295 + nmap_warn_keep_trace = []
     296 + if len(nmap_err) > 0:
     297 + regex_warning = re.compile("^Warning: .*", re.IGNORECASE)
     298 + for line in nmap_err.split(os.linesep):
     299 + if len(line) > 0:
     300 + rgw = regex_warning.search(line)
     301 + if rgw is not None:
     302 + nmap_warn_keep_trace.append(line + os.linesep)
     303 + else:
     304 + nmap_err_keep_trace.append(nmap_err)
     305 + 
     306 + return self.analyse_nmap_xml_scan(
     307 + nmap_xml_output=self._nmap_last_output,
     308 + nmap_err=nmap_err,
     309 + nmap_err_keep_trace=nmap_err_keep_trace,
     310 + nmap_warn_keep_trace=nmap_warn_keep_trace,
     311 + )
     312 + 
     313 + def analyse_nmap_xml_scan( # NOQA: CFQ001, C901
     314 + self,
     315 + nmap_xml_output=None,
     316 + nmap_err="",
     317 + nmap_err_keep_trace="",
     318 + nmap_warn_keep_trace="",
     319 + ):
     320 + """
     321 + Analyses NMAP xml scan ouput
     322 + 
     323 + May raise PortScannerError exception if nmap output was not xml
     324 + 
     325 + Test existance of the following key to know if something went wrong : ['nmap']['scaninfo']['error']
     326 + If not present, everything was ok.
     327 + 
     328 + :param nmap_xml_output: xml string to analyse
     329 + :returns: scan_result as dictionnary
     330 + """
     331 + 
     332 + # nmap xml output looks like :
     333 + # <host starttime="1267974521" endtime="1267974522">
     334 + # <status state="up" reason="user-set"/>
     335 + # <address addr="192.168.1.1" addrtype="ipv4" />
     336 + # <hostnames><hostname name="neufbox" type="PTR" /></hostnames>
     337 + # <ports>
     338 + # <port protocol="tcp" portid="22">
     339 + # <state state="filtered" reason="no-response" reason_ttl="0"/>
     340 + # <service name="ssh" method="table" conf="3" />
     341 + # </port>
     342 + # <port protocol="tcp" portid="25">
     343 + # <state state="filtered" reason="no-response" reason_ttl="0"/>
     344 + # <service name="smtp" method="table" conf="3" />
     345 + # </port>
     346 + # </ports>
     347 + # <hostscript>
     348 + # <script id="nbstat" output="NetBIOS name: GROSTRUC, NetBIOS user: &lt;unknown&gt;, NetBIOS MAC: &lt;unknown&gt;&#xa;" /> # NOQA: E501
     349 + # <script id="smb-os-discovery" output=" &#xa; OS: Unix (Samba 3.6.3)&#xa; Name: WORKGROUP\Unknown&#xa; System time: 2013-06-23 15:37:40 UTC+2&#xa;" /> # NOQA: E501
     350 + # <script id="smbv2-enabled" output="Server doesn&apos;t support SMBv2 protocol" />
     351 + # </hostscript>
     352 + # <times srtt="-1" rttvar="-1" to="1000000" />
     353 + # </host>
     354 + 
     355 + # <port protocol="tcp" portid="25">
     356 + # <state state="open" reason="syn-ack" reason_ttl="0"/>
     357 + # <service name="smtp" product="Exim smtpd" version="4.76" hostname="grostruc" method="probed" conf="10">
     358 + # <cpe>cpe:/a:exim:exim:4.76</cpe>
     359 + # </service>
     360 + # <script id="smtp-commands" output="grostruc Hello localhost [127.0.0.1], SIZE 52428800, PIPELINING, HELP, &#xa; Commands supported: AUTH HELO EHLO MAIL RCPT DATA NOOP QUIT RSET HELP "/> # NOQA: E501
     361 + # </port>
     362 + 
     363 + if nmap_xml_output is not None:
     364 + self._nmap_last_output = nmap_xml_output
     365 + 
     366 + scan_result = {}
     367 + 
     368 + try:
     369 + dom = ET.fromstring(self._nmap_last_output)
     370 + except Exception:
     371 + if len(nmap_err) > 0:
     372 + raise PortScannerError(nmap_err)
     373 + else:
     374 + raise PortScannerError(self._nmap_last_output)
     375 + 
     376 + # nmap command line
     377 + scan_result["nmap"] = {
     378 + "command_line": dom.get("args"),
     379 + "scaninfo": {},
     380 + "scanstats": {
     381 + "timestr": dom.find("runstats/finished").get("timestr"),
     382 + "elapsed": dom.find("runstats/finished").get("elapsed"),
     383 + "uphosts": dom.find("runstats/hosts").get("up"),
     384 + "downhosts": dom.find("runstats/hosts").get("down"),
     385 + "totalhosts": dom.find("runstats/hosts").get("total"),
     386 + },
     387 + }
     388 + 
     389 + # if there was an error
     390 + if len(nmap_err_keep_trace) > 0:
     391 + scan_result["nmap"]["scaninfo"]["error"] = nmap_err_keep_trace
     392 + 
     393 + # if there was a warning
     394 + if len(nmap_warn_keep_trace) > 0:
     395 + scan_result["nmap"]["scaninfo"]["warning"] = nmap_warn_keep_trace
     396 + 
     397 + # info about scan
     398 + for dsci in dom.findall("scaninfo"):
     399 + scan_result["nmap"]["scaninfo"][dsci.get("protocol")] = {
     400 + "method": dsci.get("type"),
     401 + "services": dsci.get("services"),
     402 + }
     403 + 
     404 + scan_result["scan"] = {}
     405 + 
     406 + for dhost in dom.findall("host"):
     407 + # host ip, mac and other addresses
     408 + host = None
     409 + address_block = {}
     410 + vendor_block = {}
     411 + for address in dhost.findall("address"):
     412 + addtype = address.get("addrtype")
     413 + address_block[addtype] = address.get("addr")
     414 + if addtype == "ipv4":
     415 + host = address_block[addtype]
     416 + elif addtype == "mac" and address.get("vendor") is not None:
     417 + vendor_block[address_block[addtype]] = address.get("vendor")
     418 + 
     419 + if host is None:
     420 + host = dhost.find("address").get("addr")
     421 + 
     422 + hostnames = []
     423 + if len(dhost.findall("hostnames/hostname")) > 0:
     424 + for dhostname in dhost.findall("hostnames/hostname"):
     425 + hostnames.append(
     426 + {"name": dhostname.get("name"), "type": dhostname.get("type")}
     427 + )
     428 + else:
     429 + hostnames.append({"name": "", "type": ""})
     430 + 
     431 + scan_result["scan"][host] = PortScannerHostDict({"hostnames": hostnames})
     432 + 
     433 + scan_result["scan"][host]["addresses"] = address_block
     434 + scan_result["scan"][host]["vendor"] = vendor_block
     435 + 
     436 + for dstatus in dhost.findall("status"):
     437 + # status : up...
     438 + scan_result["scan"][host]["status"] = {
     439 + "state": dstatus.get("state"),
     440 + "reason": dstatus.get("reason"),
     441 + }
     442 + for dstatus in dhost.findall("uptime"):
     443 + # uptime : seconds, lastboot
     444 + scan_result["scan"][host]["uptime"] = {
     445 + "seconds": dstatus.get("seconds"),
     446 + "lastboot": dstatus.get("lastboot"),
     447 + }
     448 + for dport in dhost.findall("ports/port"):
     449 + # protocol
     450 + proto = dport.get("protocol")
     451 + # port number converted as integer
     452 + port = int(dport.get("portid"))
     453 + # state of the port
     454 + state = dport.find("state").get("state")
     455 + # reason
     456 + reason = dport.find("state").get("reason")
     457 + # name, product, version, extra info and conf if any
     458 + name = product = version = extrainfo = conf = cpe = ""
     459 + for dname in dport.findall("service"):
     460 + name = dname.get("name")
     461 + if dname.get("product"):
     462 + product = dname.get("product")
     463 + if dname.get("version"):
     464 + version = dname.get("version")
     465 + if dname.get("extrainfo"):
     466 + extrainfo = dname.get("extrainfo")
     467 + if dname.get("conf"):
     468 + conf = dname.get("conf")
     469 + 
     470 + for dcpe in dname.findall("cpe"):
     471 + cpe = dcpe.text
     472 + # store everything
     473 + if proto not in list(scan_result["scan"][host].keys()):
     474 + scan_result["scan"][host][proto] = {}
     475 + 
     476 + scan_result["scan"][host][proto][port] = {
     477 + "state": state,
     478 + "reason": reason,
     479 + "name": name,
     480 + "product": product,
     481 + "version": version,
     482 + "extrainfo": extrainfo,
     483 + "conf": conf,
     484 + "cpe": cpe,
     485 + }
     486 + script_id = ""
     487 + script_out = ""
     488 + # get script output if any
     489 + for dscript in dport.findall("script"):
     490 + script_id = dscript.get("id")
     491 + script_out = dscript.get("output")
     492 + if "script" not in list(
     493 + scan_result["scan"][host][proto][port].keys()
     494 + ):
     495 + scan_result["scan"][host][proto][port]["script"] = {}
     496 + 
     497 + scan_result["scan"][host][proto][port]["script"][
     498 + script_id
     499 + ] = script_out
     500 + 
     501 + # <hostscript>
     502 + # <script id="nbstat" output="NetBIOS name: GROSTRUC, NetBIOS user: &lt;unknown&gt;, NetBIOS MAC: &lt;unknown&gt;&#xa;" /> # NOQA: E501
     503 + # <script id="smb-os-discovery" output=" &#xa; OS: Unix (Samba 3.6.3)&#xa; Name: WORKGROUP\Unknown&#xa; System time: 2013-06-23 15:37:40 UTC+2&#xa;" /> # NOQA: E501
     504 + # <script id="smbv2-enabled" output="Server doesn&apos;t support SMBv2 protocol" />
     505 + # </hostscript>
     506 + for dhostscript in dhost.findall("hostscript"):
     507 + for dname in dhostscript.findall("script"):
     508 + hsid = dname.get("id")
     509 + hsoutput = dname.get("output")
     510 + 
     511 + if "hostscript" not in list(scan_result["scan"][host].keys()):
     512 + scan_result["scan"][host]["hostscript"] = []
     513 + 
     514 + scan_result["scan"][host]["hostscript"].append(
     515 + {"id": hsid, "output": hsoutput}
     516 + )
     517 + 
     518 + # <osmatch name="Juniper SA4000 SSL VPN gateway (IVE OS 7.0)" accuracy="98" line="36241">
     519 + # <osclass type="firewall" vendor="Juniper" osfamily="IVE OS" osgen="7.X"
     520 + # accuracy="98"><cpe>cpe:/h:juniper:sa4000</cpe><cpe>cpe:/o:juniper:ive_os:7</cpe></osclass>
     521 + # </osmatch>
     522 + # <osmatch name="Cymphonix EX550 firewall" accuracy="98" line="17929">
     523 + # <osclass type="firewall" vendor="Cymphonix" osfamily="embedded"
     524 + # accuracy="98"><cpe>cpe:/h:cymphonix:ex550</cpe></osclass>
     525 + # </osmatch>
     526 + for dos in dhost.findall("os"):
     527 + osmatch = []
     528 + portused = []
     529 + for dportused in dos.findall("portused"):
     530 + # <portused state="open" proto="tcp" portid="443"/>
     531 + state = dportused.get("state")
     532 + proto = dportused.get("proto")
     533 + portid = dportused.get("portid")
     534 + portused.append({"state": state, "proto": proto, "portid": portid})
     535 + 
     536 + scan_result["scan"][host]["portused"] = portused
     537 + 
     538 + for dosmatch in dos.findall("osmatch"):
     539 + # <osmatch name="Linux 3.7 - 3.15" accuracy="100" line="52790">
     540 + name = dosmatch.get("name")
     541 + accuracy = dosmatch.get("accuracy")
     542 + line = dosmatch.get("line")
     543 + 
     544 + osclass = []
     545 + for dosclass in dosmatch.findall("osclass"):
     546 + # <osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="98"/>
     547 + ostype = dosclass.get("type")
     548 + vendor = dosclass.get("vendor")
     549 + osfamily = dosclass.get("osfamily")
     550 + osgen = dosclass.get("osgen")
     551 + accuracy = dosclass.get("accuracy")
     552 + 
     553 + cpe = []
     554 + for dcpe in dosclass.findall("cpe"):
     555 + cpe.append(dcpe.text)
     556 + 
     557 + osclass.append(
     558 + {
     559 + "type": ostype,
     560 + "vendor": vendor,
     561 + "osfamily": osfamily,
     562 + "osgen": osgen,
     563 + "accuracy": accuracy,
     564 + "cpe": cpe,
     565 + }
     566 + )
     567 + 
     568 + osmatch.append(
     569 + {
     570 + "name": name,
     571 + "accuracy": accuracy,
     572 + "line": line,
     573 + "osclass": osclass,
     574 + }
     575 + )
     576 + else:
     577 + scan_result["scan"][host]["osmatch"] = osmatch
     578 + 
     579 + for dport in dhost.findall("osfingerprint"):
     580 + # <osfingerprint fingerprint="OS:SCAN(V=5.50%D=11/[...]S)&#xa;"/>
     581 + fingerprint = dport.get("fingerprint")
     582 + 
     583 + scan_result["scan"][host]["fingerprint"] = fingerprint
     584 + 
     585 + self._scan_result = scan_result # store for later use
     586 + return scan_result
     587 + 
     588 + def __getitem__(self, host):
     589 + """
     590 + returns a host detail
     591 + """
     592 + if sys.version_info[0] == 2:
     593 + assert type(host) in (
     594 + str,
     595 + ), f"Wrong type for [host], should be a string [was {type(host)}]"
     596 + else:
     597 + assert (
     598 + type(host) is str
     599 + ), f"Wrong type for [host], should be a string [was {type(host)}]"
     600 + return self._scan_result["scan"][host]
     601 + 
     602 + def all_hosts(self):
     603 + """
     604 + returns a sorted list of all hosts
     605 + """
     606 + if "scan" not in list(self._scan_result.keys()):
     607 + return []
     608 + listh = list(self._scan_result["scan"].keys())
     609 + listh.sort()
     610 + return listh
     611 + 
     612 + def command_line(self):
     613 + """
     614 + returns command line used for the scan
     615 + 
     616 + may raise AssertionError exception if called before scanning
     617 + """
     618 + assert "nmap" in self._scan_result, "Do a scan before trying to get result !"
     619 + assert (
     620 + "command_line" in self._scan_result["nmap"]
     621 + ), "Do a scan before trying to get result !"
     622 + 
     623 + return self._scan_result["nmap"]["command_line"]
     624 + 
     625 + def scaninfo(self):
     626 + """
     627 + returns scaninfo structure
     628 + {'tcp': {'services': '22', 'method': 'connect'}}
     629 + 
     630 + may raise AssertionError exception if called before scanning
     631 + """
     632 + assert "nmap" in self._scan_result, "Do a scan before trying to get result !"
     633 + assert (
     634 + "scaninfo" in self._scan_result["nmap"]
     635 + ), "Do a scan before trying to get result !"
     636 + 
     637 + return self._scan_result["nmap"]["scaninfo"]
     638 + 
     639 + def scanstats(self):
     640 + """
     641 + returns scanstats structure
     642 + {'uphosts': '3', 'timestr': 'Thu Jun 3 21:45:07 2010', 'downhosts': '253', 'totalhosts': '256', 'elapsed': '5.79'} # NOQA: E501
     643 + 
     644 + may raise AssertionError exception if called before scanning
     645 + """
     646 + assert "nmap" in self._scan_result, "Do a scan before trying to get result !"
     647 + assert (
     648 + "scanstats" in self._scan_result["nmap"]
     649 + ), "Do a scan before trying to get result !"
     650 + 
     651 + return self._scan_result["nmap"]["scanstats"]
     652 + 
     653 + def has_host(self, host):
     654 + """
     655 + returns True if host has result, False otherwise
     656 + """
     657 + assert (
     658 + type(host) is str
     659 + ), f"Wrong type for [host], should be a string [was {type(host)}]"
     660 + assert "scan" in self._scan_result, "Do a scan before trying to get result !"
     661 + 
     662 + if host in list(self._scan_result["scan"].keys()):
     663 + return True
     664 + 
     665 + return False
     666 + 
     667 + def csv(self):
     668 + """
     669 + returns CSV output as text
     670 + 
     671 + Example :
     672 + host;hostname;hostname_type;protocol;port;name;state;product;extrainfo;reason;version;conf;cpe
     673 + 127.0.0.1;localhost;PTR;tcp;22;ssh;open;OpenSSH;protocol 2.0;syn-ack;5.9p1 Debian 5ubuntu1;10;cpe
     674 + 127.0.0.1;localhost;PTR;tcp;23;telnet;closed;;;conn-refused;;3;
     675 + 127.0.0.1;localhost;PTR;tcp;24;priv-mail;closed;;;conn-refused;;3;
     676 + """
     677 + assert "scan" in self._scan_result, "Do a scan before trying to get result !"
     678 + 
     679 + if sys.version_info < (3, 0):
     680 + fd = io.BytesIO()
     681 + else:
     682 + fd = io.StringIO()
     683 + 
     684 + csv_ouput = csv.writer(fd, delimiter=";")
     685 + csv_header = [
     686 + "host",
     687 + "hostname",
     688 + "hostname_type",
     689 + "protocol",
     690 + "port",
     691 + "name",
     692 + "state",
     693 + "product",
     694 + "extrainfo",
     695 + "reason",
     696 + "version",
     697 + "conf",
     698 + "cpe",
     699 + ]
     700 + 
     701 + csv_ouput.writerow(csv_header)
     702 + 
     703 + for host in self.all_hosts():
     704 + for proto in self[host].all_protocols():
     705 + if proto not in ["tcp", "udp"]:
     706 + continue
     707 + lport = list(self[host][proto].keys())
     708 + lport.sort()
     709 + for port in lport:
     710 + hostname = ""
     711 + for h in self[host]["hostnames"]:
     712 + hostname = h["name"]
     713 + hostname_type = h["type"]
     714 + csv_row = [
     715 + host,
     716 + hostname,
     717 + hostname_type,
     718 + proto,
     719 + port,
     720 + self[host][proto][port]["name"],
     721 + self[host][proto][port]["state"],
     722 + self[host][proto][port]["product"],
     723 + self[host][proto][port]["extrainfo"],
     724 + self[host][proto][port]["reason"],
     725 + self[host][proto][port]["version"],
     726 + self[host][proto][port]["conf"],
     727 + self[host][proto][port]["cpe"],
     728 + ]
     729 + csv_ouput.writerow(csv_row)
     730 + 
     731 + return fd.getvalue()
     732 + 
     733 + 
     734 +############################################################################
     735 + 
     736 + 
     737 +def __scan_progressive__( # NOQA: CFQ002
     738 + self, hosts, ports, arguments, callback, sudo, timeout
     739 +):
     740 + """
     741 + Used by PortScannerAsync for callback
     742 + """
     743 + for host in self._nm.listscan(hosts):
     744 + try:
     745 + scan_data = self._nm.scan(host, ports, arguments, sudo, timeout)
     746 + except PortScannerError:
     747 + scan_data = None
     748 + 
     749 + if callback is not None:
     750 + callback(host, scan_data)
     751 + return
     752 + 
     753 + 
     754 +############################################################################
     755 + 
     756 + 
     757 +class PortScannerAsync(object):
     758 + """
     759 + PortScannerAsync allows to use nmap from python asynchronously
     760 + for each host scanned, callback is called with scan result for the host
     761 + 
     762 + """
     763 + 
     764 + def __init__(self):
     765 + """
     766 + Initialize the module
     767 + 
     768 + * detects nmap on the system and nmap version
     769 + * may raise PortScannerError exception if nmap is not found in the path
     770 + 
     771 + """
     772 + self._process = None
     773 + self._nm = PortScanner()
     774 + return
     775 + 
     776 + def __del__(self):
     777 + """
     778 + Cleanup when deleted
     779 + 
     780 + """
     781 + if self._process is not None:
     782 + try:
     783 + if self._process.is_alive():
     784 + self._process.terminate()
     785 + except AssertionError:
     786 + # Happens on python3.4
     787 + # when using PortScannerAsync twice in a row
     788 + pass
     789 + 
     790 + self._process = None
     791 + return
     792 + 
     793 + def scan( # NOQA: CFQ002
     794 + self,
     795 + hosts="127.0.0.1",
     796 + ports=None,
     797 + arguments="-sV",
     798 + callback=None,
     799 + sudo=False,
     800 + timeout=0,
     801 + ):
     802 + """
     803 + Scan given hosts in a separate process and return host by host result using callback function
     804 + 
     805 + PortScannerError exception from standard nmap is catched and you won't know about but get None as scan_data
     806 + 
     807 + :param hosts: string for hosts as nmap use it 'scanme.nmap.org' or '198.116.0-255.1-127' or '216.163.128.20/20'
     808 + :param ports: string for ports as nmap use it '22,53,110,143-4564'
     809 + :param arguments: string of arguments for nmap '-sU -sX -sC'
     810 + :param callback: callback function which takes (host, scan_data) as arguments
     811 + :param sudo: launch nmap with sudo if true
     812 + :param timeout: int, if > zero, will terminate scan after seconds, otherwise will wait indefintely
     813 + 
     814 + """
     815 + 
     816 + if sys.version_info[0] == 2:
     817 + assert type(hosts) in (
     818 + str,
     819 + ), f"Wrong type for [hosts], should be a string [was {type(hosts)}]"
     820 + assert type(ports) in (
     821 + str,
     822 + type(None),
     823 + ), f"Wrong type for [ports], should be a string [was {type(ports)}]"
     824 + assert type(arguments) in (
     825 + str,
     826 + ), f"Wrong type for [arguments], should be a string [was {type(arguments)}]"
     827 + else:
     828 + assert (
     829 + type(hosts) is str
     830 + ), f"Wrong type for [hosts], should be a string [was {type(hosts)}]"
     831 + assert type(ports) in (
     832 + str,
     833 + type(None),
     834 + ), f"Wrong type for [ports], should be a string [was {type(ports)}]"
     835 + assert (
     836 + type(arguments) is str
     837 + ), f"Wrong type for [arguments], should be a string [was {type(arguments)}]"
     838 + 
     839 + assert (
     840 + callable(callback) or callback is None
     841 + ), f"The [callback] {str(callback)} should be callable or None."
     842 + 
     843 + for redirecting_output in ["-oX", "-oA"]:
     844 + assert (
     845 + redirecting_output not in arguments
     846 + ), "Xml output can't be redirected from command line.\nYou can access it after a scan using:\nnmap.nm.get_nmap_last_output()" # NOQA: E501
     847 + 
     848 + self._process = Process(
     849 + target=__scan_progressive__,
     850 + args=(self, hosts, ports, arguments, callback, sudo, timeout),
     851 + )
     852 + self._process.daemon = True
     853 + self._process.start()
     854 + return
     855 + 
     856 + def stop(self):
     857 + """
     858 + Stop the current scan process
     859 + 
     860 + """
     861 + if self._process is not None:
     862 + self._process.terminate()
     863 + return
     864 + 
     865 + def wait(self, timeout=None):
     866 + """
     867 + Wait for the current scan process to finish, or timeout
     868 + 
     869 + :param timeout: default = None, wait timeout seconds
     870 + 
     871 + """
     872 + assert type(timeout) in (
     873 + int,
     874 + type(None),
     875 + ), f"Wrong type for [timeout], should be an int or None [was {type(timeout)}]"
     876 + 
     877 + self._process.join(timeout)
     878 + return
     879 + 
     880 + def still_scanning(self):
     881 + """
     882 + :returns: True if a scan is currently running, False otherwise
     883 + 
     884 + """
     885 + try:
     886 + return self._process.is_alive()
     887 + except Exception:
     888 + return False
     889 + 
     890 + 
     891 +############################################################################
     892 + 
     893 + 
     894 +class PortScannerYield(PortScannerAsync):
     895 + """
     896 + PortScannerYield allows to use nmap from python with a generator
     897 + for each host scanned, yield is called with scan result for the host
     898 + 
     899 + """
     900 + 
     901 + def __init__(self):
     902 + """
     903 + Initialize the module
     904 + 
     905 + * detects nmap on the system and nmap version
     906 + * may raise PortScannerError exception if nmap is not found in the path
     907 + 
     908 + """
     909 + PortScannerAsync.__init__(self)
     910 + return
     911 + 
     912 + def scan(
     913 + self, hosts="127.0.0.1", ports=None, arguments="-sV", sudo=False, timeout=0
     914 + ):
     915 + """
     916 + Scan given hosts in a separate process and return host by host result using callback function
     917 + 
     918 + PortScannerError exception from standard nmap is catched and you won't know about it
     919 + 
     920 + :param hosts: string for hosts as nmap use it 'scanme.nmap.org' or '198.116.0-255.1-127' or '216.163.128.20/20'
     921 + :param ports: string for ports as nmap use it '22,53,110,143-4564'
     922 + :param arguments: string of arguments for nmap '-sU -sX -sC'
     923 + :param callback: callback function which takes (host, scan_data) as arguments
     924 + :param sudo: launch nmap with sudo if true
     925 + :param timeout: int, if > zero, will terminate scan after seconds, otherwise will wait indefintely
     926 + 
     927 + """
     928 + 
     929 + assert (
     930 + type(hosts) is str
     931 + ), f"Wrong type for [hosts], should be a string [was {type(hosts)}]"
     932 + assert type(ports) in (
     933 + str,
     934 + type(None),
     935 + ), f"Wrong type for [ports], should be a string [was {type(ports)}]"
     936 + assert (
     937 + type(arguments) is str
     938 + ), f"Wrong type for [arguments], should be a string [was {type(arguments)}]"
     939 + 
     940 + for redirecting_output in ["-oX", "-oA"]:
     941 + assert (
     942 + redirecting_output not in arguments
     943 + ), "Xml output can't be redirected from command line.\nYou can access it after a scan using:\nnmap.nm.get_nmap_last_output()" # NOQA: E501
     944 + 
     945 + for host in self._nm.listscan(hosts):
     946 + try:
     947 + scan_data = self._nm.scan(host, ports, arguments, sudo, timeout)
     948 + except PortScannerError:
     949 + scan_data = None
     950 + yield (host, scan_data)
     951 + return
     952 + 
     953 + def stop(self):
     954 + pass
     955 + 
     956 + def wait(self, timeout=None):
     957 + pass
     958 + 
     959 + def still_scanning(self):
     960 + pass
     961 + 
     962 + 
     963 +############################################################################
     964 + 
     965 + 
     966 +class PortScannerHostDict(dict):
     967 + """
     968 + Special dictionnary class for storing and accessing host scan result
     969 + 
     970 + """
     971 + 
     972 + def hostnames(self):
     973 + """
     974 + :returns: list of hostnames
     975 + 
     976 + """
     977 + return self["hostnames"]
     978 + 
     979 + def hostname(self):
     980 + """
     981 + For compatibility purpose...
     982 + :returns: try to return the user record or the first hostname of the list hostnames
     983 + 
     984 + """
     985 + hostname = ""
     986 + for h in self["hostnames"]:
     987 + if h["type"] == "user":
     988 + return h["name"]
     989 + else:
     990 + if len(self["hostnames"]) > 0 and "name" in self["hostnames"][0]:
     991 + return self["hostnames"][0]["name"]
     992 + else:
     993 + return ""
     994 + 
     995 + return hostname
     996 + 
     997 + def state(self):
     998 + """
     999 + :returns: host state
     1000 + 
     1001 + """
     1002 + return self["status"]["state"]
     1003 + 
     1004 + def uptime(self):
     1005 + """
     1006 + :returns: host state
     1007 + 
     1008 + """
     1009 + return self["uptime"]
     1010 + 
     1011 + def all_protocols(self):
     1012 + """
     1013 + :returns: a list of all scanned protocols
     1014 + 
     1015 + """
     1016 + 
     1017 + def _proto_filter(x):
     1018 + return x in ["ip", "tcp", "udp", "sctp"]
     1019 + 
     1020 + lp = list(filter(_proto_filter, list(self.keys())))
     1021 + lp.sort()
     1022 + return lp
     1023 + 
     1024 + def all_tcp(self):
     1025 + """
     1026 + :returns: list of tcp ports
     1027 + 
     1028 + """
     1029 + if "tcp" in list(self.keys()):
     1030 + ltcp = list(self["tcp"].keys())
     1031 + ltcp.sort()
     1032 + return ltcp
     1033 + return []
     1034 + 
     1035 + def has_tcp(self, port):
     1036 + """
     1037 + :param port: (int) tcp port
     1038 + :returns: True if tcp port has info, False otherwise
     1039 + 
     1040 + """
     1041 + assert (
     1042 + type(port) is int
     1043 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1044 + 
     1045 + if "tcp" in list(self.keys()) and port in list(self["tcp"].keys()):
     1046 + return True
     1047 + return False
     1048 + 
     1049 + def tcp(self, port):
     1050 + """
     1051 + :param port: (int) tcp port
     1052 + :returns: info for tpc port
     1053 + 
     1054 + """
     1055 + assert (
     1056 + type(port) is int
     1057 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1058 + return self["tcp"][port]
     1059 + 
     1060 + def all_udp(self):
     1061 + """
     1062 + :returns: list of udp ports
     1063 + 
     1064 + """
     1065 + if "udp" in list(self.keys()):
     1066 + ludp = list(self["udp"].keys())
     1067 + ludp.sort()
     1068 + return ludp
     1069 + return []
     1070 + 
     1071 + def has_udp(self, port):
     1072 + """
     1073 + :param port: (int) udp port
     1074 + :returns: True if udp port has info, False otherwise
     1075 + 
     1076 + """
     1077 + assert (
     1078 + type(port) is int
     1079 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1080 + 
     1081 + if "udp" in list(self.keys()) and "port" in list(self["udp"].keys()):
     1082 + return True
     1083 + return False
     1084 + 
     1085 + def udp(self, port):
     1086 + """
     1087 + :param port: (int) udp port
     1088 + :returns: info for udp port
     1089 + 
     1090 + """
     1091 + assert (
     1092 + type(port) is int
     1093 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1094 + 
     1095 + return self["udp"][port]
     1096 + 
     1097 + def all_ip(self):
     1098 + """
     1099 + :returns: list of ip ports
     1100 + 
     1101 + """
     1102 + if "ip" in list(self.keys()):
     1103 + lip = list(self["ip"].keys())
     1104 + lip.sort()
     1105 + return lip
     1106 + return []
     1107 + 
     1108 + def has_ip(self, port):
     1109 + """
     1110 + :param port: (int) ip port
     1111 + :returns: True if ip port has info, False otherwise
     1112 + 
     1113 + """
     1114 + assert (
     1115 + type(port) is int
     1116 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1117 + 
     1118 + if "ip" in list(self.keys()) and port in list(self["ip"].keys()):
     1119 + return True
     1120 + return False
     1121 + 
     1122 + def ip(self, port):
     1123 + """
     1124 + :param port: (int) ip port
     1125 + :returns: info for ip port
     1126 + 
     1127 + """
     1128 + assert (
     1129 + type(port) is int
     1130 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1131 + 
     1132 + return self["ip"][port]
     1133 + 
     1134 + def all_sctp(self):
     1135 + """
     1136 + :returns: list of sctp ports
     1137 + 
     1138 + """
     1139 + if "sctp" in list(self.keys()):
     1140 + lsctp = list(self["sctp"].keys())
     1141 + lsctp.sort()
     1142 + return lsctp
     1143 + return []
     1144 + 
     1145 + def has_sctp(self, port):
     1146 + """
     1147 + :returns: True if sctp port has info, False otherwise
     1148 + 
     1149 + """
     1150 + assert (
     1151 + type(port) is int
     1152 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1153 + 
     1154 + if "sctp" in list(self.keys()) and port in list(self["sctp"].keys()):
     1155 + return True
     1156 + return False
     1157 + 
     1158 + def sctp(self, port):
     1159 + """
     1160 + :returns: info for sctp port
     1161 + 
     1162 + """
     1163 + assert (
     1164 + type(port) is int
     1165 + ), f"Wrong type for [port], should be an int [was {type(port)}]"
     1166 + 
     1167 + return self["sctp"][port]
     1168 + 
     1169 + 
     1170 +############################################################################
     1171 + 
     1172 + 
     1173 +class PortScannerError(Exception):
     1174 + """
     1175 + Exception error class for PortScanner class
     1176 + 
     1177 + """
     1178 + 
     1179 + def __init__(self, value):
     1180 + self.value = value
     1181 + 
     1182 + def __str__(self):
     1183 + return repr(self.value)
     1184 + 
     1185 + def __repr__(self):
     1186 + return f"PortScannerError exception {self.value}"
     1187 + 
     1188 + 
     1189 +class PortScannerTimeout(PortScannerError):
     1190 + pass
     1191 + 
     1192 + 
     1193 +############################################################################
     1194 + 
     1195 + 
     1196 +def __get_last_online_version():
     1197 + """
     1198 + Gets last python-nmap published version
     1199 + 
     1200 + WARNING : it does an http connection to http://xael.org/pages/python-nmap/python-nmap_CURRENT_VERSION.txt
     1201 + 
     1202 + :returns: a string which indicate last published version (example :'0.4.3')
     1203 + 
     1204 + """
     1205 + import http.client
     1206 + 
     1207 + conn = http.client.HTTPConnection("xael.org")
     1208 + conn.request("GET", "/pages/python-nmap/python-nmap_CURRENT_VERSION.txt")
     1209 + online_version = bytes.decode(conn.getresponse().read()).strip()
     1210 + return online_version
     1211 + 
     1212 + 
     1213 +############################################################################
     1214 + 
     1215 + 
     1216 +def convert_nmap_output_to_encoding(value, code="ascii"):
     1217 + """
     1218 + Change encoding for scan_result object from unicode to whatever
     1219 + 
     1220 + :param value: scan_result as dictionnary
     1221 + :param code: default = "ascii", encoding destination
     1222 + 
     1223 + :returns: scan_result as dictionnary with new encoding
     1224 + """
     1225 + new_value = {}
     1226 + for k in value:
     1227 + if type(value[k]) in [dict, PortScannerHostDict]:
     1228 + new_value[k] = convert_nmap_output_to_encoding(value[k], code)
     1229 + else:
     1230 + if type(value[k]) is list:
     1231 + new_value[k] = [
     1232 + convert_nmap_output_to_encoding(x, code) for x in value[k]
     1233 + ]
     1234 + else:
     1235 + new_value[k] = value[k].encode(code)
     1236 + return new_value
     1237 + 
     1238 + 
     1239 +# <EOF>######################################################################
     1240 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/nmap/test_nmap.py
     1 +#!/usr/bin/env python3
     2 +# -*- coding: utf-8 -*-
     3 + 
     4 +import nmap
     5 +import datetime
     6 +import os
     7 + 
     8 +from nose.tools import assert_equals
     9 +from nose.tools import raises
     10 +from nose import with_setup
     11 + 
     12 +from multiprocessing import Value
     13 + 
     14 +"""
     15 +test_nmap.py - tests cases for python-nmap
     16 + 
     17 +Source code : https://bitbucket.org/xael/python-nmap
     18 + 
     19 +Author :
     20 + 
     21 +* Alexandre Norman - norman at xael.org
     22 + 
     23 +Contributors:
     24 + 
     25 +* Steve 'Ashcrow' Milner - steve at gnulinux.net
     26 +* Brian Bustin - brian at bustin.us
     27 +* old.schepperhand
     28 +* Johan Lundberg
     29 +* Thomas D. maaaaz
     30 +* Robert Bost
     31 +
     32 +Licence : GPL v3 or any later version
     33 + 
     34 + 
     35 +This program is free software: you can redistribute it and/or modify
     36 +it under the terms of the GNU General Public License as published by
     37 +the Free Software Foundation, either version 3 of the License, or
     38 +any later version.
     39 + 
     40 +This program is distributed in the hope that it will be useful,
     41 +but WITHOUT ANY WARRANTY; without even the implied warranty of
     42 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     43 +GNU General Public License for more details.
     44 + 
     45 +You should have received a copy of the GNU General Public License
     46 +along with this program. If not, see <http://www.gnu.org/licenses/>.
     47 + 
     48 + 
     49 +"""
     50 + 
     51 +##########################################################################################
     52 + 
     53 +"""
     54 +This plugin provides ``--pdb`` and ``--pdb-failures`` options. The ``--pdb``
     55 +option will drop the test runner into pdb when it encounters an error. To
     56 +drop into pdb on failure, use ``--pdb-failures``.
     57 +"""
     58 + 
     59 +import pdb
     60 +from nose.plugins.base import Plugin
     61 + 
     62 + 
     63 +class Pdb(Plugin):
     64 + """
     65 + Provides --pdb and --pdb-failures options that cause the test runner to
     66 + drop into pdb if it encounters an error or failure, respectively.
     67 + """
     68 + 
     69 + enabled_for_errors = False
     70 + enabled_for_failures = False
     71 + score = 5 # run last, among builtins
     72 + 
     73 + def options(self, parser, env):
     74 + """Register commandline options.
     75 + """
     76 + parser.add_option(
     77 + "--pdb",
     78 + action="store_true",
     79 + dest="debugBoth",
     80 + default=env.get("NOSE_PDB", False),
     81 + help="Drop into debugger on failures or errors",
     82 + )
     83 + parser.add_option(
     84 + "--pdb-failures",
     85 + action="store_true",
     86 + dest="debugFailures",
     87 + default=env.get("NOSE_PDB_FAILURES", False),
     88 + help="Drop into debugger on failures",
     89 + )
     90 + parser.add_option(
     91 + "--pdb-errors",
     92 + action="store_true",
     93 + dest="debugErrors",
     94 + default=env.get("NOSE_PDB_ERRORS", False),
     95 + help="Drop into debugger on errors",
     96 + )
     97 + 
     98 + def configure(self, options, conf):
     99 + """Configure which kinds of exceptions trigger plugin.
     100 + """
     101 + self.conf = conf
     102 + self.enabled_for_errors = options.debugErrors or options.debugBoth
     103 + self.enabled_for_failures = options.debugFailures or options.debugBoth
     104 + self.enabled = self.enabled_for_failures or self.enabled_for_errors
     105 + 
     106 + def addError(self, test, err):
     107 + """Enter pdb if configured to debug errors.
     108 + """
     109 + if not self.enabled_for_errors:
     110 + return
     111 + self.debug(err)
     112 + 
     113 + def addFailure(self, test, err):
     114 + """Enter pdb if configured to debug failures.
     115 + """
     116 + if not self.enabled_for_failures:
     117 + return
     118 + self.debug(err)
     119 + 
     120 + def debug(self, err):
     121 + import sys # FIXME why is this import here?
     122 + 
     123 + ec, ev, tb = err
     124 + stdout = sys.stdout
     125 + sys.stdout = sys.__stdout__
     126 + try:
     127 + pdb.post_mortem(tb)
     128 + finally:
     129 + sys.stdout = stdout
     130 + 
     131 + 
     132 +##########################################################################################
     133 + 
     134 + 
     135 +def setup_module():
     136 + global nm
     137 + nm = nmap.PortScanner()
     138 + 
     139 + 
     140 +@raises(nmap.PortScannerError)
     141 +def test_wrong_args():
     142 + nm.scan(arguments="-wrongargs")
     143 + 
     144 + 
     145 +def test_host_scan_error():
     146 + assert (
     147 + "error" in nm.scan("noserver.example.com", arguments="-sP")["nmap"]["scaninfo"]
     148 + )
     149 + 
     150 + 
     151 +def xmlfile_read_setup():
     152 + nm.analyse_nmap_xml_scan(open("scanme_output.xml").read())
     153 + 
     154 + 
     155 +@with_setup(xmlfile_read_setup)
     156 +def test_command_line():
     157 + try:
     158 + global NMAP_XML_VERSION
     159 + NMAP_XML_VERSION = os.environ["NMAP_XML_VERSION"]
     160 + except Exception:
     161 + raise ValueError("Set env NMAP_XML_VERSION")
     162 + 
     163 + assert_equals(
     164 + nm.command_line(),
     165 + "./nmap-{0}/nmap -sV -oX scanme_output-{0}.xml scanme.nmap.org".format(
     166 + NMAP_XML_VERSION
     167 + ),
     168 + )
     169 + 
     170 + 
     171 +@with_setup(xmlfile_read_setup)
     172 +def test_scan_info():
     173 + assert "tcp" in nm.scaninfo()
     174 + assert "method" in nm.scaninfo()["tcp"]
     175 + assert_equals("connect", nm.scaninfo()["tcp"]["method"])
     176 + assert "services" in nm.scaninfo()["tcp"]
     177 + 
     178 + 
     179 +@with_setup(xmlfile_read_setup)
     180 +def test_all_hosts():
     181 + assert_equals(["45.33.32.156"], nm.all_hosts())
     182 + 
     183 + 
     184 +@with_setup(xmlfile_read_setup)
     185 +def test_host():
     186 + assert_equals("scanme.nmap.org", nm["45.33.32.156"].hostname())
     187 + assert {"name": "scanme.nmap.org", "type": "user"} in nm["45.33.32.156"].hostnames()
     188 + assert_equals("up", nm["45.33.32.156"].state())
     189 + assert_equals(["tcp"], nm["45.33.32.156"].all_protocols())
     190 + 
     191 + 
     192 +def test_host_no_hostname():
     193 + # Covers bug : https://bitbucket.org/xael/python-nmap/issues/7/error-with-hostname
     194 + nm.scan("127.0.0.2")
     195 + assert_equals("", nm["127.0.0.2"].hostname())
     196 + 
     197 + 
     198 +@with_setup(xmlfile_read_setup)
     199 +def test_ports():
     200 + ports = list(nm["45.33.32.156"]["tcp"].keys())
     201 + ports.sort()
     202 + assert_equals([22, 25, 80, 139, 445, 9929, 31337], ports)
     203 + assert nm["45.33.32.156"].has_tcp(22)
     204 + assert nm["45.33.32.156"].has_tcp(23) == False
     205 + assert "conf" in list(nm["45.33.32.156"]["tcp"][22])
     206 + assert "cpe" in list(nm["45.33.32.156"]["tcp"][22])
     207 + assert "name" in list(nm["45.33.32.156"]["tcp"][22])
     208 + assert "product" in list(nm["45.33.32.156"]["tcp"][22])
     209 + assert "reason" in list(nm["45.33.32.156"]["tcp"][22])
     210 + assert "state" in list(nm["45.33.32.156"]["tcp"][22])
     211 + assert "version" in list(nm["45.33.32.156"]["tcp"][22])
     212 + 
     213 + assert "10" in nm["45.33.32.156"]["tcp"][22]["conf"]
     214 + global NMAP_XML_VERSION
     215 + if NMAP_XML_VERSION == "6.40":
     216 + assert_equals("", nm["45.33.32.156"]["tcp"][22]["cpe"])
     217 + assert_equals("", nm["45.33.32.156"]["tcp"][22]["product"])
     218 + assert_equals("", nm["45.33.32.156"]["tcp"][22]["version"])
     219 + else:
     220 + assert "cpe:/o:linux:linux_kernel" in nm["45.33.32.156"]["tcp"][22]["cpe"]
     221 + assert "OpenSSH" in nm["45.33.32.156"]["tcp"][22]["product"]
     222 + assert "6.6.1p1 Ubuntu 2ubuntu2.13" in nm["45.33.32.156"]["tcp"][22]["version"]
     223 + 
     224 + assert "ssh" in nm["45.33.32.156"]["tcp"][22]["name"]
     225 + assert "syn-ack" in nm["45.33.32.156"]["tcp"][22]["reason"]
     226 + assert "open" in nm["45.33.32.156"]["tcp"][22]["state"]
     227 + 
     228 + assert_equals(nm["45.33.32.156"]["tcp"][22], nm["45.33.32.156"].tcp(22))
     229 + 
     230 + 
     231 +@with_setup(xmlfile_read_setup)
     232 +def test_listscan():
     233 + assert_equals("1", nm.scanstats()["uphosts"])
     234 + assert_equals("0", nm.scanstats()["downhosts"])
     235 + assert_equals("1", nm.scanstats()["totalhosts"])
     236 + assert "timestr" in nm.scanstats().keys()
     237 + assert "elapsed" in nm.scanstats().keys()
     238 + 
     239 + 
     240 +@with_setup(xmlfile_read_setup)
     241 +def test_csv_output():
     242 + assert_equals(
     243 + "host;hostname;hostname_type;protocol;port;name;state;product;extrainfo;reason;version;conf;cpe",
     244 + nm.csv().split("\n")[0].strip(),
     245 + )
     246 + 
     247 + global NMAP_XML_VERSION
     248 + result = None
     249 + if NMAP_XML_VERSION == "6.40":
     250 + result = "45.33.32.156;scanme.nmap.org;user;tcp;22;ssh;open;;protocol 2.0;syn-ack;;10;"
     251 + 
     252 + elif NMAP_XML_VERSION == "7.01":
     253 + result = '45.33.32.156;scanme.nmap.org;user;tcp;22;ssh;open;OpenSSH;"Ubuntu Linux; protocol 2.0";syn-ack;6.6.1p1 Ubuntu 2ubuntu2.13;10;cpe:/o:linux:linux_kernel'
     254 + 
     255 + elif NMAP_XML_VERSION == "7.70":
     256 + result = '45.33.32.156;scanme.nmap.org;user;tcp;22;ssh;open;OpenSSH;"Ubuntu Linux; protocol 2.0";syn-ack;6.6.1p1 Ubuntu 2ubuntu2.13;10;cpe:/o:linux:linux_kernel'
     257 + 
     258 + elif NMAP_XML_VERSION == "7.91":
     259 + result = '45.33.32.156;scanme.nmap.org;user;tcp;22;ssh;open;OpenSSH;"Ubuntu Linux; protocol 2.0";syn-ack;6.6.1p1 Ubuntu 2ubuntu2.13;10;cpe:/o:linux:linux_kernel'
     260 + 
     261 + if result is not None:
     262 + assert_equals(result, nm.csv().split("\n")[1].strip())
     263 + 
     264 + 
     265 +def test_listscan():
     266 + assert 0 < len(nm.listscan("192.168.1.0/30"))
     267 + assert_equals(
     268 + ["127.0.0.0", "127.0.0.1", "127.0.0.2", "127.0.0.3"],
     269 + nm.listscan("localhost/30"),
     270 + )
     271 + 
     272 + 
     273 +def test_ipv6():
     274 + if os.getuid() == 0:
     275 + r = nm.scan("127.0.0.1", arguments="-6")
     276 + else:
     277 + r = nm.scan("127.0.0.1", arguments="-6", sudo=True)
     278 + 
     279 + 
     280 +def test_ipv4_async():
     281 + global FLAG
     282 + FLAG = Value("i", 0)
     283 + nma = nmap.PortScannerAsync()
     284 + 
     285 + def callback_result(host, scan_result):
     286 + global FLAG
     287 + FLAG.value = 1
     288 + 
     289 + nma.scan(hosts="127.0.0.1", arguments="-p 22 -Pn", callback=callback_result)
     290 + 
     291 + while nma.still_scanning():
     292 + nma.wait(2)
     293 + 
     294 + assert_equals(FLAG.value, 1)
     295 + 
     296 + 
     297 +def test_ipv6_async():
     298 + global FLAG_ipv6
     299 + FLAG_ipv6 = Value("i", 0)
     300 + nma_ipv6 = nmap.PortScannerAsync()
     301 + 
     302 + def callback_result(host, scan_result):
     303 + global FLAG_ipv6
     304 + FLAG_ipv6.value = 1
     305 + 
     306 + nma_ipv6.scan(hosts="::1", arguments="-6 -p 22 -Pn", callback=callback_result)
     307 + 
     308 + while nma_ipv6.still_scanning():
     309 + nma_ipv6.wait(2)
     310 + 
     311 + assert_equals(FLAG_ipv6.value, 1)
     312 + 
     313 + 
     314 +def scan_localhost_sudo_arg_O():
     315 + lastnm = nm.get_nmap_last_output()
     316 + 
     317 + if len(lastnm) > 0:
     318 + try:
     319 + nm.analyse_nmap_xml_scan(lastnm)
     320 + except Exception:
     321 + pass
     322 + else:
     323 + if nm.command_line() == "nmap -oX - -O 127.0.0.1":
     324 + return
     325 + 
     326 + if os.getuid() == 0:
     327 + nm.scan("127.0.0.1", arguments="-O")
     328 + else:
     329 + nm.scan("127.0.0.1", arguments="-O", sudo=True)
     330 + 
     331 + 
     332 +@with_setup(scan_localhost_sudo_arg_O)
     333 +def test_sudo():
     334 + assert "osmatch" in nm["127.0.0.1"]
     335 + assert len(nm["127.0.0.1"]["osmatch"][0]["osclass"]) > 0
     336 + assert_equals("Linux", nm["127.0.0.1"]["osmatch"][0]["osclass"][0]["vendor"])
     337 + 
     338 + 
     339 +@with_setup(scan_localhost_sudo_arg_O)
     340 +def test_parsing_osmap_osclass_and_others():
     341 + # nosetests -v -s nmap/test_nmap.py:test_parsing_osmap_osclass_and_others
     342 + assert "osmatch" in nm["127.0.0.1"]
     343 + assert_equals(nm["127.0.0.1"]["osmatch"][0]["name"], "Linux 2.6.32")
     344 + 
     345 + assert "accuracy" in nm["127.0.0.1"]["osmatch"][0]
     346 + assert "line" in nm["127.0.0.1"]["osmatch"][0]
     347 + 
     348 + assert "osclass" in nm["127.0.0.1"]["osmatch"][0]
     349 + assert_equals(nm["127.0.0.1"]["osmatch"][0]["osclass"][0]["vendor"], "Linux")
     350 + 
     351 + assert "type" in nm["127.0.0.1"]["osmatch"][0]["osclass"][0]
     352 + assert "osfamily" in nm["127.0.0.1"]["osmatch"][0]["osclass"][0]
     353 + assert "osgen" in nm["127.0.0.1"]["osmatch"][0]["osclass"][0]
     354 + assert "accuracy" in nm["127.0.0.1"]["osmatch"][0]["osclass"][0]
     355 + 
     356 + 
     357 +@with_setup(scan_localhost_sudo_arg_O)
     358 +def test_all_protocols():
     359 + assert "addresses" not in nm["127.0.0.1"].all_protocols()
     360 + assert "hostnames" not in nm["127.0.0.1"].all_protocols()
     361 + assert "status" not in nm["127.0.0.1"].all_protocols()
     362 + assert "vendor" not in nm["127.0.0.1"].all_protocols()
     363 + assert "osclass" not in nm["127.0.0.1"].all_protocols()
     364 + assert "osmatch" not in nm["127.0.0.1"].all_protocols()
     365 + assert "uptime" not in nm["127.0.0.1"].all_protocols()
     366 + assert "portused" not in nm["127.0.0.1"].all_protocols()
     367 + assert "tcp" in nm["127.0.0.1"].all_protocols()
     368 + 
     369 + 
     370 +def xmlfile_read_setup_multiple_osmatch():
     371 + nm.analyse_nmap_xml_scan(open("osmatch_output.xml").read())
     372 + 
     373 + 
     374 +@with_setup(xmlfile_read_setup_multiple_osmatch)
     375 +def test_multipe_osmatch():
     376 + assert "osmatch" in nm["127.0.0.1"]
     377 + assert "portused" in nm["127.0.0.1"]
     378 + 
     379 + for osm in nm["127.0.0.1"]["osmatch"]:
     380 + assert "accuracy" in osm
     381 + assert "line" in osm
     382 + assert "name" in osm
     383 + assert "osclass" in osm
     384 + assert "accuracy" in osm["osclass"][0]
     385 + assert "cpe" in osm["osclass"][0]
     386 + assert "osfamily" in osm["osclass"][0]
     387 + assert "osgen" in osm["osclass"][0]
     388 + assert "type" in osm["osclass"][0]
     389 + assert "vendor" in osm["osclass"][0]
     390 + 
     391 + 
     392 +@with_setup(xmlfile_read_setup)
     393 +def test_convert_nmap_output_to_encoding():
     394 + a = nm.analyse_nmap_xml_scan(open("scanme_output.xml").read())
     395 + out = nmap.convert_nmap_output_to_encoding(a, code="ascii")
     396 + assert out["scan"]["45.33.32.156"]["addresses"]["ipv4"] == b"45.33.32.156"
     397 + 
     398 + 
     399 +# def test_host_and_port_as_unicode():
     400 +# # nosetests -x -s nmap/test_nmap.py:test_port_as_unicode
     401 +# # Covers bug : https://bitbucket.org/xael/python-nmap/issues/9/can-not-pass-ports-with-unicode-string-at
     402 +# nma = nm.scan(hosts=u'127.0.0.1', ports=u'22')
     403 +# assert_equals(nma['nmap']['scaninfo']['error'], '')
     404 + 
     405 + 
     406 +def test_WARNING_case_sensitive():
     407 + nm.scan("localhost", arguments="-S 127.0.0.1")
     408 + assert "warning" in nm.scaninfo()
     409 + assert "WARNING" in nm.scaninfo()["warning"][0]
     410 + 
     411 + 
     412 +def test_scan_progressive():
     413 + nmp = nmap.PortScannerAsync()
     414 + 
     415 + def callback(host, scan_data):
     416 + assert host is not None
     417 + 
     418 + nmp.scan(hosts="127.0.0.1", arguments="-sV", callback=callback)
     419 + nmp.wait()
     420 + 
     421 + 
     422 +def test_sudo_encoding__T24():
     423 + """
     424 + When using "sudo=True" like this 'nm.scan(hosts=ip_range, arguments="-sP", sudo = True)'
     425 + i got a UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 9: ordinal not in range(128).
     426 + But if sudo is false all thing work nice.
     427 + """
     428 + r = nm.scan("192.168.1.1/24", arguments="-sP", sudo=True)
     429 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/yarl/__init__.py
     1 +from ._url import URL, cache_clear, cache_configure, cache_info
     2 + 
     3 +__version__ = "1.8.2"
     4 + 
     5 +__all__ = ("URL", "cache_clear", "cache_configure", "cache_info")
     6 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/yarl/__init__.pyi
     1 +import sys
     2 +from functools import _CacheInfo
     3 +from typing import Any, Mapping, Optional, Sequence, Tuple, Type, Union, overload
     4 + 
     5 +import multidict
     6 + 
     7 +if sys.version_info >= (3, 8):
     8 + from typing import Final, TypedDict, final
     9 +else:
     10 + from typing_extensions import Final, TypedDict, final
     11 + 
     12 +_SimpleQuery = Union[str, int, float]
     13 +_QueryVariable = Union[_SimpleQuery, Sequence[_SimpleQuery]]
     14 +_Query = Union[
     15 + None, str, Mapping[str, _QueryVariable], Sequence[Tuple[str, _QueryVariable]]
     16 +]
     17 + 
     18 +@final
     19 +class URL:
     20 + scheme: Final[str]
     21 + raw_user: Final[str]
     22 + user: Final[Optional[str]]
     23 + raw_password: Final[Optional[str]]
     24 + password: Final[Optional[str]]
     25 + raw_host: Final[Optional[str]]
     26 + host: Final[Optional[str]]
     27 + port: Final[Optional[int]]
     28 + raw_authority: Final[str]
     29 + authority: Final[str]
     30 + raw_path: Final[str]
     31 + path: Final[str]
     32 + raw_query_string: Final[str]
     33 + query_string: Final[str]
     34 + path_qs: Final[str]
     35 + raw_path_qs: Final[str]
     36 + raw_fragment: Final[str]
     37 + fragment: Final[str]
     38 + query: Final[multidict.MultiDict[str]]
     39 + raw_name: Final[str]
     40 + name: Final[str]
     41 + raw_suffix: Final[str]
     42 + suffix: Final[str]
     43 + raw_suffixes: Final[Tuple[str, ...]]
     44 + suffixes: Final[Tuple[str, ...]]
     45 + raw_parts: Final[Tuple[str, ...]]
     46 + parts: Final[Tuple[str, ...]]
     47 + parent: Final[URL]
     48 + def __init__(
     49 + self, val: Union[str, "URL"] = ..., *, encoded: bool = ...
     50 + ) -> None: ...
     51 + @classmethod
     52 + def build(
     53 + cls,
     54 + *,
     55 + scheme: str = ...,
     56 + authority: str = ...,
     57 + user: Optional[str] = ...,
     58 + password: Optional[str] = ...,
     59 + host: str = ...,
     60 + port: Optional[int] = ...,
     61 + path: str = ...,
     62 + query: Optional[_Query] = ...,
     63 + query_string: str = ...,
     64 + fragment: str = ...,
     65 + encoded: bool = ...
     66 + ) -> URL: ...
     67 + def __str__(self) -> str: ...
     68 + def __repr__(self) -> str: ...
     69 + def __eq__(self, other: Any) -> bool: ...
     70 + def __le__(self, other: Any) -> bool: ...
     71 + def __lt__(self, other: Any) -> bool: ...
     72 + def __ge__(self, other: Any) -> bool: ...
     73 + def __gt__(self, other: Any) -> bool: ...
     74 + def __hash__(self) -> int: ...
     75 + def __truediv__(self, name: str) -> URL: ...
     76 + def __mod__(self, query: _Query) -> URL: ...
     77 + def is_absolute(self) -> bool: ...
     78 + def is_default_port(self) -> bool: ...
     79 + def origin(self) -> URL: ...
     80 + def relative(self) -> URL: ...
     81 + def with_scheme(self, scheme: str) -> URL: ...
     82 + def with_user(self, user: Optional[str]) -> URL: ...
     83 + def with_password(self, password: Optional[str]) -> URL: ...
     84 + def with_host(self, host: str) -> URL: ...
     85 + def with_port(self, port: Optional[int]) -> URL: ...
     86 + def with_path(self, path: str, *, encoded: bool = ...) -> URL: ...
     87 + @overload
     88 + def with_query(self, query: _Query) -> URL: ...
     89 + @overload
     90 + def with_query(self, **kwargs: _QueryVariable) -> URL: ...
     91 + @overload
     92 + def update_query(self, query: _Query) -> URL: ...
     93 + @overload
     94 + def update_query(self, **kwargs: _QueryVariable) -> URL: ...
     95 + def with_fragment(self, fragment: Optional[str]) -> URL: ...
     96 + def with_name(self, name: str) -> URL: ...
     97 + def with_suffix(self, suffix: str) -> URL: ...
     98 + def join(self, url: URL) -> URL: ...
     99 + def human_repr(self) -> str: ...
     100 + # private API
     101 + @classmethod
     102 + def _normalize_path(cls, path: str) -> str: ...
     103 + 
     104 +@final
     105 +class cached_property:
     106 + def __init__(self, wrapped: Any) -> None: ...
     107 + def __get__(self, inst: URL, owner: Type[URL]) -> Any: ...
     108 + def __set__(self, inst: URL, value: Any) -> None: ...
     109 + 
     110 +class CacheInfo(TypedDict):
     111 + idna_encode: _CacheInfo
     112 + idna_decode: _CacheInfo
     113 + 
     114 +def cache_clear() -> None: ...
     115 +def cache_info() -> CacheInfo: ...
     116 +def cache_configure(
     117 + *, idna_encode_size: Optional[int] = ..., idna_decode_size: Optional[int] = ...
     118 +) -> None: ...
     119 + 
  • vuln_analyzer/lib/python3.11/site-packages/yarl/__pycache__/__init__.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/yarl/__pycache__/_quoting.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/yarl/__pycache__/_quoting_py.cpython-311.pyc
    Binary file.
  • vuln_analyzer/lib/python3.11/site-packages/yarl/__pycache__/_url.cpython-311.pyc
    Binary file.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/yarl/_quoting.py
     1 +import os
     2 +import sys
     3 + 
     4 +__all__ = ("_Quoter", "_Unquoter")
     5 + 
     6 + 
     7 +NO_EXTENSIONS = bool(os.environ.get("YARL_NO_EXTENSIONS")) # type: bool
     8 +if sys.implementation.name != "cpython":
     9 + NO_EXTENSIONS = True
     10 + 
     11 + 
     12 +if not NO_EXTENSIONS: # pragma: no branch
     13 + try:
     14 + from ._quoting_c import _Quoter, _Unquoter # type: ignore[misc]
     15 + except ImportError: # pragma: no cover
     16 + from ._quoting_py import _Quoter, _Unquoter # type: ignore[misc]
     17 +else:
     18 + from ._quoting_py import _Quoter, _Unquoter # type: ignore[misc]
     19 + 
  • vuln_analyzer/lib/python3.11/site-packages/yarl/_quoting_c.cpython-311-x86_64-linux-gnu.so
    Binary file.
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/yarl/_quoting_c.pyi
     1 +from typing import Optional
     2 + 
     3 +class _Quoter:
     4 + def __init__(
     5 + self,
     6 + *,
     7 + safe: str = ...,
     8 + protected: str = ...,
     9 + qs: bool = ...,
     10 + requote: bool = ...
     11 + ) -> None: ...
     12 + def __call__(self, val: Optional[str] = ...) -> Optional[str]: ...
     13 + 
     14 +class _Unquoter:
     15 + def __init__(self, *, unsafe: str = ..., qs: bool = ...) -> None: ...
     16 + def __call__(self, val: Optional[str] = ...) -> Optional[str]: ...
     17 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/yarl/_quoting_c.pyx
     1 +# cython: language_level=3
     2 + 
     3 +from cpython.exc cimport PyErr_NoMemory
     4 +from cpython.mem cimport PyMem_Free, PyMem_Malloc, PyMem_Realloc
     5 +from cpython.unicode cimport PyUnicode_DecodeASCII, PyUnicode_DecodeUTF8Stateful
     6 +from libc.stdint cimport uint8_t, uint64_t
     7 +from libc.string cimport memcpy, memset
     8 + 
     9 +from string import ascii_letters, digits
     10 + 
     11 + 
     12 +cdef str GEN_DELIMS = ":/?#[]@"
     13 +cdef str SUB_DELIMS_WITHOUT_QS = "!$'()*,"
     14 +cdef str SUB_DELIMS = SUB_DELIMS_WITHOUT_QS + '+?=;'
     15 +cdef str RESERVED = GEN_DELIMS + SUB_DELIMS
     16 +cdef str UNRESERVED = ascii_letters + digits + '-._~'
     17 +cdef str ALLOWED = UNRESERVED + SUB_DELIMS_WITHOUT_QS
     18 +cdef str QS = '+&=;'
     19 + 
     20 +DEF BUF_SIZE = 8 * 1024 # 8KiB
     21 +cdef char BUFFER[BUF_SIZE]
     22 + 
     23 +cdef inline Py_UCS4 _to_hex(uint8_t v):
     24 + if v < 10:
     25 + return <Py_UCS4>(v+0x30) # ord('0') == 0x30
     26 + else:
     27 + return <Py_UCS4>(v+0x41-10) # ord('A') == 0x41
     28 + 
     29 + 
     30 +cdef inline int _from_hex(Py_UCS4 v):
     31 + if '0' <= v <= '9':
     32 + return <int>(v) - 0x30 # ord('0') == 0x30
     33 + elif 'A' <= v <= 'F':
     34 + return <int>(v) - 0x41 + 10 # ord('A') == 0x41
     35 + elif 'a' <= v <= 'f':
     36 + return <int>(v) - 0x61 + 10 # ord('a') == 0x61
     37 + else:
     38 + return -1
     39 + 
     40 + 
     41 +cdef inline int _is_lower_hex(Py_UCS4 v):
     42 + return 'a' <= v <= 'f'
     43 + 
     44 + 
     45 +cdef inline Py_UCS4 _restore_ch(Py_UCS4 d1, Py_UCS4 d2):
     46 + cdef int digit1 = _from_hex(d1)
     47 + if digit1 < 0:
     48 + return <Py_UCS4>-1
     49 + cdef int digit2 = _from_hex(d2)
     50 + if digit2 < 0:
     51 + return <Py_UCS4>-1
     52 + return <Py_UCS4>(digit1 << 4 | digit2)
     53 + 
     54 + 
     55 +cdef uint8_t ALLOWED_TABLE[16]
     56 +cdef uint8_t ALLOWED_NOTQS_TABLE[16]
     57 + 
     58 + 
     59 +cdef inline bint bit_at(uint8_t array[], uint64_t ch):
     60 + return array[ch >> 3] & (1 << (ch & 7))
     61 + 
     62 + 
     63 +cdef inline void set_bit(uint8_t array[], uint64_t ch):
     64 + array[ch >> 3] |= (1 << (ch & 7))
     65 + 
     66 + 
     67 +memset(ALLOWED_TABLE, 0, sizeof(ALLOWED_TABLE))
     68 +memset(ALLOWED_NOTQS_TABLE, 0, sizeof(ALLOWED_NOTQS_TABLE))
     69 + 
     70 +for i in range(128):
     71 + if chr(i) in ALLOWED:
     72 + set_bit(ALLOWED_TABLE, i)
     73 + set_bit(ALLOWED_NOTQS_TABLE, i)
     74 + if chr(i) in QS:
     75 + set_bit(ALLOWED_NOTQS_TABLE, i)
     76 + 
     77 +# ----------------- writer ---------------------------
     78 + 
     79 +cdef struct Writer:
     80 + char *buf
     81 + Py_ssize_t size
     82 + Py_ssize_t pos
     83 + bint changed
     84 + 
     85 + 
     86 +cdef inline void _init_writer(Writer* writer):
     87 + writer.buf = &BUFFER[0]
     88 + writer.size = BUF_SIZE
     89 + writer.pos = 0
     90 + writer.changed = 0
     91 + 
     92 + 
     93 +cdef inline void _release_writer(Writer* writer):
     94 + if writer.buf != BUFFER:
     95 + PyMem_Free(writer.buf)
     96 + 
     97 + 
     98 +cdef inline int _write_char(Writer* writer, Py_UCS4 ch, bint changed):
     99 + cdef char * buf
     100 + cdef Py_ssize_t size
     101 + 
     102 + if writer.pos == writer.size:
     103 + # reallocate
     104 + size = writer.size + BUF_SIZE
     105 + if writer.buf == BUFFER:
     106 + buf = <char*>PyMem_Malloc(size)
     107 + if buf == NULL:
     108 + PyErr_NoMemory()
     109 + return -1
     110 + memcpy(buf, writer.buf, writer.size)
     111 + else:
     112 + buf = <char*>PyMem_Realloc(writer.buf, size)
     113 + if buf == NULL:
     114 + PyErr_NoMemory()
     115 + return -1
     116 + writer.buf = buf
     117 + writer.size = size
     118 + writer.buf[writer.pos] = <char>ch
     119 + writer.pos += 1
     120 + writer.changed |= changed
     121 + return 0
     122 + 
     123 + 
     124 +cdef inline int _write_pct(Writer* writer, uint8_t ch, bint changed):
     125 + if _write_char(writer, '%', changed) < 0:
     126 + return -1
     127 + if _write_char(writer, _to_hex(<uint8_t>ch >> 4), changed) < 0:
     128 + return -1
     129 + return _write_char(writer, _to_hex(<uint8_t>ch & 0x0f), changed)
     130 + 
     131 + 
     132 +cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol):
     133 + cdef uint64_t utf = <uint64_t> symbol
     134 + 
     135 + if utf < 0x80:
     136 + return _write_pct(writer, <uint8_t>utf, True)
     137 + elif utf < 0x800:
     138 + if _write_pct(writer, <uint8_t>(0xc0 | (utf >> 6)), True) < 0:
     139 + return -1
     140 + return _write_pct(writer, <uint8_t>(0x80 | (utf & 0x3f)), True)
     141 + elif 0xD800 <= utf <= 0xDFFF:
     142 + # surogate pair, ignored
     143 + return 0
     144 + elif utf < 0x10000:
     145 + if _write_pct(writer, <uint8_t>(0xe0 | (utf >> 12)), True) < 0:
     146 + return -1
     147 + if _write_pct(writer, <uint8_t>(0x80 | ((utf >> 6) & 0x3f)),
     148 + True) < 0:
     149 + return -1
     150 + return _write_pct(writer, <uint8_t>(0x80 | (utf & 0x3f)), True)
     151 + elif utf > 0x10FFFF:
     152 + # symbol is too large
     153 + return 0
     154 + else:
     155 + if _write_pct(writer, <uint8_t>(0xf0 | (utf >> 18)), True) < 0:
     156 + return -1
     157 + if _write_pct(writer, <uint8_t>(0x80 | ((utf >> 12) & 0x3f)),
     158 + True) < 0:
     159 + return -1
     160 + if _write_pct(writer, <uint8_t>(0x80 | ((utf >> 6) & 0x3f)),
     161 + True) < 0:
     162 + return -1
     163 + return _write_pct(writer, <uint8_t>(0x80 | (utf & 0x3f)), True)
     164 + 
     165 + 
     166 +# --------------------- end writer --------------------------
     167 + 
     168 + 
     169 +cdef class _Quoter:
     170 + cdef bint _qs
     171 + cdef bint _requote
     172 + 
     173 + cdef uint8_t _safe_table[16]
     174 + cdef uint8_t _protected_table[16]
     175 + 
     176 + def __init__(
     177 + self, *, str safe='', str protected='', bint qs=False, bint requote=True,
     178 + ):
     179 + cdef Py_UCS4 ch
     180 + 
     181 + self._qs = qs
     182 + self._requote = requote
     183 + 
     184 + if not self._qs:
     185 + memcpy(self._safe_table,
     186 + ALLOWED_NOTQS_TABLE,
     187 + sizeof(self._safe_table))
     188 + else:
     189 + memcpy(self._safe_table,
     190 + ALLOWED_TABLE,
     191 + sizeof(self._safe_table))
     192 + for ch in safe:
     193 + if ord(ch) > 127:
     194 + raise ValueError("Only safe symbols with ORD < 128 are allowed")
     195 + set_bit(self._safe_table, ch)
     196 + 
     197 + memset(self._protected_table, 0, sizeof(self._protected_table))
     198 + for ch in protected:
     199 + if ord(ch) > 127:
     200 + raise ValueError("Only safe symbols with ORD < 128 are allowed")
     201 + set_bit(self._safe_table, ch)
     202 + set_bit(self._protected_table, ch)
     203 + 
     204 + def __call__(self, val):
     205 + cdef Writer writer
     206 + if val is None:
     207 + return None
     208 + if type(val) is not str:
     209 + if isinstance(val, str):
     210 + # derived from str
     211 + val = str(val)
     212 + else:
     213 + raise TypeError("Argument should be str")
     214 + _init_writer(&writer)
     215 + try:
     216 + return self._do_quote(<str>val, &writer)
     217 + finally:
     218 + _release_writer(&writer)
     219 + 
     220 + cdef str _do_quote(self, str val, Writer *writer):
     221 + cdef Py_UCS4 ch
     222 + cdef int changed
     223 + cdef int idx = 0
     224 + cdef int length = len(val)
     225 + 
     226 + while idx < length:
     227 + ch = val[idx]
     228 + idx += 1
     229 + if ch == '%' and self._requote and idx <= length - 2:
     230 + ch = _restore_ch(val[idx], val[idx + 1])
     231 + if ch != <Py_UCS4>-1:
     232 + idx += 2
     233 + if ch < 128:
     234 + if bit_at(self._protected_table, ch):
     235 + if _write_pct(writer, ch, True) < 0:
     236 + raise
     237 + continue
     238 + 
     239 + if bit_at(self._safe_table, ch):
     240 + if _write_char(writer, ch, True) < 0:
     241 + raise
     242 + continue
     243 + 
     244 + changed = (_is_lower_hex(val[idx - 2]) or
     245 + _is_lower_hex(val[idx - 1]))
     246 + if _write_pct(writer, ch, changed) < 0:
     247 + raise
     248 + continue
     249 + else:
     250 + ch = '%'
     251 + 
     252 + if self._write(writer, ch) < 0:
     253 + raise
     254 + 
     255 + if not writer.changed:
     256 + return val
     257 + else:
     258 + return PyUnicode_DecodeASCII(writer.buf, writer.pos, "strict")
     259 + 
     260 + cdef inline int _write(self, Writer *writer, Py_UCS4 ch):
     261 + if self._qs:
     262 + if ch == ' ':
     263 + return _write_char(writer, '+', True)
     264 + 
     265 + if ch < 128 and bit_at(self._safe_table, ch):
     266 + return _write_char(writer, ch, False)
     267 + 
     268 + return _write_utf8(writer, ch)
     269 + 
     270 + 
     271 +cdef class _Unquoter:
     272 + cdef str _unsafe
     273 + cdef bint _qs
     274 + cdef _Quoter _quoter
     275 + cdef _Quoter _qs_quoter
     276 + 
     277 + def __init__(self, *, unsafe='', qs=False):
     278 + self._unsafe = unsafe
     279 + self._qs = qs
     280 + self._quoter = _Quoter()
     281 + self._qs_quoter = _Quoter(qs=True)
     282 + 
     283 + def __call__(self, val):
     284 + if val is None:
     285 + return None
     286 + if type(val) is not str:
     287 + if isinstance(val, str):
     288 + # derived from str
     289 + val = str(val)
     290 + else:
     291 + raise TypeError("Argument should be str")
     292 + return self._do_unquote(<str>val)
     293 + 
     294 + cdef str _do_unquote(self, str val):
     295 + if len(val) == 0:
     296 + return val
     297 + cdef list ret = []
     298 + cdef char buffer[4]
     299 + cdef Py_ssize_t buflen = 0
     300 + cdef Py_ssize_t consumed
     301 + cdef str unquoted
     302 + cdef Py_UCS4 ch = 0
     303 + cdef Py_ssize_t idx = 0
     304 + cdef Py_ssize_t length = len(val)
     305 + cdef Py_ssize_t start_pct
     306 + 
     307 + while idx < length:
     308 + ch = val[idx]
     309 + idx += 1
     310 + if ch == '%' and idx <= length - 2:
     311 + ch = _restore_ch(val[idx], val[idx + 1])
     312 + if ch != <Py_UCS4>-1:
     313 + idx += 2
     314 + assert buflen < 4
     315 + buffer[buflen] = ch
     316 + buflen += 1
     317 + try:
     318 + unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen,
     319 + NULL, &consumed)
     320 + except UnicodeDecodeError:
     321 + start_pct = idx - buflen * 3
     322 + buffer[0] = ch
     323 + buflen = 1
     324 + ret.append(val[start_pct : idx - 3])
     325 + try:
     326 + unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen,
     327 + NULL, &consumed)
     328 + except UnicodeDecodeError:
     329 + buflen = 0
     330 + ret.append(val[idx - 3 : idx])
     331 + continue
     332 + if not unquoted:
     333 + assert consumed == 0
     334 + continue
     335 + assert consumed == buflen
     336 + buflen = 0
     337 + if self._qs and unquoted in '+=&;':
     338 + ret.append(self._qs_quoter(unquoted))
     339 + elif unquoted in self._unsafe:
     340 + ret.append(self._quoter(unquoted))
     341 + else:
     342 + ret.append(unquoted)
     343 + continue
     344 + else:
     345 + ch = '%'
     346 + 
     347 + if buflen:
     348 + start_pct = idx - 1 - buflen * 3
     349 + ret.append(val[start_pct : idx - 1])
     350 + buflen = 0
     351 + 
     352 + if ch == '+':
     353 + if not self._qs or ch in self._unsafe:
     354 + ret.append('+')
     355 + else:
     356 + ret.append(' ')
     357 + continue
     358 + 
     359 + if ch in self._unsafe:
     360 + ret.append('%')
     361 + h = hex(ord(ch)).upper()[2:]
     362 + for ch in h:
     363 + ret.append(ch)
     364 + continue
     365 + 
     366 + ret.append(ch)
     367 + 
     368 + if buflen:
     369 + ret.append(val[length - buflen * 3 : length])
     370 + 
     371 + return ''.join(ret)
     372 + 
  • ■ ■ ■ ■ ■ ■
    vuln_analyzer/lib/python3.11/site-packages/yarl/_quoting_py.py
     1 +import codecs
     2 +import re
     3 +from string import ascii_letters, ascii_lowercase, digits
     4 +from typing import Optional, cast
     5 + 
     6 +BASCII_LOWERCASE = ascii_lowercase.encode("ascii")
     7 +BPCT_ALLOWED = {f"%{i:02X}".encode("ascii") for i in range(256)}
     8 +GEN_DELIMS = ":/?#[]@"
     9 +SUB_DELIMS_WITHOUT_QS = "!$'()*,"
     10 +SUB_DELIMS = SUB_DELIMS_WITHOUT_QS + "+&=;"
     11 +RESERVED = GEN_DELIMS + SUB_DELIMS
     12 +UNRESERVED = ascii_letters + digits + "-._~"
     13 +ALLOWED = UNRESERVED + SUB_DELIMS_WITHOUT_QS
     14 + 
     15 + 
     16 +_IS_HEX = re.compile(b"[A-Z0-9][A-Z0-9]")
     17 +_IS_HEX_STR = re.compile("[A-Fa-f0-9][A-Fa-f0-9]")
     18 + 
     19 +utf8_decoder = codecs.getincrementaldecoder("utf-8")
     20 + 
     21 + 
     22 +class _Quoter:
     23 + def __init__(
     24 + self,
     25 + *,
     26 + safe: str = "",
     27 + protected: str = "",
     28 + qs: bool = False,
     29 + requote: bool = True,
     30 + ) -> None:
     31 + self._safe = safe
     32 + self._protected = protected
     33 + self._qs = qs
     34 + self._requote = requote
     35 + 
     36 + def __call__(self, val: Optional[str]) -> Optional[str]:
     37 + if val is None:
     38 + return None
     39 + if not isinstance(val, str):
     40 + raise TypeError("Argument should be str")
     41 + if not val:
     42 + return ""
     43 + bval = cast(str, val).encode("utf8", errors="ignore")
     44 + ret = bytearray()
     45 + pct = bytearray()
     46 + safe = self._safe
     47 + safe += ALLOWED
     48 + if not self._qs:
     49 + safe += "+&=;"
     50 + safe += self._protected
     51 + bsafe = safe.encode("ascii")
     52 + idx = 0
     53 + while idx < len(bval):
     54 + ch = bval[idx]
     55 + idx += 1
     56 + 
     57 + if pct:
     58 + if ch in BASCII_LOWERCASE:
     59 + ch = ch - 32 # convert to uppercase
     60 + pct.append(ch)
     61 + if len(pct) == 3: # pragma: no branch # peephole optimizer
     62 + buf = pct[1:]
     63 + if not _IS_HEX.match(buf):
     64 + ret.extend(b"%25")
     65 + pct.clear()
     66 + idx -= 2
     67 + continue
     68 + try:
     69 + unquoted = chr(int(pct[1:].decode("ascii"), base=16))
     70 + except ValueError:
     71 + ret.extend(b"%25")
     72 + pct.clear()
     73 + idx -= 2
     74 + continue
     75 + 
     76 + if unquoted in self._protected:
     77 + ret.extend(pct)
     78 + elif unquoted in safe:
     79 + ret.append(ord(unquoted))
     80 + else:
     81 + ret.extend(pct)
     82 + pct.clear()
     83 + 
     84 + # special case, if we have only one char after "%"
     85 + elif len(pct) == 2 and idx == len(bval):
     86 + ret.extend(b"%25")
     87 + pct.clear()
     88 + idx -= 1
     89 + 
     90 + continue
     91 + 
     92 + elif ch == ord("%") and self._requote:
     93 + pct.clear()
     94 + pct.append(ch)
     95 + 
     96 + # special case if "%" is last char
     97 + if idx == len(bval):
     98 + ret.extend(b"%25")
     99 + 
     100 + continue
     101 + 
     102 + if self._qs:
     103 + if ch == ord(" "):
     104 + ret.append(ord("+"))
     105 + continue
     106 + if ch in bsafe:
     107 + ret.append(ch)
     108 + continue
     109 + 
     110 + ret.extend((f"%{ch:02X}").encode("ascii"))
     111 + 
     112 + ret2 = ret.decode("ascii")
     113 + if ret2 == val:
     114 + return val
     115 + return ret2
     116 + 
     117 + 
     118 +class _Unquoter:
     119 + def __init__(self, *, unsafe: str = "", qs: bool = False) -> None:
     120 + self._unsafe = unsafe
     121 + self._qs = qs
     122 + self._quoter = _Quoter()
     123 + self._qs_quoter = _Quoter(qs=True)
     124 + 
     125 + def __call__(self, val: Optional[str]) -> Optional[str]:
     126 + if val is None:
     127 + return None
     128 + if not isinstance(val, str):
     129 + raise TypeError("Argument should be str")
     130 + if not val:
     131 + return ""
     132 + decoder = cast(codecs.BufferedIncrementalDecoder, utf8_decoder())
     133 + ret = []
     134 + idx = 0
     135 + while idx < len(val):
     136 + ch = val[idx]
     137 + idx += 1
     138 + if ch == "%" and idx <= len(val) - 2:
     139 + pct = val[idx : idx + 2]
     140 + if _IS_HEX_STR.fullmatch(pct):
     141 + b = bytes([int(pct, base=16)])
     142 + idx += 2
     143 + try:
     144 + unquoted = decoder.decode(b)
     145 + except UnicodeDecodeError:
     146 + start_pct = idx - 3 - len(decoder.buffer) * 3
     147 + ret.append(val[start_pct : idx - 3])
     148 + decoder.reset()
     149 + try:
     150 + unquoted = decoder.decode(b)
     151 + except UnicodeDecodeError:
     152 + ret.append(val[idx - 3 : idx])
     153 + continue
     154 + if not unquoted:
     155 + continue
     156 + if self._qs and unquoted in "+=&;":
     157 + to_add = self._qs_quoter(unquoted)
     158 + if to_add is None: # pragma: no cover
     159 + raise RuntimeError("Cannot quote None")
     160 + ret.append(to_add)
     161 + elif unquoted in self._unsafe:
     162 + to_add = self._quoter(unquoted)
     163 + if to_add is None: # pragma: no cover
     164 + raise RuntimeError("Cannot quote None")
     165 + ret.append(to_add)
     166 + else:
     167 + ret.append(unquoted)
     168 + continue
     169 + 
     170 + if decoder.buffer:
     171 + start_pct = idx - 1 - len(decoder.buffer) * 3
     172 + ret.append(val[start_pct : idx - 1])
     173 + decoder.reset()
     174 + 
     175 + if ch == "+":
     176 + if not self._qs or ch in self._unsafe:
     177 + ret.append("+")
     178 + else:
     179 + ret.append(" ")
     180 + continue
     181 + 
     182 + if ch in self._unsafe:
     183 + ret.append("%")
     184 + h = hex(ord(ch)).upper()[2:]
     185 + for ch in h:
     186 + ret.append(ch)
     187 + continue
     188 + 
     189 + ret.append(ch)
     190 + 
     191 + if decoder.buffer:
     192 + ret.append(val[-len(decoder.buffer) * 3 :])
     193 + 
     194 + ret2 = "".join(ret)
     195 + if ret2 == val:
     196 + return val
     197 + return ret2
     198 + 
Please wait...
Page is in error, reload to recover