示例#1
0
 def test_empty_tree(self):
     """
     Test trie ctor, and that is doesn't match on "any" prefix.
     """
     t = StringTrie()
     for key in ['', 'f', 'foo', 'foobar']:
         with self.assertRaises(KeyError):
             t.longest_prefix_value(key)
示例#2
0
 def test_empty_tree(self):
     """
     Test trie ctor, and that is doesn't match on "any" prefix.
     """
     t = StringTrie()
     for key in [u'', u'f', u'foo', u'foobar']:
         with self.assertRaises(KeyError):
             t.longest_prefix_value(key)
示例#3
0
 def __init__(self, router_session_factory, config, reactor):
     self._router_session_factory = router_session_factory
     self._router_factory = router_session_factory._routerFactory
     self._options = config.get('options', {})
     self._realm = self._options.get('realm', None)
     self._reactor = reactor
     self._payload_mapping = StringTrie()
     for topic, pmap in self._options.get('payload_mapping', {}).items():
         self._set_payload_format(topic, pmap)
示例#4
0
    def __init__(self,
                 router,
                 uri,
                 permissions=None,
                 default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert (permissions is None or type(permissions) == list)
        if permissions:
            for p in permissions:
                assert (type(p) == dict)
        assert (default_permissions is None
                or type(default_permissions) == dict)

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None,
                                              None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()
        self._wild_permissions = StringTrie()

        # for "wildcard" URIs, there will be a ".." in them somewhere,
        # and so we want to match on the biggest prefix
        # (i.e. everything to the left of the first "..")
        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            if '..' in perms.uri:
                trunc = perms.uri[:perms.uri.index('..')]
                self._wild_permissions[trunc] = perms
            else:
                self._permissions[perms.uri] = perms
示例#5
0
 def test_longest_prefix_1(self):
     """
     Test that keys are detected as prefix of themselfes.
     """
     t = StringTrie()
     test_keys = ['f', 'foo', 'foobar', 'baz']
     for key in test_keys:
         t[key] = key
     for key in test_keys:
         self.assertEqual(t.longest_prefix_value(key), key)
示例#6
0
 def test_longest_prefix_1(self):
     """
     Test that keys are detected as prefix of themselfes.
     """
     t = StringTrie()
     test_keys = [u'f', u'foo', u'foobar', u'baz']
     for key in test_keys:
         t[key] = key
     for key in test_keys:
         self.assertEqual(t.longest_prefix_value(key), key)
示例#7
0
        def __init__(self, default_key=None):
            """

            Create a new key ring to hold public and private keys mapped from an URI space.
            """
            assert (default_key is None or isinstance(default_key, Key)
                    or type(default_key == six.text_type))
            self._uri_to_key = StringTrie()
            if type(default_key) == six.text_type:
                default_key = Key(originator_priv=default_key,
                                  responder_priv=default_key)
            self._default_key = default_key
示例#8
0
    def test_longest_prefix_3(self):
        """
        Test non-matching prefix lookups.
        """
        t = StringTrie()

        for key in ['x', 'fop', 'foobar']:
            t[key] = key

        for key in ['y', 'yfoo', 'fox', 'fooba']:
            with self.assertRaises(KeyError):
                t.longest_prefix_value(key)
示例#9
0
def is_valid(valid_list, letters):
    # create empty trie
    trie = StringTrie()

    # traverse through list of string to insert it in trie.
    # Here value of key is itself key because at last we need to retun
    for key in valid_list:
        trie[key] = key

    # values(search) method returns list of values of keys
    # which contains search pattern as prefix
    return trie.values(letters)
示例#10
0
    def test_longest_prefix_3(self):
        """
        Test non-matching prefix lookups.
        """
        t = StringTrie()

        for key in [u'x', u'fop', u'foobar']:
            t[key] = key

        for key in [u'y', u'yfoo', u'fox', u'fooba']:
            with self.assertRaises(KeyError):
                t.longest_prefix_value(key)
示例#11
0
def prefixSearch(arr, prefix):
    trie = StringTrie()
    # traverse through list of strings
    # to insert it in trie. Here value of
    # key is itself key because at last
    # we need to return
    for key in arr:
        trie[key] = key
    length = len(prefix) + 1
    for x in range(2, length):
        answer = trie.values(prefix[:x])
        answer.sort()
        print(answer)
示例#12
0
def init():

    app.meditems = StringTrie()
    drugs = ['advil', 'tylenol']

    app.conitems = StringTrie()
    conditions = ['high cholesterol', 'fatness']

    for d in drugs:
        app.meditems[d] = d

    for c in conditions:
        app.conitems[c] = c
示例#13
0
def build_trie_and_execute(map_to_search, prefix_term):
    trie = StringTrie()
    for key in map_to_search:
        trie[key] = key

    prefix_matches = trie.values(url_id)
    if len(prefix_matches) > 0:
        first_match = prefix_matches[0]
        index = map_to_search[first_match][0]
        open_url_in_browser(links[index], get_params())
        return True

    return False
示例#14
0
    def __init__(self, router, uri, permissions=None, default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert(permissions is None or isinstance(permissions, list))
        if permissions:
            for p in permissions:
                assert(isinstance(p, dict))
        assert(default_permissions is None or isinstance(default_permissions, dict))

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None, None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()
        self._wild_permissions = StringTrie()

        # for "wildcard" URIs, there will be a ".." in them somewhere,
        # and so we want to match on the biggest prefix
        # (i.e. everything to the left of the first "..")
        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            if '..' in perms.uri:
                trunc = perms.uri[:perms.uri.index('..')]
                self._wild_permissions[trunc] = perms
            else:
                self._permissions[perms.uri] = perms
示例#15
0
def init():

    app.p = Predictor()
    app.meditems = StringTrie()
    drugs = app.p.get_drugs()

    app.conitems = StringTrie()
    conditions = app.p.get_conditions()

    for d in drugs:
        app.meditems[d] = d

    for c in conditions:
        app.conitems[c] = c
示例#16
0
def prefix_search(arr, prefix):
    # create empty trie
    trie = StringTrie()

    # traverse through list of strings
    # to insert it in trie. Here value of
    # key is itself key because at last
    # we need to return
    for key in arr:
        trie[key] = key

        # values(search) method returns list
    # of values of keys which contains
    # search pattern as prefix
    return trie.values(prefix)
示例#17
0
    def test_longest_prefix_4(self):
        """
        Test that a trie with an empty string as a key contained
        matches a non-empty prefix matching lookup.
        """
        self.skip = True
        # stored_key = u'x'  # this works (and of course it should!)
        stored_key = u''  # this blows up! (and it _should_ work)
        test_key = u'xyz'

        t = StringTrie()
        t[stored_key] = stored_key
        self.assertTrue(stored_key in t)
        self.assertTrue(test_key.startswith(stored_key))
        self.assertEqual(t.longest_prefix_value(test_key), stored_key)
示例#18
0
    def test_longest_prefix_4(self):
        """
        Test that a trie with an empty string as a key contained
        matches a non-empty prefix matching lookup.
        """
        self.skip = True
        # stored_key = 'x'  # this works (and of course it should!)
        stored_key = ''  # this blows up! (and it _should_ work)
        test_key = 'xyz'

        t = StringTrie()
        t[stored_key] = stored_key
        self.assertTrue(stored_key in t)
        self.assertTrue(test_key.startswith(stored_key))
        self.assertEqual(t.longest_prefix_value(test_key), stored_key)
示例#19
0
    def __init__(self,
                 router,
                 uri,
                 permissions=None,
                 default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert (permissions is None or type(permissions) == list)
        if permissions:
            for p in permissions:
                assert (type(p) == dict)
        assert (default_permissions is None
                or type(default_permissions) == dict)

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None,
                                              None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()

        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            self._permissions[perms.uri] = perms
示例#20
0
    def __init__(self, router, uri, permissions=None, default_permissions=None):
        """
        Ctor.

        :param uri: The URI of the role.
        :type uri: str
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list
        """
        RouterRole.__init__(self, router, uri)
        self.permissions = permissions or []

        self._urimap = StringTrie()
        self._default = default_permissions or RouterPermissions('', True, False, False, False, False)

        for p in self.permissions:
            uri = p['uri']

            if len(uri) > 0 and uri[-1] == '*':
                match_by_prefix = True
                uri = uri[:-1]
            else:
                match_by_prefix = False

            perms = RouterPermissions(uri, match_by_prefix,
                                      call=p.get('call', False),
                                      register=p.get('register', False),
                                      publish=p.get('publish', False),
                                      subscribe=p.get('subscribe', False))

            if len(uri) > 0:
                self._urimap[uri] = perms
            else:
                self._default = perms
示例#21
0
    def __init__(self, ordered=False):
        # flag indicating whether observers should be maintained in a SortedSet
        # or a regular set (unordered)
        self._ordered = ordered

        # map: URI => ExactUriObservation
        self._observations_exact = {}

        # map: URI => PrefixUriObservation
        self._observations_prefix = StringTrie()

        # map: URI => WildcardUriObservation
        self._observations_wildcard = WildcardTrieMatcher()

        # map: observation ID => UriObservation
        self._observation_id_to_observation = {}
示例#22
0
class FIB:
    def __init__(self):
        self.fib = StringTrie()
        self.fib["/mbandeira"] = "int1"
        self.fib["/cdrummond"] = "int2"

    def getIface(self, contentName):
        return self.fib.longest_prefix_value(contentName)
示例#23
0
文件: wamp.py 项目: NinjaMSP/crossbar
 def __init__(self, router_session_factory, config, reactor):
     self._router_session_factory = router_session_factory
     self._router_factory = router_session_factory._routerFactory
     self._options = config.get(u'options', {})
     self._realm = self._options.get(u'realm', None)
     self._reactor = reactor
     self._payload_mapping = StringTrie()
     for topic, pmap in self._options.get(u'payload_mapping', {}).items():
         self._set_payload_format(topic, pmap)
示例#24
0
    def __init__(self,
                 router,
                 uri,
                 permissions=None,
                 default_permissions=None,
                 debug=False):
        """
        Ctor.

        :param uri: The URI of the role.
        :type uri: str
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list
        :param debug: Enable debug logging.
        :type debug: bool
        """
        RouterRole.__init__(self, router, uri, debug)
        self.permissions = permissions or []

        self._urimap = StringTrie()
        self._default = default_permissions or RouterPermissions(
            '', True, False, False, False, False)

        for p in self.permissions:
            uri = p['uri']

            if len(uri) > 0 and uri[-1] == '*':
                match_by_prefix = True
                uri = uri[:-1]
            else:
                match_by_prefix = False

            perms = RouterPermissions(uri,
                                      match_by_prefix,
                                      call=p.get('call', False),
                                      register=p.get('register', False),
                                      publish=p.get('publish', False),
                                      subscribe=p.get('subscribe', False))

            if len(uri) > 0:
                self._urimap[uri] = perms
            else:
                self._default = perms
示例#25
0
        def __init__(self, default_key=None):
            """

            Create a new key ring to hold public and private keys mapped from an URI space.
            """
            assert(default_key is None or isinstance(default_key, Key) or type(default_key == six.text_type))
            self._uri_to_key = StringTrie()
            if type(default_key) == six.text_type:
                default_key = Key(originator_priv=default_key, responder_priv=default_key)
            self._default_key = default_key
示例#26
0
def filter_argv(argv, option_strings, *blacklist):
    ptree = StringTrie({v: i for i, v in enumerate(blacklist)})
    filtered = []
    boolean_args = set(option_strings)
    i = -1
    while i + 1 < len(argv):
        i += 1
        arg = argv[i]
        has_value = arg.startswith("-") and \
            not any(arg.startswith(b) for b in boolean_args) \
            and '=' not in arg and arg != "-"
        if ptree.longest_prefix(arg, None) is None:
            filtered.append(arg)
            if has_value:
                i += 1
                filtered.append(argv[i])
        elif has_value:
            i += 1
    return filtered
示例#27
0
def prefixSearch(arr, modelName):
    # create empty trie
    trie = StringTrie()

    # traverse through list of strings
    # to insert it in trie. Here value of
    # key is itself key because at last
    # we need to return
    for key in arr:
        trie[key] = key
    save_object(trie, modelName)
示例#28
0
class Suggester(object):
    def __init__(self):
        self.trie = None

    def update_trie(self, word_list):
        self.trie = StringTrie()
        for word in word_list:
            word = word.lower()
            self.trie[word] = word

    def search_prefix(self, prefix):
        return self.trie.values(prefix=prefix)
示例#29
0
    def test_longest_prefix_2(self):
        """
        Test matching prefix lookups.
        """
        t = StringTrie()
        test_keys = [u'f', u'foo', u'foobar']
        for key in test_keys:
            t[key] = key

        test_keys = {
            u'foobarbaz': u'foobar',
            u'foobaz': u'foo',
            u'fool': u'foo',
            u'foo': u'foo',
            u'fob': u'f',
            u'fo': u'f',
            u'fx': u'f',
            u'f': u'f',
        }
        for key in test_keys:
            self.assertEqual(t.longest_prefix_value(key), test_keys[key])
示例#30
0
 def test_contains(self):
     """
     Test the contains operator.
     """
     t = StringTrie()
     test_keys = ['', 'f', 'foo', 'foobar', 'baz']
     for key in test_keys:
         t[key] = key
     for key in test_keys:
         self.assertTrue(key in t)
     for key in ['x', 'fb', 'foob', 'fooba', 'bazz']:
         self.assertFalse(key in t)
示例#31
0
    def test_longest_prefix_2(self):
        """
        Test matching prefix lookups.
        """
        t = StringTrie()
        test_keys = ['f', 'foo', 'foobar']
        for key in test_keys:
            t[key] = key

        test_keys = {
            'foobarbaz': 'foobar',
            'foobaz': 'foo',
            'fool': 'foo',
            'foo': 'foo',
            'fob': 'f',
            'fo': 'f',
            'fx': 'f',
            'f': 'f',
        }
        for key in test_keys:
            self.assertEqual(t.longest_prefix_value(key), test_keys[key])
示例#32
0
class Suggester(object):
    def __init__(self):
        self.trie = None

    def update_trie(self, word_list):
        self.trie = StringTrie()
        for word in word_list:
            word = word.lower()
            self.trie[word] = word

    def search_prefix(self, prefix):
        return self.trie.values(prefix=prefix)
示例#33
0
    def __init__(self, ordered=False):
        # flag indicating whether observers should be maintained in a SortedSet
        # or a regular set (unordered)
        self._ordered = ordered

        # map: URI => ExactUriObservation
        self._observations_exact = {}

        # map: URI => PrefixUriObservation
        self._observations_prefix = StringTrie()

        # map: URI => WildcardUriObservation
        if True:
            # use a Trie-based implementation (supposed to be faster, but
            # otherwise compatible to the naive implementation below)
            self._observations_wildcard = WildcardTrieMatcher()
        else:
            self._observations_wildcard = WildcardMatcher()

        # map: observation ID => UriObservation
        self._observation_id_to_observation = {}
示例#34
0
class GeohashContainer(object):
    """ A class which can be used as a container of geohashes and corresponding items. The underlying data structure is a trie (StringTrie)."""
    def __init__(self, itemCollection):
        self.container = StringTrie()
        for item in itemCollection:
            self.container[Geohash.encode(item.Location.Latitude, item.Location.Longitude)] = item

    def Retrieve(self, keyPrefix):
        """ Returns all items which match the specified keyPrefix """
        results = self.container.values(keyPrefix)
        return results

    def Add(self, key, value):
        """ Adds a new item to its underlying container """
        self.container[key] = value
示例#35
0
    def __init__(self, ordered=False):
        # flag indicating whether observers should be maintained in a SortedSet
        # or a regular set (unordered)
        self._ordered = ordered

        # map: URI => ExactUriObservation
        self._observations_exact = {}

        # map: URI => PrefixUriObservation
        self._observations_prefix = StringTrie()

        # map: URI => WildcardUriObservation
        self._observations_wildcard = WildcardTrieMatcher()

        # map: observation ID => UriObservation
        self._observation_id_to_observation = {}
示例#36
0
class Suggester(object):
    def __init__(self):
        self.trie = None
        self.trie = StringTrie()

    def update_trie(self, word_list):
        for word in word_list:
            # word = word.lower()
            # 拼音提取,首字母,全拼都改成小写,去空格
            word_pinyin1 = get_every_word_first(word)
            word_pinyin2 = get_all_pinying(word)

            # 拼音建立字典树
            self.trie[word] = word
            self.trie[word_pinyin1] = word_pinyin1
            self.trie[word_pinyin2] = word_pinyin2

    def search_prefix(self, prefix):
        return self.trie.values(prefix=prefix)
示例#37
0
文件: role.py 项目: schoonc/crossbar
    def __init__(self, router, uri, permissions=None, default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert(permissions is None or type(permissions) == list)
        if permissions:
            for p in permissions:
                assert(type(p) == dict)
        assert(default_permissions is None or type(default_permissions) == dict)

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None, None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()

        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            self._permissions[perms.uri] = perms
示例#38
0
    def __init__(self, ordered=False):
        # flag indicating whether observers should be maintained in a SortedSet
        # or a regular set (unordered)
        self._ordered = ordered

        # map: URI => ExactUriObservation
        self._observations_exact = {}

        # map: URI => PrefixUriObservation
        self._observations_prefix = StringTrie()

        # map: URI => WildcardUriObservation
        if True:
            # use a Trie-based implementation (supposed to be faster, but
            # otherwise compatible to the naive implementation below)
            self._observations_wildcard = WildcardTrieMatcher()
        else:
            self._observations_wildcard = WildcardMatcher()

        # map: observation ID => UriObservation
        self._observation_id_to_observation = {}
示例#39
0
文件: wamp.py 项目: NinjaMSP/crossbar
class WampMQTTServerFactory(Factory):

    log = make_logger()

    protocol = WampMQTTServerProtocol

    serializers = {
        u'json': JsonObjectSerializer(),
        u'msgpack': MsgPackObjectSerializer(),
        u'cbor': CBORObjectSerializer(),
        u'ubjson': UBJSONObjectSerializer(),
    }

    def __init__(self, router_session_factory, config, reactor):
        self._router_session_factory = router_session_factory
        self._router_factory = router_session_factory._routerFactory
        self._options = config.get(u'options', {})
        self._realm = self._options.get(u'realm', None)
        self._reactor = reactor
        self._payload_mapping = StringTrie()
        for topic, pmap in self._options.get(u'payload_mapping', {}).items():
            self._set_payload_format(topic, pmap)

    def buildProtocol(self, addr):
        protocol = self.protocol(self._reactor)
        protocol.factory = self
        return protocol

    def _get_payload_format(self, topic):
        """
        Map a WAMP topic URI to MQTT payload format.
        :param topic: WAMP URI.
        :type topic: str

        :returns: Payload format metadata.
        :rtype: dict
        """
        try:
            pmap = self._payload_mapping.longest_prefix_value(topic)
        except KeyError:
            return None
        else:
            return pmap

    def _set_payload_format(self, topic, pmap=None):
        if pmap is None:
            if topic in self._payload_mapping:
                del self._payload_mapping[topic]
        else:
            self._payload_mapping[topic] = pmap

    @inlineCallbacks
    def transform_wamp(self, topic, msg):
        # check for cached transformed payload
        cache_key = u'_{}_{}'.format(self.__class__.__name__, id(self))
        cached = msg._serialized.get(cache_key, None)

        if cached:
            payload_format, mapped_topic, payload = cached
            self.log.debug('using cached payload for {cache_key} in message {msg_id}!', msg_id=id(msg), cache_key=cache_key)
        else:
            # convert WAMP URI to MQTT topic
            mapped_topic = _wamp_topic_to_mqtt(topic)

            # for WAMP->MQTT, the payload mapping is determined from the
            # WAMP URI (not the transformed MQTT topic)
            payload_format = self._get_payload_format(topic)
            payload_format_type = payload_format[u'type']

            if payload_format_type == u'passthrough':
                payload = msg.payload

            elif payload_format_type == u'native':
                serializer = payload_format.get(u'serializer', None)
                payload = self._transform_wamp_native(serializer, msg)

            elif payload_format_type == u'dynamic':
                    encoder = payload_format.get(u'encoder', None)
                    codec_realm = payload_format.get(u'realm', self._realm)
                    payload = yield self._transform_wamp_dynamic(encoder, codec_realm, mapped_topic, topic, msg)
            else:
                raise Exception('payload format {} not implemented'.format(payload_format))

            msg._serialized[cache_key] = (payload_format, mapped_topic, payload)

        self.log.debug('transform_wamp({topic}, {msg}) -> payload_format={payload_format}, mapped_topic={mapped_topic}, payload={payload}', topic=topic, msg=msg, payload_format=payload_format, mapped_topic=mapped_topic, payload=payload)
        returnValue((payload_format, mapped_topic, payload))

    @inlineCallbacks
    def _transform_wamp_dynamic(self, encoder, codec_realm, mapped_topic, topic, msg):
        codec_session = self._router_factory.get(codec_realm)._realm.session
        payload = yield codec_session.call(encoder, mapped_topic, topic, msg.args, msg.kwargs)
        returnValue(payload)

    def _transform_wamp_native(self, serializer, msg):
        obj = {}
        for opt in [u'args',
                    u'kwargs',
                    u'exclude',
                    u'exclude_authid',
                    u'exclude_authrole',
                    u'eligible',
                    u'eligible_authid',
                    u'eligible_authrole']:
            attr = getattr(msg, opt, None)
            if attr is not None:
                obj[opt] = attr

        if serializer in self.serializers:
            payload = self.serializers[serializer].serialize(obj)
        else:
            raise Exception('MQTT native mode payload transform: invalid serializer {}'.format(serializer))

        return payload

    @inlineCallbacks
    def transform_mqtt(self, topic, payload):
        # transform MQTT topic to WAMP URI
        mapped_topic = _mqtt_topicname_to_wamp(topic)

        # for MQTT->WAMP, the payload mapping is determined from the
        # transformed WAMP URI (not the original MQTT topic)
        payload_format = self._get_payload_format(mapped_topic)
        payload_format_type = payload_format[u'type']

        if payload_format_type == u'passthrough':
            options = {
                u'payload': payload,
                u'enc_algo': u'mqtt'
            }

        elif payload_format_type == u'native':
            serializer = payload_format.get(u'serializer', None)
            options = self._transform_mqtt_native(serializer, payload)

        elif payload_format_type == u'dynamic':
            decoder = payload_format.get(u'decoder', None)
            codec_realm = payload_format.get(u'realm', self._realm)
            options = yield self._transform_mqtt_dynamic(decoder, codec_realm, mapped_topic, topic, payload)

        else:
            raise Exception('payload format {} not implemented'.format(payload_format))

        self.log.debug('transform_mqtt({topic}, {payload}) -> payload_format={payload_format}, mapped_topic={mapped_topic}, options={options}', topic=topic, payload=payload, payload_format=payload_format, mapped_topic=mapped_topic, options=options)
        returnValue((payload_format, mapped_topic, options))

    @inlineCallbacks
    def _transform_mqtt_dynamic(self, decoder, codec_realm, mapped_topic, topic, payload):
        codec_session = self._router_factory.get(codec_realm)._realm.session
        options = yield codec_session.call(decoder, mapped_topic, topic, payload)
        returnValue(options)

    def _transform_mqtt_native(self, serializer, payload):
        """
        Transform MQTT binary payload from a MQTT Publish to keyword dict
        suitable for the constructor of a WAMP Publish message,
        that is :class:`autobahn.wamp.message.Publish`.
        """
        options = {}
        if serializer in self.serializers:
            if serializer == u'json':
                if not _validator.validate(payload)[0]:
                    # invalid UTF-8: drop the event
                    raise Exception('invalid UTF8 in JSON encoded MQTT payload')
            obj = self.serializers[serializer].unserialize(payload)[0]
        else:
            raise Exception('"{}" serializer for encoded MQTT payload not implemented'.format(serializer))

        if type(obj) != dict:
            raise Exception('invalid type {} for "{}" encoded MQTT payload'.format(type(obj), serializer))

        for opt in [u'args',
                    u'kwargs',
                    u'exclude',
                    u'exclude_authid',
                    u'exclude_authrole',
                    u'eligible',
                    u'eligible_authid',
                    u'eligible_authrole']:
            if opt in obj:
                options[opt] = obj[opt]

        return options
示例#40
0
 def __init__(self):
     self.fib = StringTrie()
     self.fib["/mbandeira"] = "int1"
     self.fib["/cdrummond"] = "int2"
示例#41
0
    class KeyRing(object):
        """
        A keyring holds (cryptobox) public-private key pairs for use with WAMP-cryptobox payload
        encryption. The keyring can be set on a WAMP session and then transparently will get used
        for encrypting and decrypting WAMP message payloads.
        """
        @public
        def __init__(self, default_key=None):
            """

            Create a new key ring to hold public and private keys mapped from an URI space.
            """
            assert (default_key is None or isinstance(default_key, Key)
                    or type(default_key == six.text_type))
            self._uri_to_key = StringTrie()
            if type(default_key) == six.text_type:
                default_key = Key(originator_priv=default_key,
                                  responder_priv=default_key)
            self._default_key = default_key

        @public
        def generate_key(self):
            """
            Generate a new private key and return a pair with the base64 encodings
            of (priv_key, pub_key).
            """
            key = PrivateKey.generate()
            priv_key = key.encode(encoder=Base64Encoder)
            pub_key = key.public_key.encode(encoder=Base64Encoder)
            return (u'{}'.format(priv_key), u'{}'.format(pub_key))

        @public
        def set_key(self, uri, key):
            """
            Add a key set for a given URI.
            """
            assert (type(uri) == six.text_type)
            assert (key is None or isinstance(key, Key)
                    or type(key) == six.text_type)
            if type(key) == six.text_type:
                key = Key(originator_priv=key, responder_priv=key)
            if uri == u'':
                self._default_key = key
            else:
                if key is None:
                    if uri in self._uri_to_key:
                        del self._uri_to_key[uri]
                else:
                    self._uri_to_key[uri] = key

        @public
        def rotate_key(self, uri):
            assert (type(uri) == six.text_type)
            if uri in self._uri_to_key:
                self._uri_to_key[uri].rotate()
            else:
                self._uri_to_key[uri].rotate()

        def _get_box(self, is_originating, uri, match_exact=False):
            try:
                if match_exact:
                    key = self._uri_to_key[uri]
                else:
                    key = self._uri_to_key.longest_prefix_value(uri)
            except KeyError:
                if self._default_key:
                    key = self._default_key
                else:
                    return None

            if is_originating:
                return key.originator_box
            else:
                return key.responder_box

        @public
        def encode(self, is_originating, uri, args=None, kwargs=None):
            """
            Encrypt the given WAMP URI, args and kwargs into an EncodedPayload instance, or None
            if the URI should not be encrypted.
            """
            assert (type(is_originating) == bool)
            assert (type(uri) == six.text_type)
            assert (args is None or type(args) in (list, tuple))
            assert (kwargs is None or type(kwargs) == dict)

            box = self._get_box(is_originating, uri)

            if not box:
                # if we didn't find a crypto box, then return None, which
                # signals that the payload travel unencrypted (normal)
                return None

            payload = {u'uri': uri, u'args': args, u'kwargs': kwargs}
            nonce = random(Box.NONCE_SIZE)
            payload_ser = _json_dumps(payload).encode('utf8')

            payload_encr = box.encrypt(payload_ser, nonce, encoder=RawEncoder)

            # above returns an instance of http://pynacl.readthedocs.io/en/latest/utils/#nacl.utils.EncryptedMessage
            # which is a bytes _subclass_! hence we apply bytes() to get at the underlying plain
            # bytes "scalar", which is the concatenation of `payload_encr.nonce + payload_encr.ciphertext`
            payload_bytes = bytes(payload_encr)
            payload_key = None

            return EncodedPayload(payload_bytes,
                                  u'cryptobox',
                                  u'json',
                                  enc_key=payload_key)

        @public
        def decode(self, is_originating, uri, encoded_payload):
            """
            Decrypt the given WAMP URI and EncodedPayload into a tuple ``(uri, args, kwargs)``.
            """
            assert (type(uri) == six.text_type)
            assert (isinstance(encoded_payload, EncodedPayload))
            assert (encoded_payload.enc_algo == u'cryptobox')

            box = self._get_box(is_originating, uri)

            if not box:
                raise Exception(
                    "received encrypted payload, but can't find key!")

            payload_ser = box.decrypt(encoded_payload.payload,
                                      encoder=RawEncoder)

            if encoded_payload.enc_serializer != u'json':
                raise Exception(
                    "received encrypted payload, but don't know how to process serializer '{}'"
                    .format(encoded_payload.enc_serializer))

            payload = _json_loads(payload_ser.decode('utf8'))

            uri = payload.get(u'uri', None)
            args = payload.get(u'args', None)
            kwargs = payload.get(u'kwargs', None)

            return uri, args, kwargs
示例#42
0
    class KeyRing(object):
        """
        A keyring holds (cryptobox) public-private key pairs for use with WAMP-cryptobox payload
        encryption. The keyring can be set on a WAMP session and then transparently will get used
        for encrypting and decrypting WAMP message payloads.
        """

        @public
        def __init__(self, default_key=None):
            """

            Create a new key ring to hold public and private keys mapped from an URI space.
            """
            assert(default_key is None or isinstance(default_key, Key) or type(default_key == six.text_type))
            self._uri_to_key = StringTrie()
            if type(default_key) == six.text_type:
                default_key = Key(originator_priv=default_key, responder_priv=default_key)
            self._default_key = default_key

        @public
        def generate_key(self):
            """
            Generate a new private key and return a pair with the base64 encodings
            of (priv_key, pub_key).
            """
            key = PrivateKey.generate()
            priv_key = key.encode(encoder=Base64Encoder)
            pub_key = key.public_key.encode(encoder=Base64Encoder)
            return (u'{}'.format(priv_key), u'{}'.format(pub_key))

        @public
        def set_key(self, uri, key):
            """
            Add a key set for a given URI.
            """
            assert(type(uri) == six.text_type)
            assert(key is None or isinstance(key, Key) or type(key) == six.text_type)
            if type(key) == six.text_type:
                key = Key(originator_priv=key, responder_priv=key)
            if uri == u'':
                self._default_key = key
            else:
                if key is None:
                    if uri in self._uri_to_key:
                        del self._uri_to_key[uri]
                else:
                    self._uri_to_key[uri] = key

        @public
        def rotate_key(self, uri):
            assert(type(uri) == six.text_type)
            if uri in self._uri_to_key:
                self._uri_to_key[uri].rotate()
            else:
                self._uri_to_key[uri].rotate()

        def _get_box(self, is_originating, uri, match_exact=False):
            try:
                if match_exact:
                    key = self._uri_to_key[uri]
                else:
                    key = self._uri_to_key.longest_prefix_value(uri)
            except KeyError:
                if self._default_key:
                    key = self._default_key
                else:
                    return None

            if is_originating:
                return key.originator_box
            else:
                return key.responder_box

        @public
        def encode(self, is_originating, uri, args=None, kwargs=None):
            """
            Encrypt the given WAMP URI, args and kwargs into an EncodedPayload instance, or None
            if the URI should not be encrypted.
            """
            assert(type(is_originating) == bool)
            assert(type(uri) == six.text_type)
            assert(args is None or type(args) in (list, tuple))
            assert(kwargs is None or type(kwargs) == dict)

            box = self._get_box(is_originating, uri)

            if not box:
                # if we didn't find a crypto box, then return None, which
                # signals that the payload travel unencrypted (normal)
                return None

            payload = {
                u'uri': uri,
                u'args': args,
                u'kwargs': kwargs
            }
            nonce = random(Box.NONCE_SIZE)
            payload_ser = _json_dumps(payload).encode('utf8')

            payload_encr = box.encrypt(payload_ser, nonce, encoder=RawEncoder)

            # above returns an instance of http://pynacl.readthedocs.io/en/latest/utils/#nacl.utils.EncryptedMessage
            # which is a bytes _subclass_! hence we apply bytes() to get at the underlying plain
            # bytes "scalar", which is the concatenation of `payload_encr.nonce + payload_encr.ciphertext`
            payload_bytes = bytes(payload_encr)
            payload_key = None

            return EncodedPayload(payload_bytes, u'cryptobox', u'json', enc_key=payload_key)

        @public
        def decode(self, is_originating, uri, encoded_payload):
            """
            Decrypt the given WAMP URI and EncodedPayload into a tuple ``(uri, args, kwargs)``.
            """
            assert(type(uri) == six.text_type)
            assert(isinstance(encoded_payload, EncodedPayload))
            assert(encoded_payload.enc_algo == u'cryptobox')

            box = self._get_box(is_originating, uri)

            if not box:
                raise Exception("received encrypted payload, but can't find key!")

            payload_ser = box.decrypt(encoded_payload.payload, encoder=RawEncoder)

            if encoded_payload.enc_serializer != u'json':
                raise Exception("received encrypted payload, but don't know how to process serializer '{}'".format(encoded_payload.enc_serializer))

            payload = _json_loads(payload_ser.decode('utf8'))

            uri = payload.get(u'uri', None)
            args = payload.get(u'args', None)
            kwargs = payload.get(u'kwargs', None)

            return uri, args, kwargs
示例#43
0
def longest_match_pytrie(search):
    if longest_match_pytrie.trie is None:
        from pytrie import StringTrie
        longest_match_pytrie.trie = StringTrie.fromkeys(hosts)
    matches = longest_match_pytrie.trie.keys(prefix=search)
    return max(matches, key=len) if matches else ''
示例#44
0
class RouterRoleStaticAuth(RouterRole):
    """
    A role on a router realm that is authorized using a static configuration.
    """

    def __init__(self, router, uri, permissions=None, default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert(permissions is None or isinstance(permissions, list))
        if permissions:
            for p in permissions:
                assert(isinstance(p, dict))
        assert(default_permissions is None or isinstance(default_permissions, dict))

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None, None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()
        self._wild_permissions = StringTrie()

        # for "wildcard" URIs, there will be a ".." in them somewhere,
        # and so we want to match on the biggest prefix
        # (i.e. everything to the left of the first "..")
        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            if '..' in perms.uri:
                trunc = perms.uri[:perms.uri.index('..')]
                self._wild_permissions[trunc] = perms
            else:
                self._permissions[perms.uri] = perms

    def authorize(self, session, uri, action, options):
        """
        Authorize a session connected under this role to perform the given
        action on the given URI.

        :param session: The WAMP session that requests the action.
        :type session: Instance of :class:`autobahn.wamp.protocol.ApplicationSession`
        :param uri: The URI on which to perform the action.
        :type uri: str
        :param action: The action to be performed.
        :type action: str

        :return: bool -- Flag indicating whether session is authorized or not.
        """
        self.log.debug(
            "CrossbarRouterRoleStaticAuth.authorize {myuri} {uri} {action}",
            myuri=self.uri, uri=uri, action=action)

        try:
            # longest prefix match of the URI to be authorized against our Trie
            # of configured URIs for permissions
            permissions = self._permissions.longest_prefix_value(uri)

            # if there is a _prefix_ matching URI, check that this is actually the
            # match policy on the permission (otherwise, apply default permissions)!
            if permissions.match != u'prefix' and uri != permissions.uri:
                permissions = self._default

        except KeyError:
            # workaround because of https://bitbucket.org/gsakkis/pytrie/issues/4/string-keys-of-zero-length-are-not
            permissions = self._permissions.get(u'', self._default)

        # if we found a non-"exact" match, there might be a better one in the wildcards
        if permissions.match != u'exact':
            try:
                wildperm = self._wild_permissions.longest_prefix_value(uri)
                Pattern(wildperm.uri, Pattern.URI_TARGET_ENDPOINT).match(uri)
            except (KeyError, Exception):
                # match() raises Exception on no match
                wildperm = None

            if wildperm is not None:
                permissions = wildperm

        # we now have some permissions, either from matching something
        # or via self._default

        if action == u'publish':
            return {
                u'allow': permissions.publish,
                u'disclose': permissions.disclose_publisher,
                u'cache': permissions.cache
            }

        elif action == u'subscribe':
            return {
                u'allow': permissions.subscribe,
                u'cache': permissions.cache
            }

        elif action == u'call':
            return {
                u'allow': permissions.call,
                u'disclose': permissions.disclose_caller,
                u'cache': permissions.cache
            }

        elif action == u'register':
            return {
                u'allow': permissions.register,
                u'cache': permissions.cache
            }

        else:
            # should not arrive here
            raise Exception('logic error')
示例#45
0
class RouterRoleStaticAuth(RouterRole):
    """
    A role on a router realm that is authorized using a static configuration.
    """
    def __init__(self,
                 router,
                 uri,
                 permissions=None,
                 default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert (permissions is None or type(permissions) == list)
        if permissions:
            for p in permissions:
                assert (type(p) == dict)
        assert (default_permissions is None
                or type(default_permissions) == dict)

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None,
                                              None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()
        self._wild_permissions = StringTrie()

        # for "wildcard" URIs, there will be a ".." in them somewhere,
        # and so we want to match on the biggest prefix
        # (i.e. everything to the left of the first "..")
        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            if '..' in perms.uri:
                trunc = perms.uri[:perms.uri.index('..')]
                self._wild_permissions[trunc] = perms
            else:
                self._permissions[perms.uri] = perms

    def authorize(self, session, uri, action, options):
        """
        Authorize a session connected under this role to perform the given
        action on the given URI.

        :param session: The WAMP session that requests the action.
        :type session: Instance of :class:`autobahn.wamp.protocol.ApplicationSession`
        :param uri: The URI on which to perform the action.
        :type uri: str
        :param action: The action to be performed.
        :type action: str

        :return: bool -- Flag indicating whether session is authorized or not.
        """
        self.log.debug(
            "CrossbarRouterRoleStaticAuth.authorize {myuri} {uri} {action}",
            myuri=self.uri,
            uri=uri,
            action=action)

        try:
            # longest prefix match of the URI to be authorized against our Trie
            # of configured URIs for permissions
            permissions = self._permissions.longest_prefix_value(uri)

            # if there is a _prefix_ matching URI, check that this is actually the
            # match policy on the permission (otherwise, apply default permissions)!
            if permissions.match != u'prefix' and uri != permissions.uri:
                permissions = self._default

        except KeyError:
            # workaround because of https://bitbucket.org/gsakkis/pytrie/issues/4/string-keys-of-zero-length-are-not
            permissions = self._permissions.get(u'', self._default)

        # if we found a non-"exact" match, there might be a better one in the wildcards
        if permissions.match != u'exact':
            try:
                wildperm = self._wild_permissions.longest_prefix_value(uri)
                Pattern(wildperm.uri, Pattern.URI_TARGET_ENDPOINT).match(uri)
            except (KeyError, Exception):
                # match() raises Exception on no match
                wildperm = None

            if wildperm is not None:
                permissions = wildperm

        # we now have some permissions, either from matching something
        # or via self._default

        if action == u'publish':
            return {
                u'allow': permissions.publish,
                u'disclose': permissions.disclose_publisher,
                u'cache': permissions.cache
            }

        elif action == u'subscribe':
            return {
                u'allow': permissions.subscribe,
                u'cache': permissions.cache
            }

        elif action == u'call':
            return {
                u'allow': permissions.call,
                u'disclose': permissions.disclose_caller,
                u'cache': permissions.cache
            }

        elif action == u'register':
            return {
                u'allow': permissions.register,
                u'cache': permissions.cache
            }

        else:
            # should not arrive here
            raise Exception('logic error')
示例#46
0
    class KeyRing(object):
        """
        A keyring holds (cryptobox) public-private key pairs for use with WAMP-cryptobox payload
        encryption. The keyring can be set on a WAMP session and then transparently will get used
        for encrypting and decrypting WAMP message payloads.
        """

        def __init__(self, default_key=None):
            """

            Create a new key ring to hold public and private keys mapped from an URI space.
            """
            assert(default_key is None or isinstance(default_key, Key) or type(default_key == six.text_type))
            self._uri_to_key = StringTrie()
            if type(default_key) == six.text_type:
                default_key = Key(originator_priv=default_key, responder_priv=default_key)
            self._default_key = default_key

        def generate_key(self):
            """
            Generate a new private key and return a pair with the base64 encodings
            of (priv_key, pub_key).
            """
            key = PrivateKey.generate()
            priv_key = key.encode(encoder=Base64Encoder)
            pub_key = key.public_key.encode(encoder=Base64Encoder)
            return (u'{}'.format(priv_key), u''.format(pub_key))

        def set_key(self, uri, key):
            """
            Add a key set for a given URI.
            """
            assert(type(uri) == six.text_type)
            assert(key is None or isinstance(key, Key) or type(key) == six.text_type)
            if type(key) == six.text_type:
                key = Key(originator_priv=key, responder_priv=key)
            if uri == u'':
                self._default_key = key
            else:
                if key is None:
                    if uri in self._uri_to_key:
                        del self._uri_to_key[uri]
                else:
                    self._uri_to_key[uri] = key

        def _get_box(self, is_originator, uri, match_exact=False):
            try:
                if match_exact:
                    key = self._uri_to_key[uri]
                else:
                    key = self._uri_to_key.longest_prefix_value(uri)
            except KeyError:
                if self._default_key:
                    key = self._default_key
                else:
                    return None

            if is_originator:
                return key.originator_box
            else:
                return key.responder_box

        def encrypt(self, is_originator, uri, args=None, kwargs=None):
            """
            Encrypt the given WAMP URI, args and kwargs into an EncryptedPayload instance, or None
            if the URI should not be encrypted.
            """
            assert(type(uri) == six.text_type)
            assert(type(is_originator) == bool)
            assert(args is None or type(args) in (list, tuple))
            assert(kwargs is None or type(kwargs) == dict)

            box = self._get_box(is_originator, uri)

            if not box:
                return

            payload = {
                u'uri': uri,
                u'args': args,
                u'kwargs': kwargs
            }
            nonce = random(Box.NONCE_SIZE)
            payload_ser = json.dumps(payload)
            payload_encr = box.encrypt(payload_ser, nonce, encoder=Base64Encoder)
            payload_bytes = payload_encr.encode().decode('ascii')
            payload_key = None

            return EncryptedPayload(u'cryptobox', payload_key, u'json', payload_bytes)

        def decrypt(self, is_originator, uri, encrypted_payload):
            """
            Decrypt the given WAMP URI and EncryptedPayload into a tuple (uri, args, kwargs).
            """
            assert(type(uri) == six.text_type)
            assert(isinstance(encrypted_payload, EncryptedPayload))

            box = self._get_box(is_originator, uri)

            if not box:
                raise Exception("received encrypted payload, but can't find key!")

            payload_ser = box.decrypt(encrypted_payload.payload, encoder=Base64Encoder)

            if encrypted_payload.serializer != u'json':
                raise Exception("received encrypted payload, but don't know how to process serializer '{}'".format(encrypted_payload.serializer))

            payload = json.loads(payload_ser)

            uri = payload[u'uri']
            args = payload.get(u'args', None)
            kwargs = payload.get(u'kwargs', None)

            return uri, args, kwargs
示例#47
0
文件: role.py 项目: schoonc/crossbar
class RouterRoleStaticAuth(RouterRole):
    """
    A role on a router realm that is authorized using a static configuration.
    """

    def __init__(self, router, uri, permissions=None, default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert(permissions is None or type(permissions) == list)
        if permissions:
            for p in permissions:
                assert(type(p) == dict)
        assert(default_permissions is None or type(default_permissions) == dict)

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None, None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()

        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            self._permissions[perms.uri] = perms

    def authorize(self, session, uri, action):
        """
        Authorize a session connected under this role to perform the given
        action on the given URI.

        :param session: The WAMP session that requests the action.
        :type session: Instance of :class:`autobahn.wamp.protocol.ApplicationSession`
        :param uri: The URI on which to perform the action.
        :type uri: str
        :param action: The action to be performed.
        :type action: str

        :return: bool -- Flag indicating whether session is authorized or not.
        """
        self.log.debug(
            "CrossbarRouterRoleStaticAuth.authorize {myuri} {uri} {action}",
            myuri=self.uri, uri=uri, action=action)

        try:
            # longest prefix match of the URI to be authorized against our Trie
            # of configured URIs for permissions
            permissions = self._permissions.longest_prefix_value(uri)

            # if there is a _prefix_ matching URI, check that this is actually the
            # match policy on the permission (otherwise, apply default permissions)!
            if permissions.match != u'prefix' and uri != permissions.uri:
                permissions = self._default

        except KeyError:
            # workaround because of https://bitbucket.org/gsakkis/pytrie/issues/4/string-keys-of-zero-length-are-not
            if u'' in self._permissions:
                permissions = self._permissions[u'']
            else:
                permissions = self._default

        if action == u'publish':
            return {
                u'allow': permissions.publish,
                u'disclose': permissions.disclose_publisher,
                u'cache': permissions.cache
            }

        elif action == u'subscribe':
            return {
                u'allow': permissions.subscribe,
                u'cache': permissions.cache
            }

        elif action == u'call':
            return {
                u'allow': permissions.call,
                u'disclose': permissions.disclose_caller,
                u'cache': permissions.cache
            }

        elif action == u'register':
            return {
                u'allow': permissions.register,
                u'cache': permissions.cache
            }

        else:
            # should not arrive here
            raise Exception('logic error')
示例#48
0
"""Script that loads a trie of French words,
to be used in other scripts"""

import os
import logging
from pytrie import StringTrie

path = "French-Dictionary-master/dictionary"

files = os.listdir(path)

dico = StringTrie()

for file in files:
    logging.info(f"Loading {file}")
    with open(path + "/" + file) as f:
        mots = [line.split(";")[0].strip() for line in f.readlines()]
        for mot in mots:
            dico[mot] = mot

logging.info("Dico loaded")
示例#49
0
 def update_trie(self, word_list):
     self.trie = StringTrie()
     for word in word_list:
         word = word.lower()
         self.trie[word] = word
示例#50
0
from pytrie import StringTrie as trie
from bitstring import BitArray

words = open('words.txt')
t = trie.fromkeys(words.read().splitlines())

def evaluate(target):
	good = BitArray(len(target)) # all characters that are part of a meaningful word
	bestLength = 0 # length of the longest word
	bestPattern = BitArray(len(target)) # characters that form the longest word

	for i in range(len(target)):
		match = t.longest_prefix(key=target[i:], default="")
		if len(match)>0:
			temp = BitArray(len(target))
			temp.set(1, range(i, i+len(match))) # set mathcing character positions to 1
			good.set(1, range(i, i+len(match))) # set mathcing character positions to 1
			if len(match)>bestLength:
				bestLength = len(match)
				bestPattern = temp
	return bestPattern, good
示例#51
0
class UriObservationMap(object):

    """
    Represents the current set of observations maintained by a broker/dealer.

    To test: trial crossbar.router.test.test_subscription
    """

    __slots__ = (
        "_ordered",
        "_observations_exact",
        "_observations_prefix",
        "_observations_wildcard",
        "_observation_id_to_observation",
    )

    def __init__(self, ordered=False):
        # flag indicating whether observers should be maintained in a SortedSet
        # or a regular set (unordered)
        self._ordered = ordered

        # map: URI => ExactUriObservation
        self._observations_exact = {}

        # map: URI => PrefixUriObservation
        self._observations_prefix = StringTrie()

        # map: URI => WildcardUriObservation
        if True:
            # use a Trie-based implementation (supposed to be faster, but
            # otherwise compatible to the naive implementation below)
            self._observations_wildcard = WildcardTrieMatcher()
        else:
            self._observations_wildcard = WildcardMatcher()

        # map: observation ID => UriObservation
        self._observation_id_to_observation = {}

    def __repr__(self):
        return "{}(_ordered={}, _observations_exact={}, _observations_wildcard={})".format(
            self.__class__.__name__,
            self._ordered,
            self._observations_exact,
            self._observations_prefix,
            self._observations_wildcard,
            self._observation_id_to_observation,
        )

    def add_observer(self, observer, uri, match=u"exact", extra=None):
        """
        Adds a observer to the observation set and returns the respective observation.

        :param observer: The observer to add (this can be any opaque object).
        :type observer: obj
        :param uri: The URI (or URI pattern) to add the observer to add to.
        :type uri: unicode
        :param match: The matching policy for observing, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``.
        :type match: unicode

        :returns: A tuple ``(observation, was_already_observed, was_first_observer)``. Here,
            ``observation`` is an instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``.
        :rtype: tuple
        """
        if not isinstance(uri, six.text_type):
            raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__))

        if match == u"exact":

            # if the exact-matching URI isn't in our map, create a new observation
            #
            if uri not in self._observations_exact:
                self._observations_exact[uri] = ExactUriObservation(uri, ordered=self._ordered, extra=extra)
                is_first_observer = True
            else:
                is_first_observer = False

            # get the observation
            #
            observation = self._observations_exact[uri]

        elif match == u"prefix":

            # if the prefix-matching URI isn't in our map, create a new observation
            #
            if uri not in self._observations_prefix:
                self._observations_prefix[uri] = PrefixUriObservation(uri, ordered=self._ordered, extra=extra)
                is_first_observer = True
            else:
                is_first_observer = False

            # get the observation
            #
            observation = self._observations_prefix[uri]

        elif match == u"wildcard":

            # if the wildcard-matching URI isn't in our map, create a new observation
            #
            if uri not in self._observations_wildcard:
                self._observations_wildcard[uri] = WildcardUriObservation(uri, ordered=self._ordered, extra=extra)
                is_first_observer = True
            else:
                is_first_observer = False

            # get the observation
            #
            observation = self._observations_wildcard[uri]

        else:
            raise Exception("invalid match strategy '{}'".format(match))

        # note observation in observation ID map
        #
        if is_first_observer:
            self._observation_id_to_observation[observation.id] = observation

        # add observer if not already in observation
        #
        if observer not in observation.observers:
            observation.observers.add(observer)
            was_already_observed = False
        else:
            was_already_observed = True

        return observation, was_already_observed, is_first_observer

    def get_observation(self, uri, match=u"exact"):
        """
        Get a observation (if any) for given URI and match policy.

        :param uri: The URI (or URI pattern) to get the observation for.
        :type uri: unicode
        :param match: The matching policy for observation to retrieve, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``.
        :type match: unicode

        :returns: The observation (instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``)
            or ``None``.
        :rtype: obj or None
        """

        if not isinstance(uri, six.text_type):
            raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__))

        if match == u"exact":
            return self._observations_exact.get(uri, None)

        elif match == u"prefix":
            return self._observations_prefix.get(uri, None)

        elif match == u"wildcard":
            return self._observations_wildcard.get(uri, None)

        else:
            raise Exception("invalid match strategy '{}'".format(match))

    def match_observations(self, uri):
        """
        Returns the observations matching the given URI. This is the core method called
        by a broker to actually dispatch events.

        :param uri: The URI to match.
        :type uri: unicode

        :returns: A list of observations matching the URI. This is a list of instance of
            one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``.
        :rtype: list
        """
        observations = []

        if not isinstance(uri, six.text_type):
            raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__))

        if uri in self._observations_exact:
            observations.append(self._observations_exact[uri])

        for observation in self._observations_prefix.iter_prefix_values(uri):
            observations.append(observation)

        for observation in self._observations_wildcard.iter_matches(uri):
            observations.append(observation)

        return observations

    def best_matching_observation(self, uri):
        """
        Returns the observation that best matches the given URI. This is the core method called
        by a dealer to actually forward calls.

        :param uri: The URI to match.
        :type uri: unicode

        :returns: The observation best matching the URI. This is an instance of
            ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` or ``None``.
        :rtype: obj or None
        """
        if not isinstance(uri, six.text_type):
            raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__))

        # a exact matching observation is always "best", if any
        #
        if uri in self._observations_exact:
            return self._observations_exact[uri]

        # "second best" is the longest prefix-matching observation, if any
        # FIXME: do we want this to take precedence over _any_ wildcard (see below)?
        #
        try:
            return self._observations_prefix.longest_prefix_value(uri)
        except KeyError:
            pass

        # FIXME: for wildcard observations, when there are multiple matching, we'd
        # like to deterministically select the "most selective one"
        # We first need a definition of "most selective", and then we need to implement
        # this here.
        #
        for observation in self._observations_wildcard.iter_matches(uri):
            return observation

    def get_observation_by_id(self, id):
        """
        Get a observation by ID.

        :param id: The ID of the observation to retrieve.
        :type id: int

        :returns: The observation for the given ID or ``None``.
        :rtype: obj or None
        """
        return self._observation_id_to_observation.get(id, None)

    def drop_observer(self, observer, observation):
        """
        Drop a observer from a observation.

        :param observer: The observer to drop from the given observation.
        :type observer: obj
        :param observation: The observation from which to drop the observer. An instance
            of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` previously
            created and handed out by this observation map.
        :type observation: obj

        :returns: A tuple ``(was_observed, was_last_observer)``.
        :rtype: tuple
        """
        if observer in observation.observers:

            was_observed = True

            # remove observer from observation
            #
            observation.observers.discard(observer)

            # no more observers on this observation!
            #
            if not observation.observers:

                if observation.match == u"exact":
                    del self._observations_exact[observation.uri]

                elif observation.match == u"prefix":
                    del self._observations_prefix[observation.uri]

                elif observation.match == u"wildcard":
                    del self._observations_wildcard[observation.uri]

                else:
                    # should not arrive here
                    raise Exception("logic error")

                was_last_observer = True

                del self._observation_id_to_observation[observation.id]

            else:
                was_last_observer = False

        else:
            # observer wasn't on this observation
            was_observed = False

        return was_observed, was_last_observer
示例#52
0
def incrementInTrie(key,trie):
        if trie.has_key(key):
                curCount = corpus.__getitem__(key)
                trie.__setitem__(key,curCount+1)
        else:
                trie.__setitem__(key,1)
示例#53
0
class RouterRoleStaticAuth(RouterRole):
    """
    A role on a router realm that is authorized using a static configuration.
    """
    def __init__(self,
                 router,
                 uri,
                 permissions=None,
                 default_permissions=None):
        """

        :param router: The router this role is defined on.
        :type router: obj
        :param uri: The URI of the role.
        :type uri: unicode
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list of dict
        :param default_permissions: The default permissions to apply when no other
            configured permission matches. The default permissions when not explicitly
            set is to deny all actions on all URIs!
        :type default_permissions: dict
        """
        RouterRole.__init__(self, router, uri)
        assert (permissions is None or type(permissions) == list)
        if permissions:
            for p in permissions:
                assert (type(p) == dict)
        assert (default_permissions is None
                or type(default_permissions) == dict)

        # default permissions (used when nothing else is matching)
        # note: default permissions have their matching URI and match policy set to None!
        if default_permissions:
            self._default = RouterPermissions.from_dict(default_permissions)
        else:
            self._default = RouterPermissions(None,
                                              None,
                                              call=False,
                                              register=False,
                                              publish=False,
                                              subscribe=False,
                                              disclose_caller=False,
                                              disclose_publisher=False,
                                              cache=True)

        # Trie of explicitly configured permissions
        self._permissions = StringTrie()

        for obj in permissions or []:
            perms = RouterPermissions.from_dict(obj)
            self._permissions[perms.uri] = perms

    def authorize(self, session, uri, action):
        """
        Authorize a session connected under this role to perform the given
        action on the given URI.

        :param session: The WAMP session that requests the action.
        :type session: Instance of :class:`autobahn.wamp.protocol.ApplicationSession`
        :param uri: The URI on which to perform the action.
        :type uri: str
        :param action: The action to be performed.
        :type action: str

        :return: bool -- Flag indicating whether session is authorized or not.
        """
        self.log.debug(
            "CrossbarRouterRoleStaticAuth.authorize {myuri} {uri} {action}",
            myuri=self.uri,
            uri=uri,
            action=action)

        try:
            # longest prefix match of the URI to be authorized against our Trie
            # of configured URIs for permissions
            permissions = self._permissions.longest_prefix_value(uri)

            # if there is a _prefix_ matching URI, check that this is actually the
            # match policy on the permission (otherwise, apply default permissions)!
            if permissions.match != u'prefix' and uri != permissions.uri:
                permissions = self._default

        except KeyError:
            # workaround because of https://bitbucket.org/gsakkis/pytrie/issues/4/string-keys-of-zero-length-are-not
            if u'' in self._permissions:
                permissions = self._permissions[u'']
            else:
                permissions = self._default

        if action == u'publish':
            return {
                u'allow': permissions.publish,
                u'disclose': permissions.disclose_publisher,
                u'cache': permissions.cache
            }

        elif action == u'subscribe':
            return {
                u'allow': permissions.subscribe,
                u'cache': permissions.cache
            }

        elif action == u'call':
            return {
                u'allow': permissions.call,
                u'disclose': permissions.disclose_caller,
                u'cache': permissions.cache
            }

        elif action == u'register':
            return {
                u'allow': permissions.register,
                u'cache': permissions.cache
            }

        else:
            # should not arrive here
            raise Exception('logic error')
示例#54
0
class RouterRoleStaticAuth(RouterRole):

    """
    A role on a router realm that is authorized using a static configuration.
    """

    def __init__(self, router, uri, permissions=None, default_permissions=None, debug=False):
        """
        Ctor.

        :param uri: The URI of the role.
        :type uri: str
        :param permissions: A permissions configuration, e.g. a list
           of permission dicts like `{'uri': 'com.example.*', 'call': True}`
        :type permissions: list
        :param debug: Enable debug logging.
        :type debug: bool
        """
        RouterRole.__init__(self, router, uri, debug)
        self.permissions = permissions or []

        self._urimap = StringTrie()
        self._default = default_permissions or RouterPermissions('', True, False, False, False, False)

        for p in self.permissions:
            uri = p['uri']

            if len(uri) > 0 and uri[-1] == '*':
                match_by_prefix = True
                uri = uri[:-1]
            else:
                match_by_prefix = False

            perms = RouterPermissions(uri, match_by_prefix,
                                      call=p.get('call', False),
                                      register=p.get('register', False),
                                      publish=p.get('publish', False),
                                      subscribe=p.get('subscribe', False))

            if len(uri) > 0:
                self._urimap[uri] = perms
            else:
                self._default = perms

    def authorize(self, session, uri, action):
        """
        Authorize a session connected under this role to perform the given action
        on the given URI.

        :param session: The WAMP session that requests the action.
        :type session: Instance of :class:`autobahn.wamp.protocol.ApplicationSession`
        :param uri: The URI on which to perform the action.
        :type uri: str
        :param action: The action to be performed.
        :type action: str

        :return: bool -- Flag indicating whether session is authorized or not.
        """
        if self.debug:
            log.msg("CrossbarRouterRoleStaticAuth.authorize", self.uri, uri, action)
        # if action == 'publish':
        #   f = 1/0
        try:
            permissions = self._urimap.longest_prefix_value(uri)
            if not permissions.match_by_prefix and uri != permissions.uri:
                return False
            return getattr(permissions, action)
        except KeyError:
            return getattr(self._default, action)
示例#55
0
class WampMQTTServerFactory(Factory):

    log = make_logger()

    protocol = WampMQTTServerProtocol

    serializers = {
        'json': JsonObjectSerializer(),
        'msgpack': MsgPackObjectSerializer(),
        'cbor': CBORObjectSerializer(),
        'ubjson': UBJSONObjectSerializer(),
    }

    def __init__(self, router_session_factory, config, reactor):
        self._router_session_factory = router_session_factory
        self._router_factory = router_session_factory._routerFactory
        self._options = config.get('options', {})
        self._realm = self._options.get('realm', None)
        self._reactor = reactor
        self._payload_mapping = StringTrie()
        for topic, pmap in self._options.get('payload_mapping', {}).items():
            self._set_payload_format(topic, pmap)

    def buildProtocol(self, addr):
        protocol = self.protocol(self._reactor)
        protocol.factory = self
        return protocol

    def _get_payload_format(self, topic):
        """
        Map a WAMP topic URI to MQTT payload format.
        :param topic: WAMP URI.
        :type topic: str

        :returns: Payload format metadata.
        :rtype: dict
        """
        try:
            pmap = self._payload_mapping.longest_prefix_value(topic)
        except KeyError:
            return None
        else:
            return pmap

    def _set_payload_format(self, topic, pmap=None):
        if pmap is None:
            if topic in self._payload_mapping:
                del self._payload_mapping[topic]
        else:
            self._payload_mapping[topic] = pmap

    @inlineCallbacks
    def transform_wamp(self, topic, msg):
        # check for cached transformed payload
        cache_key = '_{}_{}'.format(self.__class__.__name__, id(self))
        cached = msg._serialized.get(cache_key, None)

        if cached:
            payload_format, mapped_topic, payload = cached
            self.log.debug(
                'using cached payload for {cache_key} in message {msg_id}!',
                msg_id=id(msg),
                cache_key=cache_key)
        else:
            # convert WAMP URI to MQTT topic
            mapped_topic = _wamp_topic_to_mqtt(topic)

            # for WAMP->MQTT, the payload mapping is determined from the
            # WAMP URI (not the transformed MQTT topic)
            payload_format = self._get_payload_format(topic)
            payload_format_type = payload_format['type']

            if payload_format_type == 'passthrough':
                payload = msg.payload

            elif payload_format_type == 'native':
                serializer = payload_format.get('serializer', None)
                payload = self._transform_wamp_native(serializer, msg)

            elif payload_format_type == 'dynamic':
                encoder = payload_format.get('encoder', None)
                codec_realm = payload_format.get('realm', self._realm)
                payload = yield self._transform_wamp_dynamic(
                    encoder, codec_realm, mapped_topic, topic, msg)
            else:
                raise Exception(
                    'payload format {} not implemented'.format(payload_format))

            msg._serialized[cache_key] = (payload_format, mapped_topic,
                                          payload)

        self.log.debug(
            'transform_wamp({topic}, {msg}) -> payload_format={payload_format}, mapped_topic={mapped_topic}, payload={payload}',
            topic=topic,
            msg=msg,
            payload_format=payload_format,
            mapped_topic=mapped_topic,
            payload=payload)
        returnValue((payload_format, mapped_topic, payload))

    @inlineCallbacks
    def _transform_wamp_dynamic(self, encoder, codec_realm, mapped_topic,
                                topic, msg):
        codec_session = self._router_factory.get(codec_realm)._realm.session
        payload = yield codec_session.call(encoder, mapped_topic, topic,
                                           msg.args, msg.kwargs)
        returnValue(payload)

    def _transform_wamp_native(self, serializer, msg):
        obj = {}
        for opt in [
                'args', 'kwargs', 'exclude', 'exclude_authid',
                'exclude_authrole', 'eligible', 'eligible_authid',
                'eligible_authrole'
        ]:
            attr = getattr(msg, opt, None)
            if attr is not None:
                obj[opt] = attr

        if serializer in self.serializers:
            payload = self.serializers[serializer].serialize(obj)
        else:
            raise Exception(
                'MQTT native mode payload transform: invalid serializer {}'.
                format(serializer))

        return payload

    @inlineCallbacks
    def transform_mqtt(self, topic, payload):
        # transform MQTT topic to WAMP URI
        mapped_topic = _mqtt_topicname_to_wamp(topic)

        # for MQTT->WAMP, the payload mapping is determined from the
        # transformed WAMP URI (not the original MQTT topic)
        payload_format = self._get_payload_format(mapped_topic)
        payload_format_type = payload_format['type']

        if payload_format_type == 'passthrough':
            options = {'payload': payload, 'enc_algo': 'mqtt'}

        elif payload_format_type == 'native':
            serializer = payload_format.get('serializer', None)
            options = self._transform_mqtt_native(serializer, payload)

        elif payload_format_type == 'dynamic':
            decoder = payload_format.get('decoder', None)
            codec_realm = payload_format.get('realm', self._realm)
            options = yield self._transform_mqtt_dynamic(
                decoder, codec_realm, mapped_topic, topic, payload)

        else:
            raise Exception(
                'payload format {} not implemented'.format(payload_format))

        self.log.debug(
            'transform_mqtt({topic}, {payload}) -> payload_format={payload_format}, mapped_topic={mapped_topic}, options={options}',
            topic=topic,
            payload=payload,
            payload_format=payload_format,
            mapped_topic=mapped_topic,
            options=options)
        returnValue((payload_format, mapped_topic, options))

    @inlineCallbacks
    def _transform_mqtt_dynamic(self, decoder, codec_realm, mapped_topic,
                                topic, payload):
        codec_session = self._router_factory.get(codec_realm)._realm.session
        options = yield codec_session.call(decoder, mapped_topic, topic,
                                           payload)
        returnValue(options)

    def _transform_mqtt_native(self, serializer, payload):
        """
        Transform MQTT binary payload from a MQTT Publish to keyword dict
        suitable for the constructor of a WAMP Publish message,
        that is :class:`autobahn.wamp.message.Publish`.
        """
        options = {}
        if serializer in self.serializers:
            if serializer == 'json':
                if not _validator.validate(payload)[0]:
                    # invalid UTF-8: drop the event
                    raise Exception(
                        'invalid UTF8 in JSON encoded MQTT payload')
            obj = self.serializers[serializer].unserialize(payload)[0]
        else:
            raise Exception(
                '"{}" serializer for encoded MQTT payload not implemented'.
                format(serializer))

        if not isinstance(obj, dict):
            raise Exception(
                'invalid type {} for "{}" encoded MQTT payload'.format(
                    type(obj), serializer))

        for opt in [
                'args', 'kwargs', 'exclude', 'exclude_authid',
                'exclude_authrole', 'eligible', 'eligible_authid',
                'eligible_authrole'
        ]:
            if opt in obj:
                options[opt] = obj[opt]

        return options
示例#56
0
# Author: John Maheswaran

import csv  # used to read csv files
from pytrie import StringTrie  # used to match prefixes efficiently.
# A trie allows you to match prefixes efficiently instead of the naive approach of looking
#  through all the strings and checking one by one, if we used a list instead of a trie
import locale  # used for formatting the currency in prices

products = dict(
)  # a dict is a hashmap representing the products, allows constant time lookup of product price
# informaton based on the product id

rungup = set(
)  # this stores the products that we have rung up and allows constant insertion time

trie = StringTrie(
)  # a trie that allows us to look up all the strings matching a
# prefix in faster than O(n) time where n is the number of strings

# set the locate for currency formatting
locale.setlocale(locale.LC_ALL, '')

# first we will get the csv file name from the user
print(
    "Please enter the csv product data filename or press ENTER to use the default (productdata.csv)"
)
filename = input()
if len(filename) == 0:
    filename = 'productdata.csv'

# use a try block in case opening the csv file fails
try:
示例#57
0
class UriObservationMap(object):

    """
    Represents the current set of observations maintained by a broker/dealer.

    To test: trial crossbar.router.test.test_subscription
    """

    def __init__(self, ordered=False):
        # flag indicating whether observers should be maintained in a SortedSet
        # or a regular set (unordered)
        self._ordered = ordered

        # map: URI => ExactUriObservation
        self._observations_exact = {}

        # map: URI => PrefixUriObservation
        self._observations_prefix = StringTrie()

        # map: URI => WildcardUriObservation
        self._observations_wildcard = {}

        # map: pattern length => (map: pattern => pattern count)
        self._observations_wildcard_patterns = {}

        # map: observation ID => UriObservation
        self._observation_id_to_observation = {}

    def add_observer(self, observer, uri, match=u"exact", extra=None):
        """
        Adds a observer to the observation set and returns the respective observation.

        :param observer: The observer to add (this can be any opaque object).
        :type observer: obj
        :param uri: The URI (or URI pattern) to add the observer to add to.
        :type uri: unicode
        :param match: The matching policy for observing, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``.
        :type match: unicode

        :returns: A tuple ``(observation, was_already_observed, was_first_observer)``. Here,
            ``observation`` is an instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``.
        :rtype: tuple
        """
        if match == u"exact":

            # if the exact-matching URI isn't in our map, create a new observation
            #
            if uri not in self._observations_exact:
                self._observations_exact[uri] = ExactUriObservation(uri, ordered=self._ordered, extra=extra)
                is_first_observer = True
            else:
                is_first_observer = False

            # get the observation
            #
            observation = self._observations_exact[uri]

        elif match == u"prefix":

            # if the prefix-matching URI isn't in our map, create a new observation
            #
            if uri not in self._observations_prefix:
                self._observations_prefix[uri] = PrefixUriObservation(uri, ordered=self._ordered, extra=extra)
                is_first_observer = True
            else:
                is_first_observer = False

            # get the observation
            #
            observation = self._observations_prefix[uri]

        elif match == u"wildcard":

            # if the wildcard-matching URI isn't in our map, create a new observation
            #
            if uri not in self._observations_wildcard:

                observation = WildcardUriObservation(uri, ordered=self._ordered, extra=extra)

                self._observations_wildcard[uri] = observation
                is_first_observer = True

                # setup map: pattern length -> patterns
                if observation.pattern_len not in self._observations_wildcard_patterns:
                    self._observations_wildcard_patterns[observation.pattern_len] = {}

                # setup map: (pattern length, pattern) -> pattern count
                if observation.pattern not in self._observations_wildcard_patterns[observation.pattern_len]:
                    self._observations_wildcard_patterns[observation.pattern_len][observation.pattern] = 1
                else:
                    self._observations_wildcard_patterns[observation.pattern_len][observation.pattern] += 1

            else:
                is_first_observer = False

            # get the observation
            #
            observation = self._observations_wildcard[uri]

        else:
            raise Exception("invalid match strategy '{}'".format(match))

        # note observation in observation ID map
        #
        if is_first_observer:
            self._observation_id_to_observation[observation.id] = observation

        # add observer if not already in observation
        #
        if observer not in observation.observers:
            observation.observers.add(observer)
            was_already_observed = False
        else:
            was_already_observed = True

        return observation, was_already_observed, is_first_observer

    def get_observation(self, uri, match=u"exact"):
        """
        Get a observation (if any) for given URI and match policy.

        :param uri: The URI (or URI pattern) to get the observation for.
        :type uri: unicode
        :param match: The matching policy for observation to retrieve, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``.
        :type match: unicode

        :returns: The observation (instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``)
            or ``None``.
        :rtype: obj or None
        """
        if match == u"exact":

            return self._observations_exact.get(uri, None)

        elif match == u"prefix":

            return self._observations_prefix.get(uri, None)

        elif match == u"wildcard":

            return self._observations_wildcard.get(uri, None)

        else:
            raise Exception("invalid match strategy '{}'".format(match))

    def match_observations(self, uri):
        """
        Returns the observations matching the given URI. This is the core method called
        by a broker to actually dispatch events.

        :param uri: The URI to match.
        :type uri: unicode

        :returns: A list of observations matching the URI. This is a list of instance of
            one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``.
        :rtype: list
        """
        observations = []

        if uri in self._observations_exact:
            observations.append(self._observations_exact[uri])

        for observation in self._observations_prefix.iter_prefix_values(uri):
            observations.append(observation)

        uri_parts = tuple(uri.split('.'))
        uri_parts_len = len(uri_parts)
        if uri_parts_len in self._observations_wildcard_patterns:
            for pattern in self._observations_wildcard_patterns[uri_parts_len]:
                patterned_uri = '.'.join(['' if pattern[i] else uri_parts[i] for i in range(uri_parts_len)])
                if patterned_uri in self._observations_wildcard:
                    observations.append(self._observations_wildcard[patterned_uri])

        return observations

    def best_matching_observation(self, uri):
        """
        Returns the observation that best matches the given URI. This is the core method called
        by a dealer to actually forward calls.

        :param uri: The URI to match.
        :type uri: unicode

        :returns: The observation best matching the URI. This is an instance of
            ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` or ``None``.
        :rtype: obj or None
        """
        # a exact matching observation is always "best", if any
        #
        if uri in self._observations_exact:
            return self._observations_exact[uri]

        # "second best" is the longest prefix-matching observation, if any
        # FIXME: do we want this to take precedence over _any_ wildcard (see below)?
        #
        try:
            return self._observations_prefix.longest_prefix_value(uri)
        except KeyError:
            pass

        # FIXME: for wildcard observations, when there are multiple matching, we'd
        # like to deterministically select the "most selective one"
        # We first need a definition of "most selective", and then we need to implement
        # this here.
        #
        uri_parts = tuple(uri.split('.'))
        uri_parts_len = len(uri_parts)
        if uri_parts_len in self._observations_wildcard_patterns:
            for pattern in self._observations_wildcard_patterns[uri_parts_len]:
                patterned_uri = '.'.join(['' if pattern[i] else uri_parts[i] for i in range(uri_parts_len)])
                if patterned_uri in self._observations_wildcard:
                    return self._observations_wildcard[patterned_uri]

    def get_observation_by_id(self, id):
        """
        Get a observation by ID.

        :param id: The ID of the observation to retrieve.
        :type id: int

        :returns: The observation for the given ID or ``None``.
        :rtype: obj or None
        """
        return self._observation_id_to_observation.get(id, None)

    def drop_observer(self, observer, observation):
        """
        Drop a observer from a observation.

        :param observer: The observer to drop from the given observation.
        :type observer: obj
        :param observation: The observation from which to drop the observer. An instance
            of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` previously
            created and handed out by this observation map.
        :type observation: obj

        :returns: A tuple ``(was_observed, was_last_observer)``.
        :rtype: tuple
        """
        if observer in observation.observers:

            was_observed = True

            # remove observer from observation
            #
            observation.observers.discard(observer)

            # no more observers on this observation!
            #
            if not observation.observers:

                if observation.match == u"exact":
                    del self._observations_exact[observation.uri]

                elif observation.match == u"prefix":
                    del self._observations_prefix[observation.uri]

                elif observation.match == u"wildcard":

                    # cleanup if this was the last observation with given pattern
                    self._observations_wildcard_patterns[observation.pattern_len][observation.pattern] -= 1
                    if not self._observations_wildcard_patterns[observation.pattern_len][observation.pattern]:
                        del self._observations_wildcard_patterns[observation.pattern_len][observation.pattern]

                    # cleanup if this was the last observation with given pattern length
                    if not self._observations_wildcard_patterns[observation.pattern_len]:
                        del self._observations_wildcard_patterns[observation.pattern_len]

                    # remove actual observation
                    del self._observations_wildcard[observation.uri]

                else:
                    # should not arrive here
                    raise Exception("logic error")

                was_last_observer = True

                del self._observation_id_to_observation[observation.id]

            else:
                was_last_observer = False

        else:
            # observer wasn't on this observation
            was_observed = False

        return was_observed, was_last_observer
示例#58
0
    class KeyRing(object):
        """
        A keyring holds (cryptobox) public-private key pairs for use with WAMP-cryptobox payload
        encryption. The keyring can be set on a WAMP session and then transparently will get used
        for encrypting and decrypting WAMP message payloads.
        """
        def __init__(self, default_key=None):
            """

            Create a new key ring to hold public and private keys mapped from an URI space.
            """
            assert (default_key is None or isinstance(default_key, Key)
                    or type(default_key == six.text_type))
            self._uri_to_key = StringTrie()
            if type(default_key) == six.text_type:
                default_key = Key(originator_priv=default_key,
                                  responder_priv=default_key)
            self._default_key = default_key

        def generate_key(self):
            """
            Generate a new private key and return a pair with the base64 encodings
            of (priv_key, pub_key).
            """
            key = PrivateKey.generate()
            priv_key = key.encode(encoder=Base64Encoder)
            pub_key = key.public_key.encode(encoder=Base64Encoder)
            return (u'{}'.format(priv_key), u''.format(pub_key))

        def set_key(self, uri, key):
            """
            Add a key set for a given URI.
            """
            assert (type(uri) == six.text_type)
            assert (key is None or isinstance(key, Key)
                    or type(key) == six.text_type)
            if type(key) == six.text_type:
                key = Key(originator_priv=key, responder_priv=key)
            if uri == u'':
                self._default_key = key
            else:
                if key is None:
                    if uri in self._uri_to_key:
                        del self._uri_to_key[uri]
                else:
                    self._uri_to_key[uri] = key

        def _get_box(self, is_originator, uri, match_exact=False):
            try:
                if match_exact:
                    key = self._uri_to_key[uri]
                else:
                    key = self._uri_to_key.longest_prefix_value(uri)
            except KeyError:
                if self._default_key:
                    key = self._default_key
                else:
                    return None

            if is_originator:
                return key.originator_box
            else:
                return key.responder_box

        def encrypt(self, is_originator, uri, args=None, kwargs=None):
            """
            Encrypt the given WAMP URI, args and kwargs into an EncryptedPayload instance, or None
            if the URI should not be encrypted.
            """
            assert (type(uri) == six.text_type)
            assert (type(is_originator) == bool)
            assert (args is None or type(args) in (list, tuple))
            assert (kwargs is None or type(kwargs) == dict)

            box = self._get_box(is_originator, uri)

            if not box:
                return

            payload = {u'uri': uri, u'args': args, u'kwargs': kwargs}
            nonce = random(Box.NONCE_SIZE)
            payload_ser = json.dumps(payload)
            payload_encr = box.encrypt(payload_ser,
                                       nonce,
                                       encoder=Base64Encoder)
            payload_bytes = payload_encr.encode().decode('ascii')
            payload_key = None

            return EncryptedPayload(u'cryptobox', payload_key, u'json',
                                    payload_bytes)

        def decrypt(self, is_originator, uri, encrypted_payload):
            """
            Decrypt the given WAMP URI and EncryptedPayload into a tuple (uri, args, kwargs).
            """
            assert (type(uri) == six.text_type)
            assert (isinstance(encrypted_payload, EncryptedPayload))

            box = self._get_box(is_originator, uri)

            if not box:
                raise Exception(
                    "received encrypted payload, but can't find key!")

            payload_ser = box.decrypt(encrypted_payload.payload,
                                      encoder=Base64Encoder)

            if encrypted_payload.serializer != u'json':
                raise Exception(
                    "received encrypted payload, but don't know how to process serializer '{}'"
                    .format(encrypted_payload.serializer))

            payload = json.loads(payload_ser)

            uri = payload[u'uri']
            args = payload.get(u'args', None)
            kwargs = payload.get(u'kwargs', None)

            return uri, args, kwargs