0584ebdc74
Co-authored-by: Cursor <cursoragent@cursor.com>
93 lines
3.4 KiB
Python
93 lines
3.4 KiB
Python
import json
|
|
|
|
from flask import Blueprint, flash, jsonify, redirect, request, url_for
|
|
from flask_login import current_user, login_required, login_user
|
|
|
|
from app import db
|
|
from app.passkey_service import (
|
|
authentication_options,
|
|
delete_passkey,
|
|
is_passkey_enabled,
|
|
registration_options,
|
|
verify_authentication,
|
|
verify_registration,
|
|
)
|
|
from webauthn.helpers.options_to_json import options_to_json
|
|
|
|
bp = Blueprint("passkey", __name__, url_prefix="/auth/passkey")
|
|
|
|
|
|
@bp.route("/register/options", methods=["POST"])
|
|
@login_required
|
|
def register_options():
|
|
if not is_passkey_enabled():
|
|
return jsonify({"error": "Passkey отключён администратором"}), 403
|
|
options = registration_options(current_user)
|
|
return jsonify(json.loads(options_to_json(options)))
|
|
|
|
|
|
@bp.route("/register/verify", methods=["POST"])
|
|
@login_required
|
|
def register_verify():
|
|
if not is_passkey_enabled():
|
|
return jsonify({"error": "Passkey отключён администратором"}), 403
|
|
data = request.get_json(silent=True) or {}
|
|
name = data.get("name", "Passkey")
|
|
credential = data.get("credential")
|
|
if not credential:
|
|
return jsonify({"error": "Нет данных passkey"}), 400
|
|
try:
|
|
passkey = verify_registration(current_user, credential, name)
|
|
return jsonify({"ok": True, "id": passkey.id, "name": passkey.name})
|
|
except Exception as exc:
|
|
return jsonify({"error": str(exc)}), 400
|
|
|
|
|
|
@bp.route("/login/options", methods=["POST"])
|
|
def login_options():
|
|
if not is_passkey_enabled():
|
|
return jsonify({"error": "Passkey отключён администратором"}), 403
|
|
from app.models import User
|
|
|
|
username = (request.get_json(silent=True) or {}).get("username", "").strip()
|
|
if not username:
|
|
return jsonify({"error": "Укажите логин или email"}), 400
|
|
|
|
user = User.query.filter(
|
|
(User.username == username) | (User.email == username.lower())
|
|
).first()
|
|
if not user or not user.is_active:
|
|
return jsonify({"error": "Passkey не найден для этого аккаунта"}), 404
|
|
|
|
try:
|
|
options = authentication_options(user)
|
|
return jsonify(json.loads(options_to_json(options)))
|
|
except ValueError as exc:
|
|
return jsonify({"error": str(exc)}), 400
|
|
|
|
|
|
@bp.route("/login/verify", methods=["POST"])
|
|
def login_verify():
|
|
if not is_passkey_enabled():
|
|
return jsonify({"error": "Passkey отключён администратором"}), 403
|
|
from app.folder_utils import process_pending_invites
|
|
from app.session_service import create_user_session
|
|
|
|
data = request.get_json(silent=True) or {}
|
|
credential = data.get("credential")
|
|
remember = bool(data.get("remember"))
|
|
if not credential:
|
|
return jsonify({"error": "Нет данных passkey"}), 400
|
|
|
|
try:
|
|
user = verify_authentication(credential)
|
|
if not user.is_active:
|
|
return jsonify({"error": "Аккаунт заблокирован"}), 403
|
|
login_user(user, remember=remember)
|
|
create_user_session(user, remember=remember)
|
|
process_pending_invites(user)
|
|
redirect_url = url_for("admin.dashboard") if user.is_admin else url_for("cabinet.index")
|
|
return jsonify({"ok": True, "redirect": redirect_url})
|
|
except Exception as exc:
|
|
return jsonify({"error": str(exc)}), 400
|