import json from quart import Blueprint, jsonify, request from flask_login import current_user from flipbook.helpers import verify_signature from flipbook.models import Wallet, rand_id bp = Blueprint('api', 'api', url_prefix='/api/v1') @bp.route('/user_authenticated') async def user_authenticated(): """ Check to see if sender is authenticated. Useful for AJAX calls to "check" we're still authenticated instead of assuming (especially with old, loaded forms/pages). """ return jsonify(current_user.is_authenticated) @bp.route('/user_exists/') async def user_exists(wallet_address): """ Check to see if a given wallet exists in the database. This logic will help the login/connect MetaMask flow. """ nonce = rand_id() wallet = Wallet.select().where( Wallet.address == wallet_address.lower() ).first() if wallet: nonce = wallet.nonce return jsonify({ 'user_exists': wallet is not None, 'nonce': nonce, 'success': True }) @bp.route('/authenticate/metamask', methods=['POST']) async def authenticate_metamask(): """ This is the login/authenticate route for this dApp. Users POST a `signedData` blob, a message signed by the user with MetaMask (`personal_sign` method). This route will verify the signed data against the user's public ETH address. If no user exists, they get an entry in the database. If user does exist, they get logged in. """ data = await request.get_data() data = json.loads(data) if current_user.is_authenticated: return jsonify({ 'success': False, 'message': 'Already registered and authenticated.' }) _u = Wallet.select().where( Wallet.address == data['public_address'] ).first() if _u: if data['message'].endswith(_u.nonce): if verify_signature(data['message'], data['signed_data'], data['public_address']): _u.login() return jsonify({ 'success': True, 'message': 'Logged in' }) else: return jsonify({ 'success': False, 'message': 'Invalid signature' }) else: return jsonify({ 'success': False, 'message': 'Invalid nonce in signed message' }) else: w = Wallet( address=data['public_address'].lower() ) w.save() w.login() return jsonify({ 'success': True, 'message': 'Registered' })