def checkObject(self, obj, inbound): if type(obj) != bool: raise Violation("not a bool") if self.value != None: if obj != self.value: raise Violation("not %s" % self.value)
def checkObject(self, obj, inbound): if not isinstance(obj, tuple): raise Violation("not a tuple") if len(obj) != len(self.constraints): raise Violation("wrong size tuple") for i in range(len(self.constraints)): self.constraints[i].checkObject(obj[i], inbound)
def open(self, opentype): # called (by delegation) by the top Unslicer on the stack, regardless # of what kind of unslicer it is. This is only used for "internal" # objects: non-top-level nodes assert len(self.protocol.receiveStack) > 1 if opentype[0] == 'copyable': if len(opentype) > 1: copyablename = opentype[1] try: factory = copyable.CopyableRegistry[copyablename] except KeyError: raise Violation("unknown RemoteCopy name '%s'" \ % copyablename) child = factory() return child return None # still waiting for copyablename for reg in self.openRegistries: opener = reg.get(opentype) if opener is not None: child = opener() return child raise Violation("unknown OPEN type %s" % (opentype, ))
def openerCheckToken(self, typebyte, size, opentype): if typebyte == tokens.STRING: if len(opentype) == 0: if size > self.maxIndexLength: why = "first opentype STRING token is too long, %d>%d" % \ (size, self.maxIndexLength) raise Violation(why) if opentype == ("copyable", ): # TODO: this is silly, of course (should pre-compute maxlen) maxlen = reduce(max, [len(cname) \ for cname in copyable.CopyableRegistry.keys()] ) if size > maxlen: why = "copyable-classname token is too long, %d>%d" % \ (size, maxlen) raise Violation(why) elif typebyte == tokens.VOCAB: return else: # TODO: hack for testing raise Violation("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte)) raise BananaError("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte))
def checkAllArgs(self, args, kwargs, inbound): # first we map the positional arguments allargs = {} if len(args) > len(self.argumentNames): raise Violation("method takes %d positional arguments (%d given)" % (len(self.argumentNames), len(args))) for i, argvalue in enumerate(args): allargs[self.argumentNames[i]] = argvalue for argname, argvalue in list(kwargs.items()): if argname in allargs: raise Violation( "got multiple values for keyword argument '%s'" % (argname, )) allargs[argname] = argvalue for argname, argvalue in list(allargs.items()): accept, constraint = self.getKeywordArgConstraint(argname) if not accept: # this argument will be ignored by the far end. TODO: emit a # warning pass try: constraint.checkObject(argvalue, inbound) except Violation as v: v.setLocation("%s=" % argname) raise for argname in self.required: if argname not in allargs: raise Violation("missing required argument '%s'" % argname)
def checkObject(self, obj, inbound): if not isinstance(obj, dict): raise Violation("'%s' (%s) is not a Dictionary" % (obj, type(obj))) if self.maxKeys != None and len(obj) > self.maxKeys: raise Violation("Dict keys=%d > maxKeys=%d" % (len(obj), self.maxKeys)) for key, value in obj.items(): self.keyConstraint.checkObject(key, inbound) self.valueConstraint.checkObject(value, inbound)
def checkObject(self, obj, inbound): if not isinstance(obj, six.binary_type): raise Violation("'%r' is not a bytestring" % (obj, )) if self.maxLength != None and len(obj) > self.maxLength: raise Violation("string too long (%d > %d)" % (len(obj), self.maxLength)) if len(obj) < self.minLength: raise Violation("string too short (%d < %d)" % (len(obj), self.minLength))
def checkObject(self, obj, inbound): if not isinstance(obj, six.integer_types): raise Violation("'%r' is not a number" % (obj, )) if self.maxBytes == -1: if obj >= 2**31 or obj < -2**31: raise Violation("number too large") elif self.maxBytes != None: if abs(obj) >= 2**(8 * self.maxBytes): raise Violation("number too large")
def checkObject(self, obj, inbound): if not isinstance(obj, list): raise Violation("not a list") if self.maxLength is not None and len(obj) > self.maxLength: raise Violation("list too long") if len(obj) < self.minLength: raise Violation("list too short") for o in obj: self.constraint.checkObject(o, inbound)
def checkObject(self, obj, inbound): if not isinstance(obj, six.text_type): raise Violation("not a unicode object") if self.maxLength != None and len(obj) > self.maxLength: raise Violation("string too long (%d > %d)" % (len(obj), self.maxLength)) if len(obj) < self.minLength: raise Violation("string too short (%d < %d)" % (len(obj), self.minLength)) if self.regexp: if not self.regexp.search(obj): raise Violation("regexp failed to match")
def checkObject(self, obj, inbound): if not isinstance(obj, (set, frozenset)): raise Violation("not a set") if (self.mutable == True and not isinstance(obj, set)): raise Violation("obj is a set, but not a mutable one") if (self.mutable == False and not isinstance(obj, frozenset)): raise Violation("obj is a set, but not an immutable one") if self.maxLength is not None and len(obj) > self.maxLength: raise Violation("set is too large") if self.constraint: for o in obj: self.constraint.checkObject(o, inbound)
def checkObject(self, obj, inbound): if not isinstance(obj, str): raise Violation("'%r' is not a bytestring" % (obj, )) if self.maxLength != None and len(obj) > self.maxLength: raise Violation("string too long (%d > %d)" % (len(obj), self.maxLength)) if len(obj) < self.minLength: raise Violation("string too short (%d < %d)" % (len(obj), self.minLength)) if self.regexp: if not self.regexp.search(obj): raise Violation("regexp failed to match")
def openerCheckToken(self, typebyte, size, opentype): if typebyte == tokens.STRING: if size > self.maxIndexLength: why = "STRING token is too long, %d>%d" % \ (size, self.maxIndexLength) raise Violation(why) elif typebyte == tokens.VOCAB: return else: # TODO: hack for testing raise Violation("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte)) raise BananaError("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte))
def checkToken(self, typebyte, size): """Check the token type. Raise an exception if it is not accepted right now, or if the body-length limit is exceeded.""" limit = self.taster.get(typebyte, "not in list") if limit == "not in list": if self.strictTaster: raise BananaError("invalid token type: %s" % tokenNames[typebyte]) else: raise Violation("%s token rejected by %s" % (tokenNames[typebyte], self.name)) if limit and size > limit: raise Violation("%s token too large: %d>%d" % (tokenNames[typebyte], size, limit))
def slicerForObject(self, obj): # could use a table here if you think it'd be faster than an # adapter lookup if self.debug: log.msg("slicerForObject(%s)" % type(obj)) # do the adapter lookup first, so that registered adapters override # UnsafeSlicerTable's InstanceSlicer slicer = tokens.ISlicer(obj, None) if slicer: if self.debug: log.msg("got ISlicer %s" % slicer) return slicer # zope.interface doesn't do transitive adaptation, which is a shame # because we want to let people register ICopyable adapters for # third-party code, and there is an ICopyable->ISlicer adapter # defined in copyable.py, but z.i won't do the transitive # ThirdPartyClass -> ICopyable -> ISlicer # so instead we manually do it here copier = copyable.ICopyable(obj, None) if copier: s = tokens.ISlicer(copier) return s slicerFactory = self.slicerTable.get(type(obj)) if slicerFactory: if self.debug: log.msg(" got slicerFactory %s" % slicerFactory) return slicerFactory(obj) if issubclass(type(obj), types.InstanceType): name = str(obj.__class__) else: name = str(type(obj)) if self.debug: log.msg("cannot serialize %s (%s)" % (obj, name)) raise Violation("cannot serialize %s (%s)" % (obj, name))
def receiveChild(self, obj, ready_deferred=None): if ready_deferred: self._ready_deferreds.append(ready_deferred) if self.debug: log.msg("%s[%d].receiveChild(%s)" % (self, self.count, obj)) # obj could be a primitive type, a Deferred, or a complex type like # those returned from an InstanceUnslicer. However, the individual # object has already been through the schema validation process. The # only remaining question is whether the larger schema will accept # it. if self.maxLength != None and len(self.set) >= self.maxLength: # this is redundant # (if it were a non-primitive one, it would be caught in doOpen) # (if it were a primitive one, it would be caught in checkToken) raise Violation("the set is full") if isinstance(obj, defer.Deferred): if self.debug: log.msg(" adding my update[%d] to %s" % (len(self.set), obj)) # note: the placeholder isn't strictly necessary, but it will # help debugging to see a _Placeholder sitting in the set when it # shouldn't rather than seeing a set that is smaller than it # ought to be. If a remote method ever sees a _Placeholder, then # something inside Foolscap has broken. placeholder = _Placeholder() obj.addCallback(self.update, placeholder) obj.addErrback(self.printErr) self.set.add(placeholder) else: self.set.add(obj)
def checkToken(self, typebyte, size): if self.maxLength != None and len(self.set) >= self.maxLength: # list is full, no more tokens accepted # this is hit if the max+1 item is a primitive type raise Violation("the set is full") if self.itemConstraint: self.itemConstraint.checkToken(typebyte, size)
def receiveChild(self, obj, ready_deferred=None): if ready_deferred: self._ready_deferreds.append(ready_deferred) if self.debug: log.msg("%s[%d].receiveChild(%s)" % (self, self.count, obj)) # obj could be a primitive type, a Deferred, or a complex type like # those returned from an InstanceUnslicer. However, the individual # object has already been through the schema validation process. The # only remaining question is whether the larger schema will accept # it. if self.maxLength is not None and len(self.content) >= self.maxLength: # this is redundant # (if it were a non-primitive one, it would be caught in doOpen) # (if it were a primitive one, it would be caught in checkToken) raise Violation("the list is full") if isinstance(obj, Deferred): if self.debug: log.msg(" adding my update[%d] to %s" % (len(self.content), obj)) obj.addCallback(self.update, len(self.content)) obj.addErrback(self.printErr) placeholder = "list placeholder for arg[%d], rd=%s" % (len( self.content), ready_deferred) self.content.append(placeholder) else: self.content.append(obj)
def openerCheckToken(self, typebyte, size, opentype): if opentype == (b'copyable',) and typebyte in (tokens.STRING, tokens.SVOCAB): # TODO: this is silly, of course (should pre-compute maxlen) maxlen = reduce(max, map(len, copyable.CopyableRegistry.keys())) if maxlen < size: raise Violation('copyable-classname token is too long, {:d} > {:d}'\ .format(size, maxlen)) elif typebyte == tokens.BYTES: if self.maxIndexLength < size: raise Violation('first opentype BYTES token is too long, {:d} > {:d}'\ .format(size, self.maxIndexLength)) elif typebyte != tokens.BVOCAB: raise Violation('opentype not <copyable> ({!r}) and index token 0x{:02x} not BYTES or BVOCAB'\ .format(opentype, ord(typebyte)))
def checkOpentype(self, opentype): """Check the OPEN type (the tuple of Index Tokens). Raise an exception if it is not accepted. """ if self.opentypes == None: return opentype = ensure_tuple_str(opentype) # shared references are always accepted. checkOpentype() is a defense # against resource-exhaustion attacks, and references don't consume # any more resources than any other token. For inbound method # arguments, the CallUnslicer will perform a final check on all # arguments (after these shared references have been resolved), and # that will get to verify that they have resolved to the correct # type. #if opentype == ReferenceSlicer.opentype: if opentype == ('reference', ): return for o in self.opentypes: if len(o) == len(opentype): if o == opentype: return if len(o) > len(opentype): # we might have a partial match: they haven't flunked yet if opentype == o[:len(opentype)]: return # still in the running raise Violation("unacceptable OPEN type: %s not in my list %s" % (opentype, self.opentypes))
def receiveChild(self, obj, ready_deferred=None): assert not isinstance(obj, Deferred) assert ready_deferred is None assert type(obj) == int if self.constraint: if self.constraint.value != None: if bool(obj) != self.constraint.value: raise Violation("This boolean can only be %s" % \ self.constraint.value) self.value = bool(obj)
def getPositionalArgConstraint(self, argnum): if argnum >= len(self.argumentNames): raise Violation("too many positional arguments: %d >= %d" % (argnum, len(self.argumentNames))) argname = self.argumentNames[argnum] c = self.argConstraints.get(argname) assert c if isinstance(c, Optional): c = c.constraint return (True, c)
def checkToken(self, typebyte, size): if self.maxKeys != None: if len(self.d) >= self.maxKeys: raise Violation("the dict is full") if self.gettingKey: if self.keyConstraint: self.keyConstraint.checkToken(typebyte, size) else: if self.valueConstraint: self.valueConstraint.checkToken(typebyte, size)
def getKeywordArgConstraint(self, argname, num_posargs=0, previous_kwargs=[]): previous_args = self.argumentNames[:num_posargs] for pkw in previous_kwargs: assert pkw not in previous_args previous_args.append(pkw) if argname in previous_args: raise Violation("got multiple values for keyword argument '%s'" % (argname,)) c = self.argConstraints.get(argname) if c: if isinstance(c, Optional): c = c.constraint return (True, c) # what do we do with unknown arguments? if self.ignoreUnknown: return (False, None) if self.acceptUnknown: return (True, None) raise Violation("unknown argument '%s'" % argname)
def checkObject(self, obj, inbound): ok = False for c in self.alternatives: try: c.checkObject(obj, inbound) ok = True except Violation: pass if not ok: raise Violation("object type %s does not satisfy any of %s" % (type(obj), self.alternatives))
def checkToken(self, typebyte, size): ok = False for c in self.alternatives: try: c.checkToken(typebyte, size) ok = True except (Violation, BananaError): pass if not ok: raise Violation("typebyte %s does not satisfy any of %s" % (tokenNames[typebyte], self.alternatives))
def testReject2(self): # answer a request with a result that violates the constraint req = TestRequest(12) req.setConstraint(IConstraint(int)) self.broker.addRequest(req) u = self.newUnslicer() u.checkToken(INT, 0) u.receiveChild(12) self.assertRaises(Violation, u.checkToken, STRING, 42) # this does not yet errback the request self.assertFalse(req.answers) # it gets errbacked when banana reports the violation v = Violation("icky") v.setLocation("here") u.reportViolation(BananaFailure(v)) self.assertEqual(len(req.answers), 1) err = req.answers[0] self.assertFalse(err[0]) f = err[1] self.assertTrue(f.check(Violation))
def checkToken(self, typebyte, size): if self.maxKeys is not None and len(self.d) >= self.maxKeys: raise Violation("the table is full") if self.key is None: if typebyte != INT: raise BananaError("VocabUnslicer only accepts INT keys") else: if typebyte != STRING: raise BananaError("VocabUnslicer only accepts STRING values") if self.valueConstraint: self.valueConstraint.checkToken(typebyte, size)
def doOpen(self, opentype): where = len(self.content) if self.constraints != None: if where >= len(self.constraints): raise Violation("the tuple is full") self.constraints[where].checkOpentype(opentype) unslicer = self.open(opentype) if unslicer: if self.constraints != None: unslicer.setConstraint(self.constraints[where]) return unslicer
def testReject2(self): # answer a request with a result that violates the constraint req = TestRequest(12) req.setConstraint(IConstraint(int)) self.broker.addRequest(req) u = self.newUnslicer() u.checkToken(INT, 0) u.receiveChild(12) self.failUnlessRaises(Violation, u.checkToken, STRING, 42) # this does not yet errback the request self.failIf(req.answers) # it gets errbacked when banana reports the violation v = Violation("icky") v.setLocation("here") u.reportViolation(BananaFailure(v)) self.failUnlessEqual(len(req.answers), 1) err = req.answers[0] self.failIf(err[0]) f = err[1] self.failUnless(f.check(Violation))
def checkToken(self, typebyte, size): if self.index is None: if typebyte != INT: raise BananaError("Vocab key must be an INT") elif self.value is None: if typebyte != STRING: raise BananaError("Vocab value must be a STRING") if self.valueConstraint: self.valueConstraint.checkToken(typebyte, size) else: raise Violation("add-vocab only accepts two values")