implement registration, login, starting wallet dashboard

mm-logging
lza_menace 4 years ago
parent 561d0155f3
commit 59ea26b8f1

@ -6,3 +6,4 @@ requests
Flask-WTF Flask-WTF
flask_sqlalchemy flask_sqlalchemy
flask-bcrypt flask-bcrypt
flask-login

@ -1,3 +1,3 @@
from .account import account_bp from .wallet import wallet_bp
from .authentication import authentication_bp from .authentication import authentication_bp
from .meta import meta_bp from .meta import meta_bp

@ -1,28 +0,0 @@
from flask import request, render_template, session
from flask import redirect, url_for, current_app
from wowstash.blueprints.account import account_bp
@account_bp.route("/account")
def overview():
if session.get("public_address"):
return render_template("account.html",
session_data=session,
h=daemon.get_height(),
wallet=wallet)
else:
return redirect(url_for("index"))
@account_bp.route("/account/wallet")
def connect_wallet():
if session.get("public_address"):
wallet.init(host=current_app.config['DAEMON_HOST'],
port=current_app.config['DAEMON_PORT'],
public_view_key=session['public_view_key'],
wallet_password=session['wallet_password'],
mnemonic_seed=session['seed'],
restore_height=daemon.get_height(),
path=current_app.config['BINARY_PATH'])
return redirect(url_for("account.overview"))
else:
return redirect(url_for("index"))

@ -1,27 +1,79 @@
from flask import request, render_template, session, redirect, url_for from flask import request, render_template, session, redirect, url_for, flash
from flask_login import login_user, logout_user, current_user
from wowstash.blueprints.authentication import authentication_bp from wowstash.blueprints.authentication import authentication_bp
from wowstash.forms import Register from wowstash.forms import Register, Login
from wowstash.models import User from wowstash.models import User
from wowstash.library.jsonrpc import wallet
from wowstash.factory import db, bcrypt
@authentication_bp.route("/register", methods=["GET", "POST"]) @authentication_bp.route("/register", methods=["GET", "POST"])
def register(): def register():
form = Register() form = Register()
if current_user.is_authenticated:
flash('Already registered and authenticated.')
return redirect(url_for('wallet.dashboard'))
if form.validate_on_submit(): if form.validate_on_submit():
print(dir(User)) # Check if Wownero wallet is available
# user = User.query if wallet.connected is False:
user = User.objects.filter(email=form.email.data) flash('Wallet RPC interface is unavailable at this time. Try again later.')
print(user) return redirect(url_for('authentication.register'))
return "ok"
else: # Check if email already exists
print(form) user = User.query.filter_by(email=form.email.data).first()
if user:
flash('This email is already registered.')
return redirect(url_for('authentication.login'))
# Create new subaddress
subaddress = wallet.new_address(label=form.email.data)
# Save new user
user = User(
email=form.email.data,
password=bcrypt.generate_password_hash(form.password.data).decode('utf8'),
subaddress_index=subaddress[0]
)
db.session.add(user)
db.session.commit()
# Login user and redirect to wallet page
login_user(user)
return redirect(url_for('wallet.dashboard'))
return render_template("authentication/register.html", form=form) return render_template("authentication/register.html", form=form)
@authentication_bp.route("/login", methods=["GET", "POST"]) @authentication_bp.route("/login", methods=["GET", "POST"])
def login(): def login():
return render_template("authentication/login.html") form = Login()
if current_user.is_authenticated:
flash('Already registered and authenticated.')
return redirect(url_for('wallet.dashboard'))
if form.validate_on_submit():
# Check if user doesn't exist
user = User.query.filter_by(email=form.email.data).first()
if not user:
flash('Invalid username or password.')
return redirect(url_for('authentication.login'))
# Check if password is correct
password_matches = bcrypt.check_password_hash(
user.password,
form.password.data
)
if not password_matches:
flash('Invalid username or password.')
return redirect(url_for('authentication.login'))
# Login user and redirect to wallet page
login_user(user)
return redirect(url_for('wallet.dashboard'))
return render_template("authentication/login.html", form=form)
@authentication_bp.route("/logout") @authentication_bp.route("/logout")
def logout(): def logout():
session.clear() logout_user()
return redirect(url_for('index')) return redirect(url_for('meta.index'))

@ -1,5 +1,5 @@
from flask import Blueprint from flask import Blueprint
account_bp = Blueprint("account", __name__) wallet_bp = Blueprint("wallet", __name__)
from . import routes from . import routes

@ -0,0 +1,21 @@
from flask import request, render_template, session, redirect, url_for, current_app
from flask_login import login_required, current_user
from wowstash.blueprints.wallet import wallet_bp
from wowstash.library.jsonrpc import wallet, daemon
from wowstash.factory import login_manager
from wowstash.models import User
@wallet_bp.route("/wallet/dashboard")
@login_required
def dashboard():
user = User.query.get(current_user.id)
wallet_height = wallet.height()['height']
daemon_height = daemon.height()['height']
subaddress = wallet.get_address(0, user.subaddress_index)['addresses'][0]['address']
return render_template(
"account/dashboard.html",
wallet_height=wallet_height,
daemon=daemon_height,
subaddress=subaddress
)

@ -11,7 +11,7 @@ DAEMON_PASS = ''
# Wallet # Wallet
WALLET_PROTO = 'http' WALLET_PROTO = 'http'
WALLET_HOST = 'localhost' WALLET_HOST = 'localhost'
WALLET_PORT = 8888 WALLET_PORT = 9999
WALLET_USER = 'yyyyy' WALLET_USER = 'yyyyy'
WALLET_PASS = 'xxxxx' WALLET_PASS = 'xxxxx'

@ -2,6 +2,7 @@ from flask import Flask
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_session import Session from flask_session import Session
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from redis import Redis from redis import Redis
from wowstash import config from wowstash import config
@ -40,6 +41,8 @@ def _setup_bcrypt(app: Flask):
def create_app(): def create_app():
global app global app
global db global db
global bcrypt
global login_manager
app = Flask(__name__) app = Flask(__name__)
app.config.from_envvar('FLASK_SECRETS') app.config.from_envvar('FLASK_SECRETS')
app.secret_key = app.config['SECRET_KEY'] app.secret_key = app.config['SECRET_KEY']
@ -49,13 +52,22 @@ def create_app():
_setup_session(app) _setup_session(app)
_setup_bcrypt(app) _setup_bcrypt(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'authentication.login'
@login_manager.user_loader
def load_user(user_id):
from wowstash.models import User
return User.query.get(user_id)
# Routes # Routes
from wowstash.blueprints.authentication import authentication_bp from wowstash.blueprints.authentication import authentication_bp
from wowstash.blueprints.account import account_bp from wowstash.blueprints.wallet import wallet_bp
from wowstash.blueprints.meta import meta_bp from wowstash.blueprints.meta import meta_bp
app.register_blueprint(meta_bp) app.register_blueprint(meta_bp)
app.register_blueprint(authentication_bp) app.register_blueprint(authentication_bp)
app.register_blueprint(account_bp) app.register_blueprint(wallet_bp)
app.app_context().push() app.app_context().push()
return app return app

@ -1,8 +1,15 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired from wtforms.validators import DataRequired
class Register(FlaskForm): class Register(FlaskForm):
email = StringField('Email Address:', validators=[DataRequired()], render_kw={"placeholder": "Email", "class": "form-control", "type": "email"}) email = StringField('Email Address:', validators=[DataRequired()], render_kw={"placeholder": "Email", "class": "form-control", "type": "email"})
password = StringField('Password:', validators=[DataRequired()], render_kw={"placeholder": "Password", "class": "form-control", "type": "password"}) password = StringField('Password:', validators=[DataRequired()], render_kw={"placeholder": "Password", "class": "form-control", "type": "password"})
faq_reviewed = BooleanField('FAQ Reviewed:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
terms_reviewed = BooleanField('Terms Reviewed:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
privacy_reviewed = BooleanField('Privacy Policy Reviewed:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
class Login(FlaskForm):
email = StringField('Email Address:', validators=[DataRequired()], render_kw={"placeholder": "Email", "class": "form-control", "type": "email"})
password = StringField('Password:', validators=[DataRequired()], render_kw={"placeholder": "Password", "class": "form-control", "type": "password"})

@ -1,7 +1,9 @@
import json import json
import requests import requests
import operator
from wowstash import config from wowstash import config
class JSONRPC(object): class JSONRPC(object):
def __init__(self, proto, host, port, username='', password=''): def __init__(self, proto, host, port, username='', password=''):
self.endpoint = '{}://{}:{}/'.format( self.endpoint = '{}://{}:{}/'.format(
@ -32,11 +34,32 @@ class JSONRPC(object):
except: except:
return {} return {}
class Wallet(JSONRPC): class Wallet(JSONRPC):
def __init__(self, **kwargs):
super().__init__(**kwargs)
if 'height' in self.height():
self.connected = True
else:
self.connected = False
def height(self): def height(self):
return self.make_rpc('get_height', {}) return self.make_rpc('get_height', {})
def new_address(self, account_index=0, label=None):
data = {'account_index': account_index, 'label': label}
_address = self.make_rpc('create_address', data)
return (_address['address_index'], _address['address'])
def get_address(self, account_index, subaddress_index):
data = {'account_index': account_index, 'address_index': [subaddress_index]}
return self.make_rpc('get_address', data)
class Daemon(JSONRPC): class Daemon(JSONRPC):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def info(self): def info(self):
return self.make_rpc('get_info', {}, json_rpc=False) return self.make_rpc('get_info', {}, json_rpc=False)
@ -44,4 +67,18 @@ class Daemon(JSONRPC):
return self.make_rpc('get_height', {}, json_rpc=False) return self.make_rpc('get_height', {}, json_rpc=False)
daemon = Daemon(proto=config.DAEMON_PROTO, host=config.DAEMON_HOST, port=config.DAEMON_PORT) daemon = Daemon(
proto=config.DAEMON_PROTO,
host=config.DAEMON_HOST,
port=config.DAEMON_PORT,
username=config.DAEMON_USER,
password=config.DAEMON_PASS
)
wallet = Wallet(
proto=config.WALLET_PROTO,
host=config.WALLET_HOST,
port=config.WALLET_PORT,
username=config.WALLET_USER,
password=config.WALLET_PASS
)

@ -1,7 +1,6 @@
from sqlalchemy import Column, Integer, DateTime, String from sqlalchemy import Column, Integer, DateTime, String
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import func from sqlalchemy.sql import func
from flask_bcrypt import generate_password_hash, check_password_hash
from wowstash.factory import db from wowstash.factory import db
@ -16,8 +15,24 @@ class User(db.Model):
subaddress_index = db.Column(db.Integer) subaddress_index = db.Column(db.Integer)
registered_on = db.Column(db.DateTime, server_default=func.now()) registered_on = db.Column(db.DateTime, server_default=func.now())
def hash_password(self): @property
self.password = generate_password_hash(self.password).decode('utf8') def is_authenticated(self):
return True
def check_password(self, password): @property
return check_password_hash(self.password, password) def is_active(self):
return True
@property
def is_anonymous(self):
return False
@property
def is_admin(self):
return self.admin
def get_id(self):
return self.id
def __repr__(self):
return self.username

@ -7,21 +7,30 @@
{% include 'navbar.html' %} {% include 'navbar.html' %}
<header class="masthead"> <!-- Height ({{ daemon_height }} / {{ wallet_height }})
Transactions - Send - Receive
Your Address
Transaction History
Balance: -->
<!-- <header class="masthead">
<div class="container h-100"> <div class="container h-100">
<div class="row h-100"> <div class="row h-100">
<div class="col-lg-4 my-auto"> <div class="col-lg-4 my-auto">
<div class="header-content mx-auto"> <div class="header-content mx-auto">
<h1 class="mb-5">Welcome Back</h1> <h2 class="mb-5">Welcome Back {{ current_user.email }}</h2>
<h3 class="sm">Account Address</h3> <h3 class="sm">Account Address</h3>
<p class="small">{{ session_data.public_address }}</p> <p class="small">address</p>
<h3 class="sm">Wallet Persistence</h3> <h3 class="sm">Wallet Persistence</h3>
<p class="small">{{ session_data.wallet_persistence }}</p> {% if wallet %}
{% if wallet.connected %}
<h3 class="sm">Account Balance</h3> <h3 class="sm">Account Balance</h3>
<p class="small">{{ h }}</p> <p class="small">{{ h }}</p>
<h3 class="sm">Wallet File</h3> <h3 class="sm">Wallet File</h3>
<p class="small">{{ config.WALLET_PATH }}/{{ session_data.wallet_path }}</p> <p class="small">{{ config.WALLET_PATH }}</p>
{% else %} {% else %}
<h3 class="sm">Wallet Status</h3> <h3 class="sm">Wallet Status</h3>
<p class="small">Not Connected</p> <p class="small">Not Connected</p>
@ -30,20 +39,40 @@
<a href="/account/wallet/" class="btn btn-outline btn-xl">Connect Wallet</a> <a href="/account/wallet/" class="btn btn-outline btn-xl">Connect Wallet</a>
</div> </div>
</div> </div>
<!-- <div class="col-lg-6 my-auto"> <div class="col-lg-6 my-auto">
<div class="header-content mx-auto"> <div class="header-content mx-auto">
<h1 class="mb-5">Logs</h1> <h1 class="mb-5">Logs</h1>
<h3 class="sm">Transaction Log</h3> <h3 class="sm">Transaction Log</h3>
<p class="small">{{ session_data.public_address }}</p> <p class="small">asd</p>
<p class="small">{{ session_data.public_address }}</p> </div>
<p class="small">{{ session_data.public_address }}</p> </div>
<p class="small">{{ session_data.public_address }}</p>
<p class="small">{{ session_data.public_address }}</p>
</div> </div>
</div>
</header> -->
<section class="section2" id="">
<div class="container">
<!-- <div class="section-heading text-center">
<h2>Welcome</h2>
<p>Prices and network information</p>
<hr>
</div> --> </div> -->
<div class="row fp-row">
<div class="col-lg-4">
<a class="btn btn-lg btn-link btn-outline btn-xl" href="#">Transactions</a>
</div>
<div class="col-lg-4">
<a class="btn btn-lg btn-link btn-outline btn-xl" href="#">Send</a>
</div>
<div class="col-lg-4">
<a class="btn btn-lg btn-link btn-outline btn-xl" href="#">Receive</a>
</div>
</div>
<div class="row fp-row">
<p>Your address: {{ subaddress }}</p>
</div> </div>
</div> </div>
</header> </section>
<!-- <section class="section1" id="seed"> <!-- <section class="section1" id="seed">
<div class="container"> <div class="container">

@ -12,26 +12,26 @@
<div class="row h-100"> <div class="row h-100">
<div class="col-lg-12 my-auto"> <div class="col-lg-12 my-auto">
<div class="header-content mx-auto"> <div class="header-content mx-auto">
<form method="post" action="/login"> <form method="POST" action="{{ url_for('authentication.login') }}">
{{ form.csrf_token }}
{% for f in form %}
{% if f.name != 'csrf_token' %}
<div class="form-group"> <div class="form-group">
<label for="seed">Account Seed</label> {{ f.label }}
<input type="text" class="form-control" name="seed" placeholder="Enter account seed"> {{ f }}
</div> </div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="persistence">
<label class="form-check-label" for="persistence">Wallet Persistence</label>
</div>
{% if error %}
<p>{{ error }}</p>
{% endif %} {% endif %}
<br> {% endfor %}
<span> <ul>
<button type="submit" class="btn btn-link btn-outline btn-xl">Submit</button> {% for field, errors in form.errors.items() %}
</span> <li>{{ form[field].label }}: {{ ', '.join(errors) }}</li>
{% endfor %}
</ul>
<input type="submit" value="Login" class="btn btn-link btn-outline btn-xl">
</form> </form>
<hr><br> <hr>
<p>Need an account? Register below:</p> <p class="small">Click <a href="{{ url_for('authentication.register') }}" class="">here</a> if you need to register.</p>
<a href="{{ url_for('authentication.register') }}" class="btn btn-outline btn-xl">Register</a>
</div> </div>
</div> </div>
</div> </div>

@ -13,8 +13,12 @@
<div class="col-lg-7 my-auto"> <div class="col-lg-7 my-auto">
<div class="header-content mx-auto"> <div class="header-content mx-auto">
<h1 class="mb-5">Manage your Wownero funds securely and anonymously.</h1> <h1 class="mb-5">Manage your Wownero funds securely and anonymously.</h1>
{% if current_user.is_authenticated %}
<a href="{{ url_for('wallet.dashboard') }}" class="btn btn-outline btn-xl">Wallet Dashboard</a>
{% else %}
<a href="{{ url_for('authentication.register') }}" class="btn btn-outline btn-xl">Register</a> <a href="{{ url_for('authentication.register') }}" class="btn btn-outline btn-xl">Register</a>
<a href="{{ url_for('authentication.login') }}" class="btn btn-outline btn-xl">Login</a> <a href="{{ url_for('authentication.login') }}" class="btn btn-outline btn-xl">Login</a>
{% endif %}
</div> </div>
</div> </div>
<div class="col-lg-5 my-auto"> <div class="col-lg-5 my-auto">

@ -12,13 +12,17 @@
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#about">About</a></li> <li class="nav-item"><a class="nav-link js-scroll-trigger" href="#about">About</a></li>
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#statistics">Statistics</a></li> <li class="nav-item"><a class="nav-link js-scroll-trigger" href="#statistics">Statistics</a></li>
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#contact">Contact</a></li> <li class="nav-item"><a class="nav-link js-scroll-trigger" href="#contact">Contact</a></li>
<li class="nav-item"><a class="nav-link" href="/login">Login</a></li>
{% else %} {% else %}
<li class="nav-item"><a class="nav-link" href="/">Home</a></li> <li class="nav-item"><a class="nav-link" href="/">Home</a></li>
<li class="nav-item"><a class="nav-link" href="/#about">About</a></li> <li class="nav-item"><a class="nav-link" href="/#about">About</a></li>
<li class="nav-item"><a class="nav-link" href="/#statistics">Statistics</a></li> <li class="nav-item"><a class="nav-link" href="/#statistics">Statistics</a></li>
<li class="nav-item"><a class="nav-link" href="/#contact">Contact</a></li> <li class="nav-item"><a class="nav-link" href="/#contact">Contact</a></li>
<li class="nav-item"><a class="nav-link" href="/login">Login</a></li> {% endif %}
{% if current_user.is_authenticated %}
<li class="nav-item"><a class="nav-link" href="{{ url_for('wallet.dashboard') }}">Wallet</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('authentication.logout') }}">Logout</a></li>
{% else %}
<li class="nav-item"><a class="nav-link" href="{{ url_for('authentication.login') }}">Login</a></li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>

Loading…
Cancel
Save