modify workflow to allow seed restoral

seed-restores
lza_menace 3 years ago
parent a43fae4a1b
commit 13b1b9e1a9

@ -35,7 +35,7 @@ def register():
# Capture event, login user and redirect to wallet page # Capture event, login user and redirect to wallet page
send_es({'type': 'register', 'user': user.email}) send_es({'type': 'register', 'user': user.email})
login_user(user) login_user(user)
return redirect(url_for('wallet.dashboard')) return redirect(url_for('wallet.setup'))
return render_template("auth/register.html", form=form) return render_template("auth/register.html", form=form)

@ -13,12 +13,31 @@ from wowstash.library.docker import docker
from wowstash.library.elasticsearch import send_es from wowstash.library.elasticsearch import send_es
from wowstash.library.jsonrpc import Wallet, to_atomic from wowstash.library.jsonrpc import Wallet, to_atomic
from wowstash.library.cache import cache from wowstash.library.cache import cache
from wowstash.forms import Send, Delete from wowstash.forms import Send, Delete, Restore
from wowstash.factory import db from wowstash.factory import db
from wowstash.models import User from wowstash.models import User
from wowstash import config from wowstash import config
@wallet_bp.route('/wallet/setup', methods=['GET', 'POST'])
@login_required
def setup():
if current_user.wallet_created:
return redirect(url_for('wallet.dashboard'))
restore_form = Restore()
if restore_form.validate_on_submit():
if current_user.wallet_created is False:
docker.create_wallet(current_user.id, restore_form.seed.data)
current_user.wallet_created = True
db.session.commit()
return redirect(url_for('wallet.loading'))
else:
return redirect(url_for('wallet.dashboard'))
return render_template(
'wallet/setup.html',
restore_form=restore_form
)
@wallet_bp.route('/wallet/loading') @wallet_bp.route('/wallet/loading')
@login_required @login_required
def loading(): def loading():

@ -1,6 +1,6 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired from wtforms.validators import DataRequired, ValidationError
class Register(FlaskForm): class Register(FlaskForm):
@ -20,3 +20,10 @@ class Send(FlaskForm):
class Delete(FlaskForm): class Delete(FlaskForm):
confirm = BooleanField('Confirm Account and Wallet Deletion:', validators=[DataRequired()], render_kw={"class": "form-control-span"}) confirm = BooleanField('Confirm Account and Wallet Deletion:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
class Restore(FlaskForm):
seed = StringField('Seed Phrase', validators=[DataRequired()], render_kw={"placeholder": "25 word mnemonic seed phrase", "class": "form-control"})
def validate_seed(self, seed):
if len(self.seed.data.split()) != 25:
raise ValidationError("Invalid seed provided; must be 25 word format")

@ -19,21 +19,36 @@ class Docker(object):
self.wallet_dir = expanduser(getattr(config, 'WALLET_DIR', '~/data/wallets')) self.wallet_dir = expanduser(getattr(config, 'WALLET_DIR', '~/data/wallets'))
self.listen_port = 8888 self.listen_port = 8888
def create_wallet(self, user_id): def create_wallet(self, user_id, seed=None):
u = User.query.get(user_id) u = User.query.get(user_id)
volume_name = self.get_user_volume(u.id) volume_name = self.get_user_volume(u.id)
u.wallet_password = token_urlsafe(12) u.wallet_password = token_urlsafe(12)
db.session.commit() db.session.commit()
command = f"""wownero-wallet-cli \ if seed:
--generate-new-wallet /wallet/{u.id}.wallet \ action = "restore"
--restore-height {daemon.info()['height']} \ command = f"""sh -c "yes '' | wownero-wallet-cli \
--password {u.wallet_password} \ --restore-deterministic-wallet \
--mnemonic-language English \ --generate-new-wallet /wallet/{u.id}.wallet \
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \ --restore-height 0 \
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \ --password {u.wallet_password} \
--log-file /wallet/{u.id}-create.log --daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \
--command version --daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \
""" --electrum-seed '{seed}' \
--log-file /wallet/{u.id}-{action}.log \
--command refresh"
"""
else:
action = "create"
command = f"""wownero-wallet-cli \
--generate-new-wallet /wallet/{u.id}.wallet \
--restore-height {daemon.info()['height']} \
--password {u.wallet_password} \
--mnemonic-language English \
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \
--log-file /wallet/{u.id}-{action}.log \
--command version
"""
if not self.volume_exists(volume_name): if not self.volume_exists(volume_name):
self.client.volumes.create( self.client.volumes.create(
name=volume_name, name=volume_name,
@ -43,7 +58,7 @@ class Docker(object):
self.wownero_image, self.wownero_image,
command=command, command=command,
auto_remove=True, auto_remove=True,
name=f'create_wallet_{u.id}', name=f'{action}_wallet_{u.id}',
remove=True, remove=True,
detach=True, detach=True,
volumes={ volumes={
@ -53,7 +68,7 @@ class Docker(object):
} }
} }
) )
send_es({'type': 'create_wallet', 'user': u.email}) send_es({'type': f'{action}_wallet', 'user': u.email})
return container.short_id return container.short_id
def start_wallet(self, user_id): def start_wallet(self, user_id):

@ -14,7 +14,7 @@
<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 %} {% if current_user.is_authenticated %}
<a href="{{ url_for('wallet.dashboard') }}" class="btn btn-outline btn-xl">{% if current_user.wallet_created %}Wallet Dashboard{% else %}Create Wallet{% endif %}</a> <a href="{{ url_for('wallet.setup') }}" class="btn btn-outline btn-xl">{% if current_user.wallet_created %}Wallet Dashboard{% else %}Setup Wallet{% endif %}</a>
{% else %} {% else %}
<a href="{{ url_for('auth.register') }}" class="btn btn-outline btn-xl">Register</a> <a href="{{ url_for('auth.register') }}" class="btn btn-outline btn-xl">Register</a>
<a href="{{ url_for('auth.login') }}" class="btn btn-outline btn-xl">Login</a> <a href="{{ url_for('auth.login') }}" class="btn btn-outline btn-xl">Login</a>

@ -19,7 +19,7 @@
<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>
{% endif %} {% endif %}
{% if current_user.is_authenticated %} {% 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('wallet.setup') }}">Wallet</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('auth.logout') }}">Logout</a></li> <li class="nav-item"><a class="nav-link" href="{{ url_for('auth.logout') }}">Logout</a></li>
{% else %} {% else %}
<li class="nav-item"><a class="nav-link" href="{{ url_for('auth.login') }}">Login</a></li> <li class="nav-item"><a class="nav-link" href="{{ url_for('auth.login') }}">Login</a></li>

@ -15,7 +15,7 @@
{% else %} {% else %}
<h2>Your wallet is connecting</h2> <h2>Your wallet is connecting</h2>
{% endif %} {% endif %}
<p>Go smoke a fatty. This page should auto-refresh when it's ready...if not, click the button below</p> <p>Go smoke a fatty. This page should auto-refresh when it's ready...if not, click the button below. <br /><br />If you are restoring from a seed, please allow several minutes for the process to complete.</p>
<img src="/static/img/loading-cat.gif" width=300> <img src="/static/img/loading-cat.gif" width=300>
<span class="dashboard-buttons"> <span class="dashboard-buttons">
<div class="col-sm-12 dashboard-button"> <div class="col-sm-12 dashboard-button">

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
{% include 'head.html' %}
<body id="page-top">
{% include 'navbar.html' %}
<section class="section2">
<div class="container">
<div class="section-heading text-center">
<h2>Pick An Option</h2>
<p>Alrighty there hoss, pick an option below...</p>
<a class="btn btn-lg btn-link btn-outline btn-xl" href="{{ url_for('wallet.dashboard') }}">Create new wallet</a>
<hr><br /><br />
<form method="POST" action="{{ url_for('wallet.setup') }}" class="send-form">
{{ restore_form.csrf_token }}
{% for f in restore_form %}
{% if f.name != 'csrf_token' %}
<div class="form-group">
{{ f.label }}
{{ f }}
</div>
{% endif %}
{% endfor %}
<ul>
{% for field, errors in restore_form.errors.items() %}
<li>{{ restore_form[field].label }}: {{ ', '.join(errors) }}</li>
{% endfor %}
</ul>
<input type="submit" value="Restore From Seed" class="btn btn-link btn-outline btn-xl">
</form>
</div>
</div>
</section>
{% include 'footer.html' %}
{% include 'scripts.html' %}
</body>
</html>