def message_arrived(self, msg): """Called when a payment message is received via the controller. Is responsible for piecing it back together into the actual message. @param msg: the data received from Tor @type msg: str""" self.buffer += msg # is the whole message here? msgLen, msgData = Basic.read_short(self.buffer) if len(msgData) >= msgLen: msgData = msgData[:msgLen] # we just discard the rest of the cell, two messages are never packed in the same cell currently self.buffer = "" # what type of message is this? msgType, msgData = Basic.read_byte(msgData) # ok, now handle that message: for msgName in MESSAGE_CODES.keys(): if msgType == MESSAGE_CODES[msgName]: # if we don't know how to handle this message, just close the circuit if msgName not in self.messageHandlers: log_msg("Remote request for %s, which we do not know how to handle" % (msgName), 1) self.close() return # get the handler: handler = self.messageHandlers[msgName] # get the handler function: funcName = "handle_%s" % (msgName) if not hasattr(handler, funcName): raise Exception("%s cannot handle %s payment message?" % (handler, msgName)) f = getattr(handler, funcName) f(msgData) return # uhh, not sure how to handle this message: raise Exception("Unknown message type for payment message: %s" % (msgType))
def unpack_and_mint(self, msg): """unpacks the request retreiving the number of coins packed and the total value desired. Verification: values must be positive! """ self.number, msg = Basic.read_short(msg) value, msg = Basic.read_int(msg) log_msg('REQUEST:: %s %s' % (self.number, self.hexId), 0) if not BankUtil.is_positive_integer(self.number): raise ValueError('number of coins must be greater than 0!') if value != ACOIN_VALUE or not BankUtil.is_positive_integer(value): raise ValueError('coins must have a positive, integer value') self.bill = 0 self.signatures = "" for i in range(0, self.number): #TODO: move to a worker pool or something sig = Globals.ACOIN_KEY.decrypt(msg[:Globals.ACOIN_KEY_BYTES], False) self.signatures += struct.pack('!%ss' % (Globals.ACOIN_KEY_BYTES), sig) msg = msg[Globals.ACOIN_KEY_BYTES:] self.bill += value #TODO: move this constraint to postgres to get rid of any potential race conditions sql = "SELECT balance FROM Accounts WHERE Username = %s" inj = (self.user, ) d = db.read(sql, inj) return d
def unpack_and_mint(self, msg): """unpacks the request retreiving the number of coins packed and the total value desired. Verification: values must be positive! """ self.number, msg = Basic.read_short(msg) value, msg = Basic.read_int(msg) log_msg('REQUEST:: %s %s'%(self.number, self.hexId), 0) if not BankUtil.is_positive_integer(self.number): raise ValueError('number of coins must be greater than 0!') if value != ACOIN_VALUE or not BankUtil.is_positive_integer(value): raise ValueError('coins must have a positive, integer value') self.bill = 0 self.signatures = "" for i in range(0, self.number): #TODO: move to a worker pool or something sig = Globals.ACOIN_KEY.decrypt(msg[:Globals.ACOIN_KEY_BYTES], False) self.signatures += struct.pack('!%ss'%(Globals.ACOIN_KEY_BYTES), sig) msg = msg[Globals.ACOIN_KEY_BYTES:] self.bill += value #TODO: move this constraint to postgres to get rid of any potential race conditions sql = "SELECT balance FROM Accounts WHERE Username = %s" inj = (self.user,) d = db.read(sql, inj) return d
def message_arrived(self, msg): """Called when a payment message is received via the controller. Is responsible for piecing it back together into the actual message. @param msg: the data received from Tor @type msg: str""" self.buffer += msg #is the whole message here? msgLen, msgData = Basic.read_short(self.buffer) if len(msgData) >= msgLen: msgData = msgData[:msgLen] #we just discard the rest of the cell, two messages are never packed in the same cell currently self.buffer = "" #what type of message is this? msgType, msgData = Basic.read_byte(msgData) #ok, now handle that message: for msgName in MESSAGE_CODES.keys(): if msgType == MESSAGE_CODES[msgName]: #if we don't know how to handle this message, just close the circuit if msgName not in self.messageHandlers: log_msg("Remote request for %s, which we do not know how to handle" % (msgName), 1) self.close() return #get the handler: handler = self.messageHandlers[msgName] #get the handler function: funcName = "handle_%s" % (msgName) if not hasattr(handler, funcName): raise Exception("%s cannot handle %s payment message?" % (handler, msgName)) f = getattr(handler, funcName) f(msgData) return #uhh, not sure how to handle this message: raise Exception("Unknown message type for payment message: %s" % (msgType))
def read_request(self, data, host, transport): try: #read the header: data = self._read_header(data, "request") #read the protocol type: protocolType, data = Basic.read_byte(data) assert protocolType in self.TEST_TYPES, "Unknown echo protocol: %s" % (protocolType) protocol = self.TEST_TYPES[protocolType] #read the port: port, data = Basic.read_short(data) except AssertionError, error: raise BadEchoMessageFormat(str(error))
def read_request(self, data, host, transport): try: #read the header: data = self._read_header(data, "request") #read the protocol type: protocolType, data = Basic.read_byte(data) assert protocolType in self.TEST_TYPES, "Unknown echo protocol: %s" % ( protocolType) protocol = self.TEST_TYPES[protocolType] #read the port: port, data = Basic.read_short(data) except AssertionError, error: raise BadEchoMessageFormat(str(error))
def handle_dht_request(self, data): log_msg("Got remote DHT request", 4, "dht") #unpack and validate the message: version, data = Basic.read_byte(data) assert version == Node.VERSION #read the infohash: vals, data = Basic.read_message("20s", data) infohash = vals[0] #read each peer: peers = set() while len(data) > 0: #what type of peer? (ip or url) peerType, data = Basic.read_byte(data) #IP peer: if peerType == 0: vals, data = Basic.read_message("!4sH", data) host = socket.inet_ntoa(vals[0]) port = vals[1] #URL peer: elif peerType == 1: host, data = Basic.read_lenstr(data) port, data = Basic.read_short(data) #bad peer type: else: raise Exception("Unknown peer address type: %s" % (peerType)) peers.add((host, port)) #note that there is a new transaction: transactionId = self.currentTransactionId self.responses[transactionId] = "" self.currentTransactionId += 1 #now add each peer: for host, port in peers: #make sure it's not one of our defaults #TODO: in the future, make sure we don't already know about it anyway? Eh, maybe that will break DHT somehow? if (host, port) not in Node.BOOTSTRAP_NODES: log_msg("Neat, someone told us about a new DHT node", 2) self.dhtNode.add_contact(host, port) #and then send out the request: def response(data, transactionId=transactionId): #is this the last message? if len(data) <= 0: #then send the response for this transaction: self._send_peers(transactionId) #otherwise, just accumulate the data for later: else: self.responses[transactionId] += "".join(data[0]) self.dhtNode.get_peers(infohash, response)
def update_db(self, blob): """utility function that updates verifies the nonce in the msg and then updates the nonce in the db""" protocol, blob = Basic.read_byte(blob) if protocol is not 1: raise Exception('change protocol') msgNum, blob = Basic.read_short(blob) #the msgNum is a nonce to prevent replay attacks- #the client always increases it by one, we just check that it is bigger if msgNum > self.previousMsgnum: #update the msgnum in the db to be this msgnum of course - #not generally threadsafe sql = "UPDATE Relays SET Msgnum = %s WHERE tor_id = %s" inj = (msgNum, self.hexId) d = db.write(sql, inj) else: raise Exception('replay attack or something') return blob
def unpack_and_verify(self, blob): """verifies that... 1. the coin is valid 2. isn't expired 3. hasn't been deposited before returns one of 4 statements""" self.number, blob = Basic.read_short(blob) log_msg('DEPOSIT:: %s %s'%(self.number, self.hexId), 0) total = 0 self.returnSlip = "" if BankUtil.is_positive_integer(self.number): #we don't want the interval to roll over half way through a request current = Globals.CURRENT_ACOIN_INTERVAL[0] for i in range(self.number): result, coin, blob = deposit_acoin(blob, current) self.returnSlip += result if result == '0': total += ACoin.VALUE self.amountEarned = total return total
def unpack_and_verify(self, blob): """verifies that... 1. the coin is valid 2. isn't expired 3. hasn't been deposited before returns one of 4 statements""" self.number, blob = Basic.read_short(blob) log_msg('DEPOSIT:: %s %s' % (self.number, self.hexId), 0) total = 0 self.returnSlip = "" if BankUtil.is_positive_integer(self.number): #we don't want the interval to roll over half way through a request current = Globals.CURRENT_ACOIN_INTERVAL[0] for i in range(self.number): result, coin, blob = deposit_acoin(blob, current) self.returnSlip += result if result == '0': total += ACoin.VALUE self.amountEarned = total return total