/ src / network / bmobject.py.bak
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()