Пример #1
0
    def get_secrets(self, user: User) -> Dict:
        """
        Get Google OAuth2 credentials.

        Will use the creators token associated with the `SocialApp` that the source
        was originally linked with.

        Falls back to the source's creator if available, falling back to those of
        the request's user. Note that in these two cases the user may not have
        permissions to access resource.
        """
        token = None

        if getattr(self, "creator", None) and getattr(self, "social_app",
                                                      None):
            app = self.social_app
            token = get_user_social_token(self.creator, Provider.from_app(app))

        if getattr(self, "creator", None):
            token, app = get_user_google_token(self.creator)

        if token is None and user and user.is_authenticated:
            token, app = get_user_google_token(user)

        return dict(
            access_token=token.token if token else None,
            refresh_token=token.token_secret if token else None,
            client_id=app.client_id if app else None,
            client_secret=app.secret if app else None,
        )
Пример #2
0
    def get_secrets(self, user: User) -> Dict:
        """
        Get GitHub API token.

        Will use the token of the source's creator if available, falling back
        to request user's token.
        """
        token = None

        if self.creator:
            token = get_user_social_token(self.creator, Provider.github)

        if token is None and user and user.is_authenticated:
            token = get_user_social_token(user, Provider.github)

        return dict(token=token.token if token else None)
Пример #3
0
    def refresh_for_user(user: User, token: Optional[SocialToken] = None):
        """
        Refresh the list of repos for the user.
        """
        # Get a token for the user
        if not token:
            token = get_user_social_token(user, Provider.github)
            if not token:
                return

        # Get all the repositories the user has explicit permission to access
        # See https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#list-repositories-for-the-authenticated-user   # noqa
        #   "The authenticated user has explicit permission to access repositories
        #   they own, repositories where they are a collaborator, and repositories
        #   that they can access through an organization membership."
        try:
            repos = list(Github(token.token).get_user().get_repos())
        except github.BadCredentialsException:
            logger.warning("Bad GitHub credentials for user",
                           extra={"username": user.username})
            return

        # Remove all repos for the user so we can do `bulk_create`
        GithubRepo.objects.filter(user=user).delete()

        # Bulk create repos for the user
        # Previously we used `update_or_create` for this, but `bulk_create`
        # is much faster, particularly when a user has lots of repos.
        GithubRepo.objects.bulk_create([
            GithubRepo(
                user=user,
                full_name=repo.full_name,
                image_url=repo.owner.avatar_url,
                permissions=dict(
                    admin=repo.permissions.admin,
                    pull=repo.permissions.pull,
                    push=repo.permissions.push,
                ),
                updated=timezone.make_aware(repo.updated_at,
                                            timezone=timezone.utc),
            ) for repo in repos
        ])
Пример #4
0
    def test_an_existing_refresh_token(self):
        """
        A user that has an existing refresh token.
        """
        app, created = SocialApp.objects.get_or_create(
            provider=Provider.twitter.name)
        account, created = SocialAccount.objects.get_or_create(
            user=self.bob, provider=Provider.twitter.name)
        SocialToken.objects.create(
            account=account,
            app=app,
            token="existing-access-token",
            token_secret="existing-refresh-token",
        )

        refresh_user_access_token(self.bob, "Twitter", "new-access-token")

        token = get_user_social_token(self.bob, Provider.twitter)
        assert token.token == "new-access-token"
        assert token.token_secret == "existing-refresh-token"
Пример #5
0
    def unwatch(self, user: User):
        """
        Unwatch this source by deleting it's GitHub repository Webhook.

        Instead of deleting the Webhook we could set it to inactive. But that would
        result in multiple hooks if a user toggle's whether a `GithubSource` is watched or not.
        """
        token = get_user_social_token(user, Provider.github)
        if not token:
            raise exceptions.SocialTokenMissing(
                "To unwatch a GitHub source you must be a admin for the repository and"
                " have your GitHub account connected to your Stencila Hub account."
            )

        if self.subscription:
            repo = Github(token.token).get_repo(self.repo)
            hook_id = self.subscription.get("id")
            hook = repo.get_hook(hook_id)
            hook.delete()
            self.subscription = None
            self.save()
Пример #6
0
    def watch(self, user: User):
        """
        Watch this source by creating a GitHub repository Webhook.

        Requires that the user be an admin on the repository and has their Github account linked
        to their Stencila Hub account. Ass

        Currently, only subscribing to "push" events.
        For a full list of GitHub events see https://developer.github.com/webhooks/event-payloads/.

        This is not an async task so that permissions errors (i.e. not a repo admin) can
        be reported back to the user.
        """
        token = get_user_social_token(user, Provider.github)
        if not token:
            raise exceptions.SocialTokenMissing(
                "To watch a GitHub source you must be a admin for the repository and"
                " have your GitHub account connected to your Stencila Hub account."
            )

        url = self.get_event_url()
        try:
            hook = (Github(token.token).get_repo(self.repo).create_hook(
                "web",
                active=True,
                config=dict(
                    url=url,
                    content_type="json",
                ),
                events=["push"],
            ))
        except GithubException as exc:
            if exc.status == 403:
                raise PermissionError(
                    f"Permission denied by GitHub: {exc.data.get('message')}")
            else:
                raise exc
        else:
            self.subscription = hook.raw_data
            self.save()
Пример #7
0
    def test_no_existing_token(self):
        """
        A user that does not yet have a token.
        """
        app, created = SocialApp.objects.get_or_create(
            provider=Provider.google.name)

        # First request
        refresh_user_access_token(self.ada, "Google", "new-access-token")

        token = get_user_social_token(self.ada, Provider.google)
        assert token.token == "new-access-token"
        assert token.token_secret == ""

        # Second request
        refresh_user_access_token(self.ada, "Google", "refreshed-access-token")

        token = get_user_social_tokens(self.ada)[Provider.google]
        assert token.token == "refreshed-access-token"

        # Get token using Google specific function
        token, app_back = get_user_google_token(self.ada)
        assert token.token == "refreshed-access-token"
        assert app_back == app