diff --git a/app/blueprints/github/__init__.py b/app/blueprints/github/__init__.py index 3b78b60e..87906189 100644 --- a/app/blueprints/github/__init__.py +++ b/app/blueprints/github/__init__.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from flask import Blueprint +from flask import Blueprint, abort from flask_babel import gettext bp = Blueprint("github", __name__) @@ -24,13 +24,19 @@ from flask_login import current_user from sqlalchemy import func, or_, and_ from app import github, csrf from app.models import db, User, APIToken, Package, Permission, AuditSeverity, PackageState -from app.utils import abs_url_for, add_audit_log, login_user_set_active +from app.utils import abs_url_for, add_audit_log, login_user_set_active, is_safe_url from app.blueprints.api.support import error, api_create_vcs_release import hmac, requests + @bp.route("/github/start/") def start(): - return github.authorize("", redirect_uri=abs_url_for("github.callback")) + next = request.args.get("next") + if next and not is_safe_url(next): + abort(400) + + return github.authorize("", redirect_uri=abs_url_for("github.callback", next=next)) + @bp.route("/github/view/") def view_permissions(): @@ -46,6 +52,14 @@ def callback(oauth_token): flash(gettext("Authorization failed [err=gh-oauth-login-failed]"), "danger") return redirect(url_for("users.login")) + next = request.args.get("next") + if next and not is_safe_url(next): + abort(400) + + redirect_to = next + if redirect_to is None: + redirect_to = url_for("homepage.home") + # Get GitGub username url = "https://api.github.com/user" r = requests.get(url, headers={"Authorization": "token " + oauth_token}) @@ -60,10 +74,10 @@ def callback(oauth_token): current_user.github_username = username db.session.commit() flash(gettext("Linked GitHub to account"), "success") - return redirect(url_for("homepage.home")) + return redirect(redirect_to) else: flash(gettext("GitHub account is already associated with another user"), "danger") - return redirect(url_for("homepage.home")) + return redirect(redirect_to) # If not logged in, log in else: @@ -71,13 +85,13 @@ def callback(oauth_token): flash(gettext("Unable to find an account for that GitHub user"), "danger") return redirect(url_for("users.claim_forums")) - ret = login_user_set_active(userByGithub, remember=True) + ret = login_user_set_active(userByGithub, next, remember=True) if ret is None: flash(gettext("Authorization failed [err=gh-login-failed]"), "danger") return redirect(url_for("users.login")) add_audit_log(AuditSeverity.USER, userByGithub, "Logged in using GitHub OAuth", - url_for("users.profile", username=userByGithub.username)) + url_for("users.profile", username=userByGithub.username)) db.session.commit() return ret diff --git a/app/blueprints/users/account.py b/app/blueprints/users/account.py index 548039d7..57f66f3b 100644 --- a/app/blueprints/users/account.py +++ b/app/blueprints/users/account.py @@ -71,11 +71,11 @@ def handle_login(form): @bp.route("/user/login/", methods=["GET", "POST"]) def login(): - if current_user.is_authenticated: - next = request.args.get("next") - if next and not is_safe_url(next): - abort(400) + next = request.args.get("next") + if next and not is_safe_url(next): + abort(400) + if current_user.is_authenticated: return redirect(next or url_for("homepage.home")) form = LoginForm(request.form) @@ -87,7 +87,7 @@ def login(): if request.method == "GET": form.remember_me.data = True - return render_template("users/login.html", form=form) + return render_template("users/login.html", form=form, next=next) @bp.route("/user/logout/", methods=["GET", "POST"]) diff --git a/app/templates/users/login.html b/app/templates/users/login.html index f73ebd30..ffa7ed1d 100644 --- a/app/templates/users/login.html +++ b/app/templates/users/login.html @@ -25,7 +25,7 @@

- + {{ _("GitHub") }} diff --git a/app/utils/user.py b/app/utils/user.py index f2b15407..bd0c3813 100644 --- a/app/utils/user.py +++ b/app/utils/user.py @@ -16,6 +16,7 @@ from functools import wraps +from typing import Optional from flask_babel import gettext from flask_login import login_user, current_user @@ -57,7 +58,7 @@ def post_login(user: User, next_url): return redirect(url_for("homepage.home")) -def login_user_set_active(user: User, next_url: str = None, *args, **kwargs): +def login_user_set_active(user: User, next_url: Optional[str] = None, *args, **kwargs): if user.rank == UserRank.NOT_JOINED and user.email is None: user.rank = UserRank.NEW_MEMBER user.notification_preferences = UserNotificationPreferences(user)