def _parse_or_address_line(descriptor, entries): all_values = _values('or-address', entries) or_addresses = [] for entry in all_values: line = 'or-address %s' % entry if ':' not in entry: raise ValueError('or-address line missing a colon: %s' % line) address, port = entry.rsplit(':', 1) if not stem.util.connection.is_valid_ipv4_address( address) and not stem.util.connection.is_valid_ipv6_address( address, allow_brackets=True): raise ValueError('or-address line has a malformed address: %s' % line) if not stem.util.connection.is_valid_port(port): raise ValueError('or-address line has a malformed port: %s' % line) or_addresses.append( (address.lstrip('[').rstrip(']'), int(port), stem.util.connection.is_valid_ipv6_address(address, allow_brackets=True))) descriptor.or_addresses = or_addresses
def _parse_m_line(descriptor, entries): # "m" methods 1*(algorithm "=" digest) # example: m 8,9,10,11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs all_hashes = [] for value in _values('m', entries): m_comp = value.split(' ') if not (descriptor.document and descriptor.document.is_vote): vote_status = 'vote' if descriptor.document else '<undefined document>' raise ValueError("%s 'm' line should only appear in votes (appeared in a %s): m %s" % (descriptor._name(), vote_status, value)) elif len(m_comp) < 1: raise ValueError("%s 'm' line needs to start with a series of methods: m %s" % (descriptor._name(), value)) try: methods = [int(entry) for entry in m_comp[0].split(',')] except ValueError: raise ValueError('%s microdescriptor methods should be a series of comma separated integers: m %s' % (descriptor._name(), value)) hashes = {} for entry in m_comp[1:]: if '=' not in entry: raise ValueError("%s can only have a series of 'algorithm=digest' mappings after the methods: m %s" % (descriptor._name(), value)) hash_name, digest = entry.split('=', 1) hashes[hash_name] = digest all_hashes.append((methods, hashes)) descriptor.microdescriptor_hashes = all_hashes
def _parse_a_line(descriptor: 'stem.descriptor.Descriptor', entries: ENTRY_TYPE) -> None: # "a" SP address ":" portlist # example: a [2001:888:2133:0:82:94:251:204]:9001 or_addresses = [] for value in _values('a', entries): if ':' not in value: raise ValueError( "%s 'a' line must be of the form '[address]:[ports]': a %s" % (descriptor._name(), value)) address, port = value.rsplit(':', 1) if not stem.util.connection.is_valid_ipv4_address( address) and not stem.util.connection.is_valid_ipv6_address( address, allow_brackets=True): raise ValueError( "%s 'a' line must start with an IPv6 address: a %s" % (descriptor._name(), value)) if stem.util.connection.is_valid_port(port): or_addresses.append((address.lstrip('[').rstrip(']'), int(port), stem.util.connection.is_valid_ipv6_address( address, allow_brackets=True))) else: raise ValueError("%s 'a' line had an invalid port (%s): a %s" % (descriptor._name(), port, value)) descriptor.or_addresses = or_addresses
def _parse_or_address_line(descriptor, entries): all_values = _values('or-address', entries) or_addresses = [] for entry in all_values: line = 'or-address %s' % entry if ':' not in entry: raise ValueError('or-address line missing a colon: %s' % line) address, port = entry.rsplit(':', 1) is_ipv6 = address.startswith('[') and address.endswith(']') if is_ipv6: address = address[1:-1] # remove brackets if not ( (not is_ipv6 and stem.util.connection.is_valid_ipv4_address(address)) or (is_ipv6 and stem.util.connection.is_valid_ipv6_address(address))): raise ValueError('or-address line has a malformed address: %s' % line) if not stem.util.connection.is_valid_port(port): raise ValueError('or-address line has a malformed port: %s' % line) or_addresses.append((address, int(port), is_ipv6)) descriptor.or_addresses = or_addresses
def _parse_or_address_line(descriptor, entries): all_values = _values('or-address', entries) or_addresses = [] for entry in all_values: line = 'or-address %s' % entry if ':' not in entry: raise ValueError('or-address line missing a colon: %s' % line) address, port = entry.rsplit(':', 1) is_ipv6 = address.startswith('[') and address.endswith(']') if is_ipv6: address = address[1:-1] # remove brackets if not ((not is_ipv6 and stem.util.connection.is_valid_ipv4_address(address)) or (is_ipv6 and stem.util.connection.is_valid_ipv6_address(address))): raise ValueError('or-address line has a malformed address: %s' % line) if not stem.util.connection.is_valid_port(port): raise ValueError('or-address line has a malformed port: %s' % line) or_addresses.append((address, int(port), is_ipv6)) descriptor.or_addresses = or_addresses
def _parse_a_line(descriptor, entries): # "a" SP address ":" portlist # example: a [2001:888:2133:0:82:94:251:204]:9001 or_addresses = [] for value in _values('a', entries): if ':' not in value: raise ValueError("%s 'a' line must be of the form '[address]:[ports]': a %s" % (descriptor._name(), value)) address, port = value.rsplit(':', 1) is_ipv6 = address.startswith('[') and address.endswith(']') if is_ipv6: address = address[1:-1] # remove brackets if not ((not is_ipv6 and stem.util.connection.is_valid_ipv4_address(address)) or (is_ipv6 and stem.util.connection.is_valid_ipv6_address(address))): raise ValueError("%s 'a' line must start with an IPv6 address: a %s" % (descriptor._name(), value)) if stem.util.connection.is_valid_port(port): or_addresses.append((address, int(port), is_ipv6)) else: raise ValueError("%s 'a' line had an invalid port (%s): a %s" % (descriptor._name(), port, value)) descriptor.or_addresses = or_addresses
def _parse_transport_line(descriptor, entries): # "transport" transportname address:port [arglist] # Everything after the transportname is scrubbed in published bridge # descriptors, so we'll never see it in practice. # # These entries really only make sense for bridges, but have been seen # on non-bridges in the wild when the relay operator configured it this # way. transports = {} for value in _values('transport', entries): name, address, port, args = None, None, None, None if ' ' not in value: # scrubbed name = value else: # not scrubbed value_comp = value.split() if len(value_comp) < 1: raise ValueError( 'Transport line is missing its transport name: transport %s' % value) elif len(value_comp) < 2: raise ValueError( 'Transport line is missing its address:port value: transport %s' % value) elif ':' not in value_comp[1]: raise ValueError( "Transport line's address:port entry is missing a colon: transport %s" % value) name = value_comp[0] address, port_str = value_comp[1].rsplit(':', 1) if not stem.util.connection.is_valid_ipv4_address(address) or \ stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True): raise ValueError( 'Transport line has a malformed address: transport %s' % value) elif not stem.util.connection.is_valid_port(port_str): raise ValueError( 'Transport line has a malformed port: transport %s' % value) address.lstrip('[').rstrip(']') port = int(port_str) args = value_comp[2:] if len(value_comp) >= 3 else [] transports[name] = (address, port, args) descriptor.transport = transports
def _parse_id_line(descriptor: 'stem.descriptor.Descriptor', entries: ENTRY_TYPE) -> None: identities = {} for entry in _values('id', entries): entry_comp = entry.split() if len(entry_comp) >= 2: key_type, key_value = entry_comp[0], entry_comp[1] if key_type in identities: raise ValueError("There can only be one 'id' line per a key type, but '%s' appeared multiple times" % key_type) identities[key_type] = key_value else: raise ValueError("'id' lines should contain both the key type and digest: id %s" % entry) descriptor.identifiers = identities
def _parse_transport_line(descriptor, entries): # "transport" transportname address:port [arglist] # Everything after the transportname is scrubbed in published bridge # descriptors, so we'll never see it in practice. # # These entries really only make sense for bridges, but have been seen # on non-bridges in the wild when the relay operator configured it this # way. transports = {} for value in _values('transport', entries): name, address, port, args = None, None, None, None if ' ' not in value: # scrubbed name = value else: # not scrubbed value_comp = value.split() if len(value_comp) < 1: raise ValueError('Transport line is missing its transport name: transport %s' % value) elif len(value_comp) < 2: raise ValueError('Transport line is missing its address:port value: transport %s' % value) elif ':' not in value_comp[1]: raise ValueError("Transport line's address:port entry is missing a colon: transport %s" % value) name = value_comp[0] address, port_str = value_comp[1].rsplit(':', 1) if not stem.util.connection.is_valid_ipv4_address(address) or \ stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True): raise ValueError('Transport line has a malformed address: transport %s' % value) elif not stem.util.connection.is_valid_port(port_str): raise ValueError('Transport line has a malformed port: transport %s' % value) address.lstrip('[').rstrip(']') port = int(port_str) args = value_comp[2:] if len(value_comp) >= 3 else [] transports[name] = (address, port, args) descriptor.transport = transports
def _parse_id_line(descriptor, entries): identities = {} for entry in _values('id', entries): entry_comp = entry.split() if len(entry_comp) >= 2: key_type, key_value = entry_comp[0], entry_comp[1] if key_type in identities: raise ValueError("There can only be one 'id' line per a key type, but '%s' appeared multiple times" % key_type) descriptor.identifier_type = key_type descriptor.identifier = key_value identities[key_type] = key_value else: raise ValueError("'id' lines should contain both the key type and digest: id %s" % entry) descriptor.identifiers = identities
def _parse_or_address_line(descriptor, entries): all_values = _values('or-address', entries) or_addresses = [] for entry in all_values: line = 'or-address %s' % entry if ':' not in entry: raise ValueError('or-address line missing a colon: %s' % line) address, port = entry.rsplit(':', 1) if not stem.util.connection.is_valid_ipv4_address(address) and not stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True): raise ValueError('or-address line has a malformed address: %s' % line) if not stem.util.connection.is_valid_port(port): raise ValueError('or-address line has a malformed port: %s' % line) or_addresses.append((address.lstrip('[').rstrip(']'), int(port), stem.util.connection.is_valid_ipv6_address(address, allow_brackets = True))) descriptor.or_addresses = or_addresses