コード例 #1
0
def generate_atom(gplus_id, page_id):
    """Generate an Atom-format feed for the given G+ id."""
    # If no page id specified, use the special value 'me' which refers to the
    # stream for the owner of the OAuth2 token.
    request = requests.Request('GET',
                               GPLUS_API_ACTIVITIES_ENDPOINT %
                               (page_id or 'me'),
                               params={
                                   'maxResults': 10,
                                   'userIp': flask.request.remote_addr
                               })
    api_response = oauth2.authed_request_for_id(gplus_id, request)
    result = api_response.json()

    if page_id:
        request_url = full_url_for('page_atom',
                                   gplus_id=gplus_id,
                                   page_id=page_id)
    else:
        request_url = full_url_for('user_atom', gplus_id=gplus_id)

    params = {
        'server_url': full_url_for('main'),
        'feed_id': page_id or gplus_id,
        'request_url': request_url,
        'to_atom_date': dateutils.to_atom_format,
    }

    items = result.get('items')
    if not items:
        params['last_update'] = datetime.datetime.today()
        body = flask.render_template('atom/empty.xml', **params)
    else:
        last_update = max(
            dateutils.from_iso_format(item['updated']) for item in items)
        params['last_update'] = last_update
        params['items'] = process_feed_items(items)
        params['actor'] = params['items'][0]['actor']
        body = flask.render_template('atom/feed.xml', **params)

    response = flask.make_response(body)
    response.headers['Content-Type'] = 'application/atom+xml; charset=utf-8'
    response.date = params['last_update']
    return response
コード例 #2
0
ファイル: main.py プロジェクト: ayust/pluss
def main():
    """Display the homepage."""
    gplus_id = flask.request.cookies.get('gplus_id')
    if gplus_id:
        # If we lost rights, but someone still has the cookie, get rid of it.
        if not TokenIdMapping.lookup_refresh_token(gplus_id):
            return flask.redirect(flask.url_for('clear'))
        # Display a page indicating the user's feed URL, since they've authed.
        return flask.render_template('authed_main.html', datetime=datetime, gplus_id=gplus_id,
            feed_url=full_url_for('user_atom', gplus_id=gplus_id))
    else:
        return flask.render_template('main.html', datetime=datetime)
コード例 #3
0
ファイル: oauth2.py プロジェクト: seraphyn/pluss
def auth():
    """Redirect the user to Google to obtain authorization."""
    data = {
        # Basic OAuth2 parameters
        'client_id': Config.get('oauth', 'client-id'),
        'redirect_uri': full_url_for('oauth2'),
        'scope': OAUTH2_SCOPE,
        'response_type': 'code',

        # Settings necessary for daemon operation
        'access_type': 'offline',
        'approval_prompt': 'force',
    }
    return flask.redirect('%s/auth?%s' % (OAUTH2_BASE, urllib.urlencode(data)))
コード例 #4
0
ファイル: oauth2.py プロジェクト: ayust/pluss
def auth():
    """Redirect the user to Google to obtain authorization."""
    data = {
        # Basic OAuth2 parameters
        'client_id': Config.get('oauth', 'client-id'),
        'redirect_uri': full_url_for('oauth2'),
        'scope': OAUTH2_SCOPE,
        'response_type': 'code',

        # Settings necessary for daemon operation
        'access_type': 'offline',
        'approval_prompt': 'force',
    }
    return flask.redirect('%s/auth?%s' % (OAUTH2_BASE, urllib.urlencode(data)))
コード例 #5
0
def main():
    """Display the homepage."""
    gplus_id = flask.request.cookies.get('gplus_id')
    if gplus_id:
        # If we lost rights, but someone still has the cookie, get rid of it.
        if not TokenIdMapping.lookup_refresh_token(gplus_id):
            return flask.redirect(flask.url_for('clear'))
        # Display a page indicating the user's feed URL, since they've authed.
        return flask.render_template('authed_main.html',
                                     datetime=datetime,
                                     gplus_id=gplus_id,
                                     feed_url=full_url_for('user_atom',
                                                           gplus_id=gplus_id))
    else:
        return flask.render_template('main.html', datetime=datetime)
コード例 #6
0
ファイル: atom.py プロジェクト: seraphyn/pluss
def generate_atom(gplus_id, page_id):
    """Generate an Atom-format feed for the given G+ id."""
    # If no page id specified, use the special value 'me' which refers to the
    # stream for the owner of the OAuth2 token.
    request = requests.Request('GET', GPLUS_API_ACTIVITIES_ENDPOINT % (page_id or 'me'),
        params={'maxResults': 10, 'userIp': flask.request.remote_addr})
    api_response = oauth2.authed_request_for_id(gplus_id, request)
    result = api_response.json()

    if page_id:
        request_url = full_url_for('page_atom', gplus_id=gplus_id, page_id=page_id)
    else:
        request_url = full_url_for('user_atom', gplus_id=gplus_id)

    params = {
        'server_url': full_url_for('main'),
        'feed_id': page_id or gplus_id,
        'request_url': request_url,
        'to_atom_date': dateutils.to_atom_format,
    }

    items = result.get('items')
    if not items:
        params['last_update'] = datetime.datetime.today()
        body = flask.render_template('atom/empty.xml', **params)
    else:
        last_update = max(dateutils.from_iso_format(item['updated']) for item in items)
        params['last_update'] = last_update
        params['items'] = process_feed_items(items)
        params['actor'] = params['items'][0]['actor']
        body = flask.render_template('atom/feed.xml', **params)

    response = flask.make_response(body)
    response.headers['Content-Type'] = 'application/atom+xml; charset=utf-8'
    response.date = params['last_update']
    return response
コード例 #7
0
ファイル: oauth2.py プロジェクト: seraphyn/pluss
def oauth2():
    """Google redirects the user back to this endpoint to continue the OAuth2 flow."""

    # Check for errors from the OAuth2 process
    err = flask.request.args.get('error')
    if err == 'access_denied':
        return flask.redirect(flask.url_for('denied'))
    elif err is not None:
        app.logger.warning("OAuth2 callback received error: %s", err)
        # TODO: handle this better (flash message?)
        message = 'Whoops, something went wrong (error=%s). Please try again later.'
        return message % flask.escape(err), 500

    # Okay, no errors, so we should have a valid authorization code.
    # Time to go get our server-side tokens for this user from Google.
    auth_code = flask.request.args['code']
    if auth_code is None:
        return 'Authorization code is missing.', 400  # Bad Request

    data = {
        'code': auth_code,
        'client_id': Config.get('oauth', 'client-id'),
        'client_secret': Config.get('oauth', 'client-secret'),
        'redirect_uri': full_url_for('oauth2'),
        'grant_type': 'authorization_code',
    }
    try:
        response = session.post(OAUTH2_BASE + '/token',
                                data,
                                timeout=GOOGLE_API_TIMEOUT)
    except requests.exceptions.Timeout:
        app.logger.error('OAuth2 token request timed out.')
        # TODO: handle this better (flash message?)
        message = 'Whoops, Google took too long to respond. Please try again later.'
        return message, 504  # Gateway Timeout

    if response.status_code != 200:
        app.logger.error(
            'OAuth2 token request got HTTP response %s for code "%s".',
            response.status_code, auth_code)
        # TODO: handle this better (flash message?)
        message = (
            'Whoops, we failed to finish processing your authorization with Google.'
            ' Please try again later.')
        return message, 401  # Unauthorized

    try:
        result = response.json()
    except ValueError:
        app.logger.error(
            'OAuth2 token request got non-JSON response for code "%s".',
            auth_code)
        # TODO: handle this better (flash message?)
        message = (
            'Whoops, we got an invalid response from Google for your authorization.'
            ' Please try again later.')
        return message, 502  # Bad Gateway

    # Sanity check: we always expect Bearer tokens.
    if result.get('token_type') != 'Bearer':
        app.logger.error(
            'OAuth2 token request got unknown token type "%s" for code "%s".',
            result['token_type'], auth_code)
        # TODO: handle this better (flash message?)
        message = (
            'Whoops, we got an invalid response from Google for your authorization.'
            ' Please try again later.')
        return message, 502  # Bad Gateway

    # All non-error responses should have an access token.
    access_token = result['access_token']
    refresh_token = result.get('refresh_token')

    # This is in seconds, but we convert it to an absolute timestamp so that we can
    # account for the potential delay it takes to look up the G+ id we should associate
    # the access tokens with. (Could be up to GOOGLE_API_TIMEOUT seconds later.)
    expiry = datetime.datetime.today() + datetime.timedelta(
        seconds=result['expires_in'])

    try:
        person = get_person_by_access_token(access_token)
    except UnavailableException as e:
        app.logger.error('Unable to finish OAuth2 flow: %r.' % e)
        message = (
            'Whoops, we got an invalid response from Google for your authorization.'
            ' Please try again later.')
        return message, 502  # Bad Gateway

    if refresh_token is not None:
        TokenIdMapping.update_refresh_token(person['id'], refresh_token)

    # Convert the absolute expiry timestamp back into a duration in seconds
    expires_in = int((expiry - datetime.datetime.today()).total_seconds())
    Cache.set(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % person['id'],
              access_token,
              time=expires_in)

    # Whew, all done! Set a cookie with the user's G+ id and send them back to the homepage.
    app.logger.info("Successfully authenticated G+ id %s.", person['id'])
    response = flask.make_response(flask.redirect(flask.url_for('main')))
    response.set_cookie('gplus_id', person['id'])
    return response
コード例 #8
0
ファイル: oauth2.py プロジェクト: ayust/pluss
def oauth2():
    """Google redirects the user back to this endpoint to continue the OAuth2 flow."""

    # Check for errors from the OAuth2 process
    err = flask.request.args.get('error')
    if err == 'access_denied':
        return flask.redirect(flask.url_for('denied'))
    elif err is not None:
        app.logger.warning("OAuth2 callback received error: %s", err)
        # TODO: handle this better (flash message?)
        message = 'Whoops, something went wrong (error=%s). Please try again later.'
        return message % flask.escape(err), 500

    # Okay, no errors, so we should have a valid authorization code.
    # Time to go get our server-side tokens for this user from Google.
    auth_code = flask.request.args['code']
    if auth_code is None:
        return 'Authorization code is missing.', 400 # Bad Request

    data =  {
        'code': auth_code,
        'client_id': Config.get('oauth', 'client-id'),
        'client_secret': Config.get('oauth', 'client-secret'),
        'redirect_uri': full_url_for('oauth2'),
        'grant_type': 'authorization_code',
    }
    try:
        response = session.post(OAUTH2_BASE + '/token', data, timeout=GOOGLE_API_TIMEOUT)
    except requests.exceptions.Timeout:
        app.logger.error('OAuth2 token request timed out.')
        # TODO: handle this better (flash message?)
        message = 'Whoops, Google took too long to respond. Please try again later.'
        return message, 504 # Gateway Timeout

    if response.status_code != 200:
        app.logger.error('OAuth2 token request got HTTP response %s for code "%s".',
            response.status_code, auth_code)
        # TODO: handle this better (flash message?)
        message = ('Whoops, we failed to finish processing your authorization with Google.'
                   ' Please try again later.')
        return message, 401 # Unauthorized

    try:
        result = response.json()
    except ValueError:
        app.logger.error('OAuth2 token request got non-JSON response for code "%s".', auth_code)
        # TODO: handle this better (flash message?)
        message = ('Whoops, we got an invalid response from Google for your authorization.'
                   ' Please try again later.')
        return message, 502 # Bad Gateway

    # Sanity check: we always expect Bearer tokens.
    if result.get('token_type') != 'Bearer':
        app.logger.error('OAuth2 token request got unknown token type "%s" for code "%s".',
            result['token_type'], auth_code)
        # TODO: handle this better (flash message?)
        message = ('Whoops, we got an invalid response from Google for your authorization.'
                   ' Please try again later.')
        return message, 502 # Bad Gateway

    # All non-error responses should have an access token.
    access_token = result['access_token']
    refresh_token = result.get('refresh_token')

    # This is in seconds, but we convert it to an absolute timestamp so that we can
    # account for the potential delay it takes to look up the G+ id we should associate
    # the access tokens with. (Could be up to GOOGLE_API_TIMEOUT seconds later.)
    expiry = datetime.datetime.today() + datetime.timedelta(seconds=result['expires_in'])

    try:
        person = get_person_by_access_token(access_token)
    except UnavailableException as e:
        app.logger.error('Unable to finish OAuth2 flow: %r.' % e)
        message = ('Whoops, we got an invalid response from Google for your authorization.'
                   ' Please try again later.')
        return message, 502 # Bad Gateway

    if refresh_token is not None:
        TokenIdMapping.update_refresh_token(person['id'], refresh_token)

    # Convert the absolute expiry timestamp back into a duration in seconds
    expires_in = int((expiry - datetime.datetime.today()).total_seconds())
    Cache.set(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % person['id'], access_token, time=expires_in)

    # Whew, all done! Set a cookie with the user's G+ id and send them back to the homepage.
    app.logger.info("Successfully authenticated G+ id %s.", person['id'])
    response = flask.make_response(flask.redirect(flask.url_for('main')))
    response.set_cookie('gplus_id', person['id'])
    return response