<commit_before>import json
import base64
import urllib2
import logging
from rauth import OAuth2Service
from openid import oidutil, fetchers
from openid.consumer import consumer as openid
from openid.extensions import ax, sreg
from flask import Blueprint, render_template, request, redirect, url_for, abort, current_app, session
from acoustid.web import db
from acoustid.web.utils import require_user, is_our_url
from acoustid.models import Account, AccountOpenID, AccountGoogle
from acoustid.utils import generate_api_key
from acoustid.data.account import (
    lookup_account_id_by_mbuser,
    lookup_account_id_by_openid,
    insert_account,
    get_account_details,
    reset_account_apikey,
    update_account_lastlogin,
    is_moderator,
)

logger = logging.getLogger(__name__)

user_page = Blueprint('user', __name__)


# monkey-patch uidutil.log to use the standard logging framework
openid_logger = logging.getLogger('openid')
def log_openid_messages(message, level=0):
    openid_logger.info(message)
oidutil.log = log_openid_messages


# force the use urllib2 with a timeout
fetcher = fetchers.Urllib2Fetcher()
fetcher.urlopen = lambda req: urllib2.urlopen(req, timeout=5)
fetchers.setDefaultFetcher(fetcher)


@user_page.route('/login', methods=['GET', 'POST'])
def login():
    if 'id' in session:
        return redirect(url_for('general.index'))
    errors = list(request.args.getlist('error'))
    if request.method == 'POST':
        login_method = request.form.get('login')
        if login_method == 'musicbrainz':
            return musicbrainz_login()
        elif login_method == 'google':
            return google_login()
        elif login_method == 'openid':
            return openid_login()
    return render_template('login.html', errors=errors,
        return_url=request.values.get('return_url'))


def find_or_create_musicbrainz_user(mb_user_name):
    user = db.session.query(Account).filter_by(mbuser=mb_user_name).first()
    if user is not None:
        return user

    user = Account()
    user.name = mb_user_name
    user.mbuser = mb_user_name
    user.apikey = generate_api_key()
    user.submission_count = 0
    db.session.add(user)
    db.session.flush()

    return user


def login_user_and_redirect(user_id):
    session['id'] = user_id
    return_url = request.values.get('return_url')
    if return_url and is_our_url(return_url):
        return redirect(return_url)
    return redirect(url_for('general.index'))


def handle_musicbrainz_oauth2_login():
    musicbrainz = OAuth2Service(
        name='musicbrainz',
        client_id=current_app.config['MB_OAUTH_CLIENT_ID'],
        client_secret=current_app.config['MB_OAUTH_CLIENT_SECRET'],
        base_url='https://musicbrainz.org',
        authorize_url='https://musicbrainz.org/oauth2/authorize',
        access_token_url='https://musicbrainz.org/oauth2/token',
    )

    code = request.args.get('code')
    if not code:
        url = musicbrainz.get_authorize_url(**{
            'response_type': 'code',
            'scope': 'profile',
            'redirect_uri': url_for('.musicbrainz_login', _external=True),
        })
        return redirect(url)

    auth_session = musicbrainz.get_auth_session(data={
        'grant_type': 'authorization_code',
        'code': code,
        'redirect_uri': url_for('.musicbrainz_login', _external=True),
    }, decoder=json.loads)

    response = auth_session.get('oauth2/userinfo').json()

    user = find_or_create_musicbrainz_user(response['sub'])
    logger.info('MusicBrainz user %s "%s" logged in', user.id, user.name)

    return login_user_and_redirect(user.id)


@user_page.route('/login/musicbrainz')
def musicbrainz_login():
    try:
        response = handle_musicbrainz_oauth2_login()
        db.session.commit()
    except Exception:
        logger.exception('MusicBrainz login failed')
        db.session.rollback()
        return redirect(url_for('.login', error='MusicBrainz login failed'))
    return response


def handle_openid_login_request():
    openid_url = request.form['openid_identifier']
    try:
        consumer = openid.Consumer(session, None)
        openid_req = consumer.begin(openid_url)
    except openid.DiscoveryFailure:
        logger.exception('Error in OpenID discovery')
        raise
    else:
        if openid_req is None:
            raise Exception('No OpenID services found for the given URL')
        else:
            ax_req = ax.FetchRequest()
            ax_req.add(ax.AttrInfo('http://schema.openid.net/contact/email',<commit_msg>Don't lose return_url during MB login<commit_after>import json
import base64
import urllib2
import logging
import random
from itsdangerous import URLSafeSerializer
from rauth import OAuth2Service
from openid import oidutil, fetchers
from openid.consumer import consumer as openid
from openid.extensions import ax, sreg
from flask import Blueprint, render_template, request, redirect, url_for, abort, current_app, session
from acoustid.web import db
from acoustid.web.utils import require_user, is_our_url
from acoustid.models import Account, AccountOpenID, AccountGoogle
from acoustid.utils import generate_api_key
from acoustid.data.account import (
    lookup_account_id_by_mbuser,
    lookup_account_id_by_openid,
    insert_account,
    get_account_details,
    reset_account_apikey,
    update_account_lastlogin,
    is_moderator,
)

logger = logging.getLogger(__name__)

user_page = Blueprint('user', __name__)


# monkey-patch uidutil.log to use the standard logging framework
openid_logger = logging.getLogger('openid')
def log_openid_messages(message, level=0):
    openid_logger.info(message)
oidutil.log = log_openid_messages


# force the use urllib2 with a timeout
fetcher = fetchers.Urllib2Fetcher()
fetcher.urlopen = lambda req: urllib2.urlopen(req, timeout=5)
fetchers.setDefaultFetcher(fetcher)


@user_page.route('/login', methods=['GET', 'POST'])
def login():
    if 'id' in session:
        return redirect(url_for('general.index'))
    errors = list(request.args.getlist('error'))
    if request.method == 'POST':
        login_method = request.form.get('login')
        if login_method == 'musicbrainz':
            return musicbrainz_login()
        elif login_method == 'google':
            return google_login()
        elif login_method == 'openid':
            return openid_login()
    return render_template('login.html', errors=errors,
        return_url=request.values.get('return_url'))


def find_or_create_musicbrainz_user(mb_user_name):
    user = db.session.query(Account).filter_by(mbuser=mb_user_name).first()
    if user is not None:
        return user

    user = Account()
    user.name = mb_user_name
    user.mbuser = mb_user_name
    user.apikey = generate_api_key()
    user.submission_count = 0
    db.session.add(user)
    db.session.flush()

    return user


def login_user_and_redirect(user_id, return_url=None):
    session['id'] = user_id
    if not return_url:
        return_url = request.values.get('return_url')
    if return_url and is_our_url(return_url):
        return redirect(return_url)
    return redirect(url_for('general.index'))


def handle_musicbrainz_oauth2_login():
    musicbrainz = OAuth2Service(
        name='musicbrainz',
        client_id=current_app.config['MB_OAUTH_CLIENT_ID'],
        client_secret=current_app.config['MB_OAUTH_CLIENT_SECRET'],
        base_url='https://musicbrainz.org',
        authorize_url='https://musicbrainz.org/oauth2/authorize',
        access_token_url='https://musicbrainz.org/oauth2/token',
    )

    serializer = URLSafeSerializer(current_app.config['SECRET_KEY'])

    code = request.args.get('code')
    if not code:
        token = str(random.getrandbits(64))
        session['mb_login_token'] = token
        url = musicbrainz.get_authorize_url(**{
            'response_type': 'code',
            'scope': 'profile',
            'redirect_uri': url_for('.musicbrainz_login', _external=True),
            'state': serializer.dumps({
                'return_url': request.values.get('return_url'),
                'token': token,
            }),
        })
        return redirect(url)

    serialized_state = request.args.get('state')
    if serialized_state:
        state = serializer.loads(serialized_state)
    else:
        state = {}

    token = session.get('mb_login_token')
    if not token:
        raise Exception('token not found in session')

    if token != state.get('token'):
        raise Exception('token from session does not match token from oauth2 state')

    auth_session = musicbrainz.get_auth_session(data={
        'grant_type': 'authorization_code',
        'code': code,
        'redirect_uri': url_for('.musicbrainz_login', _external=True),
    }, decoder=json.loads)

    response = auth_session.get('oauth2/userinfo').json()

    user = find_or_create_musicbrainz_user(response['sub'])
    logger.info('MusicBrainz user %s "%s" logged in', user.id, user.name)

    return login_user_and_redirect(user.id, return_url=state.get('return_url'))


@user_page.route('/login/musicbrainz')
def musicbrainz_login():
    try:
        response = handle_musicbrainz_oauth2_login()
        db.session.commit()
    except Exception:
        logger.exception('MusicBrainz login failed')
        db.session.rollback()
        return redirect(url_for('.login', error='MusicBrainz login failed'))
    return response


def handle_openid_login_request():
    openid_url = request.form['openid_identifier']
    try:
        consumer = openid.Consumer(session, None)
        openid_req = consumer.begin(openid_url)
    except openid.DiscoveryFailure:
        logger.exception('Error in OpenID discovery')
        raise
    else:
        if openid_req is None:
            raise Exception('No OpenID services found for the given URL')
        else:
            ax_req = ax.FetchRequest()
            ax_req.add(ax.AttrInfo('http://schema.openid.net/contact/email',
{'fraction_non_alphanumeric': 0.10543292006854148, 'fraction_numerical': 0.003527870174377583, 'mean_word_length': 3.570244127130355, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2196797', 'n_tokens_mistral': 3151, 'n_tokens_neox': 3052, 'n_words': 630}