def _send_webhook(self):
     safe_urlread(
         safe_urlopen(
             url=self.sentry_app.webhook_url,
             data=self.request.body,
             headers=self.request.headers,
             timeout=5,
         ))
Esempio n. 2
0
 def _send_webhook(self):
     safe_urlread(
         safe_urlopen(
             url=self.sentry_app.webhook_url,
             data=self.request.body,
             headers=self.request.headers,
             timeout=5,
         )
     )
    def _make_request(self):
        try:
            req = send_and_save_sentry_app_request(
                self._build_url(),
                self.sentry_app,
                self.install.organization_id,
                "alert_rule_action.requested",
                headers=self._build_headers(),
                method=self.http_method,
                data=self.body,
            )
            body = safe_urlread(req)
            response = {
                "success": True,
                "message": "",
                "body": json.loads(body)
            }
        except Exception as e:
            logger.info(
                "alert_rule_action.error",
                extra={
                    "sentry_app_slug": self.sentry_app.slug,
                    "install_uuid": self.install.uuid,
                    "uri": self.uri,
                    "error_message": str(e),
                },
            )
            # Bubble up error message from Sentry App to the UI for the user.
            response = {
                "success": False,
                "message": str(e.response.text),
                "body": {}
            }

        return response
Esempio n. 4
0
    def exchange_token(self, request, pipeline, code):
        from urllib.parse import parse_qsl

        from sentry.http import safe_urlopen, safe_urlread
        from sentry.utils import json
        from sentry.utils.http import absolute_uri

        req = safe_urlopen(
            url=self.access_token_url,
            headers={
                "Content-Type": "application/x-www-form-urlencoded",
                "Content-Length": "1322"
            },
            data={
                "client_assertion_type":
                "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                "client_assertion": self.client_secret,
                "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
                "assertion": code,
                "redirect_uri": absolute_uri(pipeline.redirect_url()),
            },
        )
        body = safe_urlread(req)
        if req.headers["Content-Type"].startswith(
                "application/x-www-form-urlencoded"):
            return dict(parse_qsl(body))
        return json.loads(body)
Esempio n. 5
0
    def refresh_identity(self, identity, *args, **kwargs):
        refresh_token = identity.data.get('refresh_token')
        refresh_token_url = kwargs.get('refresh_token_url')

        if not refresh_token:
            raise IdentityNotValid('Missing refresh token')

        if not refresh_token_url:
            raise IdentityNotValid('Missing refresh token url')

        data = self.get_refresh_token_params(refresh_token, *args, **kwargs)

        req = safe_urlopen(
            url=refresh_token_url,
            headers={},
            data=data,
        )

        try:
            body = safe_urlread(req)
            payload = json.loads(body)
        except Exception:
            payload = {}

        self.handle_refresh_error(req, payload)

        identity.data.update(get_oauth_data(payload))
        return identity.update(data=identity.data)
Esempio n. 6
0
    def create_issue(self, request, group, form_data, **kwargs):
        json_data = {
            'story_type': 'bug',
            'name': force_text(form_data['title'], encoding='utf-8', errors='replace'),
            'description': force_text(form_data['description'], encoding='utf-8', errors='replace'),
            'labels': ['sentry'],
        }

        try:
            _url = self.build_api_url(group, 'stories')
            req = self.make_api_request(group.project, _url, json_data=json_data)
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = six.text_type(e)
            raise PluginError('Error communicating with Pivotal: %s' % (msg, ))

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = six.text_type(e)
            raise PluginError('Error communicating with Pivotal: %s' % (msg, ))

        if req.status_code > 399:
            raise PluginError(json_resp['error'])

        return json_resp['id']
Esempio n. 7
0
 def exchange_token(self, request, pipeline, code):
     # TODO: this needs the auth yet
     data = self.get_token_params(
         code=code,
         redirect_uri=absolute_uri(pipeline.redirect_url()),
     )
     verify_ssl = pipeline.config.get('verify_ssl', True)
     try:
         req = safe_urlopen(self.access_token_url, data=data, verify_ssl=verify_ssl)
         body = safe_urlread(req)
         if req.headers.get('Content-Type', '').startswith('application/x-www-form-urlencoded'):
             return dict(parse_qsl(body))
         return json.loads(body)
     except SSLError:
         logger.info('identity.oauth2.ssl-error', extra={
             'url': self.access_token_url,
             'verify_ssl': verify_ssl,
         })
         url = self.access_token_url
         return {
             'error': 'Could not verify SSL certificate',
             'error_description': u'Ensure that {} has a valid SSL certificate'.format(url)
         }
     except JSONDecodeError:
         logger.info('identity.oauth2.json-error', extra={
             'url': self.access_token_url,
         })
         return {
             'error': 'Could not decode a JSON Response',
             'error_description': u'We were not able to parse a JSON response, please try again.'
         }
Esempio n. 8
0
    def view_autocomplete(self, request, group, **kwargs):
        field = request.GET.get('autocomplete_field')
        query = request.GET.get('autocomplete_query')
        if field != 'issue_id' or not query:
            return Response({'issue_id': []})
        query = query.encode('utf-8')
        _url = '%s?%s' % (self.build_api_url(
            group, 'search'), urlencode({'query': query}))
        try:
            req = self.make_api_request(group.project, _url)
            body = safe_urlread(req)
        except (requests.RequestException, PluginError) as e:
            return self.handle_api_error(e)

        try:
            json_resp = json.loads(body)

        except ValueError as e:
            return self.handle_api_error(e)

        resp = json_resp.get('stories', {})
        stories = resp.get('stories', [])
        issues = [{
            'text': '(#%s) %s' % (i['id'], i['name']),
            'id': i['id']
        } for i in stories]

        return Response({field: issues})
Esempio n. 9
0
    def get_issue_title_by_id(self, request, group, issue_id):
        _url = "{}/{}".format(self.build_api_url(group, "stories"), issue_id)
        req = self.make_api_request(group.project, _url)

        body = safe_urlread(req)
        json_resp = json.loads(body)
        return json_resp["name"]
Esempio n. 10
0
    def exchange_token(self, request, helper, code):
        # TODO: this needs the auth yet
        data = self.get_token_params(code=code, redirect_uri=absolute_uri(helper.get_redirect_url()))
        req = safe_urlopen(self.access_token_url, data=data)
        body = safe_urlread(req)

        return json.loads(body)
Esempio n. 11
0
    def create_issue(self, request, group, form_data, **kwargs):
        json_data = {
            "story_type":
            "bug",
            "name":
            force_text(form_data["title"], encoding="utf-8", errors="replace"),
            "description":
            force_text(form_data["description"],
                       encoding="utf-8",
                       errors="replace"),
            "labels": ["sentry"],
        }

        try:
            _url = self.build_api_url(group, "stories")
            req = self.make_api_request(group.project,
                                        _url,
                                        json_data=json_data)
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = str(e)
            raise PluginError(f"Error communicating with Pivotal: {msg}")

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = str(e)
            raise PluginError(f"Error communicating with Pivotal: {msg}")

        if req.status_code > 399:
            raise PluginError(json_resp["error"])

        return json_resp["id"]
Esempio n. 12
0
 def exchange_token(self, request, pipeline, code):
     from sentry.http import safe_urlopen, safe_urlread
     from sentry.utils.http import absolute_uri
     from six.moves.urllib.parse import parse_qsl
     from sentry.utils import json
     req = safe_urlopen(
         url=self.access_token_url,
         headers={
             'Content-Type': 'application/x-www-form-urlencoded',
             'Content-Length': '1322',
         },
         data={
             'client_assertion_type':
             'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
             'client_assertion': self.client_secret,
             'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
             'assertion': code,
             'redirect_uri': absolute_uri(pipeline.redirect_url()),
         },
     )
     body = safe_urlread(req)
     if req.headers['Content-Type'].startswith(
             'application/x-www-form-urlencoded'):
         return dict(parse_qsl(body))
     return json.loads(body)
Esempio n. 13
0
    def _make_request(self):
        req = safe_urlopen(url=self._build_url(),
                           headers=self._build_headers(),
                           method="POST",
                           data=self.body)

        try:
            body = safe_urlread(req)
            response = json.loads(body)
        except Exception:
            logger.info(
                "issue-link-requester.error",
                extra={
                    "sentry_app": self.sentry_app.slug,
                    "install": self.install.uuid,
                    "project": self.group.project.slug,
                    "group": self.group.id,
                    "uri": self.uri,
                },
            )
            response = {}

        if not self._validate_response(response):
            raise APIError()

        return response
Esempio n. 14
0
    def dispatch(self, request, helper):
        access_token = helper.fetch_state('data')['access_token']

        req = safe_urlopen('{0}?{1}&alt=json'.format(
            USER_DETAILS_ENDPOINT, urlencode({
                'access_token': access_token,
            })))
        body = safe_urlread(req)
        data = json.loads(body)

        if not data.get('data'):
            logger.error('Invalid response: %s' % body)
            return helper.error(ERR_INVALID_RESPONSE)

        if not data.get('data').get('email'):
            logger.error('Invalid response: %s' % body)
            return helper.error(ERR_INVALID_RESPONSE)

        domain = extract_domain(data.get('data').get('email'))

        if domain in DOMAIN_BLOCKLIST:
            return helper.error(ERR_INVALID_DOMAIN % (domain, ))

        if self.domain and self.domain != domain:
            return helper.error(ERR_INVALID_DOMAIN % (domain, ))

        helper.bind_state('domain', domain)
        helper.bind_state('user', data.get('data'))

        return helper.next_step()
Esempio n. 15
0
    def _make_request(self):
        try:
            req = send_and_save_sentry_app_request(
                self._build_url(),
                self.sentry_app,
                self.install.organization_id,
                "alert_rule_action.requested",
                headers=self._build_headers(),
                method=self.http_method,
                data=self.body,
            )
            body = safe_urlread(req)
            response = json.loads(body)
        except Exception as e:
            logger.info(
                "alert_rule_action.error",
                extra={
                    "sentry_app_slug": self.sentry_app.slug,
                    "install_uuid": self.install.uuid,
                    "uri": self.uri,
                    "error_message": str(e),
                },
            )
            response = {}

        return response
Esempio n. 16
0
    def refresh_identity(self, identity, *args, **kwargs):
        refresh_token = identity.data.get('refresh_token')
        refresh_token_url = kwargs.get('refresh_token_url')

        if not refresh_token:
            raise IdentityNotValid('Missing refresh token')

        if not refresh_token_url:
            raise IdentityNotValid('Missing refresh token url')

        data = self.get_refresh_token_params(refresh_token, *args, **kwargs)

        req = safe_urlopen(
            url=refresh_token_url,
            headers={},
            data=data,
        )

        try:
            body = safe_urlread(req)
            payload = json.loads(body)
        except Exception as e:
            self.logger('gitlab.refresh-identity-failure',
                        extra={
                            'identity_id': identity.id,
                            'error_status': e.code,
                            'error_message': e.message,
                        })
            payload = {}

        self.handle_refresh_error(req, payload)

        identity.data.update(get_oauth_data(payload))
        return identity.update(data=identity.data)
Esempio n. 17
0
    def refresh_identity(self, auth_identity):
        refresh_token = auth_identity.data.get("refresh_token")

        if not refresh_token:
            raise IdentityNotValid("Missing refresh token")

        data = self.get_refresh_token_params(refresh_token=refresh_token)
        req = safe_urlopen(self.get_refresh_token_url(), data=data)

        try:
            body = safe_urlread(req)
            payload = json.loads(body)
        except Exception:
            payload = {}

        error = payload.get("error", "unknown_error")
        error_description = payload.get("error_description", "no description available")

        formatted_error = "HTTP {} ({}): {}".format(req.status_code, error, error_description)

        if req.status_code == 401:
            raise IdentityNotValid(formatted_error)

        if req.status_code == 400:
            # this may not be common, but at the very least Google will return
            # an invalid grant when a user is suspended
            if error == "invalid_grant":
                raise IdentityNotValid(formatted_error)

        if req.status_code != 200:
            raise Exception(formatted_error)

        auth_identity.data.update(self.get_oauth_data(payload))
        auth_identity.update(data=auth_identity.data)
Esempio n. 18
0
    def _make_request(self):
        try:
            body = safe_urlread(
                safe_urlopen(
                    url=self._build_url(),
                    headers=self._build_headers(),
                )
            )

            response = json.loads(body)
        except Exception as e:
            logger.info(
                'select-requester.error',
                extra={
                    'sentry_app': self.sentry_app.slug,
                    'install': self.install.uuid,
                    'project': self.project and self.project.slug,
                    'uri': self.uri,
                    'error_message': e.message,
                }
            )
            response = {}

        if not self._validate_response(response):
            raise APIError()

        return self._format_response(response)
Esempio n. 19
0
    def refresh_identity(self, identity, *args, **kwargs):
        refresh_token = identity.data.get("refresh_token")
        refresh_token_url = kwargs.get("refresh_token_url")

        if not refresh_token:
            raise IdentityNotValid("Missing refresh token")

        if not refresh_token_url:
            raise IdentityNotValid("Missing refresh token url")

        data = self.get_refresh_token_params(refresh_token, *args, **kwargs)

        req = safe_urlopen(url=refresh_token_url, headers={}, data=data)

        try:
            body = safe_urlread(req)
            payload = json.loads(body)
        except Exception as e:
            self.logger(
                "gitlab.refresh-identity-failure",
                extra={
                    "identity_id": identity.id,
                    "error_status": e.code,
                    "error_message": str(e),
                },
            )
            payload = {}

        self.handle_refresh_error(req, payload)

        identity.data.update(get_oauth_data(payload))
        return identity.update(data=identity.data)
Esempio n. 20
0
    def view(self, request, group, **kwargs):
        if request.GET.get('autocomplete_query'):
            query = request.GET.get('q')
            if not query:
                return JSONResponse({'issues': []})
            repo = self.get_option('repo', group.project)
            query = 'repo:%s %s' % (repo, query)
            url = 'https://api.github.com/search/issues?%s' % (urlencode({'q': query}),)

            try:
                req = self.make_api_request(request.user, url)
                body = safe_urlread(req)
            except requests.RequestException as e:
                msg = unicode(e)
                self.handle_api_error(request, msg)
                return JSONResponse({}, status=502)

            try:
                json_resp = json.loads(body)
            except ValueError as e:
                msg = unicode(e)
                self.handle_api_error(request, msg)
                return JSONResponse({}, status=502)

            issues = [{
                'text': '(#%s) %s' % (i['number'], i['title']),
                'id': i['number']
            } for i in json_resp.get('items', [])]
            return JSONResponse({'issues': issues})

        return super(GitHubPlugin, self).view(request, group, **kwargs)
Esempio n. 21
0
    def _make_request(self):
        req = safe_urlopen(
            url=self._build_url(),
            headers=self._build_headers(),
            method='POST',
            data=self.body,
        )

        try:
            body = safe_urlread(req)
            response = json.loads(body)
        except Exception:
            logger.info('issue-link-requester.error',
                        extra={
                            'sentry_app': self.sentry_app.slug,
                            'install': self.install.uuid,
                            'project': self.group.project.slug,
                            'group': self.group.id,
                            'uri': self.uri,
                        })
            response = {}

        if not self._validate_response(response):
            raise APIError()

        return response
Esempio n. 22
0
    def get_issue_title_by_id(self, request, group, issue_id):
        url = '%s/%s' % (self.build_api_url(group, 'issues'), issue_id)
        req = self.make_api_request(request.user, url)

        body = safe_urlread(req)
        json_resp = json.loads(body)
        return json_resp['title']
Esempio n. 23
0
    def create_issue(self, request, group, form_data, **kwargs):
        # TODO: support multiple identities via a selection input in the form?
        json_data = {
            "title": form_data['title'],
            "body": form_data['description'],
            "assignee": form_data.get('assignee'),
        }

        try:
            url = self.build_api_url(group, 'issues')
            req = self.make_api_request(request.user, url, json_data=json_data)
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = unicode(e)
            raise forms.ValidationError(_('Error communicating with GitHub: %s') % (msg,))

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = unicode(e)
            raise forms.ValidationError(_('Error communicating with GitHub: %s') % (msg,))

        if req.status_code > 399:
            raise forms.ValidationError(json_resp['message'])

        return json_resp['number']
Esempio n. 24
0
    def _make_request(self) -> Mapping[str, Union[bool, str]]:

        try:
            req = send_and_save_sentry_app_request(
                self._build_url(),
                self.sentry_app,
                self.install.organization_id,
                "alert_rule_action.requested",
                headers=self._build_headers(),
                method=self.http_method,
                data=self.body,
            )
        except Exception as e:
            logger.info(
                "alert_rule_action.error",
                extra={
                    "sentry_app_slug": self.sentry_app.slug,
                    "install_uuid": self.install.uuid,
                    "uri": self.uri,
                    "error_message": str(e),
                },
            )
            message = f"{self.sentry_app.name}: {str(e.response.text) or DEFAULT_ERROR_MESSAGE}"
            # Bubble up error message from Sentry App to the UI for the user.
            return {"success": False, "message": message}

        body_raw = safe_urlread(req)
        body = body_raw.decode() if body_raw else None
        message = f"{self.sentry_app.name}: {body or DEFAULT_SUCCESS_MESSAGE}"
        return {"success": True, "message": message}
Esempio n. 25
0
    def view_autocomplete(self, request, group, **kwargs):
        field = request.GET.get("autocomplete_field")
        query = request.GET.get("autocomplete_query")
        if field != "issue_id" or not query:
            return Response({"issue_id": []})
        query = query.encode("utf-8")
        _url = "{}?{}".format(self.build_api_url(group, "search"),
                              urlencode({"query": query}))
        try:
            req = self.make_api_request(group.project, _url)
            body = safe_urlread(req)
        except (requests.RequestException, PluginError) as e:
            return self.handle_api_error(e)

        try:
            json_resp = json.loads(body)

        except ValueError as e:
            return self.handle_api_error(e)

        resp = json_resp.get("stories", {})
        stories = resp.get("stories", [])
        issues = [{
            "text": "(#{}) {}".format(i["id"], i["name"]),
            "id": i["id"]
        } for i in stories]

        return Response({field: issues})
Esempio n. 26
0
    def _make_request(self):
        action_to_past_tense = {"create": "created", "link": "linked"}

        try:
            req = send_and_save_sentry_app_request(
                self._build_url(),
                self.sentry_app,
                self.install.organization_id,
                "external_issue.{}".format(action_to_past_tense[self.action]),
                headers=self._build_headers(),
                method="POST",
                data=self.body,
            )
            body = safe_urlread(req)
            response = json.loads(body)
        except Exception as e:
            logger.info(
                "issue-link-requester.error",
                extra={
                    "sentry_app": self.sentry_app.slug,
                    "install": self.install.uuid,
                    "project": self.group.project.slug,
                    "group": self.group.id,
                    "uri": self.uri,
                    "error_message": str(e),
                },
            )
            response = {}

        if not self._validate_response(response):
            raise APIError()

        return response
Esempio n. 27
0
    def get_issue_title_by_id(self, request, group, issue_id):
        _url = '%s/%s' % (self.build_api_url(group, 'stories'), issue_id)
        req = self.make_api_request(group.project, _url)

        body = safe_urlread(req)
        json_resp = json.loads(body)
        return json_resp['name']
Esempio n. 28
0
    def get_issue_title_by_id(self, request, group, issue_id):
        _url = '%s/%s' % (self.build_api_url(group, 'stories'), issue_id)
        req = self.make_api_request(group.project, _url)

        body = safe_urlread(req)
        json_resp = json.loads(body)
        return json_resp['name']
Esempio n. 29
0
    def github_request(self, request, url, **kwargs):
        """
        Make a GitHub request on behalf of the logged in user. Return JSON
        response on success or raise forms.ValidationError on any exception
        """
        auth = self.get_auth_for_user(user=request.user)
        if auth is None:
            raise forms.ValidationError(_("You have not yet associated GitHub with your account."))

        headers = kwargs.pop("headers", None) or {}
        headers["Authorization"] = "token %s" % auth.tokens["access_token"]
        try:
            req = safe_urlopen(url, headers=headers, **kwargs)
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = unicode(e)
            raise forms.ValidationError(_("Error communicating with GitHub: %s") % (msg,))

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = unicode(e)
            raise forms.ValidationError(_("Error communicating with GitHub: %s") % (msg,))

        if req.status_code > 399:
            raise forms.ValidationError(json_resp["message"])

        return json_resp
Esempio n. 30
0
 def exchange_token(self, request, pipeline, code):
     # TODO: this needs the auth yet
     data = self.get_token_params(code=code, redirect_uri=absolute_uri(pipeline.redirect_url()))
     verify_ssl = pipeline.config.get("verify_ssl", True)
     try:
         req = safe_urlopen(self.access_token_url, data=data, verify_ssl=verify_ssl)
         body = safe_urlread(req)
         if req.headers.get("Content-Type", "").startswith("application/x-www-form-urlencoded"):
             return dict(parse_qsl(body))
         return json.loads(body)
     except SSLError:
         logger.info(
             "identity.oauth2.ssl-error",
             extra={"url": self.access_token_url, "verify_ssl": verify_ssl},
         )
         url = self.access_token_url
         return {
             "error": "Could not verify SSL certificate",
             "error_description": u"Ensure that {} has a valid SSL certificate".format(url),
         }
     except JSONDecodeError:
         logger.info("identity.oauth2.json-error", extra={"url": self.access_token_url})
         return {
             "error": "Could not decode a JSON Response",
             "error_description": u"We were not able to parse a JSON response, please try again.",
         }
Esempio n. 31
0
    def create_issue(self, request, group, form_data, **kwargs):
        json_data = {
            'story_type':
            'bug',
            'name':
            force_text(form_data['title'], encoding='utf-8', errors='replace'),
            'description':
            force_text(form_data['description'],
                       encoding='utf-8',
                       errors='replace'),
            'labels': ['sentry'],
        }

        try:
            _url = self.build_api_url(group, 'stories')
            req = self.make_api_request(group.project,
                                        _url,
                                        json_data=json_data)
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = six.text_type(e)
            raise PluginError('Error communicating with Pivotal: %s' % (msg, ))

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = six.text_type(e)
            raise PluginError('Error communicating with Pivotal: %s' % (msg, ))

        if req.status_code > 399:
            raise PluginError(json_resp['error'])

        return json_resp['id']
Esempio n. 32
0
 def exchange_token(self, request, pipeline, code):
     # TODO: this needs the auth yet
     data = self.get_token_params(
         code=code,
         redirect_uri=absolute_uri(pipeline.redirect_url()),
     )
     verify_ssl = pipeline.config.get('verify_ssl', True)
     try:
         req = safe_urlopen(self.access_token_url, data=data, verify_ssl=verify_ssl)
         body = safe_urlread(req)
         if req.headers.get('Content-Type', '').startswith('application/x-www-form-urlencoded'):
             return dict(parse_qsl(body))
         return json.loads(body)
     except SSLError:
         logger.info('identity.oauth2.ssl-error', extra={
             'url': self.access_token_url,
             'verify_ssl': verify_ssl,
         })
         url = self.access_token_url
         return {
             'error': 'Could not verify SSL certificate',
             'error_description': u'Ensure that {} has a valid SSL certificate'.format(url)
         }
     except JSONDecodeError:
         logger.info('identity.oauth2.json-error', extra={
             'url': self.access_token_url,
         })
         return {
             'error': 'Could not decode a JSON Response',
             'error_description': u'We were not able to parse a JSON response, please try again.'
         }
Esempio n. 33
0
    def _make_request(self):
        try:
            body = safe_urlread(
                send_and_save_sentry_app_request(
                    self._build_url(),
                    self.sentry_app,
                    self.install.organization_id,
                    "select_options.requested",
                    headers=self._build_headers(),
                ))

            response = json.loads(body)
        except Exception as e:
            logger.info(
                "select-requester.error",
                extra={
                    "sentry_app": self.sentry_app.slug,
                    "install": self.install.uuid,
                    "project": self.project and self.project.slug,
                    "uri": self.uri,
                    "error_message": six.text_type(e),
                },
            )
            response = {}

        if not self._validate_response(response):
            raise APIError()

        return self._format_response(response)
Esempio n. 34
0
    def refresh_identity(self, auth_identity):
        refresh_token = auth_identity.data.get("refresh_token")

        if not refresh_token:
            raise IdentityNotValid("Missing refresh token")

        data = self.get_refresh_token_params(refresh_token=refresh_token)
        req = safe_urlopen(self.get_refresh_token_url(), data=data)

        try:
            body = safe_urlread(req)
            payload = json.loads(body)
        except Exception:
            payload = {}

        error = payload.get("error", "unknown_error")
        error_description = payload.get("error_description", "no description available")

        formatted_error = f"HTTP {req.status_code} ({error}): {error_description}"

        if req.status_code == 401:
            raise IdentityNotValid(formatted_error)

        if req.status_code == 400:
            # this may not be common, but at the very least Google will return
            # an invalid grant when a user is suspended
            if error == "invalid_grant":
                raise IdentityNotValid(formatted_error)

        if req.status_code != 200:
            raise Exception(formatted_error)

        auth_identity.data.update(self.get_oauth_data(payload))
        auth_identity.update(data=auth_identity.data)
Esempio n. 35
0
    def _make_request(self):
        req = safe_urlopen(
            url=self._build_url(),
            headers=self._build_headers(),
            method='POST',
            data=self.body,
        )

        try:
            body = safe_urlread(req)
            response = json.loads(body)
        except Exception:
            logger.info(
                'issue-link-requester.error',
                extra={
                    'sentry_app': self.sentry_app.slug,
                    'install': self.install.uuid,
                    'project': self.group.project.slug,
                    'group': self.group.id,
                    'uri': self.uri,
                }
            )
            response = {}

        if not self._validate_response(response):
            raise APIError()

        return response
Esempio n. 36
0
    def _make_request(self):
        req = safe_urlopen(
            url=self._build_url(),
            headers=self._build_headers(),
        )

        try:
            body = safe_urlread(req)
            response = json.loads(body)
        except Exception:
            logger.info(
                'select-requester.error',
                extra={
                    'sentry_app': self.sentry_app.slug,
                    'install': self.install.uuid,
                    'project': self.project.slug,
                    'uri': self.uri,
                }
            )
            response = {}

        if not self._validate_response(response):
            raise APIError()

        return self._format_response(response)
Esempio n. 37
0
    def dispatch(self, request, helper):
        access_token = helper.fetch_state('data')['access_token']

        req = safe_urlopen('{0}?{1}&alt=json'.format(
            USER_DETAILS_ENDPOINT,
            urlencode({
                'access_token': access_token,
            })
        ))
        body = safe_urlread(req)
        data = json.loads(body)

        if not data.get('data'):
            logger.error('Invalid response: %s' % body)
            return helper.error(ERR_INVALID_RESPONSE)

        if not data.get('data').get('email'):
            logger.error('Invalid response: %s' % body)
            return helper.error(ERR_INVALID_RESPONSE)

        domain = extract_domain(data.get('data').get('email'))

        if domain in DOMAIN_BLOCKLIST:
            return helper.error(ERR_INVALID_DOMAIN % (domain,))

        if self.domain and self.domain != domain:
            return helper.error(ERR_INVALID_DOMAIN % (domain,))

        helper.bind_state('domain', domain)
        helper.bind_state('user', data.get('data'))

        return helper.next_step()
Esempio n. 38
0
 def exchange_token(self, request, helper, code):
     # TODO: this needs the auth yet
     data = self.get_token_params(code=code, redirect_uri=absolute_uri(helper.get_redirect_url()))
     req = safe_urlopen(self.access_token_url, data=data)
     body = safe_urlread(req)
     if req.headers["Content-Type"].startswith("application/x-www-form-urlencoded"):
         return dict(parse_qsl(body))
     return json.loads(body)
Esempio n. 39
0
 def exchange_token(self, request, helper, code):
     # TODO: this needs the auth yet
     data = self.get_token_params(code=code, redirect_uri=helper.get_redirect_url())
     req = safe_urlopen(self.access_token_url, data=data)
     body = safe_urlread(req)
     if req.headers["Content-Type"].startswith("application/x-www-form-urlencoded"):
         return dict(parse_qsl(body))
     return json.loads(body)
Esempio n. 40
0
    def exchange_token(self, request, helper, code):
        # TODO: this needs the auth yet
        data = self.get_token_params(
            code=code,
            redirect_uri=absolute_uri(helper.get_redirect_url()),
        )
        req = safe_urlopen(self.access_token_url, data=data)
        body = safe_urlread(req)

        return json.loads(body)
Esempio n. 41
0
    def test_simple(self):
        responses.add(responses.GET, 'http://example.com', body='foo bar')

        resp = safe_urlopen('http://example.com')
        data = safe_urlread(resp)
        assert data == 'foo bar'

        request = responses.calls[0].request
        assert 'User-Agent' in request.headers
        assert 'gzip' in request.headers.get('Accept-Encoding', '')
Esempio n. 42
0
    def test_simple(self, mock_getaddrinfo):
        mock_getaddrinfo.return_value = [(2, 1, 6, '', ('81.0.0.1', 0))]
        responses.add(responses.GET, 'http://example.com', body='foo bar')

        resp = http.safe_urlopen('http://example.com')
        data = http.safe_urlread(resp)
        assert data.decode('utf-8') == 'foo bar'

        request = responses.calls[0].request
        assert 'User-Agent' in request.headers
        assert 'gzip' in request.headers.get('Accept-Encoding', '')
Esempio n. 43
0
def fetch_url(url, project=None):
    """
    Pull down a URL, returning a UrlResult object.

    Attempts to fetch from the cache.
    """

    cache_key = 'source:%s' % (
        hashlib.md5(url.encode('utf-8')).hexdigest(),)
    result = cache.get(cache_key)
    if result is None:
        # lock down domains that are problematic
        domain = urlparse(url).netloc
        domain_key = 'source:%s' % (hashlib.md5(domain.encode('utf-8')).hexdigest(),)
        domain_result = cache.get(domain_key)
        if domain_result:
            return BAD_SOURCE

        headers = []
        if project and is_valid_origin(url, project=project):
            token = project.get_option('sentry:token')
            if token:
                headers.append(('X-Sentry-Token', token))

        try:
            request = safe_urlopen(
                url,
                allow_redirects=True,
                headers=headers,
                timeout=settings.SENTRY_SOURCE_FETCH_TIMEOUT,
            )
        except HTTPError:
            result = BAD_SOURCE
        except Exception:
            # it's likely we've failed due to a timeout, dns, etc so let's
            # ensure we can't cascade the failure by pinning this for 5 minutes
            cache.set(domain_key, 1, 300)
            logger.warning('Disabling sources to %s for %ss', domain, 300,
                           exc_info=True)
            return BAD_SOURCE
        else:
            try:
                body = safe_urlread(request)
            except Exception:
                result = BAD_SOURCE
            else:
                result = (dict(request.headers), body)

        cache.set(cache_key, result, 60)

    if result == BAD_SOURCE:
        return result

    return UrlResult(url, *result)
Esempio n. 44
0
    def test_simple(self, mock_gethostbyname):
        mock_gethostbyname.return_value = '81.0.0.1'
        responses.add(responses.GET, 'http://example.com', body='foo bar')

        resp = http.safe_urlopen('http://example.com')
        data = http.safe_urlread(resp)
        assert data == 'foo bar'

        request = responses.calls[0].request
        assert 'User-Agent' in request.headers
        assert 'gzip' in request.headers.get('Accept-Encoding', '')
Esempio n. 45
0
 def exchange_token(self, request, pipeline, code):
     # TODO: this needs the auth yet
     data = self.get_token_params(
         code=code,
         redirect_uri=absolute_uri(pipeline.redirect_url()),
     )
     verify_ssl = pipeline.config.get('verify_ssl', True)
     req = safe_urlopen(self.access_token_url, data=data, verify_ssl=verify_ssl)
     body = safe_urlread(req)
     if req.headers['Content-Type'].startswith('application/x-www-form-urlencoded'):
         return dict(parse_qsl(body))
     return json.loads(body)
Esempio n. 46
0
def send_beacon():
    """
    Send a Beacon to a remote server operated by the Sentry team.

    See the documentation for more details.
    """
    from sentry import options
    from sentry.models import Organization, Project, Team, User

    if not settings.SENTRY_BEACON:
        logger.info('Not sending beacon (disabled)')
        return

    # TODO(dcramer): move version code off of PyPi and into beacon
    install_id = options.get('sentry:install-id')
    if not install_id:
        logger.info('Generated installation ID: %s', install_id)
        install_id = sha1(uuid4().hex).hexdigest()
        options.set('sentry:install-id', install_id)

    internal_project_ids = filter(bool, [
        settings.SENTRY_PROJECT, settings.SENTRY_FRONTEND_PROJECT,
    ])
    platform_list = list(set(Project.objects.exclude(
        id__in=internal_project_ids,
    ).values_list('platform', flat=True)))

    payload = {
        'install_id': install_id,
        'version': sentry.get_version(),
        'admin_email': settings.SENTRY_ADMIN_EMAIL,
        'data': {
            # TODO(dcramer): we'd also like to get an idea about the throughput
            # of the system (i.e. events in 24h)
            'platforms': platform_list,
            'users': User.objects.count(),
            'projects': Project.objects.count(),
            'teams': Team.objects.count(),
            'organizations': Organization.objects.count(),
        }
    }

    # TODO(dcramer): relay the response 'notices' as admin broadcasts
    try:
        request = safe_urlopen(BEACON_URL, json=payload, timeout=5)
        response = safe_urlread(request)
    except Exception:
        logger.warning('Failed sending beacon', exc_info=True)
        return

    data = json.loads(response)
    if 'version' in data:
        options.set('sentry:latest_version', data['version']['stable'])
Esempio n. 47
0
def send_beacon():
    """
    Send a Beacon to a remote server operated by the Sentry team.

    See the documentation for more details.
    """
    from sentry import options
    from sentry.models import Organization, Project, Team, User

    if not settings.SENTRY_BEACON:
        logger.info('Not sending beacon (disabled)')
        return

    install_id = options.get('sentry:install-id')
    if not install_id:
        logger.info('Generated installation ID: %s', install_id)
        install_id = sha1(uuid4().hex).hexdigest()
        options.set('sentry:install-id', install_id)

    end = timezone.now()
    events_24h = tsdb.get_sums(
        model=tsdb.models.internal,
        keys=['events.total'],
        start=end - timedelta(hours=24),
        end=end,
    )['events.total']

    payload = {
        'install_id': install_id,
        'version': sentry.get_version(),
        'admin_email': settings.SENTRY_ADMIN_EMAIL,
        'data': {
            # TODO(dcramer): we'd also like to get an idea about the throughput
            # of the system (i.e. events in 24h)
            'users': User.objects.count(),
            'projects': Project.objects.count(),
            'teams': Team.objects.count(),
            'organizations': Organization.objects.count(),
            'events.24h': events_24h,
        }
    }

    # TODO(dcramer): relay the response 'notices' as admin broadcasts
    try:
        request = safe_urlopen(BEACON_URL, json=payload, timeout=5)
        response = safe_urlread(request)
    except Exception:
        logger.warning('Failed sending beacon', exc_info=True)
        return

    data = json.loads(response)
    if 'version' in data:
        options.set('sentry:latest_version', data['version']['stable'])
Esempio n. 48
0
    def test_simple(self, mock_gethostbyname):
        responses.add(responses.GET, 'http://example.com', body='foo bar')

        # this test fails if you dont have working DNS as it resolves it to
        # localhost, so we patch gethostbyname
        mock_gethostbyname.return_value = '208.1.41.1'

        resp = safe_urlopen('http://example.com')
        data = safe_urlread(resp)
        assert data == 'foo bar'

        request = responses.calls[0].request
        assert 'User-Agent' in request.headers
        assert 'gzip' in request.headers.get('Accept-Encoding', '')
Esempio n. 49
0
    def dispatch(self, request, helper):
        access_token = helper.fetch_state('data')['access_token']

        req = safe_urlopen('{0}?{1}'.format(
            USER_DETAILS_ENDPOINT,
            urlencode({
                'access_token': access_token,
            }),
        ))
        body = safe_urlread(req)
        data = json.loads(body)

        helper.bind_state('user', data)

        return helper.next_step()
Esempio n. 50
0
    def create_issue(self, request, group, form_data, **kwargs):
        # TODO: support multiple identities via a selection input in the form?
        auth = self.get_auth_for_user(user=request.user)
        if auth is None:
            raise forms.ValidationError(_('You have not yet associated GitHub with your account.'))

        repo = self.get_option('repo', group.project)
        endpoint = self.get_option('endpoint', group.project) or 'https://api.github.com'

        url = '%s/repos/%s/issues' % (endpoint, repo,)

        json_data = {
            "title": form_data['title'],
            "body": form_data['description'],
            # "assignee": form_data['asignee'],
            # "milestone": 1,
            # "labels": [
            #   "Label1",
            #   "Label2"
            # ]
        }

        req_headers = {
            'Authorization': 'token %s' % auth.tokens['access_token'],
        }
        try:
            req = safe_urlopen(url, json=json_data, headers=req_headers)
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = unicode(e)
            raise forms.ValidationError(_('Error communicating with GitHub: %s') % (msg,))

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = unicode(e)
            raise forms.ValidationError(_('Error communicating with GitHub: %s') % (msg,))

        if req.status_code > 399:
            raise forms.ValidationError(json_resp['message'])

        return json_resp['number']
Esempio n. 51
0
def check_update():
    """
    Daily retrieving latest available Sentry version from PyPI
    """
    from sentry.receivers import set_sentry_version

    try:
        request = safe_urlopen(PYPI_URL)
        result = safe_urlread(request)
    except Exception:
        logger.warning('Failed update info of latest version Sentry', exc_info=True)
        return

    try:
        version = json.loads(result)['info']['version']
        set_sentry_version(version)
    except JSONDecodeError:
        logger.warning('Failed parsing data json from PYPI')
    except Exception:
        logger.warning('Failed update info of latest version Sentry', exc_info=True)
Esempio n. 52
0
    def link_issue(self, request, group, form_data, **kwargs):
        comment = form_data.get('comment')
        if not comment:
            return
        url = '%s/%s/comments' % (self.build_api_url(group, 'issues'), form_data['issue_id'])
        try:
            req = self.make_api_request(request.user, url, json_data={'body': comment})
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = unicode(e)
            raise forms.ValidationError(_('Error communicating with GitHub: %s') % (msg,))

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = unicode(e)
            raise forms.ValidationError(_('Error communicating with GitHub: %s') % (msg,))

        if req.status_code > 399:
            raise forms.ValidationError(json_resp['message'])
Esempio n. 53
0
    def link_issue(self, request, group, form_data, **kwargs):
        comment = form_data.get('comment')
        if not comment:
            return
        _url = '%s/%s/comments' % (self.build_api_url(group, 'stories'), form_data['issue_id'])
        try:
            req = self.make_api_request(group.project, _url, json_data={"text": comment})
            body = safe_urlread(req)
        except requests.RequestException as e:
            msg = six.text_type(e)
            raise PluginError('Error communicating with Pivotal: %s' % (msg, ))

        try:
            json_resp = json.loads(body)
        except ValueError as e:
            msg = six.text_type(e)
            raise PluginError('Error communicating with Pivotal: %s' % (msg, ))

        if req.status_code > 399:
            raise PluginError(json_resp['error'])
Esempio n. 54
0
    def dispatch(self, request, helper):
        access_token = helper.fetch_state('data')['access_token']

        req = safe_urlopen('{0}?{1}'.format(
            USER_DETAILS_ENDPOINT,
            urlencode({
                'access_token': access_token,
            }),
        ))
        body = safe_urlread(req)
        data = json.loads(body)

        if not data.get('domain'):
            return helper.error(ERR_INVALID_DOMAIN)

        # a domain may not yet be configured as this could be the setup flow
        if self.domain and self.domain != data['domain']:
            return helper.error(ERR_INVALID_DOMAIN)

        helper.bind_state('user', data)

        return helper.next_step()
Esempio n. 55
0
 def exchange_token(self, request, pipeline, code):
     from sentry.http import safe_urlopen, safe_urlread
     from sentry.utils.http import absolute_uri
     from six.moves.urllib.parse import parse_qsl
     from sentry.utils import json
     req = safe_urlopen(
         url=self.access_token_url,
         headers={
             'Content-Type': 'application/x-www-form-urlencoded',
             'Content-Length': '1322',
         },
         data={
             'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
             'client_assertion': self.client_secret,
             'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
             'assertion': code,
             'redirect_uri': absolute_uri(pipeline.redirect_url()),
         },
     )
     body = safe_urlread(req)
     if req.headers['Content-Type'].startswith('application/x-www-form-urlencoded'):
         return dict(parse_qsl(body))
     return json.loads(body)
Esempio n. 56
0
    def refresh_identity(self, identity, *args, **kwargs):
        refresh_token = identity.data.get('refresh_token')

        if not refresh_token:
            raise IdentityNotValid('Missing refresh token')

        data = self.get_refresh_token_params(refresh_token, *args, **kwargs)

        req = safe_urlopen(
            url=self.get_refresh_token_url(),
            headers=self.get_refresh_token_headers(),
            data=data,
        )

        try:
            body = safe_urlread(req)
            payload = json.loads(body)
        except Exception:
            payload = {}

        self.handle_refresh_error(req, payload)

        identity.data.update(self.get_oauth_data(payload))
        return identity.update(data=identity.data)