def combinedLogFormatter(timestamp: str, request: IRequest) -> str:
    """
    @return: A combined log formatted log line for the given request.

    @see: L{IAccessLogFormatter}
    """
    referrer = _escape(request.getHeader("referer") or "-")
    agent = _escape(request.getHeader("user-agent") or "-")

    clientIP = request.getClientIP()

    forwardedFor = (
        request.requestHeaders
        .getRawHeaders(b"x-forwarded-for", [b""])[0]
        .split(b",")[0]
        .strip()
    ).decode("charmap")

    if forwardedFor:
        ip = f"{forwardedFor} > {clientIP}"
    else:
        ip = clientIP


    if hasattr(request, "user") and request.user is not None:
        username = request.user.shortNames[0]
        try:
            username = _escape(username)
        except Exception:
            username = _escape(repr(username))
    else:
        username = "******"

    line = (
        '"{ip}" {user} - {timestamp} "{method} {uri} {protocol}" '
        '{code} {length} "{referrer}" "{agent}"'.format(
            ip=_escape(ip or "-"),
            timestamp=timestamp,
            method=_escape(request.method),
            uri=_escape(request.uri),
            protocol=_escape(request.clientproto),
            code=request.code,
            length=request.sentLength or "-",
            referrer=referrer,
            agent=agent,
            user=username,
        )
    )
    return line
Beispiel #2
0
 def urlFor(
     self,
     request: IRequest,
     endpoint: str,
     values: Optional[Mapping[str, KleinQueryValue]] = None,
     method: Optional[str] = None,
     force_external: bool = False,
     append_unknown: bool = True,
 ) -> str:
     host = request.getHeader(b"host")
     if host is None:
         if force_external:
             raise ValueError(
                 "Cannot build external URL if request"
                 " doesn't contain Host header"
             )
         host = b""
     return buildURL(
         self.url_map.bind(host),
         endpoint,
         values,
         method,
         force_external,
         append_unknown,
     )
Beispiel #3
0
    def extractValue(self, request: IRequest) -> Any:
        """
        Extract a value from the request.

        In the case of key/value form posts, this attempts to reliably make the
        value into str.  In the case of a JSON post, however, it will simply
        extract the value from the top-level dictionary, which means it could
        be any arrangement of JSON-serializiable objects.
        """
        fieldName = self.formFieldName
        if fieldName is None:
            raise ValueError("Cannot extract unnamed form field.")
        contentType = request.getHeader(b"content-type")
        if contentType is not None and contentType.startswith(
                b"application/json"):
            # TODO: parse only once, please.
            parsed = request.getComponent(IParsedJSONBody)
            if parsed is None:
                request.content.seek(0)
                octets = request.content.read()
                characters = octets.decode("utf-8")
                parsed = json.loads(characters)
                request.setComponent(IParsedJSONBody, parsed)
            if fieldName not in parsed:
                return None
            return parsed[fieldName]
        allValues = request.args.get(fieldName.encode("utf-8"))
        if allValues:
            return allValues[0].decode("utf-8")
        else:
            return None
Beispiel #4
0
def combinedLogFormatter(timestamp: str, request: IRequest) -> str:
    """
    @return: A combined log formatted log line for the given request.

    @see: L{IAccessLogFormatter}
    """
    referrer = _escape(request.getHeader("referer") or "-")
    agent = _escape(request.getHeader("user-agent") or "-")

    clientIP = request.getClientIP()

    forwardedFor = (
        request.requestHeaders.getRawHeaders(b"x-forwarded-for", [b""])[0]
        .split(b",")[0]
        .strip()
    ).decode("charmap")

    if forwardedFor:
        ip = f"{forwardedFor} > {clientIP}"
    else:
        ip = clientIP

    if hasattr(request, "user") and request.user is not None:
        username = request.user.shortNames[0]
        try:
            username = _escape(username)
        except Exception:
            username = _escape(repr(username))
    else:
        username = "******"

    line = (
        '"{ip}" {user} - {timestamp} "{method} {uri} {protocol}" '
        '{code} {length} "{referrer}" "{agent}"'.format(
            ip=_escape(ip or "-"),
            timestamp=timestamp,
            method=_escape(request.method),
            uri=_escape(request.uri),
            protocol=_escape(request.clientproto),
            code=request.code,
            length=request.sentLength or "-",
            referrer=referrer,
            agent=agent,
            user=username,
        )
    )
    return line
Beispiel #5
0
 def render(self, request: IRequest) -> bytes:
     # Pick an encoding based on client and server preferences.
     # We strongly prefer gzip because we save on bandwidth and
     # have pre-compressed the resource.
     accept = AcceptedEncodings.parse(request.getHeader('accept-encoding'))
     if 4.0 * accept['gzip'] > accept['identity']:
         request.setHeader('Content-Encoding', 'gzip')
         return self.__gzippedResource.render(request)
     else:
         return super().render(request)
Beispiel #6
0
def get_request_user_agent(request: IRequest, default: str = "") -> str:
    """Return the last User-Agent header, or the given default."""
    # There could be raw utf-8 bytes in the User-Agent header.

    # N.B. if you don't do this, the logger explodes cryptically
    # with maximum recursion trying to log errors about
    # the charset problem.
    # c.f. https://github.com/matrix-org/synapse/issues/3471

    h = request.getHeader(b"User-Agent")
    return h.decode("ascii", "replace") if h else default
Beispiel #7
0
    def __init__(self, request: IRequest, frameAncestors: str,
                 userAgent: UserAgent):
        super().__init__()

        self._request = request
        self._frameAncestors = frameAncestors
        self.userAgent = userAgent

        # Determine whether or not we will gzip the body.
        # We prefer gzip to save on bandwidth.
        accept = AcceptedEncodings.parse(request.getHeader('accept-encoding'))
        self._gzipContent = 2.0 * accept['gzip'] > accept['identity']
Beispiel #8
0
        def notAuthenticatedError(app: Any, request: IRequest,
                                  failure: Failure) -> KleinRenderable:
            """
            Not authenticated.
            """
            requestedWith = request.getHeader("X-Requested-With")
            if requestedWith is not None:
                if requestedWith == "XMLHttpRequest":
                    return forbiddenResponse(request)

            element = redirect(request, URLs.login, origin="o")
            return renderElement(request, element)
        def notAuthenticatedError(
            app: Any, request: IRequest, failure: Failure
        ) -> KleinRenderable:
            """
            Not authenticated.
            """
            requestedWith = request.getHeader("X-Requested-With")
            if requestedWith is not None:
                if requestedWith == "XMLHttpRequest":
                    return forbiddenResponse(request)

            element = redirect(request, URLs.login, origin="o")
            return renderElement(request, element)
Beispiel #10
0
def defaultValidationFailureHandler(
    instance: Optional[object],
    request: IRequest,
    fieldValues: "FieldValues",
) -> Element:
    """
    This is the default validation failure handler, which will be used by form
    handlers (i.e. any routes which use L{klein.Requirer} to require a field)
    in the case of any input validation failure when no other validation
    failure handler is registered via L{Form.onValidationFailureFor}.

    Its behavior is to simply return an HTML rendering of the form object,
    which includes inline information about fields which failed to validate.

    @param instance: The instance associated with the router that the form
        handler was handled on.
    @type instance: L{object}

    @param request: The request including the form submission.
    @type request: L{twisted.web.iweb.IRequest}

    @return: Any object acceptable from a Klein route.
    """
    session = request.getComponent(ISession)
    request.setResponseCode(400)
    enctype = ((request.getHeader(b"content-type")
                or RenderableForm.ENCTYPE_URL_ENCODED.encode("ascii")
                ).split(b";")[0].decode("charmap"))
    renderable = RenderableForm(
        fieldValues.form,
        session,
        "/".join(
            segment.decode("utf-8", errors="replace")
            for segment in request.prepath),
        request.method,
        enctype,
        "utf-8",
        fieldValues.prevalidationValues,
        fieldValues.validationErrors,
    )

    return Element(TagLoader(renderable))
Beispiel #11
0
def urlFromRequest(request: IRequest) -> DecodedURL:
    sentHeader = request.getHeader(b"host")
    if sentHeader is not None:
        sentHeader = sentHeader.decode("charmap")
        if ":" in sentHeader:
            host, port = sentHeader.split(":")
            port = int(port)
        else:
            host = sentHeader
            port = None
    else:
        host = request.client.host
        port = request.client.port

    url = DecodedURL.fromText(request.uri.decode("charmap"))
    url = url.replace(
        scheme="https" if request.isSecure() else "http",
        host=host,
        port=port,
    )
    return url
Beispiel #12
0
def _get_requested_host(request: IRequest) -> bytes:
    hostname = request.getHeader(b"host")
    if hostname:
        return hostname

    # no Host header, use the address/port that the request arrived on
    host: Union[address.IPv4Address, address.IPv6Address] = request.getHost()

    hostname = host.host.encode("ascii")

    if request.isSecure() and host.port == 443:
        # default port for https
        return hostname

    if not request.isSecure() and host.port == 80:
        # default port for http
        return hostname

    return b"%s:%i" % (
        hostname,
        host.port,
    )
Beispiel #13
0
    def procureSession(self,
                       request: IRequest,
                       forceInsecure: bool = False) -> Any:
        alreadyProcured = request.getComponent(ISession)
        if alreadyProcured is not None:
            if not forceInsecure or not request.isSecure():
                returnValue(alreadyProcured)

        if request.isSecure():
            if forceInsecure:
                tokenHeader = self._insecureTokenHeader
                cookieName: Union[str, bytes] = self._insecureCookie
                sentSecurely = False
            else:
                tokenHeader = self._secureTokenHeader
                cookieName = self._secureCookie
                sentSecurely = True
        else:
            # Have we inadvertently disclosed a secure token over an insecure
            # transport, for example, due to a buggy client?
            allPossibleSentTokens: Sequence[str] = sum(
                [
                    request.requestHeaders.getRawHeaders(header, [])
                    for header in [
                        self._secureTokenHeader,
                        self._insecureTokenHeader,
                    ]
                ],
                [],
            ) + [
                it for it in [
                    request.getCookie(cookie)
                    for cookie in [self._secureCookie, self._insecureCookie]
                ] if it
            ]
            # Does it seem like this check is expensive? It sure is! Don't want
            # to do it? Turn on your dang HTTPS!
            yield self._store.sentInsecurely(allPossibleSentTokens)
            tokenHeader = self._insecureTokenHeader
            cookieName = self._insecureCookie
            sentSecurely = False
            # Fun future feature: honeypot that does this over HTTPS, but sets
            # isSecure() to return false because it serves up a cert for the
            # wrong hostname or an invalid cert, to keep API clients honest
            # about chain validation.
        sentHeader = (request.getHeader(tokenHeader) or b"").decode("utf-8")
        sentCookie = (request.getCookie(cookieName) or b"").decode("utf-8")
        if sentHeader:
            mechanism = SessionMechanism.Header
        else:
            mechanism = SessionMechanism.Cookie
        if not (sentHeader or sentCookie):
            session = None
        else:
            try:
                session = yield self._store.loadSession(
                    sentHeader or sentCookie, sentSecurely, mechanism)
            except NoSuchSession:
                if mechanism == SessionMechanism.Header:
                    raise
                session = None
        if mechanism == SessionMechanism.Cookie and (
                session is None or session.identifier != sentCookie):
            if session is None:
                if request.startedWriting:
                    # At this point, if the mechanism is Header, we either have
                    # a valid session or we bailed after NoSuchSession above.
                    raise TooLateForCookies(
                        "You tried initializing a cookie-based session too"
                        " late in the request pipeline; the headers"
                        " were already sent.")
                if request.method != b"GET":
                    # Sessions should only ever be auto-created by GET
                    # requests; there's no way that any meaningful data
                    # manipulation could succeed (no CSRF token check could
                    # ever succeed, for example).
                    raise NoSuchSession(
                        "Can't initialize a session on a "
                        "{method} request.".format(
                            method=request.method.decode("ascii")))
                if not self._setCookieOnGET:
                    # We don't have a session ID at all, and we're not allowed
                    # by policy to set a cookie on the client.
                    raise NoSuchSession(
                        "Cannot auto-initialize a session for this request.")
                session = yield self._store.newSession(sentSecurely, mechanism)
            identifierInCookie = session.identifier
            if not isinstance(identifierInCookie, str):
                identifierInCookie = identifierInCookie.encode("ascii")
            if not isinstance(cookieName, str):
                cookieName = cookieName.decode("ascii")
            request.addCookie(
                cookieName,
                identifierInCookie,
                max_age=str(self._maxAge),
                domain=self._cookieDomain,
                path=self._cookiePath,
                secure=sentSecurely,
                httpOnly=True,
            )
        if sentSecurely or not request.isSecure():
            # Do not cache the insecure session on the secure request, thanks.
            request.setComponent(ISession, session)
        returnValue(session)