def __init__(self, sso, account): gobject.GObject.__init__(self) self._signals = [] self._transport = SSLTCPClient(self.host, self.port) self._signals.append( self._transport.connect("notify::status", self.on_status_changed)) self._signals.append( self._transport.connect("received", self.on_message_received)) self._answered = False self._src = None self._msg_queue = [] self._requests = {} self._relays = [] self._account = account self._sso = sso self._tokens = {}
def __init__(self, sso, account, host="relay.voice.messenger.msn.com", port=443): gobject.GObject.__init__(self) Timer.__init__(self) self._sso = sso self._account = account self._signals = [] self._transport = SSLTCPClient(host, port) self._signals.append(self._transport.connect("notify::status", self.on_status_changed)) self._signals.append(self._transport.connect("received", self.on_message_received)) self._tokens = {} self._msg_queue = [] self._transactions = {} # id => (initial_request) self._request_id = 0 self._requests = {} # id => (callback, errback, count, relays)
def __init__(self, sso, account): gobject.GObject.__init__(self) self._signals = [] self._transport = SSLTCPClient(self.host, self.port) self._signals.append(self._transport.connect("notify::status", self.on_status_changed)) self._signals.append(self._transport.connect("received", self.on_message_received)) self._answered = False self._src = None self._msg_queue = [] self._requests = {} self._relays = [] self._account = account self._sso = sso self._tokens = {}
class TURNClient(gobject.GObject): host = "relay.voice.messenger.msn.com" port = 443 # Signal emitted when all requests were answered or failed __gsignals__ = { 'done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object,)) } def __init__(self, sso, account): gobject.GObject.__init__(self) self._signals = [] self._transport = SSLTCPClient(self.host, self.port) self._signals.append(self._transport.connect("notify::status", self.on_status_changed)) self._signals.append(self._transport.connect("received", self.on_message_received)) self._answered = False self._src = None self._msg_queue = [] self._requests = {} self._relays = [] self._account = account self._sso = sso self._tokens = {} def send(self, message): self._requests[message.id] = message if self._transport.status != IoStatus.OPEN: self._msg_queue.append(message) self._transport.open() return self._transport.send(str(message)) @RequireSecurityTokens(LiveService.MESSENGER_SECURE) def request_shared_secret(self, callback, errcb, count=4): self._src = gobject.timeout_add(REQUEST_TIMEOUT, self.on_timeout) for _ in range(count): token = self._tokens[LiveService.MESSENGER_SECURE] username = "******" % token attrs = [TURNAttribute(AttributeTypes.USERNAME, username)] msg = TURNMessage(MessageTypes.SHARED_SECRET_REQUEST, attrs) self.send(msg) @RequireSecurityTokens(LiveService.MESSENGER_SECURE) def request_shared_secret_with_integrity(self, callback, errcb, realm, nonce): token = self._tokens[LiveService.MESSENGER_SECURE] username = "******" % token attrs = [TURNAttribute(AttributeTypes.USERNAME, username), TURNAttribute(AttributeTypes.REALM, realm), TURNAttribute(AttributeTypes.NONCE, nonce)] msg = TURNMessage(MessageTypes.SHARED_SECRET_REQUEST, attrs, 24) hmac = self.build_message_integrity(msg, token, nonce) msg.attributes.append(TURNAttribute(AttributeTypes.MESSAGE_INTEGRITY, hmac)) msg.extra_size = 0 self.send(msg) def build_message_integrity(self, msg, token, nonce): nonce = nonce.strip("\"") m = hashlib.md5() m.update("RPS_%s\x00\x00\x00:" % token) m.update("%s:%s" % (nonce, self._account)) key = m.digest() + ("\x00" * 16) msg = str(msg) padding = 64 - (len(msg) % 64) if padding is 64: padding = 0 msg += "\x00" * padding h = hmac.new(key, msg, hashlib.sha1) return h.digest() def on_status_changed(self, transport, param): if self._transport.status == IoStatus.OPEN: while self._msg_queue: self.send(self._msg_queue.pop()) elif self._transport.status == IoStatus.CLOSED: self._done() def on_message_received(self, transport, data, length): msg = TURNMessage() msg.parse(data) if self._requests.get(msg.id, None) is None: return else: del self._requests[msg.id] if msg.type == MessageTypes.SHARED_SECRET_ERROR: error_msg = None realm = None nonce = None for attr in msg.attributes: if attr.type == AttributeTypes.REALM: realm = attr.value elif attr.type == AttributeTypes.NONCE: nonce = attr.value elif attr.type == AttributeTypes.ERROR_CODE: error_msg = attr.value[4:] if error_msg == "Unauthorized": if realm is not None or nonce is not None: self.request_shared_secret_with_integrity(None, None, realm, nonce) return elif msg.type == MessageTypes.SHARED_SECRET_RESPONSE: relay = MediaRelay() for attr in msg.attributes: if attr.type == AttributeTypes.USERNAME: relay.username = base64.b64encode(attr.value) elif attr.type == AttributeTypes.PASSWORD: relay.password = base64.b64encode(attr.value) elif attr.type == AttributeTypes.ALTERNATE_SERVER: server = struct.unpack("!HHcccc", attr.value) ip = map(lambda x: ord(x), server[2:6]) relay.ip = "%i.%i.%i.%i" % tuple(ip) relay.port = server[1] self._relays.append(relay) if not self._requests: self._done() def on_timeout(self): self._done() return False def _done(self): if not self._answered: self._answered = True self._requests = {} self._msg_queue = [] for signal_id in self._signals: self._transport.disconnect(signal_id) if self._src is not None: gobject.source_remove(self._src) self._src = None self.emit("done", self._relays) self._transport.close()
class TURNClient(gobject.GObject, Timer): def __init__(self, sso, account, host="relay.voice.messenger.msn.com", port=443): gobject.GObject.__init__(self) Timer.__init__(self) self._sso = sso self._account = account self._signals = [] self._transport = SSLTCPClient(host, port) self._signals.append(self._transport.connect("notify::status", self.on_status_changed)) self._signals.append(self._transport.connect("received", self.on_message_received)) self._tokens = {} self._msg_queue = [] self._transactions = {} # id => (initial_request) self._request_id = 0 self._requests = {} # id => (callback, errback, count, relays) def send(self, message): self._transactions[message.id] = message if self._transport.status != IoStatus.OPEN: self._msg_queue.append(message) self._transport.open() return self._transport.send(str(message)) @RequireSecurityTokens(LiveService.MESSENGER_SECURE) def request_shared_secret(self, callback, errback, count=1): logger.info("Sending shared secret requests (%i)" % count) self._request_id += 1 self._requests[self._request_id] = (callback, errback, count, []) self.start_timeout_with_id("request", self._request_id, REQUEST_TIMEOUT) for _ in range(count): token = self._tokens[LiveService.MESSENGER_SECURE] username = "******" % token attrs = [TURNAttribute(AttributeTypes.USERNAME, username)] msg = TURNMessage(None, MessageTypes.SHARED_SECRET_REQUEST, attrs) self.send(msg) @RequireSecurityTokens(LiveService.MESSENGER_SECURE) def request_shared_secret_with_integrity(self, callback, errcb, realm, nonce): logger.info("Sending shared secret request with integrity") token = self._tokens[LiveService.MESSENGER_SECURE] username = "******" % token attrs = [TURNAttribute(AttributeTypes.USERNAME, username), TURNAttribute(AttributeTypes.REALM, realm), TURNAttribute(AttributeTypes.NONCE, nonce)] msg = TURNMessage(None, MessageTypes.SHARED_SECRET_REQUEST, attrs, 24) hmac = self.build_message_integrity(msg, token, nonce) msg.attributes.append(TURNAttribute(AttributeTypes.MESSAGE_INTEGRITY, hmac)) msg.extra_size = 0 self.send(msg) def build_message_integrity(self, msg, token, nonce): nonce = nonce.strip("\"") m = hashlib.md5() m.update("RPS_%s\x00\x00\x00:" % token) m.update("%s:%s" % (nonce, self._account)) key = m.digest() + ("\x00" * 16) msg = str(msg) padding = 64 - (len(msg) % 64) if padding is 64: padding = 0 msg += "\x00" * padding h = hmac.new(key, msg, hashlib.sha1) return h.digest() def on_status_changed(self, transport, param): if self._transport.status == IoStatus.OPEN: while self._msg_queue: self.send(self._msg_queue.pop()) elif self._transport.status == IoStatus.CLOSED: pass #TODO something.. def on_message_received(self, transport, data, length): try: msg = parse_message(data) initial_request = self._transactions.pop(msg.id, None) if initial_request is None: logger.warning("Received TURN response with invalid ID") return if msg.type == MessageTypes.SHARED_SECRET_ERROR: self.on_shared_secret_error(msg) elif msg.type == MessageTypes.SHARED_SECRET_RESPONSE: self.on_shared_secret_response(msg) else: logger.warning("Received unexpected message: %i" % msg.type) except Exception, e: logger.exception(e) logger.error("Received invalid TURN message")
class TURNClient(gobject.GObject): host = "relay.voice.messenger.msn.com" port = 443 # Signal emitted when all requests were answered or failed __gsignals__ = { 'done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (object, )) } def __init__(self, sso, account): gobject.GObject.__init__(self) self._signals = [] self._transport = SSLTCPClient(self.host, self.port) self._signals.append( self._transport.connect("notify::status", self.on_status_changed)) self._signals.append( self._transport.connect("received", self.on_message_received)) self._answered = False self._src = None self._msg_queue = [] self._requests = {} self._relays = [] self._account = account self._sso = sso self._tokens = {} def send(self, message): self._requests[message.id] = message if self._transport.status != IoStatus.OPEN: self._msg_queue.append(message) self._transport.open() return self._transport.send(str(message)) @RequireSecurityTokens(LiveService.MESSENGER_SECURE) def request_shared_secret(self, callback, errcb, count=4): self._src = gobject.timeout_add(REQUEST_TIMEOUT, self.on_timeout) for _ in range(count): token = self._tokens[LiveService.MESSENGER_SECURE] username = "******" % token attrs = [TURNAttribute(AttributeTypes.USERNAME, username)] msg = TURNMessage(MessageTypes.SHARED_SECRET_REQUEST, attrs) self.send(msg) @RequireSecurityTokens(LiveService.MESSENGER_SECURE) def request_shared_secret_with_integrity(self, callback, errcb, realm, nonce): token = self._tokens[LiveService.MESSENGER_SECURE] username = "******" % token attrs = [ TURNAttribute(AttributeTypes.USERNAME, username), TURNAttribute(AttributeTypes.REALM, realm), TURNAttribute(AttributeTypes.NONCE, nonce) ] msg = TURNMessage(MessageTypes.SHARED_SECRET_REQUEST, attrs, 24) hmac = self.build_message_integrity(msg, token, nonce) msg.attributes.append( TURNAttribute(AttributeTypes.MESSAGE_INTEGRITY, hmac)) msg.extra_size = 0 self.send(msg) def build_message_integrity(self, msg, token, nonce): nonce = nonce.strip("\"") m = hashlib.md5() m.update("RPS_%s\x00\x00\x00:" % token) m.update("%s:%s" % (nonce, self._account)) key = m.digest() + ("\x00" * 16) msg = str(msg) padding = 64 - (len(msg) % 64) if padding is 64: padding = 0 msg += "\x00" * padding h = hmac.new(key, msg, hashlib.sha1) return h.digest() def on_status_changed(self, transport, param): if self._transport.status == IoStatus.OPEN: while self._msg_queue: self.send(self._msg_queue.pop()) elif self._transport.status == IoStatus.CLOSED: self._done() def on_message_received(self, transport, data, length): msg = TURNMessage() msg.parse(data) if self._requests.get(msg.id, None) is None: return else: del self._requests[msg.id] if msg.type == MessageTypes.SHARED_SECRET_ERROR: error_msg = None realm = None nonce = None for attr in msg.attributes: if attr.type == AttributeTypes.REALM: realm = attr.value elif attr.type == AttributeTypes.NONCE: nonce = attr.value elif attr.type == AttributeTypes.ERROR_CODE: error_msg = attr.value[4:] if error_msg == "Unauthorized": if realm is not None or nonce is not None: self.request_shared_secret_with_integrity( None, None, realm, nonce) return elif msg.type == MessageTypes.SHARED_SECRET_RESPONSE: relay = MediaRelay() for attr in msg.attributes: if attr.type == AttributeTypes.USERNAME: relay.username = base64.b64encode(attr.value) elif attr.type == AttributeTypes.PASSWORD: relay.password = base64.b64encode(attr.value) elif attr.type == AttributeTypes.ALTERNATE_SERVER: server = struct.unpack("!HHcccc", attr.value) ip = map(lambda x: ord(x), server[2:6]) relay.ip = "%i.%i.%i.%i" % tuple(ip) relay.port = server[1] self._relays.append(relay) if not self._requests: self._done() def on_timeout(self): self._done() return False def _done(self): if not self._answered: self._answered = True self._requests = {} self._msg_queue = [] for signal_id in self._signals: self._transport.disconnect(signal_id) if self._src is not None: gobject.source_remove(self._src) self._src = None self.emit("done", self._relays) self._transport.close()