mirror of
https://git.wownero.com/lza_menace/wowstash.git
synced 2024-08-15 00:33:15 +00:00
introducing auth blueprints, refactoring app init, setting up forms and sqlalchemy, starting user registration process
This commit is contained in:
parent
f245272796
commit
218500c20c
20 changed files with 225 additions and 100 deletions
2
bin/dev
2
bin/dev
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
source .venv/bin/activate
|
||||
export FLASK_APP=wowstash/run.py
|
||||
export FLASK_APP=wowstash/app.py
|
||||
export FLASK_SECRETS=config.py
|
||||
export FLASK_DEBUG=1
|
||||
flask run
|
||||
|
|
|
@ -3,3 +3,6 @@ psycopg2-binary
|
|||
redis
|
||||
flask_session
|
||||
requests
|
||||
Flask-WTF
|
||||
flask_sqlalchemy
|
||||
flask-bcrypt
|
||||
|
|
6
wowstash/app.py
Normal file
6
wowstash/app.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from wowstash.factory import create_app
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = create_app()
|
||||
app.run()
|
|
@ -1,2 +1,3 @@
|
|||
from .account import account_bp
|
||||
from .authentication import authentication_bp
|
||||
from .meta import meta_bp
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
from flask import request, render_template, session
|
||||
from flask import redirect, url_for, current_app
|
||||
from wallet.blueprints.account import account_bp
|
||||
from wallet.library.daemon import daemon
|
||||
from wallet.library.wallet import wallet
|
||||
from wowstash.blueprints.account import account_bp
|
||||
|
||||
|
||||
@account_bp.route("/account")
|
||||
def overview():
|
||||
|
|
|
@ -1,42 +1,25 @@
|
|||
from flask import request, render_template, session, redirect, url_for
|
||||
from wallet.blueprints.authentication import authentication_bp
|
||||
from wallet.library.daemon import daemon
|
||||
from wallet.library.wallet import wallet
|
||||
from monero.seed import Seed
|
||||
from binascii import hexlify
|
||||
from datetime import datetime
|
||||
from os import urandom
|
||||
from wowstash.blueprints.authentication import authentication_bp
|
||||
from wowstash.forms import Register
|
||||
from wowstash.models import User
|
||||
|
||||
|
||||
@authentication_bp.route("/register", methods=["GET", "POST"])
|
||||
def register():
|
||||
form = Register()
|
||||
if form.validate_on_submit():
|
||||
print(dir(User))
|
||||
# user = User.query
|
||||
user = User.objects.filter(email=form.email.data)
|
||||
print(user)
|
||||
return "ok"
|
||||
else:
|
||||
print(form)
|
||||
return render_template("authentication/register.html", form=form)
|
||||
|
||||
@authentication_bp.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
error = None
|
||||
if request.method == "POST":
|
||||
if request.form.get('seed'):
|
||||
try:
|
||||
seed = Seed(str(request.form['seed']))
|
||||
|
||||
session['seed'] = seed.phrase
|
||||
session['start_time'] = datetime.utcnow()
|
||||
session['public_address'] = seed.public_address()
|
||||
session['private_spend_key'] = seed.secret_spend_key()
|
||||
session['public_spend_key'] = seed.public_spend_key()
|
||||
session['private_view_key'] = seed.secret_view_key()
|
||||
session['public_view_key'] = seed.public_view_key()
|
||||
session['wallet_password'] = hexlify(urandom(64))
|
||||
if request.form.get('persistence'):
|
||||
session['wallet_persistence'] = "Enabled"
|
||||
else:
|
||||
session['wallet_persistence'] = "Disabled"
|
||||
return redirect(url_for('account.overview'))
|
||||
except AssertionError:
|
||||
error = "Invalid seed checksum"
|
||||
except Exception as e:
|
||||
error = "Invalid seed {0}".format(e)
|
||||
|
||||
else:
|
||||
error = "Must provide a seed"
|
||||
|
||||
return render_template("login.html", error=error)
|
||||
return render_template("authentication/login.html")
|
||||
|
||||
@authentication_bp.route("/logout")
|
||||
def logout():
|
||||
|
|
5
wowstash/blueprints/meta/__init__.py
Normal file
5
wowstash/blueprints/meta/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from flask import Blueprint
|
||||
|
||||
meta_bp = Blueprint("meta", __name__)
|
||||
|
||||
from . import routes
|
23
wowstash/blueprints/meta/routes.py
Normal file
23
wowstash/blueprints/meta/routes.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from flask import request, render_template, session, redirect, url_for, make_response, jsonify
|
||||
from wowstash.blueprints.meta import meta_bp
|
||||
from wowstash.library.jsonrpc import daemon
|
||||
from wowstash.library.info import info
|
||||
from wowstash.library.db import Database
|
||||
|
||||
|
||||
@meta_bp.route('/')
|
||||
def index():
|
||||
return render_template('index.html', node=daemon.info(), info=info.get_info())
|
||||
|
||||
@meta_bp.route('/health')
|
||||
def health():
|
||||
return make_response(jsonify({
|
||||
'cache': info.redis.ping(),
|
||||
'db': Database().connected
|
||||
}), 200)
|
||||
|
||||
# @app.errorhandler(404)
|
||||
# def not_found(error):
|
||||
# return make_response(jsonify({
|
||||
# 'error': 'Page not found'
|
||||
# }), 404)
|
12
wowstash/cli.py
Normal file
12
wowstash/cli.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def not_found(error):
|
||||
return make_response(jsonify({
|
||||
'error': 'Page not found'
|
||||
}), 404)
|
||||
|
||||
@app.cli.command('initdb')
|
||||
def initdb():
|
||||
from wowstash.models import *
|
||||
db.create_all()
|
61
wowstash/factory.py
Normal file
61
wowstash/factory.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
import wowstash.models
|
||||
from flask import Flask
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_session import Session
|
||||
from flask_bcrypt import Bcrypt
|
||||
from redis import Redis
|
||||
from wowstash.blueprints.authentication import authentication_bp
|
||||
from wowstash.blueprints.account import account_bp
|
||||
from wowstash.blueprints.meta import meta_bp
|
||||
from wowstash import config
|
||||
|
||||
|
||||
app = None
|
||||
db = None
|
||||
bcrypt = None
|
||||
|
||||
def _setup_db(app: Flask):
|
||||
global db
|
||||
uri = 'postgresql+psycopg2://{user}:{pw}@{url}/{db}'.format(
|
||||
user=config.DB_USER,
|
||||
pw=config.DB_PASS,
|
||||
url=config.DB_HOST,
|
||||
db=config.DB_NAME
|
||||
)
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = uri
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
db = SQLAlchemy(app)
|
||||
db.create_all()
|
||||
|
||||
def _setup_session(app: Flask):
|
||||
app.config['SESSION_TYPE'] = 'redis'
|
||||
app.config['SESSION_COOKIE_NAME'] = app.config.get('SESSION_COOKIE_NAME', 'wowstash')
|
||||
app.config['SESSION_REDIS'] = Redis(
|
||||
host=app.config['REDIS_HOST'],
|
||||
port=app.config['REDIS_PORT']
|
||||
)
|
||||
Session(app)
|
||||
|
||||
def _setup_bcrypt(app: Flask):
|
||||
bcrypt = Bcrypt(app)
|
||||
|
||||
def create_app():
|
||||
global app
|
||||
global db
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_envvar('FLASK_SECRETS')
|
||||
app.secret_key = app.config['SECRET_KEY']
|
||||
|
||||
# Setup backends
|
||||
_setup_db(app)
|
||||
_setup_session(app)
|
||||
_setup_bcrypt(app)
|
||||
|
||||
# Routes
|
||||
app.register_blueprint(meta_bp)
|
||||
app.register_blueprint(authentication_bp)
|
||||
app.register_blueprint(account_bp)
|
||||
|
||||
app.app_context().push()
|
||||
return app
|
8
wowstash/forms.py
Normal file
8
wowstash/forms.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
|
||||
class Register(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"})
|
|
@ -68,7 +68,7 @@ class Wallet(object):
|
|||
_account = self.make_wallet_rpc('create_account', {'label': label})
|
||||
return _account['account_index']
|
||||
|
||||
def addresses(self, account, addr_indices=None):
|
||||
def addresses(self, account=0, addr_indices=None):
|
||||
qdata = {'account_index': account}
|
||||
if addr_indices:
|
||||
qdata['address_index'] = addr_indices
|
||||
|
@ -78,12 +78,12 @@ class Wallet(object):
|
|||
addresses[_addr['address_index']] = _addr['address']
|
||||
return addresses
|
||||
|
||||
def new_address(self, account, label=None):
|
||||
def new_address(self, account=0, label=None):
|
||||
data = {'account_index': account, 'label': label}
|
||||
_address = self.make_wallet_rpc('create_address', data)
|
||||
return (_address['address_index'], _address['address'])
|
||||
|
||||
def balances(self, account):
|
||||
def balances(self, account=0):
|
||||
data = {'account_index': account}
|
||||
_balance = self.make_wallet_rpc('get_balance', data)
|
||||
return (from_atomic(_balance['balance']), from_atomic(_balance['unlocked_balance']))
|
||||
|
|
23
wowstash/models.py
Normal file
23
wowstash/models.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from sqlalchemy import Column, Integer, DateTime, String
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.sql import func
|
||||
from flask_bcrypt import generate_password_hash, check_password_hash
|
||||
from wowstash.factory import db
|
||||
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class User(db.Model):
|
||||
__tablename__ = 'users'
|
||||
|
||||
id = db.Column('user_id', db.Integer, primary_key=True)
|
||||
password = db.Column(db.String(120))
|
||||
email = db.Column(db.String(50), unique=True, index=True)
|
||||
subaddress_index = db.Column(db.Integer)
|
||||
registered_on = db.Column(db.DateTime, server_default=func.now())
|
||||
|
||||
def hash_password(self):
|
||||
self.password = generate_password_hash(self.password).decode('utf8')
|
||||
|
||||
def check_password(self, password):
|
||||
return check_password_hash(self.password, password)
|
|
@ -1,51 +0,0 @@
|
|||
from flask import Flask, jsonify, request, make_response, render_template, session, redirect, url_for, escape
|
||||
from flask_session import Session
|
||||
from datetime import timedelta, datetime
|
||||
from redis import Redis
|
||||
from wowstash.library.jsonrpc import daemon
|
||||
from wowstash.library.info import info
|
||||
from wowstash.library.db import Database
|
||||
from wowstash import config
|
||||
# from wowstash.blueprints.account import account_bp
|
||||
# from wowstash.blueprints.authentication import authentication_bp
|
||||
|
||||
# Setup app
|
||||
app = Flask(__name__)
|
||||
app.config.from_envvar('FLASK_SECRETS')
|
||||
app.secret_key = app.config['SECRET_KEY']
|
||||
|
||||
# Setup sessions
|
||||
app.config['SESSION_REDIS'] = Redis(
|
||||
host=app.config['REDIS_HOST'],
|
||||
port=app.config['REDIS_PORT']
|
||||
)
|
||||
sess = Session()
|
||||
sess.init_app(app)
|
||||
|
||||
# app.register_blueprint(account_bp)
|
||||
# app.register_blueprint(authentication_bp)
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('home.html', node=daemon.info(), info=info.get_info())
|
||||
|
||||
@app.route('/health')
|
||||
def health():
|
||||
return make_response(jsonify({
|
||||
'cache': info.redis.ping(),
|
||||
'db': Database().connected
|
||||
}), 200)
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def not_found(error):
|
||||
return make_response(jsonify({
|
||||
'error': 'Page not found'
|
||||
}), 404)
|
||||
|
||||
@app.cli.command('eviscerate')
|
||||
def eviscerate():
|
||||
print('Eviscerate the proletariat')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
|
@ -78,7 +78,6 @@ section h2 {
|
|||
}
|
||||
|
||||
#mainNav .navbar-brand {
|
||||
color: white;
|
||||
font-family: 'Catamaran', 'Helvetica', 'Arial', 'sans-serif';
|
||||
font-weight: 200;
|
||||
letter-spacing: 1px;
|
||||
|
@ -126,7 +125,7 @@ section h2 {
|
|||
background-color: transparent;
|
||||
}
|
||||
#mainNav .navbar-brand {
|
||||
color: fade(white, 70%);
|
||||
color: white;
|
||||
}
|
||||
#mainNav .navbar-brand:hover, #mainNav .navbar-brand:focus {
|
||||
color: white;
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
var navbarCollapse = function() {
|
||||
if ($("#mainNav").offset().top > 100) {
|
||||
$("#mainNav").addClass("navbar-shrink");
|
||||
$("#navbar-brand").addClass("navbar-brand");
|
||||
} else {
|
||||
$("#mainNav").removeClass("navbar-shrink");
|
||||
// $("#navbar-brand").removeClass("navbar-brand");
|
||||
}
|
||||
};
|
||||
// Collapse now if page is not at top
|
||||
|
|
|
@ -27,10 +27,11 @@
|
|||
<br>
|
||||
<span>
|
||||
<button type="submit" class="btn btn-link btn-outline btn-xl">Submit</button>
|
||||
<a href="/new" class="btn btn-outline btn-xl">Create Account</a>
|
||||
</span>
|
||||
</form>
|
||||
|
||||
<hr><br>
|
||||
<p>Need an account? Register below:</p>
|
||||
<a href="{{ url_for('authentication.register') }}" class="btn btn-outline btn-xl">Register</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
44
wowstash/templates/authentication/register.html
Normal file
44
wowstash/templates/authentication/register.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
{% include 'head.html' %}
|
||||
|
||||
<body id="page-top">
|
||||
|
||||
{% include 'navbar.html' %}
|
||||
|
||||
<header class="masthead">
|
||||
<div class="container h-100">
|
||||
<div class="row h-100">
|
||||
<div class="col-lg-12 my-auto">
|
||||
<div class="header-content mx-auto">
|
||||
<form method="POST" action="{{ url_for('authentication.register') }}">
|
||||
{{ form.csrf_token }}
|
||||
<div class="form-group">
|
||||
{{ form.email.label }}
|
||||
{{ form.email }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.password.label }}
|
||||
{{ form.password }}
|
||||
</div>
|
||||
<ul>
|
||||
{% for field, errors in form.errors.items() %}
|
||||
<li>{{ form[field].label }}: {{ ', '.join(errors) }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<input type="submit" value="Register" class="btn btn-link btn-outline btn-xl">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{% include 'footer.html' %}
|
||||
|
||||
{% include 'scripts.html' %}
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -13,8 +13,8 @@
|
|||
<div class="col-lg-7 my-auto">
|
||||
<div class="header-content mx-auto">
|
||||
<h1 class="mb-5">Manage your Wownero funds securely and anonymously.</h1>
|
||||
<a href="/register" class="btn btn-outline btn-xl">Register</a>
|
||||
<a href="/login" class="btn btn-outline btn-xl">Login</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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5 my-auto">
|
|
@ -1,6 +1,6 @@
|
|||
<nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav">
|
||||
<div class="container">
|
||||
<a class="navbar-brand js-scroll-trigger" href="#page-top">{{ config.SITE_NAME }}</a>
|
||||
<a id="navbar-brand" class="navbar-brand js-scroll-trigger" href="#page-top">{{ config.SITE_NAME }}</a>
|
||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||
Menu
|
||||
<i class="fa fa-bars"></i>
|
||||
|
@ -13,6 +13,12 @@
|
|||
<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" href="/login">Login</a></li>
|
||||
{% else %}
|
||||
<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="/#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="/login">Login</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue