def register_by_password_status(): """AJAX 刷新教务验证状态""" if not request.args.get("request", None) or not isinstance( request.args["request"], str): return "Invalid request" req = IdentityVerification.get_request_by_id(request.args.get("request")) if not req: return "Invalid request" if req["verification_method"] != "password": logger.warn( "Non-password verification request is trying get status from password interface" ) return "Invalid request" # fetch status from everyclass-auth with tracer.trace('get_result'): try: rpc_result = Auth.get_result(str(request.args.get("request"))) except Exception as e: return handle_exception_with_error_page(e) logger.info(f"RPC result: {rpc_result}") if rpc_result.success: # 密码验证通过,设置请求状态并新增用户 IdentityVerification.set_request_status( str(request.args.get("request")), ID_STATUS_PWD_SUCCESS) verification_req = IdentityVerification.get_request_by_id( str(request.args.get("request"))) # 从 api-server 查询学生基本信息 try: student = Entity.get_student(verification_req["sid_orig"]) except Exception as e: return handle_exception_with_error_page(e) # 添加用户 try: User.add_user(sid_orig=verification_req["sid_orig"], password=verification_req["password"], password_encrypted=True) except ValueError: pass # 已经注册成功,但不知为何进入了中间状态,没有执行下面的删除 session 的代码,并且用户刷新页面 # write login state to session flash(MSG_REGISTER_SUCCESS) if SESSION_PWD_VER_REQ_ID in session: del session[SESSION_PWD_VER_REQ_ID] session[SESSION_CURRENT_USER] = StudentSession( sid_orig=student.student_id, sid=student.student_id_encoded, name=student.name) return jsonify({"message": "SUCCESS"}) elif rpc_result.message in ("PASSWORD_WRONG", "INTERNAL_ERROR", "INVALID_REQUEST_ID"): return jsonify({"message": rpc_result.message}) else: return jsonify({"message": "NEXT_TIME"})
def register_by_password(): """注册:第三步:使用密码验证注册""" if request.method == 'POST': if any( map(lambda x: not request.form.get(x, None), ("password", "password2", "jwPassword"))): flash(MSG_EMPTY_PASSWORD) return redirect(url_for("user.register_by_password")) # 密码强度检查 pwd_strength_report = zxcvbn(password=request.form["password"]) if pwd_strength_report['score'] < 2: SimplePassword.new( password=request.form["password"], sid_orig=session[SESSION_STUDENT_TO_REGISTER].sid_orig) flash(MSG_WEAK_PASSWORD) return redirect(url_for("user.register_by_password")) if request.form["password"] != request.form["password2"]: flash(MSG_PWD_DIFFERENT) return redirect(url_for("user.register_by_password")) # captcha if not TencentCaptcha.verify_old(): flash(MSG_INVALID_CAPTCHA) return redirect(url_for("user.register_by_password")) request_id = IdentityVerification.new_register_request( session[SESSION_STUDENT_TO_REGISTER].sid_orig, "password", ID_STATUS_WAIT_VERIFY, password=request.form["password"]) # call everyclass-auth to verify password with tracer.trace('register_by_password'): try: rpc_result = Auth.register_by_password( request_id=str(request_id), student_id=session[SESSION_STUDENT_TO_REGISTER].sid_orig, password=request.form["jwPassword"]) except Exception as e: return handle_exception_with_error_page(e) if rpc_result['acknowledged']: session[SESSION_PWD_VER_REQ_ID] = request_id return render_template('user/passwordRegistrationPending.html', request_id=request_id) else: return render_template('common/error.html', message=MSG_INTERNAL_ERROR) else: # show password registration page if not session.get(SESSION_STUDENT_TO_REGISTER, None): return render_template('common/error.html', message=MSG_VIEW_SCHEDULE_FIRST) return render_template("user/passwordRegistration.html", name=session[SESSION_STUDENT_TO_REGISTER].name)
def register_by_email(): """注册:第三步:使用邮箱验证注册""" if not session.get(SESSION_STUDENT_TO_REGISTER, None): # 步骤异常,跳回第一步 return redirect(url_for('user.register')) sid_orig = session[SESSION_STUDENT_TO_REGISTER].sid_orig if User.exist(sid_orig): return render_template("common/error.html", message=MSG_ALREADY_REGISTERED) request_id = IdentityVerification.new_register_request(sid_orig, "email", ID_STATUS_SENT) with elasticapm.capture_span('send_email'): try: rpc_result = Auth.register_by_email(request_id, sid_orig) except Exception as e: return handle_exception_with_error_page(e) if rpc_result['acknowledged']: return render_template('user/emailSent.html', request_id=request_id) else: return render_template('common/error.html', message=MSG_INTERNAL_ERROR)
def email_verification(): """注册:邮箱验证""" if request.method == 'POST': # 设置密码表单提交 if not session.get(SESSION_EMAIL_VER_REQ_ID, None): return render_template("common/error.html", message=MSG_400) req = IdentityVerification.get_request_by_id( session[SESSION_EMAIL_VER_REQ_ID]) if not req: return render_template("common/error.html", message=MSG_TOKEN_INVALID) # 此处不是一定需要验证状态,但是为了保险还是判断一下 if req["status"] != ID_STATUS_TKN_PASSED: return render_template("common/error.html", message=MSG_TOKEN_INVALID) if any( map(lambda x: not request.form.get(x, None), ("password", "password2"))): # check if empty password flash(MSG_EMPTY_PASSWORD) return redirect(url_for("user.email_verification")) if request.form["password"] != request.form["password2"]: flash(MSG_PWD_DIFFERENT) return redirect(url_for("user.email_verification")) sid_orig = req['sid_orig'] # 密码强度检查 pwd_strength_report = zxcvbn(password=request.form["password"]) if pwd_strength_report['score'] < 2: SimplePassword.new(password=request.form["password"], sid_orig=sid_orig) flash(MSG_WEAK_PASSWORD) return redirect(url_for("user.email_verification")) try: User.add_user(sid_orig=sid_orig, password=request.form['password']) except ValueError: flash(MSG_ALREADY_REGISTERED) logger.info( f"User {sid_orig} try to register again by email token. Filtered when posting." ) return redirect(url_for("user.email_verification")) del session[SESSION_EMAIL_VER_REQ_ID] IdentityVerification.set_request_status(str(req["request_id"]), ID_STATUS_PASSWORD_SET) flash(MSG_REGISTER_SUCCESS) # 查询 api-server 获得学生基本信息 try: student = Entity.get_student(sid_orig) except Exception as e: return handle_exception_with_error_page(e) # 登录态写入 session session[SESSION_CURRENT_USER] = StudentSession( sid_orig=student.student_id, sid=student.student_id_encoded, name=student.name) return redirect(url_for("user.main")) else: # 设置密码页面 if not session.get(SESSION_EMAIL_VER_REQ_ID, None): if not request.args.get("token", None): return render_template("common/error.html", message=MSG_400) with tracer.trace('verify_email_token'): try: rpc_result = Auth.verify_email_token( token=request.args.get("token", None)) except Exception as e: return handle_exception_with_error_page(e) if rpc_result.success: session[SESSION_EMAIL_VER_REQ_ID] = rpc_result.request_id IdentityVerification.set_request_status( rpc_result.request_id, ID_STATUS_TKN_PASSED) req = IdentityVerification.get_request_by_id( rpc_result.request_id) student_id = req["sid_orig"] if User.exist(student_id): flash(MSG_ALREADY_REGISTERED) logger.info( f"User {student_id} try to register again by email token. Request filtered." ) return redirect(url_for("main.main")) return render_template('user/emailVerificationProceed.html') else: return render_template("common/error.html", message=MSG_TOKEN_INVALID) else: # have session return render_template('user/emailVerificationProceed.html')
def email_verification(): """注册:邮箱验证""" if request.method == 'POST': # 设置密码表单提交 if not session.get(SESSION_VER_REQ_ID, None): return render_template("common/error.html", message=MSG_400) req = IdentityVerification.get_request_by_id(session[SESSION_VER_REQ_ID]) if not req: return render_template("common/error.html", message=MSG_TOKEN_INVALID) # 由于 SESSION_VER_REQ_ID 在密码验证和邮件验证两个验证方式中共享,当使用密码验证写入了 session 之后,如果马上在邮件验证页面 # POST,并且此处不做请求状态的判断,将会绕过验证过程直接设置密码 if req["status"] != ID_STATUS_TKN_PASSED: return render_template("common/error.html", message=MSG_TOKEN_INVALID) if any(map(lambda x: not request.form.get(x, None), ("password", "password2"))): # check if empty password flash(MSG_EMPTY_PASSWORD) return redirect(url_for("user.email_verification")) if request.form["password"] != request.form["password2"]: flash(MSG_PWD_DIFFERENT) return redirect(url_for("user.email_verification")) sid_orig = req['sid_orig'] # 密码强度检查 pwd_strength_report = zxcvbn(password=request.form["password"]) if pwd_strength_report['score'] < 2: SimplePassword.new(password=request.form["password"], sid_orig=sid_orig) flash(MSG_WEAK_PASSWORD) return redirect(url_for("user.email_verification")) User.add_user(sid_orig=sid_orig, password=request.form['password']) del session[SESSION_VER_REQ_ID] IdentityVerification.set_request_status(str(req["request_id"]), ID_STATUS_PASSWORD_SET) flash(MSG_REGISTER_SUCCESS) # 查询 api-server 获得学生基本信息 try: student = APIServer.get_student(sid_orig) except Exception as e: return handle_exception_with_error_page(e) # 登录态写入 session session[SESSION_CURRENT_USER] = StudentSession(sid_orig=student.student_id, sid=student.student_id_encoded, name=student.name) return redirect(url_for("user.main")) else: # 设置密码页面 if not session.get(SESSION_VER_REQ_ID, None): if not request.args.get("token", None): return render_template("common/error.html", message=MSG_400) with elasticapm.capture_span('verify_email_token'): try: rpc_result = Auth.verify_email_token(token=request.args.get("token", None)) except Exception as e: return handle_exception_with_error_page(e) if rpc_result['success']: session[SESSION_VER_REQ_ID] = rpc_result['request_id'] IdentityVerification.set_request_status(rpc_result['request_id'], ID_STATUS_TKN_PASSED) return render_template('user/emailVerificationProceed.html') else: return render_template("common/error.html", message=MSG_TOKEN_INVALID) else: # have session return render_template('user/emailVerificationProceed.html')