-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Flask Floppy bird API and various bugfixses on sdk
- Loading branch information
Your Name
committed
Aug 2, 2018
1 parent
cb5028c
commit c3accc5
Showing
9 changed files
with
318 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
These are instructions to run the floppy-bird Flask API | ||
Remember this is a example app and is not intended for production use, only to test the mobius python sdk and showcase It's Classes/Functions, | ||
So there's some steps to take before you can run the app. | ||
|
||
1.Create virtualenv with: $ virtualenv -p python3 env | ||
2.Activate env with : $ source env/bin/activate | ||
3.Install requirements from python sdk with : $ pip install -r requirements.txt | ||
4.Export needed vars for the api to work : $ export FLASK_ENV=development | ||
$ export APP_KEY={you're developer keypair} | ||
$ export FLASK_APP={path to api.py} | ||
5.Run the API with (Do this from directory outside the mobius sdk folder): $ python -m flask run | ||
6.Get the challenge and token from API recommended to use some API development tool like Postman or anyother rest client | ||
-Get challenge xdr from : GET http://{API_DOMAIN}/api/ | ||
-Post challenge xdr to get the token: : POST http://{API_DOMAIN}/api/ with {"xdr":"(you're challenge xdr from last step)"} | ||
(I'll leave get_token.py script that does above requests and writes token to token.txt) | ||
-Post token to : POST http://{API_DOMAIN}/api/test?token={you're token} to get public key | ||
7.Go to https://mobius.network/friendbot and add some MOBI coins to you're account | ||
8.Change DAPP_API in flappy-dapp/frontend/public/js/main.js into url of the api (localhost:5000/api in my case) | ||
9.go to http://{APP_DOMAIN}/?token={you're token} and enjoy the game. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
import os | ||
import json | ||
import binascii | ||
import datetime | ||
from functools import wraps | ||
|
||
from flask import Flask | ||
from flask_cors import CORS | ||
from flask import jsonify, abort, request | ||
|
||
from ..mobius_client_python.app.app_builder import AppBuilder | ||
from ..mobius_client_python.auth.challenge import Challenge | ||
from ..mobius_client_python.auth.token import Token | ||
from ..mobius_client_python.auth.jwt import Jwt | ||
from ..mobius_client_python.auth.sign import Sign | ||
from ..mobius_client_python.blockchain.friend_bot import FriendBot # working ! | ||
from ..mobius_client_python.blockchain.add_cosigner import AddCosigner # working | ||
from ..mobius_client_python.blockchain.create_trustline import CreateTrustline # working | ||
from ..mobius_client_python.client import Client # working | ||
|
||
from stellar_base.keypair import Keypair | ||
|
||
from flask_jwt import JWT, jwt_required, current_identity | ||
from werkzeug.security import safe_str_cmp | ||
|
||
# Flask app | ||
app = Flask(__name__) | ||
|
||
# Enable cors | ||
CORS(app) | ||
|
||
app.config['DEBUG'] = True | ||
app.config['APP_KEY'] = os.environ['APP_KEY'] | ||
app_key = app.config['APP_KEY'] | ||
|
||
# Developer | ||
f = FriendBot() | ||
|
||
dev_keypair = Keypair.from_seed(app_key) | ||
dev_created = f.call(dev_keypair) | ||
trust_line_dev = CreateTrustline().call(keypair=dev_keypair) | ||
|
||
class User(object): | ||
def __init__(self, id, username, password): | ||
self.id = id | ||
self.username = username | ||
self.password = password | ||
self.keypair = Keypair.random() | ||
self.address = self.keypair.address().decode() | ||
|
||
# Mobi balance and dev user cosign config | ||
user_created = f.call(self.keypair) | ||
cosig = AddCosigner().call(keypair=self.keypair, cosigner_keypair=dev_keypair) | ||
trust_line_user = CreateTrustline().call(keypair=self.keypair) | ||
|
||
def __str__(self): | ||
return "User(id='%s')" % self.id | ||
|
||
|
||
users = [ | ||
User(1, 'test', 'test'), | ||
User(2, 'mobius', 'mobius'), | ||
User(3, 'crowdbotics', 'crowdbotics'), | ||
] | ||
|
||
username_table = {u.username: u for u in users} | ||
userid_table = {u.id: u for u in users} | ||
|
||
# quick auth handle | ||
def authenticate(username, password): | ||
user = username_table.get(username, None) | ||
if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')): | ||
return user | ||
|
||
def identity(payload): | ||
user_id = payload['identity'] | ||
return userid_table.get(user_id, None) | ||
|
||
def app_instance(user): | ||
app = AppBuilder().build(dev_keypair.seed(),user.address) | ||
|
||
return app | ||
|
||
jwt = JWT(app, authenticate, identity) | ||
|
||
def login_required(f): | ||
@wraps(f) | ||
def decorated_function(*args, **kwargs): | ||
if request.args.get('token') is None: | ||
return abort(403, description='Token missing') | ||
else: | ||
token = request.args.get('token') | ||
jwt = Jwt(secret=app_key) | ||
jwt_token = jwt.decode(value=token) | ||
current_user = None | ||
|
||
for user in users: | ||
if jwt_token['public_key'] == user.address: | ||
current_user = user | ||
|
||
if current_user == None: | ||
return abort(403, description='Token not matched') | ||
|
||
return f(user=current_user, *args, **kwargs) | ||
return decorated_function | ||
|
||
|
||
|
||
@app.route('/api/', methods=['GET','POST']) | ||
def index(): | ||
try: | ||
user = users[0] # test user | ||
|
||
if request.method == 'GET': | ||
|
||
time = datetime.datetime.now() + datetime.timedelta(days=60) | ||
|
||
challenge_te_xdr = Challenge(developer_secret=dev_keypair.seed(), | ||
expires_in=time)\ | ||
.call() | ||
|
||
|
||
te_xdr = Sign(user_secret=user.keypair.seed(),te_xdr=challenge_te_xdr.decode(),address=dev_keypair.address().decode()).call() | ||
|
||
|
||
return jsonify(te_xdr) | ||
|
||
elif request.method == 'POST': | ||
|
||
data = json.loads(request.data.decode('utf-8')) | ||
dapp = app_instance(user) | ||
|
||
|
||
token = Token( | ||
developer_secret=app_key, | ||
te_xdr=data['xdr'], | ||
address=user.keypair.address().decode(), | ||
) | ||
|
||
token.validate() | ||
jwt = Jwt(secret=app_key) | ||
|
||
jwt_token = jwt.encode(token=token) | ||
|
||
return jsonify(jwt_token.decode()) | ||
|
||
except Exception as error: | ||
return error | ||
|
||
@app.route('/api/test', methods=['POST']) | ||
@login_required | ||
def test(user=None): | ||
try: | ||
print(user) | ||
return jsonify(user.address) | ||
except Exception as error: | ||
return error | ||
|
||
@app.route('/api/balance',methods=['GET']) | ||
@login_required | ||
def balance(user=None): | ||
try: | ||
dapp = app_instance(user) | ||
return jsonify({'balance': dapp.user_balance()}) | ||
except Exception as error: | ||
return error | ||
|
||
@app.route('/api/charge',methods=['POST']) | ||
@login_required | ||
def charge(user=None): | ||
try: | ||
dapp = app_instance(user) | ||
|
||
try: | ||
data = json.loads(request.data.decode('utf-8')) | ||
amount = data['amount'] | ||
except: | ||
amount = 1 | ||
|
||
if not amount or not float(amount): | ||
return abort(400, description='Invalid amount') | ||
|
||
response = dapp.charge(amount) | ||
|
||
hash_meta = binascii.hexlify(response.hash_meta()).decode() | ||
|
||
return jsonify({ | ||
'status': 'ok', | ||
'tx_hash': hash_meta, | ||
'balance': dapp.user_balance(), | ||
}) | ||
|
||
except Exception as error: | ||
return error | ||
|
||
@app.route('/api/payout') | ||
@login_required | ||
def payout(user=None): | ||
try: | ||
dapp = app_instance(current_identity) | ||
data = json.loads(request.data.decode('utf-8')) | ||
amount = data['amount'] | ||
target = data['target_address'] | ||
|
||
if not amount or not float(amount): | ||
return abort(400, description='Invalid amount') | ||
|
||
response = dapp.payout(amount,target) | ||
|
||
return jsonify({ | ||
'status': 'ok', | ||
'tx_hash': response.hash_meta(), | ||
'balance': dapp.user_balance(), | ||
}) | ||
|
||
except Exception as error: | ||
return error | ||
|
||
@app.route('/api/transfer') | ||
@login_required | ||
def transfer(user=None): | ||
try: | ||
dapp = app_instance(user) | ||
data = json.loads(request.data.decode('utf-8')) | ||
|
||
amount = data['amount'] | ||
target = data['target_address'] | ||
|
||
if not amount or not float(amount): | ||
return abort(400, description='Invalid amount') | ||
|
||
response = dapp.transfer(amount,target) | ||
|
||
return jsonify({ | ||
'status': 'ok', | ||
'tx_hash': response.hash_meta(), | ||
'balance': response.user_balance(), | ||
}) | ||
|
||
except Exception as error: | ||
return error |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import requests | ||
|
||
base_url = "http://localhost:5000/api/" | ||
|
||
friend_bot_url = "https://mobius.network/friendbot" | ||
|
||
xdr = requests.get(base_url) | ||
|
||
token = requests.post(base_url,json={"xdr":xdr.text}) | ||
token = str(token.text) | ||
|
||
f = open('token.txt', 'w') | ||
|
||
f.write(token) | ||
|
||
f.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.