# Path: azmq/constants.py
# DEALER = b'DEALER'
# 
# ROUTER = b'ROUTER'
# 
# Path: azmq/common.py
# class CompositeClosableAsyncObject(ClosableAsyncObject):
#     """
#     Base class for objects that can be asynchronously closed and awaited and
#     have ownership of other closable objects.
#     """
#     def on_open(self):
#         self._children = set()
# 
#     async def on_close(self):
#         await asyncio.gather(
#             *[
#                 self.on_close_child(child)
#                 for child in self._children
#             ],
#             loop=self.loop,
#         )
#         del self._children
# 
#     async def on_close_child(self, child):
#         """
#         Called whenever a child instance must be closed.
# 
#         :returns: An awaitable that must only complete when the specified child
#             instance is effectively closed.
# 
#         May be redefined by child-classes. The default implementation calls
#             `close` followed by `wait_closed` on the specified child instance.
#         """
#         child.close()
#         await child.wait_closed()
# 
#     def register_child(self, child):
#         """
#         Register a new child that will be closed whenever the current instance
#         closes.
# 
#         :param child: The child instance.
#         """
#         if self.closing:
#             child.close()
#         else:
#             self._children.add(child)
#             child.on_closed.connect(self.unregister_child)
# 
#     def unregister_child(self, child):
#         """
#         Unregister an existing child that is no longer to be owned by the
#         current instance.
# 
#         :param child: The child instance.
#         """
#         self._children.remove(child)
#         child.on_closed.disconnect(self.unregister_child)
# 
# def cancel_on_closing(func):
#     """
#     Automatically cancels a function or coroutine when the defining instance
#     gets closed.
# 
#     :param func: The function to cancel on closing.
#     :returns: A decorated function or coroutine.
#     """
#     @wraps(func)
#     async def wrapper(self, *args, **kwargs):
#         return await self.await_until_closing(func(self, *args, **kwargs))
# 
#     return wrapper
# 
# Path: azmq/errors.py
# class ZAPTemporaryError(ZAPError):
#     def __init__(self, text, code=300):
#         super().__init__(text, code)
# 
# class ZAPAuthenticationFailure(ZAPError):
#     def __init__(self, text, code=400):
#         super().__init__(text, code)
# 
# class ZAPInternalError(ZAPError):
#     def __init__(self, text, code=500):
#         super().__init__(text, code)
# 
# class ZAPError(AZMQError):
#     def __init__(self, text, code):
#         super().__init__("ZAP error: %s (%s)" % (text, code))
#         self.text = text
#         self.code = code
# 
# Path: azmq/metadata.py
# def buffer_to_metadata(buffer):
#     """
#     Transform a buffer to a metadata dictionary.
# 
#     :param buffer: The buffer, as received in a READY command.
#     :returns: A metadata dictionary, with its keys normalized (in
#         lowercase).
#     """
#     offset = 0
#     size = len(buffer)
#     metadata = {}
# 
#     while offset < size:
#         name_size = struct.unpack_from('B', buffer, offset)[0]
#         offset += 1
# 
#         if name_size > size - 4:
#             raise ProtocolError(
#                 "Invalid name size in metadata",
#                 fatal=True,
#             )
# 
#         name = buffer[offset:offset + name_size]
#         offset += name_size
# 
#         value_size = struct.unpack_from('!I', buffer, offset)[0]
#         offset += 4
# 
#         if value_size > size - name_size - 5:
#             raise ProtocolError(
#                 "Invalid value size in metadata",
#                 fatal=True,
#             )
# 
#         value = buffer[offset:offset + value_size]
#         offset += value_size
#         metadata[name.lower()] = value
# 
#     return metadata
# 
# def metadata_to_buffers(metadata):
#     """
#     Transform a dict of metadata into a sequence of buffers.
# 
#     :param metadata: The metadata, as a dict.
#     :returns: A list of buffers.
#     """
#     results = []
# 
#     for key, value in metadata.items():
#         assert len(key) < 256
#         assert len(value) < 2 ** 32
#         results.extend([
#             struct.pack('!B', len(key)),
#             key,
#             struct.pack('!I', len(value)),
#             value,
#         ])
# 
#     return results
# 
# Path: azmq/log.py



import asyncio
from itertools import count
from .constants import (
    DEALER,
    ROUTER,
)
from .common import (
    CompositeClosableAsyncObject,
    cancel_on_closing,
)
from .errors import (
    ZAPTemporaryError,
    ZAPAuthenticationFailure,
    ZAPInternalError,
    ZAPError,
)
from .metadata import (
    buffer_to_metadata,
    metadata_to_buffers,
)
from .log import logger
    async def on_request(
        self,
        domain,
        address,
        identity,
        mechanism,
        credentials,
    ):
        """
        Handle a ZAP request.
        """
        logger.debug(
            "Request in domain %s for %s (%r): %r (%r)",
            domain,
            address,
            identity,
            mechanism,
            credentials,
        )

        user_id = None
        metadata = {}

        if self.whitelist:
            if address not in self.whitelist:
                raise ZAPAuthenticationFailure(
                    "IP address is not in the whitelist",
                )
        elif self.blacklist:
            if address in self.blacklist:

# Path: azmq/constants.py
# DEALER = b'DEALER'
# 
# ROUTER = b'ROUTER'
# 
# Path: azmq/common.py
# class CompositeClosableAsyncObject(ClosableAsyncObject):
#     """
#     Base class for objects that can be asynchronously closed and awaited and
#     have ownership of other closable objects.
#     """
#     def on_open(self):
#         self._children = set()
# 
#     async def on_close(self):
#         await asyncio.gather(
#             *[
#                 self.on_close_child(child)
#                 for child in self._children
#             ],
#             loop=self.loop,
#         )
#         del self._children
# 
#     async def on_close_child(self, child):
#         """
#         Called whenever a child instance must be closed.
# 
#         :returns: An awaitable that must only complete when the specified child
#             instance is effectively closed.
# 
#         May be redefined by child-classes. The default implementation calls
#             `close` followed by `wait_closed` on the specified child instance.
#         """
#         child.close()
#         await child.wait_closed()
# 
#     def register_child(self, child):
#         """
#         Register a new child that will be closed whenever the current instance
#         closes.
# 
#         :param child: The child instance.
#         """
#         if self.closing:
#             child.close()
#         else:
#             self._children.add(child)
#             child.on_closed.connect(self.unregister_child)
# 
#     def unregister_child(self, child):
#         """
#         Unregister an existing child that is no longer to be owned by the
#         current instance.
# 
#         :param child: The child instance.
#         """
#         self._children.remove(child)
#         child.on_closed.disconnect(self.unregister_child)
# 
# def cancel_on_closing(func):
#     """
#     Automatically cancels a function or coroutine when the defining instance
#     gets closed.
# 
#     :param func: The function to cancel on closing.
#     :returns: A decorated function or coroutine.
#     """
#     @wraps(func)
#     async def wrapper(self, *args, **kwargs):
#         return await self.await_until_closing(func(self, *args, **kwargs))
# 
#     return wrapper
# 
# Path: azmq/errors.py
# class ZAPTemporaryError(ZAPError):
#     def __init__(self, text, code=300):
#         super().__init__(text, code)
# 
# class ZAPAuthenticationFailure(ZAPError):
#     def __init__(self, text, code=400):
#         super().__init__(text, code)
# 
# class ZAPInternalError(ZAPError):
#     def __init__(self, text, code=500):
#         super().__init__(text, code)
# 
# class ZAPError(AZMQError):
#     def __init__(self, text, code):
#         super().__init__("ZAP error: %s (%s)" % (text, code))
#         self.text = text
#         self.code = code
# 
# Path: azmq/metadata.py
# def buffer_to_metadata(buffer):
#     """
#     Transform a buffer to a metadata dictionary.
# 
#     :param buffer: The buffer, as received in a READY command.
#     :returns: A metadata dictionary, with its keys normalized (in
#         lowercase).
#     """
#     offset = 0
#     size = len(buffer)
#     metadata = {}
# 
#     while offset < size:
#         name_size = struct.unpack_from('B', buffer, offset)[0]
#         offset += 1
# 
#         if name_size > size - 4:
#             raise ProtocolError(
#                 "Invalid name size in metadata",
#                 fatal=True,
#             )
# 
#         name = buffer[offset:offset + name_size]
#         offset += name_size
# 
#         value_size = struct.unpack_from('!I', buffer, offset)[0]
#         offset += 4
# 
#         if value_size > size - name_size - 5:
#             raise ProtocolError(
#                 "Invalid value size in metadata",
#                 fatal=True,
#             )
# 
#         value = buffer[offset:offset + value_size]
#         offset += value_size
#         metadata[name.lower()] = value
# 
#     return metadata
# 
# def metadata_to_buffers(metadata):
#     """
#     Transform a dict of metadata into a sequence of buffers.
# 
#     :param metadata: The metadata, as a dict.
#     :returns: A list of buffers.
#     """
#     results = []
# 
#     for key, value in metadata.items():
#         assert len(key) < 256
#         assert len(value) < 2 ** 32
#         results.extend([
#             struct.pack('!B', len(key)),
#             key,
#             struct.pack('!I', len(value)),
#             value,
#         ])
# 
#     return results
# 
# Path: azmq/log.py



# Path: azmq/zap.py
import asyncio
from itertools import count
from .constants import (
    DEALER,
    ROUTER,
)
from .common import (
    CompositeClosableAsyncObject,
    cancel_on_closing,
)
from .errors import (
    ZAPTemporaryError,
    ZAPAuthenticationFailure,
    ZAPInternalError,
    ZAPError,
)
from .metadata import (
    buffer_to_metadata,
    metadata_to_buffers,
)
from .log import logger

    async def on_request(
        self,
        domain,
        address,
        identity,
        mechanism,
        credentials,
    ):
        """
        Handle a ZAP request.
        """
        logger.debug(
            "Request in domain %s for %s (%r): %r (%r)",
            domain,
            address,
            identity,
            mechanism,
            credentials,
        )

        user_id = None
        metadata = {}

        if self.whitelist:
            if address not in self.whitelist:
                raise ZAPAuthenticationFailure(
                    "IP address is not in the whitelist",
                )
        elif self.blacklist:
            if address in self.blacklist:

                raise ZAPAuthenticationFailure("IP address is blacklisted")