示例#1
0
class OAuth2FrontendController(RedditController):
    def pre(self):
        RedditController.pre(self)
        require_https()

    def _check_redirect_uri(self, client, redirect_uri):
        if not redirect_uri or not client or redirect_uri != client.redirect_uri:
            abort(403)

    def _error_response(self, resp):
        if (errors.OAUTH2_INVALID_CLIENT, "client_id") in c.errors:
            resp["error"] = "unauthorized_client"
        elif (errors.OAUTH2_ACCESS_DENIED, "authorize") in c.errors:
            resp["error"] = "access_denied"
        elif (errors.BAD_HASH, None) in c.errors:
            resp["error"] = "access_denied"
        elif (errors.INVALID_OPTION, "response_type") in c.errors:
            resp["error"] = "unsupported_response_type"
        elif (errors.INVALID_OPTION, "scope") in c.errors:
            resp["error"] = "invalid_scope"
        else:
            resp["error"] = "invalid_request"

    @validate(VUser(),
              response_type=VOneOf("response_type", ("code", )),
              client=VClientID(),
              redirect_uri=VRequired("redirect_uri",
                                     errors.OAUTH2_INVALID_REDIRECT_URI),
              scope=VOneOf("scope", scope_info.keys()),
              state=VRequired("state", errors.NO_TEXT))
    def GET_authorize(self, response_type, client, redirect_uri, scope, state):
        """
        First step in [OAuth 2.0](http://oauth.net/2/) authentication.
        End users will be prompted for their credentials (username/password)
        and asked if they wish to authorize the application identified by
        the **client_id** parameter with the permissions specified by the
        **scope** parameter.  They are then redirected to the endpoint on
        the client application's side specified by **redirect_uri**.

        If the user granted permission to the application, the response will
        contain a **code** parameter with a temporary authorization code
        which can be exchanged for an access token at
        [/api/v1/access_token](#api_method_access_token).

        **redirect_uri** must match the URI configured for the client in the
        [app preferences](/prefs/apps).  If **client_id** or **redirect_uri**
        is not valid, or if the call does not take place over SSL, a 403
        error will be returned.  For all other errors, a redirect to
        **redirect_uri** will be returned, with a **error** parameter
        indicating why the request failed.
        """

        self._check_redirect_uri(client, redirect_uri)

        resp = {}
        if not c.errors:
            c.deny_frames = True
            return OAuth2AuthorizationPage(client, redirect_uri,
                                           scope_info[scope], state).render()
        else:
            self._error_response(resp)
            return self.redirect(redirect_uri + "?" + urlencode(resp),
                                 code=302)

    @validate(VUser(),
              VModhash(fatal=False),
              client=VClientID(),
              redirect_uri=VRequired("redirect_uri",
                                     errors.OAUTH2_INVALID_REDIRECT_URI),
              scope=VOneOf("scope", scope_info.keys()),
              state=VRequired("state", errors.NO_TEXT),
              authorize=VRequired("authorize", errors.OAUTH2_ACCESS_DENIED))
    def POST_authorize(self, authorize, client, redirect_uri, scope, state):
        """Endpoint for OAuth2 authorization."""

        self._check_redirect_uri(client, redirect_uri)

        resp = {}
        if state:
            resp["state"] = state

        if not c.errors:
            code = OAuth2AuthorizationCode._new(client._id, redirect_uri,
                                                c.user._id, scope)
            resp["code"] = code._id
        else:
            self._error_response(resp)

        return self.redirect(redirect_uri + "?" + urlencode(resp), code=302)
示例#2
0
class MeetupsController(RedditController):
    def response_func(self, **kw):
        return self.sendstring(json.dumps(kw))

    @validate(VUser(),
              VCreateMeetup(),
              title=ValueOrBlank('title'),
              description=ValueOrBlank('description'),
              location=ValueOrBlank('location'),
              latitude=ValueOrBlank('latitude'),
              longitude=ValueOrBlank('longitude'),
              timestamp=ValueOrBlank('timestamp'),
              tzoffset=ValueOrBlank('tzoffset'))
    def GET_new(self, *a, **kw):
        return BoringPage(pagename='New Meetup',
                          content=NewMeetup(*a, **kw)).render()

    @Json
    @validate(VUser(),
              VCreateMeetup(),
              VModhash(),
              ip=ValidIP(),
              title=VRequired('title', errors.NO_TITLE),
              description=VRequired('description', errors.NO_DESCRIPTION),
              location=VRequired('location', errors.NO_LOCATION),
              latitude=VFloat('latitude', error=errors.NO_LOCATION),
              longitude=VFloat('longitude', error=errors.NO_LOCATION),
              timestamp=VTimestamp('timestamp'),
              tzoffset=VFloat('tzoffset', error=errors.INVALID_DATE))
    def POST_create(self, res, title, description, location, latitude,
                    longitude, timestamp, tzoffset, ip):
        if res._chk_error(errors.NO_TITLE):
            res._chk_error(errors.TITLE_TOO_LONG)
            res._focus('title')

        res._chk_errors((errors.NO_LOCATION, errors.NO_DESCRIPTION,
                         errors.INVALID_DATE, errors.NO_DATE))

        if res.error: return

        meetup = Meetup(author_id=c.user._id,
                        title=title,
                        description=description,
                        location=location,
                        latitude=latitude,
                        longitude=longitude,
                        timestamp=timestamp,
                        tzoffset=tzoffset)

        # Expire all meetups in the render cache
        g.rendercache.invalidate_key_group(Meetup.group_cache_key())

        meetup._commit()

        l = Link._submit(meetup_article_title(meetup),
                         meetup_article_text(meetup), 'self', c.user,
                         Subreddit._by_name('meetups'), ip, [])

        l.meetup = meetup._id36
        l._commit()
        meetup.assoc_link = l._id
        meetup._commit()

        when = datetime.now(g.tz) + timedelta(
            0,
            3600)  # Leave a short window of time before notification, in case
        # the meetup is edited/deleted soon after its creation
        PendingJob.store(when, 'process_new_meetup', {'meetup_id': meetup._id})

        #update the queries
        if g.write_query_queue:
            queries.new_link(l)

        res._redirect(url_for(action='show', id=meetup._id36))

    @Json
    @validate(VUser(),
              VModhash(),
              meetup=VEditMeetup('id'),
              title=VRequired('title', errors.NO_TITLE),
              description=VRequired('description', errors.NO_DESCRIPTION),
              location=VRequired('location', errors.NO_LOCATION),
              latitude=VFloat('latitude', error=errors.NO_LOCATION),
              longitude=VFloat('longitude', error=errors.NO_LOCATION),
              timestamp=VTimestamp('timestamp'),
              tzoffset=VFloat('tzoffset', error=errors.INVALID_DATE))
    def POST_update(self, res, meetup, title, description, location, latitude,
                    longitude, timestamp, tzoffset):
        if res._chk_error(errors.NO_TITLE):
            res._chk_error(errors.TITLE_TOO_LONG)
            res._focus('title')

        res._chk_errors((errors.NO_LOCATION, errors.NO_DESCRIPTION,
                         errors.INVALID_DATE, errors.NO_DATE))

        if res.error: return

        meetup.title = title
        meetup.description = description

        meetup.location = location
        meetup.latitude = latitude
        meetup.longitude = longitude

        meetup.timestamp = timestamp
        meetup.tzoffset = tzoffset

        # Expire all meetups in the render cache
        g.rendercache.invalidate_key_group(Meetup.group_cache_key())

        meetup._commit()

        # Update the linked article
        article = Link._byID(meetup.assoc_link)
        article._load()
        article_old_url = article.url
        article.title = meetup_article_title(meetup)
        article.article = meetup_article_text(meetup)
        article._commit()
        article.update_url_cache(article_old_url)

        res._redirect(url_for(action='show', id=meetup._id36))

    @validate(VUser(), meetup=VEditMeetup('id'))
    def GET_edit(self, meetup):
        return BoringPage(pagename='Edit Meetup',
                          content=EditMeetup(
                              meetup,
                              title=meetup.title,
                              description=meetup.description,
                              location=meetup.location,
                              latitude=meetup.latitude,
                              longitude=meetup.longitude,
                              timestamp=int(meetup.timestamp * 1000),
                              tzoffset=meetup.tzoffset)).render()

    # Show a meetup.  Most of this code was coped from GET_comments in front.py
    @validate(meetup=VMeetup('id'),
              sort=VMenu('controller', CommentSortMenu),
              num_comments=VMenu('controller', NumCommentsMenu))
    def GET_show(self, meetup, sort, num_comments):
        article = Link._byID(meetup.assoc_link)

        # figure out number to show based on the menu
        user_num = c.user.pref_num_comments or g.num_comments
        num = g.max_comments if num_comments == 'true' else user_num

        builder = CommentBuilder(article, CommentSortMenu.operator(sort), None,
                                 None)
        listing = NestedListing(builder,
                                num=num,
                                parent_name=article._fullname)
        displayPane = PaneStack()

        # insert reply box only for logged in user
        if c.user_is_loggedin:
            displayPane.append(CommentReplyBox())
            displayPane.append(CommentReplyBox(link_name=article._fullname))

        # finally add the comment listing
        displayPane.append(listing.listing())

        sort_menu = CommentSortMenu(default=sort, type='dropdown2')
        nav_menus = [
            sort_menu,
            NumCommentsMenu(article.num_comments, default=num_comments)
        ]

        content = CommentListing(
            content=displayPane,
            num_comments=article.num_comments,
            nav_menus=nav_menus,
        )

        # Update last viewed time, and return the previous last viewed time.  Actually tracked on the article
        lastViewed = None
        if c.user_is_loggedin:
            clicked = article._getLastClickTime(c.user)
            lastViewed = clicked._date if clicked else None
            article._click(c.user)

        res = ShowMeetup(meetup=meetup,
                         content=content,
                         fullname=article._fullname,
                         lastViewed=lastViewed)

        return BoringPage(pagename=meetup.title,
                          content=res,
                          body_class='meetup').render()
示例#3
0
文件: oauth2.py 项目: tjr1351/reddit
class OAuth2FrontendController(RedditController):
    def pre(self):
        RedditController.pre(self)
        require_https()

    def _check_redirect_uri(self, client, redirect_uri):
        if not redirect_uri or not client or redirect_uri != client.redirect_uri:
            abort(403)

    def _error_response(self, resp):
        if (errors.OAUTH2_INVALID_CLIENT, "client_id") in c.errors:
            resp["error"] = "unauthorized_client"
        elif (errors.OAUTH2_ACCESS_DENIED, "authorize") in c.errors:
            resp["error"] = "access_denied"
        elif (errors.BAD_HASH, None) in c.errors:
            resp["error"] = "access_denied"
        elif (errors.INVALID_OPTION, "response_type") in c.errors:
            resp["error"] = "unsupported_response_type"
        elif (errors.INVALID_OPTION, "scope") in c.errors:
            resp["error"] = "invalid_scope"
        else:
            resp["error"] = "invalid_request"

    @validate(VUser(),
              response_type=VOneOf("response_type", ("code", )),
              client=VClientID(),
              redirect_uri=VUrl("redirect_uri", allow_self=False,
                                lookup=False),
              scope=VOneOf("scope", scope_info.keys()),
              state=VRequired("state", errors.NO_TEXT))
    def GET_authorize(self, response_type, client, redirect_uri, scope, state):
        self._check_redirect_uri(client, redirect_uri)

        resp = {}
        if not c.errors:
            c.deny_frames = True
            return OAuth2AuthorizationPage(client, redirect_uri,
                                           scope_info[scope], state).render()
        else:
            self._error_response(resp)
            return self.redirect(redirect_uri + "?" + urlencode(resp),
                                 code=302)

    @validate(VUser(),
              VModhash(fatal=False),
              client=VClientID(),
              redirect_uri=VUrl("redirect_uri", allow_self=False,
                                lookup=False),
              scope=VOneOf("scope", scope_info.keys()),
              state=VRequired("state", errors.NO_TEXT),
              authorize=VRequired("authorize", errors.OAUTH2_ACCESS_DENIED))
    def POST_authorize(self, authorize, client, redirect_uri, scope, state):
        self._check_redirect_uri(client, redirect_uri)

        resp = {}
        if state:
            resp["state"] = state

        if not c.errors:
            code = OAuth2AuthorizationCode._new(client._id, redirect_uri,
                                                c.user._id, scope)
            resp["code"] = code._id
        else:
            self._error_response(resp)

        return self.redirect(redirect_uri + "?" + urlencode(resp), code=302)