You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.4 KiB
Python

from secrets import token_urlsafe
3 years ago
from flask import Blueprint, request, jsonify
from flask_login import current_user
from suchwowx.factory import db
from suchwowx.helpers import verify_signature
from suchwowx.models import User, Meme
bp = Blueprint('api', 'api', url_prefix='/api/v1')
3 years ago
@bp.route('/memes')
def memes():
"""
List all the approved memes on the server to allow remote syncing.
"""
all_memes = dict()
memes = Meme.query.filter(Meme.approved == True).all()
for meme in memes:
all_memes[meme.id] = meme.as_dict()
all_memes[meme.id]['user'] = meme.user.as_dict()
return jsonify(all_memes)
@bp.route('/user_exists')
def user_exists():
"""
Check to see if a given user exists (handle or wallet address).
This logic will help the login/connect MetaMask flow.
"""
if 'public_address' in request.args:
query_str = 'public_address'
query_field = User.public_address
elif 'handle' in request.args:
query_str = 'handle'
query_field = User.handle
else:
return jsonify({'success': False})
u = User.query.filter(
query_field == request.args[query_str].lower()
).first()
if u:
nonce = u.nonce
else:
nonce = User().generate_nonce()
return jsonify({
'user_exists': u is not None,
'nonce': nonce,
'query': query_str,
'success': True
})
3 years ago
@bp.route('/update/user', methods=['POST'])
def update_user():
if not current_user.is_authenticated:
return jsonify({
'success': False,
'message': 'Must be authenticated in order to update.'
})
data = request.get_json()
_u = User.query.get(int(data['user_id']))
if _u:
if current_user.id == _u.id:
3 years ago
user_exists = User.query.filter(
User.handle == data['handle']
).first()
if user_exists and not current_user.id == user_exists.id:
return jsonify({
'success': False,
'message': 'That user handle already exists on this server'
})
_u.wownero_address = data['wownero_address']
_u.ipfs_hash = data['ipfs_hash']
_u.handle = data['handle']
db.session.commit()
return jsonify({
'success': True,
'message': 'Updated user record.'
})
else:
return jsonify({
'success': False,
'message': 'Cannot edit another record.'
})
else:
return jsonify({
'success': False,
'message': 'User does not exist.'
})
@bp.route('/authenticate/metamask', methods=['POST'])
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 with a
default handle assigned. If user does exist, they get logged in.
"""
data = request.get_json()
if current_user.is_authenticated:
return jsonify({
'success': False,
'message': 'Already registered and authenticated.'
})
_u = User.query.filter_by(
public_address=data['public_address'].lower()
).first()
if _u:
if data['message'].endswith(_u.nonce):
3 years ago
if verify_signature(data['message'], data['signed_data'], data['public_address']): # noqa
_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:
rand_str = token_urlsafe(6)
user = User(
public_address=data['public_address'].lower()
)
db.session.add(user)
db.session.commit()
user.handle = f'anon{user.id}-{rand_str}'
db.session.commit()
user.login()
return jsonify({
'success': True,
'message': 'Registered'
})