Beispiel #1
0
def index(request, uri):
    """
    Proxies render requests to graphite-web, as configured in graphite.conf
    """
    base = CONFIG.get('graphiteweb', 'base')

    if request.method in ('GET', 'HEAD'):
        query = _inject_default_arguments(request.GET)
        url = urljoin(base, uri + ('?' + query) if query else '')
        req = Request(url)
    elif request.method == 'POST':
        data = _inject_default_arguments(request.POST)
        url = urljoin(base, uri)
        req = Request(url, data)
    else:
        return HttpResponseNotAllowed(['GET', 'POST', 'HEAD'])

    LOGGER.debug("proxying request to %r", url)
    proxy = urlopen(req)
    headers = proxy.info()
    content_type = headers.getheader('Content-Type', 'text/html')

    if request.method == 'HEAD':
        response = HttpResponse(content_type=content_type)
        response['Content-Length'] = headers.getheader('Content-Length', '0')
    else:
        response = HttpResponse(proxy.read(), content_type=content_type)

    response['X-Where-Am-I'] = request.get_full_path()
    return response
Beispiel #2
0
    def get_file_http(self, url, path, revision):
        logging.info('Fetching file from %s' % url)

        try:
            request = URLRequest(url)

            if self.username:
                auth_string = base64.b64encode('%s:%s' % (self.username,
                                                          self.password))
                request.add_header('Authorization', 'Basic %s' % auth_string)

            return urlopen(request).read()
        except HTTPError as e:
            if e.code == 404:
                logging.error('404')
                raise FileNotFoundError(path, revision)
            else:
                msg = "HTTP error code %d when fetching file from %s: %s" % \
                      (e.code, url, e)
                logging.error(msg)
                raise SCMError(msg)
        except Exception as e:
            msg = "Unexpected error fetching file from %s: %s" % (url, e)
            logging.error(msg)
            raise SCMError(msg)
    def _send_web_request(self, url, payload, attempts=1):
        """Send out a web request and retry on failure.

        TODO: Currently this is a blocking operation. Devising a way to send
        these requests without blocking would be benificial.

        Args:
            url (unicode):
                The URL to send the request to.

            payload (unicode):
                The JSON-encoded payload to send.

            attempts (int):
                The number of retry attempts left.
        """
        request = Request(url)
        arguments = urlencode({
            'payload': payload,
        })
        # The addition of data automatically converts request to a POST.
        request.add_data(arguments)

        while attempts:
            try:
                return urlopen(request)
            except URLError:
                attempts -= 1

        logging.warning('Sending WebHook Request failed: %s ' % url)
Beispiel #4
0
    def get_file_http(self, url, path, revision):
        logging.info('Fetching file from %s' % url)

        try:
            request = URLRequest(url)

            if self.username:
                auth_string = base64.b64encode('%s:%s' %
                                               (self.username, self.password))
                request.add_header('Authorization', 'Basic %s' % auth_string)

            return urlopen(request).read()
        except HTTPError as e:
            if e.code == 404:
                logging.error('404')
                raise FileNotFoundError(path, revision)
            else:
                msg = "HTTP error code %d when fetching file from %s: %s" % \
                      (e.code, url, e)
                logging.error(msg)
                raise SCMError(msg)
        except Exception as e:
            msg = "Unexpected error fetching file from %s: %s" % (url, e)
            logging.error(msg)
            raise SCMError(msg)
Beispiel #5
0
    def get_file_http(self, url, path, revision):
        """Return the contents of a file from an HTTP(S) URL.

        This is a convenience for looking up the contents of files that are
        referenced in diffs through an HTTP(S) request.

        Authentication is performed using the username and password provided
        (if any).

        Args:
            url (unicode):
                The URL to fetch the file contents from.

            path (unicode):
                The path of the file, as referenced in the diff.

            revision (Revision):
                The revision of the file, as referenced in the diff.

        Returns:
            bytes:
            The contents of the file.

        Raises:
            reviewboard.scmtools.errors.FileNotFoundError:
                The file could not be found.

            reviewboard.scmtools.errors.SCMError:
                Unexpected error in fetching the file. This may be an
                unexpected HTTP status code.
        """
        logging.info('Fetching file from %s' % url)

        try:
            request = URLRequest(url)

            if self.username:
                auth_string = base64.b64encode('%s:%s' %
                                               (self.username, self.password))
                request.add_header('Authorization', 'Basic %s' % auth_string)

            return urlopen(request).read()
        except HTTPError as e:
            if e.code == 404:
                logging.error('404')
                raise FileNotFoundError(path, revision)
            else:
                msg = "HTTP error code %d when fetching file from %s: %s" % \
                      (e.code, url, e)
                logging.error(msg)
                raise SCMError(msg)
        except Exception as e:
            msg = "Unexpected error fetching file from %s: %s" % (url, e)
            logging.error(msg)
            raise SCMError(msg)
Beispiel #6
0
    def get_file_http(self, url, path, revision):
        """Return the contents of a file from an HTTP(S) URL.

        This is a convenience for looking up the contents of files that are
        referenced in diffs through an HTTP(S) request.

        Authentication is performed using the username and password provided
        (if any).

        Args:
            url (unicode):
                The URL to fetch the file contents from.

            path (unicode):
                The path of the file, as referenced in the diff.

            revision (Revision):
                The revision of the file, as referenced in the diff.

        Returns:
            bytes:
            The contents of the file.

        Raises:
            reviewboard.scmtools.errors.FileNotFoundError:
                The file could not be found.

            reviewboard.scmtools.errors.SCMError:
                Unexpected error in fetching the file. This may be an
                unexpected HTTP status code.
        """
        logging.info('Fetching file from %s' % url)

        try:
            request = URLRequest(url)

            if self.username:
                auth_string = base64.b64encode('%s:%s' % (self.username,
                                                          self.password))
                request.add_header('Authorization', 'Basic %s' % auth_string)

            return urlopen(request).read()
        except HTTPError as e:
            if e.code == 404:
                logging.error('404')
                raise FileNotFoundError(path, revision)
            else:
                msg = "HTTP error code %d when fetching file from %s: %s" % \
                      (e.code, url, e)
                logging.error(msg)
                raise SCMError(msg)
        except Exception as e:
            msg = "Unexpected error fetching file from %s: %s" % (url, e)
            logging.error(msg)
            raise SCMError(msg)
Beispiel #7
0
    def _build_request(self, url, body=None, headers={}, username=None,
                       password=None):
        r = URLRequest(url, body, headers)

        if username is not None and password is not None:
            auth_key = username + ':' + password
            r.add_header(HTTPBasicAuthHandler.auth_header,
                         'Basic %s' %
                         base64.b64encode(auth_key.encode('utf-8')))

        return r
Beispiel #8
0
 def _get_request(self, request_url, request_method, **params):
     """
     Return a Request object that has the GET parameters
     attached to the url or the POST data attached to the object.
     """
     if request_method == 'GET':
         if params:
             request_url += '&%s' % urlencode(params)
         request = Request(request_url)
     elif request_method == 'POST':
         request = Request(request_url, urlencode(params, doseq=1))
     return request
Beispiel #9
0
    def _build_request(self,
                       url,
                       body=None,
                       headers={},
                       username=None,
                       password=None):
        r = URLRequest(url, body, headers)

        if username is not None and password is not None:
            auth_key = username + ':' + password
            r.add_header(
                HTTPBasicAuthHandler.auth_header,
                'Basic %s' % base64.b64encode(auth_key.encode('utf-8')))

        return r
Beispiel #10
0
def index(request, uri):
    """
    Proxies render requests to graphite-web, as configured in graphite.conf
    """
    base = CONFIG.get('graphiteweb', 'base')

    if request.method in ('GET', 'HEAD'):
        query = _inject_default_arguments(request.GET)
        url = urljoin(base, uri + ('?' + query) if query else '')
        req = Request(url)
        data = None
    elif request.method == 'POST':
        data = _inject_default_arguments(request.POST).encode('utf-8')
        url = urljoin(base, uri)
        req = Request(url, data)
    else:
        return HttpResponseNotAllowed(['GET', 'POST', 'HEAD'])

    _logger.debug("proxying request to %r", url)
    try:
        proxy = urlopen(req)
    except HTTPError as error:
        status = error.code
        headers = error.hdrs
        output = error.fp.read()

        _logger.error(
            "%s error on graphite render request: " "%r with arguments: %r",
            status,
            url,
            data,
        )

    else:
        status = proxy.getcode()
        headers = proxy.info()
        output = proxy.read()

    content_type = headers.get('Content-Type', 'text/html')

    if request.method == 'HEAD':
        response = HttpResponse(content_type=content_type, status=status)
        response['Content-Length'] = headers.get('Content-Length', '0')
    else:
        response = HttpResponse(output, content_type=content_type, status=status)

    response['X-Where-Am-I'] = request.get_full_path()
    return response
Beispiel #11
0
def _get_response(url, xml_body):
    """Takes and returns an ElementTree xml document."""
    req = Request(url, ElementTree.tostring(xml_body, encoding='utf-8'))
    response = urlopen(req)
    ret = ElementTree.fromstring(response.read())
    response.close()
    return ret
Beispiel #12
0
    def send(self, address, alert, language='en'):
        """Send a message to Slack"""
        if self._is_still_backing_off_for(address.address):
            raise DispatcherException(
                "Refusing to send Slack alert until backoff period has expired"
            )

        params = {
            'text': alert.messages.get(language=language, type='sms').message,
            'username': self.username,
            'channel': self.channel,
            'icon_emoji': self.emoji
        }
        payload = json.dumps(params)
        if isinstance(payload, six.text_type):
            payload = payload.encode("utf-8")
        request = Request(address.address, payload,
                          {'Content-Type': 'application/json'})

        try:
            urlopen(request)
        except HTTPError as error:
            if error.code == HTTP_TOO_MANY_REQUESTS:
                self._register_failure_for(address.address)
                raise DispatcherException(
                    "Slack complained there were too many requests; need to back off"
                )
            else:
                raise
Beispiel #13
0
    def notify(self, text, fields):
        """Send a webhook notification to Slack.

        Args:
            text (unicode):
                The text to send.

            fields (list of dict):
                A list of fields to include in the notification.
        """
        payload = {
            'username':
            self.settings['notify_username'],
            'icon_url':
            'http://images.reviewboard.org/rbslack/logo.png',
            'attachments': [
                {
                    'color': '#efcc96',
                    'fallback': text,
                    'fields': fields,
                },
            ],
        }

        channel = self.settings['channel']

        if channel:
            payload['channel'] = channel

        try:
            urlopen(Request(self.settings['webhook_url'], json.dumps(payload)))
        except Exception as e:
            logging.error('Failed to send notification to slack.com: %s',
                          e,
                          exc_info=True)
Beispiel #14
0
def raw_metric_query(query):
    """Runs a query for metric information against Graphite's REST API.

    :param query: A search string, e.g. "nav.devices.some-gw_example_org.*"
    :returns: A list of matching metrics, each represented by a dict.

    """
    base = CONFIG.get("graphiteweb", "base")
    url = urljoin(base, "/metrics/find")
    query = urlencode({'query': query})
    url = "%s?%s" % (url, query)

    req = Request(url)
    try:
        response_data = urlopen(req).read().decode('utf-8')
        return json.loads(response_data)
    except URLError as err:
        raise errors.GraphiteUnreachableError(
            "{0} is unreachable".format(base), err)
    except ValueError:
        # response could not be decoded
        return []
    finally:
        try:
            response.close()
        except NameError:
            pass
Beispiel #15
0
def get_metric_data(target, start="-5min", end="now"):
    """
    Retrieves raw datapoints from a graphite target for a given period of time.

    :param target: A metric path string or a list of multiple metric paths
    :param start: A start time specification that Graphite will accept.
    :param end: An end time specification that Graphite will accept.

    :returns: A raw, response from Graphite. Normally a list of dicts that
              represent the names and datapoints of each matched target,
              like so::

                  [{'target': 'x', 'datapoints': [(value, timestamp), ...]}]

    """
    if not target:
        return []  # no point in wasting time on http requests for no data

    base = CONFIG.get("graphiteweb", "base")
    url = urljoin(base, "/render/")

    # What does Graphite accept of formats? Lets check if the parameters are
    # datetime objects and try to force a format then
    if isinstance(start, datetime):
        start = start.strftime('%H:%M%Y%m%d')
    if isinstance(end, datetime):
        end = end.strftime('%H:%M%Y%m%d')

    query = {
        'target': target,
        'from': start,
        'until': end,
        'format': 'json',
    }
    query = urlencode(query, True)

    _logger.debug("get_metric_data%r", (target, start, end))
    req = Request(url, data=query.encode('utf-8'))
    try:
        response = urlopen(req)
        json_data = json.load(codecs.getreader('utf-8')(response))
        _logger.debug("get_metric_data: returning %d results", len(json_data))
        return json_data
    except HTTPError as err:
        _logger.error("Got a 500 error from graphite-web when fetching %s"
                      "with data %s", err.url, query)
        _logger.error("Graphite output: %s", err.fp.read())
        raise errors.GraphiteUnreachableError(
            "{0} is unreachable".format(base), err)
    except URLError as err:
        raise errors.GraphiteUnreachableError(
            "{0} is unreachable".format(base), err)
    except ValueError:
        # response could not be decoded
        return []
    finally:
        try:
            response.close()
        except NameError:
            pass
Beispiel #16
0
def create_idonethis_request(request_path, api_token, json_payload=None):
    """Create a urllib request for the I Done This API.

    Args:
        request_path (unicode):
            The API request path, relative to the base API URL.

        api_token (unicode):
            The user's API token for authorization.

        json_payload (unicode, optional):
            JSON payload for a POST request. If this is omitted,
            the request will be a GET.

    Returns:
        urllib2.Request:
        The I Done This API request with the provided details.
    """
    url = '%s/%s' % (IDONETHIS_API_BASE_URL, request_path)
    headers = {
        'Authorization': 'Token %s' % api_token,
    }

    if json_payload:
        headers['Content-Type'] = 'application/json'

    return Request(url, json_payload, headers)
    def find_embed(self, url, max_width=None):
        # Find provider
        endpoint = self._get_endpoint(url)
        if endpoint is None:
            raise EmbedNotFoundException

        # Work out params
        params = self.options.copy()
        params['url'] = url
        params['format'] = 'json'
        if max_width:
            params['maxwidth'] = max_width

        # Perform request
        request = Request(endpoint + '?' + urlencode(params))
        request.add_header('User-agent', 'Mozilla/5.0')
        try:
            r = urllib_request.urlopen(request)
        except URLError:
            raise EmbedNotFoundException
        oembed = json.loads(r.read().decode('utf-8'))

        # Convert photos into HTML
        if oembed['type'] == 'photo':
            html = '<img src="%s" />' % (oembed['url'], )
        else:
            html = oembed.get('html')

        # Return embed as a dict
        return {
            'title':
            oembed['title'] if 'title' in oembed else '',
            'author_name':
            oembed['author_name'] if 'author_name' in oembed else '',
            'provider_name':
            oembed['provider_name'] if 'provider_name' in oembed else '',
            'type':
            oembed['type'],
            'thumbnail_url':
            oembed.get('thumbnail_url'),
            'width':
            oembed.get('width'),
            'height':
            oembed.get('height'),
            'html':
            html,
        }
Beispiel #18
0
    def __init__(self, url, body='', headers=None, method='GET'):
        """Initialize the URLRequest.

        Args:
            url (unicode):
                The URL to make the request against.

            body (unicode or bytes):
                The content of the request.

            headers (dict, optional):
                Additional headers to attach to the request.

            method (unicode, optional):
                The request method. If not provided, it defaults to a ``GET``
                request.
        """
        BaseURLRequest.__init__(self, url, body, headers or {})
        self.method = method
Beispiel #19
0
    def __init__(self, url, body='', headers=None, method='GET'):
        """Initialize the URLRequest.

        Args:
            url (unicode):
                The URL to make the request against.

            body (unicode or bytes):
                The content of the request.

            headers (dict, optional):
                Additional headers to attach to the request.

            method (unicode, optional):
                The request method. If not provided, it defaults to a ``GET``
                request.
        """
        # Request is an old-style class and therefore we cannot use super().
        BaseURLRequest.__init__(self, url, body, headers or {})
        self.method = method
Beispiel #20
0
 def send(self, address, alert, language='en'):
     """Send a message to Slack"""
     params = {
         'text': alert.messages.get(language=language, type='sms').message,
         'username': self.username,
         'channel': self.channel,
         'icon_emoji': self.emoji
     }
     request = Request(address.address, json.dumps(params),
                       {'Content-Type': 'application/json'})
     urlopen(request)
Beispiel #21
0
    def find_embed(self, url, max_width=None):
        # Find provider
        endpoint = self._get_endpoint(url)
        if endpoint is None:
            raise EmbedNotFoundException

        # Work out params
        params = self.options.copy()
        params['url'] = url
        params['format'] = 'json'
        if max_width:
            params['maxwidth'] = max_width

        # Perform request
        request = Request(endpoint + '?' + urlencode(params))
        request.add_header('User-agent', 'Mozilla/5.0')
        try:
            r = urllib_request.urlopen(request)
        except URLError:
            raise EmbedNotFoundException
        oembed = json.loads(r.read().decode('utf-8'))

        # Convert photos into HTML
        if oembed['type'] == 'photo':
            html = '<img src="%s" />' % (oembed['url'], )
        else:
            html = oembed.get('html')

        # Return embed as a dict
        return {
            'title': oembed['title'] if 'title' in oembed else '',
            'author_name': oembed['author_name'] if 'author_name' in oembed else '',
            'provider_name': oembed['provider_name'] if 'provider_name' in oembed else '',
            'type': oembed['type'],
            'thumbnail_url': oembed.get('thumbnail_url'),
            'width': oembed.get('width'),
            'height': oembed.get('height'),
            'html': html,
        }
Beispiel #22
0
 def send(self, address, alert, language='en'):
     """Send a message to Slack"""
     params = {
         'text': alert.messages.get(language=language, type='sms').message,
         'username': self.username,
         'channel': self.channel,
         'icon_emoji': self.emoji
     }
     payload = json.dumps(params)
     if isinstance(payload, six.text_type):
         payload = payload.encode("utf-8")
     request = Request(address.address, payload,
                       {'Content-Type': 'application/json'})
     urlopen(request)
Beispiel #23
0
def dispatch_webhook_event(request, webhook_targets, event, payload):
    """Dispatch the given event and payload to the given webhook targets."""
    encoder = BasicAPIEncoder()
    bodies = {}

    for webhook_target in webhook_targets:
        if webhook_target.use_custom_content:
            body = render_custom_content(webhook_target.custom_content,
                                         payload)
        else:
            encoding = webhook_target.encoding

            if encoding not in bodies:
                if encoding == webhook_target.ENCODING_JSON:
                    adapter = JSONEncoderAdapter(encoder)
                    body = adapter.encode(payload, request=request)
                elif encoding == webhook_target.ENCODING_XML:
                    adapter = XMLEncoderAdapter(encoder)
                    body = adapter.encode(payload, request=request)
                elif encoding == webhook_target.ENCODING_FORM_DATA:
                    adapter = JSONEncoderAdapter(encoder)
                    body = urlencode({
                        'payload':
                        adapter.encode(payload, request=request),
                    })
                else:
                    logging.error(
                        'Unexpected WebHookTarget encoding "%s" for '
                        'ID %s', encoding, webhook_target.pk)
                    continue

                body = body.encode('utf-8')
                bodies[encoding] = body
            else:
                body = bodies[encoding]

        headers = {
            'X-ReviewBoard-Event': event,
            'Content-Type': webhook_target.encoding,
            'Content-Length': len(body),
            'User-Agent': 'ReviewBoard-WebHook/%s' % get_package_version(),
        }

        if webhook_target.secret:
            signer = hmac.new(webhook_target.secret.encode('utf-8'), body)
            headers['X-Hub-Signature'] = 'sha1=%s' % signer.hexdigest()

        logging.info('Dispatching webhook for event %s to %s', event,
                     webhook_target.url)
        urlopen(Request(webhook_target.url, body, headers))
Beispiel #24
0
def oembed(url, max_width=None):
    # Find provider
    provider = get_oembed_provider(url)
    if provider is None:
        raise EmbedNotFoundException

    # Work out params
    params = {"url": url, "format": "json"}
    if max_width:
        params["maxwidth"] = max_width

    # Perform request
    request = Request(provider + "?" + urlencode(params))
    request.add_header("User-agent", "Mozilla/5.0")
    try:
        r = urllib_request.urlopen(request)
    except URLError:
        raise EmbedNotFoundException
    oembed = json.loads(r.read().decode("utf-8"))

    # Convert photos into HTML
    if oembed["type"] == "photo":
        html = '<img src="%s" />' % (oembed["url"],)
    else:
        html = oembed.get("html")

    # Return embed as a dict
    return {
        "title": oembed["title"] if "title" in oembed else "",
        "author_name": oembed["author_name"] if "author_name" in oembed else "",
        "provider_name": oembed["provider_name"] if "provider_name" in oembed else "",
        "type": oembed["type"],
        "thumbnail_url": oembed.get("thumbnail_url"),
        "width": oembed.get("width"),
        "height": oembed.get("height"),
        "html": html,
    }
Beispiel #25
0
    def _visit(self, url):
        if self._is_seen(url):
            return
        req = Request(_quote_url(url), headers={'Accept': 'text/html'})
        resp = urlopen(req, timeout=TIMEOUT)
        content_type = resp.info()['Content-type']

        if 'html' in content_type.lower():
            content = resp.read()
            self._queue_links_from(content, url)
        else:
            content = None

        page = Page(url, resp.getcode(), content_type, content)
        self._add_seen(page)
        return page
Beispiel #26
0
def dispatch(request, handlers, event, payload):
    """Dispatch the given event and payload to the given handlers."""
    encoder = BasicAPIEncoder()
    adapter = JSONEncoderAdapter(encoder)
    body = adapter.encode(payload, request=request)
    body = body.encode('utf-8')

    headers = {
        'X-ReviewBoard-Event': event,
        'Content-Type': 'application/json',
        'Content-Length': len(body),
    }

    for handler in handlers:
        signer = hmac.new(handler.secret.encode('utf-8'), body)
        headers['X-ReviewBoard-Signature'] = signer.hexdigest()

        logging.info('Dispatching webhook for event %s to %s', event,
                     handler.url)
        urlopen(Request(handler.url, body, headers))
def check_recaptcha(request, context, push_messages):
    is_valid = True
    if not app_settings.USE_GOOGLE_RECAPTCHA:
        return is_valid
    ''' Begin reCAPTCHA validation '''
    recaptcha_response = request.POST.get('g-recaptcha-response')
    url = 'https://www.google.com/recaptcha/api/siteverify'
    values = {
        'secret': app_settings.GOOGLE_RECAPTCHA_SECRET_KEY,
        'response': recaptcha_response
    }
    data = urlencode(values).encode('utf-8')
    req = Request(url, data)
    response = urlopen(req)
    result = json.load(response)
    ''' End reCAPTCHA validation '''
    if not result['success']:
        is_valid = False
        error_message = _('Invalid reCAPTCHA.')
        if push_messages:
            messages.error(request, error_message)
    return is_valid
Beispiel #28
0
def dispatch_webhook_event(request, webhook_targets, event, payload):
    """Dispatch the given event and payload to the given WebHook targets.

    Args:
        request (django.http.HttpRequest):
            The HTTP request from the client.

        webhook_targets (list of
                         reviewboard.notifications.models.WebHookTarget):
            The list of WebHook targets containing endpoint URLs to dispatch
            to.

        event (unicode):
            The name of the event being dispatched.

        payload (dict):
            The payload data to encode for the WebHook payload.

    Raises:
        ValueError:
            There was an error with the payload format. Details are in the
            log and the exception message.
    """
    encoder = BasicAPIEncoder()
    bodies = {}

    raw_norm_payload = None
    json_norm_payload = None

    for webhook_target in webhook_targets:
        use_custom_content = webhook_target.use_custom_content
        encoding = webhook_target.encoding

        # See how we need to handle normalizing this payload. If we need
        # something JSON-safe, then we need to go the more aggressive route
        # and normalize keys to strings.
        if raw_norm_payload is None or json_norm_payload is None:
            try:
                if (raw_norm_payload is None
                        and (use_custom_content
                             or encoding == webhook_target.ENCODING_XML)):
                    # This payload's going to be provided for XML and custom
                    # templates. We don't want to alter the keys at all.
                    raw_norm_payload = normalize_webhook_payload(
                        payload=payload, request=request)
                elif (json_norm_payload is None and not use_custom_content
                      and encoding in (webhook_target.ENCODING_JSON,
                                       webhook_target.ENCODING_FORM_DATA)):
                    # This payload's going to be provided for JSON or
                    # form-data. We want to normalize all keys to strings.
                    json_norm_payload = normalize_webhook_payload(
                        payload=payload, request=request, use_string_keys=True)
            except TypeError as e:
                logging.exception(
                    'WebHook payload passed to '
                    'dispatch_webhook_event containing invalid '
                    'data types: %s', e)

                raise ValueError(six.text_type(e))

        if use_custom_content:
            try:
                assert raw_norm_payload is not None
                body = render_custom_content(webhook_target.custom_content,
                                             raw_norm_payload)
                body = force_bytes(body)
            except Exception as e:
                logging.exception('Could not render WebHook payload: %s', e)
                continue
        else:
            if encoding not in bodies:
                try:
                    if encoding == webhook_target.ENCODING_JSON:
                        assert json_norm_payload is not None
                        adapter = JSONEncoderAdapter(encoder)
                        body = adapter.encode(json_norm_payload,
                                              request=request)
                    elif encoding == webhook_target.ENCODING_XML:
                        assert raw_norm_payload is not None
                        adapter = XMLEncoderAdapter(encoder)
                        body = adapter.encode(raw_norm_payload,
                                              request=request)
                    elif encoding == webhook_target.ENCODING_FORM_DATA:
                        assert json_norm_payload is not None
                        adapter = JSONEncoderAdapter(encoder)
                        body = urlencode({
                            'payload':
                            adapter.encode(json_norm_payload, request=request),
                        })
                    else:
                        logging.error(
                            'Unexpected WebHookTarget encoding "%s" '
                            'for ID %s', encoding, webhook_target.pk)
                        continue
                except Exception as e:
                    logging.exception('Could not encode WebHook payload: %s',
                                      e)
                    continue

                body = force_bytes(body)
                bodies[encoding] = body
            else:
                body = bodies[encoding]

        headers = {
            b'X-ReviewBoard-Event':
            event.encode('utf-8'),
            b'Content-Type':
            webhook_target.encoding.encode('utf-8'),
            b'Content-Length':
            len(body),
            b'User-Agent':
            ('ReviewBoard-WebHook/%s' % get_package_version()).encode('utf-8'),
        }

        if webhook_target.secret:
            signer = hmac.new(webhook_target.secret.encode('utf-8'), body,
                              hashlib.sha1)
            headers[b'X-Hub-Signature'] = \
                ('sha1=%s' % signer.hexdigest()).encode('utf-8')

        logging.info('Dispatching webhook for event %s to %s', event,
                     webhook_target.url)

        try:
            url = webhook_target.url
            url_parts = urlsplit(url)

            if url_parts.username or url_parts.password:
                credentials, netloc = url_parts.netloc.split('@', 1)
                url = urlunsplit((url_parts.scheme, netloc, url_parts.path,
                                  url_parts.query, url_parts.fragment))
                headers[b'Authorization'] = \
                     b'Basic %s' % b64encode(credentials.encode('utf-8'))

            urlopen(Request(url.encode('utf-8'), body, headers))
        except Exception as e:
            logging.exception('Could not dispatch WebHook to %s: %s',
                              webhook_target.url, e)

            if isinstance(e, HTTPError):
                logging.info('Error response from %s: %s %s\n%s',
                             webhook_target.url, e.code, e.reason, e.read())
Beispiel #29
0
    def notify(self, title, title_link, fallback_text, local_site,
               review_request, event_name=None, fields={}, pre_text=None,
               body=None, color=None, thumb_url=None, image_url=None):
        """Send a webhook notification to Slack.

        This will post the given message to any Slacks/channels configured to
        receive it.

        Args:
            title (unicode):
                The title for the message.

            title_link (unicode):
                The link for the title of the message.

            fallback_text (unicode):
                The non-rich fallback text to display in the chat, for use in
                IRC and other services.

            fields (dict):
                The fields comprising the rich message to display in chat.

            local_site (reviewboard.site.models.LocalSite):
                The Local Site for the review request or review emitting
                the message. Only integration configurations matching this
                Local Site will be processed.

            review_request (reviewboard.reviews.models.ReviewRequest):
                The review request the notification is bound to.

            event_name (unicode):
                The name of the event triggering this notification.

            pre_text (unicode, optional):
                Text to display before the rest of the message.

            body (unicode, optional):
                The body of the message.

            color (unicode, optional):
                A Slack color string or RGB hex value for the message.

            thumb_url (unicode, optional):
                URL of an image to show on the side of the message.

            image_url (unicode, optional):
                URL of an image to show in the message.
        """
        if not color:
            color = self.DEFAULT_COLOR

        attachment_payload = {
            'color': color or self.DEFAULT_COLOR,
            'fallback': fallback_text,
            'title': title,
            'title_link': title_link,
            'text': body,
            'pretext': pre_text,
        }

        if fields:
            attachment_payload['fields'] = fields

        if thumb_url:
            attachment_payload['thumb_url'] = thumb_url

        if image_url:
            attachment_payload['image_url'] = image_url

        common_payload = {
            'icon_url': self.LOGO_URL,
            'attachments': [attachment_payload],
        }

        # Send a notification to any configured Slack channels.
        for config in self.get_configs(local_site):
            if not config.match_conditions(form_cls=self.config_form_cls,
                                           review_request=review_request):
                continue

            payload = dict({
                'username': config.get('notify_username'),
            }, **common_payload)

            channel = config.get('channel')

            if channel:
                payload['channel'] = channel

            webhook_url = config.get('webhook_url')

            logging.debug('Sending Slack notification for event "%s", '
                          'review_request ID %d to channel "%s", '
                          'webhook URL %s',
                          event_name, review_request.pk, channel, webhook_url)

            try:
                urlopen(Request(webhook_url, json.dumps(payload)))
            except Exception as e:
                logging.error('Failed to send notification to Slack: %s',
                              e, exc_info=True)
Beispiel #30
0
    def get_file_http(self, url, path, revision, mime_type=None):
        """Return the contents of a file from an HTTP(S) URL.

        This is a convenience for looking up the contents of files that are
        referenced in diffs through an HTTP(S) request.

        Authentication is performed using the username and password provided
        (if any).

        Args:
            url (unicode):
                The URL to fetch the file contents from.

            path (unicode):
                The path of the file, as referenced in the diff.

            revision (Revision):
                The revision of the file, as referenced in the diff.

            mime_type (unicode):
                The expected content type of the file. If not specified,
                this will default to accept everything.

        Returns:
            bytes:
            The contents of the file if content type matched, otherwise None.

        Raises:
            reviewboard.scmtools.errors.FileNotFoundError:
                The file could not be found.

            reviewboard.scmtools.errors.SCMError:
                Unexpected error in fetching the file. This may be an
                unexpected HTTP status code.
        """
        logging.info('Fetching file from %s' % url)

        try:
            request = URLRequest(url)

            if self.username:
                credentials = '%s:%s' % (self.username, self.password)
                auth_string = \
                    force_text(base64.b64encode(credentials.encode('utf-8')))
                request.add_header(force_str('Authorization'),
                                   force_str('Basic %s' % auth_string))

            response = urlopen(request)

            if (mime_type is None or
                response.info()['Content-Type'] == mime_type):
                return force_bytes(response.read())

            return None
        except HTTPError as e:
            if e.code == 404:
                raise FileNotFoundError(path, revision)
            else:
                msg = "HTTP error code %d when fetching file from %s: %s" % \
                      (e.code, url, e)
                logging.error(msg)
                raise SCMError(msg)
        except Exception as e:
            msg = "Unexpected error fetching file from %s: %s" % (url, e)
            logging.error(msg)
            raise SCMError(msg)
Beispiel #31
0
def dispatch_webhook_event(request, webhook_targets, event, payload):
    """Dispatch the given event and payload to the given WebHook targets."""
    encoder = ResourceAPIEncoder()
    bodies = {}

    for webhook_target in webhook_targets:
        if webhook_target.use_custom_content:
            try:
                body = render_custom_content(webhook_target.custom_content,
                                             payload)

                body = body.encode('utf-8')
            except Exception as e:
                logging.exception('Could not render WebHook payload: %s', e)
                continue

        else:
            encoding = webhook_target.encoding

            if encoding not in bodies:
                try:
                    if encoding == webhook_target.ENCODING_JSON:
                        adapter = JSONEncoderAdapter(encoder)
                        body = adapter.encode(payload, request=request)
                        body = body.encode('utf-8')
                    elif encoding == webhook_target.ENCODING_XML:
                        adapter = XMLEncoderAdapter(encoder)
                        body = adapter.encode(payload, request=request)
                    elif encoding == webhook_target.ENCODING_FORM_DATA:
                        adapter = JSONEncoderAdapter(encoder)
                        body = urlencode({
                            'payload':
                            adapter.encode(payload, request=request),
                        })
                        body = body.encode('utf-8')
                    else:
                        logging.error(
                            'Unexpected WebHookTarget encoding "%s" '
                            'for ID %s', encoding, webhook_target.pk)
                        continue
                except Exception as e:
                    logging.exception('Could not encode WebHook payload: %s',
                                      e)
                    continue

                bodies[encoding] = body
            else:
                body = bodies[encoding]

        headers = {
            b'X-ReviewBoard-Event':
            event.encode('utf-8'),
            b'Content-Type':
            webhook_target.encoding.encode('utf-8'),
            b'Content-Length':
            len(body),
            b'User-Agent':
            ('ReviewBoard-WebHook/%s' % get_package_version()).encode('utf-8'),
        }

        if webhook_target.secret:
            signer = hmac.new(webhook_target.secret.encode('utf-8'), body,
                              hashlib.sha1)
            headers[b'X-Hub-Signature'] = \
                ('sha1=%s' % signer.hexdigest()).encode('utf-8')

        logging.info('Dispatching webhook for event %s to %s', event,
                     webhook_target.url)
        try:
            url = webhook_target.url.encode('utf-8')
            urlopen(Request(url, body, headers))
        except Exception as e:
            logging.exception('Could not dispatch WebHook to %s: %s',
                              webhook_target.url, e)
Beispiel #32
0
def dispatch_webhook_event(request, webhook_targets, event, payload):
    """Dispatch the given event and payload to the given WebHook targets.

    Args:
        request (django.http.HttpRequest):
            The HTTP request from the client.

        webhook_targets (list of
                         reviewboard.notifications.models.WebHookTarget):
            The list of WebHook targets containing endpoint URLs to dispatch
            to.

        event (unicode):
            The name of the event being dispatched.

        payload (dict):
            The payload data to encode for the WebHook payload.

    Raises:
        ValueError:
            There was an error with the payload format. Details are in the
            log and the exception message.
    """
    try:
        payload = normalize_webhook_payload(payload, request)
    except TypeError as e:
        logging.exception('WebHook payload passed to dispatch_webhook_event '
                          'containing invalid data types: %s',
                          e)

        raise ValueError(six.text_type(e))

    encoder = BasicAPIEncoder()
    bodies = {}

    for webhook_target in webhook_targets:
        if webhook_target.use_custom_content:
            try:
                body = render_custom_content(webhook_target.custom_content,
                                             payload)
                body = body.encode('utf-8')
            except Exception as e:
                logging.exception('Could not render WebHook payload: %s', e)
                continue
        else:
            encoding = webhook_target.encoding

            if encoding not in bodies:
                try:
                    if encoding == webhook_target.ENCODING_JSON:
                        adapter = JSONEncoderAdapter(encoder)
                        body = adapter.encode(payload, request=request)
                        body = body.encode('utf-8')
                    elif encoding == webhook_target.ENCODING_XML:
                        adapter = XMLEncoderAdapter(encoder)
                        body = adapter.encode(payload, request=request)
                    elif encoding == webhook_target.ENCODING_FORM_DATA:
                        adapter = JSONEncoderAdapter(encoder)
                        body = urlencode({
                            'payload': adapter.encode(payload,
                                                      request=request),
                        })
                        body = body.encode('utf-8')
                    else:
                        logging.error('Unexpected WebHookTarget encoding "%s" '
                                      'for ID %s',
                                      encoding, webhook_target.pk)
                        continue
                except Exception as e:
                    logging.exception('Could not encode WebHook payload: %s',
                                      e)
                    continue

                bodies[encoding] = body
            else:
                body = bodies[encoding]

        headers = {
            b'X-ReviewBoard-Event': event.encode('utf-8'),
            b'Content-Type': webhook_target.encoding.encode('utf-8'),
            b'Content-Length': len(body),
            b'User-Agent':
                ('ReviewBoard-WebHook/%s' % get_package_version())
                .encode('utf-8'),
        }

        if webhook_target.secret:
            signer = hmac.new(webhook_target.secret.encode('utf-8'), body,
                              hashlib.sha1)
            headers[b'X-Hub-Signature'] = \
                ('sha1=%s' % signer.hexdigest()).encode('utf-8')

        logging.info('Dispatching webhook for event %s to %s',
                     event, webhook_target.url)
        try:
            url = webhook_target.url
            url_parts = urlsplit(url)

            if url_parts.username or url_parts.password:
                netloc = url_parts.netloc.split('@', 1)[1]
                url = urlunsplit(
                    (url_parts.scheme, netloc, url_parts.path,
                     url_parts.params, url_parts.query))

                password_mgr = HTTPPasswordMgrWithDefaultRealm()
                password_mgr.add_password(
                    None, url, url_parts.username, url_parts.password)
                handler = HTTPBasicAuthHandler(password_mgr)
                opener = build_opener(handler)
            else:
                opener = build_opener()

            opener.open(Request(url.encode('utf-8'), body, headers))
        except Exception as e:
            logging.exception('Could not dispatch WebHook to %s: %s',
                              webhook_target.url, e)
Beispiel #33
0
 def __init__(self, url, body='', headers={}, method='GET'):
     BaseURLRequest.__init__(self, url, body, headers)
     self.method = method
Beispiel #34
0
 def __init__(self, url, body='', headers={}, method='GET'):
     BaseURLRequest.__init__(self, url, body, headers)
     self.method = method
Beispiel #35
0
def dispatch_webhook_event(request, webhook_targets, event, payload):
    """Dispatch the given event and payload to the given WebHook targets."""
    encoder = ResourceAPIEncoder()
    bodies = {}

    for webhook_target in webhook_targets:
        if webhook_target.use_custom_content:
            try:
                body = render_custom_content(webhook_target.custom_content,
                                             payload)

                body = body.encode('utf-8')
            except Exception as e:
                logging.exception('Could not render WebHook payload: %s', e)
                continue

        else:
            encoding = webhook_target.encoding

            if encoding not in bodies:
                try:
                    if encoding == webhook_target.ENCODING_JSON:
                        adapter = JSONEncoderAdapter(encoder)
                        body = adapter.encode(payload, request=request)
                        body = body.encode('utf-8')
                    elif encoding == webhook_target.ENCODING_XML:
                        adapter = XMLEncoderAdapter(encoder)
                        body = adapter.encode(payload, request=request)
                    elif encoding == webhook_target.ENCODING_FORM_DATA:
                        adapter = JSONEncoderAdapter(encoder)
                        body = urlencode({
                            'payload':
                            adapter.encode(payload, request=request),
                        })
                        body = body.encode('utf-8')
                    else:
                        logging.error(
                            'Unexpected WebHookTarget encoding "%s" '
                            'for ID %s', encoding, webhook_target.pk)
                        continue
                except Exception as e:
                    logging.exception('Could not encode WebHook payload: %s',
                                      e)
                    continue

                bodies[encoding] = body
            else:
                body = bodies[encoding]

        headers = {
            b'X-ReviewBoard-Event':
            event.encode('utf-8'),
            b'Content-Type':
            webhook_target.encoding.encode('utf-8'),
            b'Content-Length':
            len(body),
            b'User-Agent':
            ('ReviewBoard-WebHook/%s' % get_package_version()).encode('utf-8'),
        }

        if webhook_target.secret:
            signer = hmac.new(webhook_target.secret.encode('utf-8'), body,
                              hashlib.sha1)
            headers[b'X-Hub-Signature'] = \
                ('sha1=%s' % signer.hexdigest()).encode('utf-8')

        logging.info('Dispatching webhook for event %s to %s', event,
                     webhook_target.url)
        try:
            url = webhook_target.url
            url_parts = urlsplit(url)

            if url_parts.username or url_parts.password:
                netloc = url_parts.netloc.split('@', 1)[1]
                url = urlunsplit((url_parts.scheme, netloc, url_parts.path,
                                  url_parts.params, url_parts.query))

                password_mgr = HTTPPasswordMgrWithDefaultRealm()
                password_mgr.add_password(None, url, url_parts.username,
                                          url_parts.password)
                handler = HTTPBasicAuthHandler(password_mgr)
                opener = build_opener(handler)
            else:
                opener = build_opener()

            opener.open(Request(url.encode('utf-8'), body, headers))
        except Exception as e:
            logging.exception('Could not dispatch WebHook to %s: %s',
                              webhook_target.url, e)