bmobject.py.bak
1 """ 2 BMObject and it's exceptions. 3 """ 4 import logging 5 import time 6 7 import protocol 8 import state 9 import connectionpool 10 from network import dandelion_ins 11 from highlevelcrypto import calculateInventoryHash 12 13 logger = logging.getLogger('default') 14 15 16 class BMObjectInsufficientPOWError(Exception): 17 """Exception indicating the object 18 doesn't have sufficient proof of work.""" 19 errorCodes = ("Insufficient proof of work") 20 21 22 class BMObjectExpiredError(Exception): 23 """Exception indicating the object's lifetime has expired.""" 24 errorCodes = ("Object expired") 25 26 27 class BMObjectUnwantedStreamError(Exception): 28 """Exception indicating the object is in a stream 29 we didn't advertise as being interested in.""" 30 errorCodes = ("Object in unwanted stream") 31 32 33 class BMObjectInvalidError(Exception): 34 """The object's data does not match object specification.""" 35 errorCodes = ("Invalid object") 36 37 38 class BMObjectAlreadyHaveError(Exception): 39 """We received a duplicate object (one we already have)""" 40 errorCodes = ("Already have this object") 41 42 43 class BMObject(object): 44 """Bitmessage Object as a class.""" 45 46 # max TTL, 28 days and 3 hours 47 maxTTL = 28 * 24 * 60 * 60 + 10800 48 # min TTL, 3 hour (in the past 49 minTTL = -3600 50 51 def __init__( 52 self, 53 nonce, 54 expiresTime, 55 objectType, 56 version, 57 streamNumber, 58 data, 59 payloadOffset 60 ): 61 self.nonce = nonce 62 self.expiresTime = expiresTime 63 self.objectType = objectType 64 self.version = version 65 self.streamNumber = streamNumber 66 self.inventoryHash = calculateInventoryHash(data) 67 # copy to avoid memory issues 68 self.data = bytearray(data) 69 self.tag = self.data[payloadOffset:payloadOffset + 32] 70 71 def checkProofOfWorkSufficient(self): 72 """Perform a proof of work check for sufficiency.""" 73 # Let us check to make sure that the proof of work is sufficient. 74 if not protocol.isProofOfWorkSufficient(self.data): 75 logger.info('Proof of work is insufficient.') 76 raise BMObjectInsufficientPOWError() 77 78 def checkEOLSanity(self): 79 """Check if object's lifetime 80 isn't ridiculously far in the past or future.""" 81 # EOL sanity check 82 if self.expiresTime - int(time.time()) > BMObject.maxTTL: 83 logger.info( 84 'This object\'s End of Life time is too far in the future.' 85 ' Ignoring it. Time is %i', self.expiresTime) 86 # .. todo:: remove from download queue 87 raise BMObjectExpiredError() 88 89 if self.expiresTime - int(time.time()) < BMObject.minTTL: 90 logger.info( 91 'This object\'s End of Life time was too long ago.' 92 ' Ignoring the object. Time is %i', self.expiresTime) 93 # .. todo:: remove from download queue 94 raise BMObjectExpiredError() 95 96 def checkStream(self): 97 """Check if object's stream matches streams we are interested in""" 98 if self.streamNumber < protocol.MIN_VALID_STREAM \ 99 or self.streamNumber > protocol.MAX_VALID_STREAM: 100 logger.warning( 101 'The object has invalid stream: %s', self.streamNumber) 102 raise BMObjectInvalidError() 103 if self.streamNumber not in connectionpool.pool.streams: 104 logger.debug( 105 'The streamNumber %i isn\'t one we are interested in.', 106 self.streamNumber) 107 raise BMObjectUnwantedStreamError() 108 109 def checkAlreadyHave(self): 110 """ 111 Check if we already have the object 112 (so that we don't duplicate it in inventory 113 or advertise it unnecessarily) 114 """ 115 # if it's a stem duplicate, pretend we don't have it 116 if dandelion_ins.hasHash(self.inventoryHash): 117 return 118 if self.inventoryHash in state.Inventory: 119 raise BMObjectAlreadyHaveError() 120 121 def checkObjectByType(self): 122 """Call a object type specific check 123 (objects can have additional checks based on their types)""" 124 if self.objectType == protocol.OBJECT_GETPUBKEY: 125 self.checkGetpubkey() 126 elif self.objectType == protocol.OBJECT_PUBKEY: 127 self.checkPubkey() 128 elif self.objectType == protocol.OBJECT_MSG: 129 self.checkMessage() 130 elif self.objectType == protocol.OBJECT_BROADCAST: 131 self.checkBroadcast() 132 # other objects don't require other types of tests 133 134 def checkMessage(self): # pylint: disable=no-self-use 135 """"Message" object type checks.""" 136 return 137 138 def checkGetpubkey(self): 139 """"Getpubkey" object type checks.""" 140 if len(self.data) < 42: 141 logger.info( 142 'getpubkey message doesn\'t contain enough data. Ignoring.') 143 raise BMObjectInvalidError() 144 145 def checkPubkey(self): 146 """"Pubkey" object type checks.""" 147 # sanity check 148 if len(self.data) < 146 or len(self.data) > 440: 149 logger.info('pubkey object too short or too long. Ignoring.') 150 raise BMObjectInvalidError() 151 152 def checkBroadcast(self): 153 """"Broadcast" object type checks.""" 154 if len(self.data) < 180: 155 logger.debug( 156 'The payload length of this broadcast' 157 ' packet is unreasonably low. Someone is probably' 158 ' trying funny business. Ignoring message.') 159 raise BMObjectInvalidError() 160 161 # this isn't supported anymore 162 if self.version < 2: 163 raise BMObjectInvalidError()