"""Device abstraction layer.""" import hashlib import io import logging import re import struct from .. import formats, util log = logging.getLogger(__name__) _identity_regexp = re.compile(''.join([ '^' r'(?:(?P.*)://)?', r'(?:(?P.*)@)?', r'(?P.*?)', r'(?::(?P\w*))?', r'(?P/.*)?', '$' ])) def string_to_identity(identity_str): """Parse string into Identity dictionary.""" m = _identity_regexp.match(identity_str) result = m.groupdict() log.debug('parsed identity: %s', result) return {k: v for k, v in result.items() if v} def identity_to_string(identity_dict): """Dump Identity dictionary into its string representation.""" result = [] if identity_dict.get('proto'): result.append(identity_dict['proto'] + '://') if identity_dict.get('user'): result.append(identity_dict['user'] + '@') result.append(identity_dict['host']) if identity_dict.get('port'): result.append(':' + identity_dict['port']) if identity_dict.get('path'): result.append(identity_dict['path']) log.debug('identity parts: %s', result) return ''.join(result) class Error(Exception): """Device-related error.""" class NotFoundError(Error): """Device could not be found.""" class DeviceError(Error): """Error during device operation.""" class Identity(object): """Represent SLIP-0013 identity, together with a elliptic curve choice.""" def __init__(self, identity_str, curve_name): """Configure for specific identity and elliptic curve usage.""" self.identity_dict = string_to_identity(identity_str) self.curve_name = curve_name def items(self): """Return a copy of identity_dict items.""" return self.identity_dict.items() def __str__(self): """Return identity serialized to string.""" return '<{}|{}>'.format(identity_to_string(self.identity_dict), self.curve_name) def get_bip32_address(self, ecdh=False): """Compute BIP32 derivation address according to SLIP-0013/0017.""" index = struct.pack('