mirror of
https://git.wownero.com/lza_menace/wowstash.git
synced 2024-08-15 00:33:15 +00:00
Add seed restore functionality (#2)
minor css adjustment simplify wallet init and enter teh matrix add another check on seed inputs add stronger language around wallet deletion and seed restores add command to manually reset wallet data for a user update connect payload and adjust minor template/js remove debug statements refactor loading javascript, html, and status payload remove unused ref to .map tighten up logic and html template save template updates Merge branch 'master' of git.wownero.com:lza_menace/wowstash into seed-restores modify workflow to allow seed restoral Co-authored-by: lza_menace <lza_menace@protonmail.com> Reviewed-on: https://git.wownero.com/lza_menace/wowstash/pulls/2
This commit is contained in:
parent
3a9c13919d
commit
e8e97c9f1c
15 changed files with 335 additions and 78 deletions
4
bin/cmd
4
bin/cmd
|
@ -3,5 +3,5 @@
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
export FLASK_APP=wowstash/app.py
|
export FLASK_APP=wowstash/app.py
|
||||||
export FLASK_SECRETS=config.py
|
export FLASK_SECRETS=config.py
|
||||||
export FLASK_DEBUG=1
|
export FLASK_DEBUG=0
|
||||||
flask $1
|
flask $@
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ def delete():
|
||||||
send_es({'type': 'delete_wallet', 'user': current_user.email})
|
send_es({'type': 'delete_wallet', 'user': current_user.email})
|
||||||
current_user.clear_wallet_data(reset_password=True, reset_wallet=True)
|
current_user.clear_wallet_data(reset_password=True, reset_wallet=True)
|
||||||
flash('Successfully deleted wallet data')
|
flash('Successfully deleted wallet data')
|
||||||
return redirect(url_for('meta.index'))
|
return redirect(url_for('wallet.setup'))
|
||||||
else:
|
else:
|
||||||
flash('Please confirm deletion of the account')
|
flash('Please confirm deletion of the account')
|
||||||
return redirect(url_for('wallet.dashboard'))
|
return redirect(url_for('wallet.dashboard'))
|
||||||
|
|
|
@ -13,18 +13,38 @@ 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'))
|
||||||
|
else:
|
||||||
|
restore_form = Restore()
|
||||||
|
if restore_form.validate_on_submit():
|
||||||
|
c = docker.create_wallet(current_user.id, restore_form.seed.data)
|
||||||
|
cache.store_data(f'init_wallet_{current_user.id}', 30, c)
|
||||||
|
current_user.wallet_created = True
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('wallet.loading'))
|
||||||
|
else:
|
||||||
|
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():
|
||||||
if current_user.wallet_connected and current_user.wallet_created:
|
if current_user.wallet_connected and current_user.wallet_created:
|
||||||
sleep(1)
|
|
||||||
return redirect(url_for('wallet.dashboard'))
|
return redirect(url_for('wallet.dashboard'))
|
||||||
|
if current_user.wallet_created is False:
|
||||||
|
return redirect(url_for('wallet.setup'))
|
||||||
return render_template('wallet/loading.html')
|
return render_template('wallet/loading.html')
|
||||||
|
|
||||||
@wallet_bp.route('/wallet/dashboard')
|
@wallet_bp.route('/wallet/dashboard')
|
||||||
|
@ -46,6 +66,7 @@ def dashboard():
|
||||||
return redirect(url_for('wallet.loading'))
|
return redirect(url_for('wallet.loading'))
|
||||||
|
|
||||||
if not wallet.connected:
|
if not wallet.connected:
|
||||||
|
sleep(1.5)
|
||||||
return redirect(url_for('wallet.loading'))
|
return redirect(url_for('wallet.loading'))
|
||||||
|
|
||||||
address = wallet.get_address()
|
address = wallet.get_address()
|
||||||
|
@ -79,6 +100,13 @@ def dashboard():
|
||||||
@wallet_bp.route('/wallet/connect')
|
@wallet_bp.route('/wallet/connect')
|
||||||
@login_required
|
@login_required
|
||||||
def connect():
|
def connect():
|
||||||
|
if current_user.wallet_created is False:
|
||||||
|
data = {
|
||||||
|
'result': 'fail',
|
||||||
|
'message': 'Wallet not yet created'
|
||||||
|
}
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
if current_user.wallet_connected is False:
|
if current_user.wallet_connected is False:
|
||||||
wallet = docker.start_wallet(current_user.id)
|
wallet = docker.start_wallet(current_user.id)
|
||||||
port = docker.get_port(wallet)
|
port = docker.get_port(wallet)
|
||||||
|
@ -87,27 +115,42 @@ def connect():
|
||||||
current_user.wallet_container = wallet
|
current_user.wallet_container = wallet
|
||||||
current_user.wallet_start = datetime.utcnow()
|
current_user.wallet_start = datetime.utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
data = {
|
||||||
|
'result': 'success',
|
||||||
|
'message': 'Wallet has been connected'
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
data = {
|
||||||
|
'result': 'fail',
|
||||||
|
'message': 'Wallet is already connected'
|
||||||
|
}
|
||||||
|
|
||||||
return 'ok'
|
return jsonify(data)
|
||||||
|
|
||||||
@wallet_bp.route('/wallet/create')
|
@wallet_bp.route('/wallet/create')
|
||||||
@login_required
|
@login_required
|
||||||
def create():
|
def create():
|
||||||
if current_user.wallet_created is False:
|
if current_user.wallet_created is False:
|
||||||
docker.create_wallet(current_user.id)
|
c = docker.create_wallet(current_user.id)
|
||||||
|
cache.store_data(f'init_wallet_{current_user.id}', 30, c)
|
||||||
current_user.wallet_created = True
|
current_user.wallet_created = True
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
return redirect(url_for('wallet.loading'))
|
||||||
return 'ok'
|
else:
|
||||||
|
return redirect(url_for('wallet.dashboard'))
|
||||||
|
|
||||||
@wallet_bp.route('/wallet/status')
|
@wallet_bp.route('/wallet/status')
|
||||||
@login_required
|
@login_required
|
||||||
def status():
|
def status():
|
||||||
|
user_vol = docker.get_user_volume(current_user.id)
|
||||||
|
create_container = cache.get_data(f'init_wallet_{current_user.id}')
|
||||||
data = {
|
data = {
|
||||||
'created': current_user.wallet_created,
|
'created': current_user.wallet_created,
|
||||||
'connected': current_user.wallet_connected,
|
'connected': current_user.wallet_connected,
|
||||||
'port': current_user.wallet_port,
|
'port': current_user.wallet_port,
|
||||||
'container': current_user.wallet_container
|
'container': current_user.wallet_container,
|
||||||
|
'volume': docker.volume_exists(user_vol),
|
||||||
|
'initializing': docker.container_exists(create_container)
|
||||||
}
|
}
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import click
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_wtf.csrf import CSRFProtect
|
from flask_wtf.csrf import CSRFProtect
|
||||||
|
@ -68,6 +69,14 @@ def create_app():
|
||||||
from wowstash.library.docker import docker
|
from wowstash.library.docker import docker
|
||||||
docker.cleanup()
|
docker.cleanup()
|
||||||
|
|
||||||
|
@app.cli.command('reset_wallet')
|
||||||
|
@click.argument('user_id')
|
||||||
|
def reset_wallet(user_id):
|
||||||
|
from wowstash.models import User
|
||||||
|
user = User.query.get(user_id)
|
||||||
|
user.clear_wallet_data()
|
||||||
|
print(f'Wallet data cleared for user {user.id}')
|
||||||
|
|
||||||
# Routes/blueprints
|
# Routes/blueprints
|
||||||
from wowstash.blueprints.auth import auth_bp
|
from wowstash.blueprints.auth import auth_bp
|
||||||
from wowstash.blueprints.wallet import wallet_bp
|
from wowstash.blueprints.wallet import wallet_bp
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
from re import match as re_match
|
||||||
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 +21,14 @@ 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"})
|
||||||
|
risks_accepted = BooleanField('I accept the risks:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
|
||||||
|
|
||||||
|
def validate_seed(self, seed):
|
||||||
|
regex = '^[\w\s]+$'
|
||||||
|
if bool(re_match(regex, self.seed.data)) is False:
|
||||||
|
raise ValidationError('Invalid seed provided; must be alphanumeric characters only')
|
||||||
|
if len(self.seed.data.split()) != 25:
|
||||||
|
raise ValidationError("Invalid seed provided; must be standard Wownero 25 word format")
|
||||||
|
|
|
@ -17,6 +17,13 @@ class Cache(object):
|
||||||
value=data
|
value=data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_data(self, item_name):
|
||||||
|
data = self.redis.get(item_name)
|
||||||
|
if data:
|
||||||
|
return data.decode()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def get_coin_info(self):
|
def get_coin_info(self):
|
||||||
info = self.redis.get("coin_info")
|
info = self.redis.get("coin_info")
|
||||||
if info:
|
if info:
|
||||||
|
|
|
@ -19,21 +19,34 @@ 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 \
|
command = f"""sh -c "yes '' | wownero-wallet-cli \
|
||||||
--restore-height {daemon.info()['height']} \
|
--restore-deterministic-wallet \
|
||||||
--password {u.wallet_password} \
|
--generate-new-wallet /wallet/{u.id}.wallet \
|
||||||
--mnemonic-language English \
|
--restore-height 0 \
|
||||||
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \
|
--password {u.wallet_password} \
|
||||||
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \
|
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \
|
||||||
--log-file /wallet/{u.id}-create.log
|
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \
|
||||||
--command version
|
--electrum-seed '{seed}' \
|
||||||
"""
|
--log-file /wallet/{u.id}-init.log \
|
||||||
|
--command refresh"
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
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}-init.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 +56,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'init_wallet_{u.id}',
|
||||||
remove=True,
|
remove=True,
|
||||||
detach=True,
|
detach=True,
|
||||||
volumes={
|
volumes={
|
||||||
|
@ -53,7 +66,7 @@ class Docker(object):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
send_es({'type': 'create_wallet', 'user': u.email})
|
send_es({'type': f'init_wallet', 'user': u.email})
|
||||||
return container.short_id
|
return container.short_id
|
||||||
|
|
||||||
def start_wallet(self, user_id):
|
def start_wallet(self, user_id):
|
||||||
|
|
|
@ -552,3 +552,82 @@ ol li {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.teh_matrix {
|
||||||
|
margin: 2em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teh_matrix img.doge {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 40px;
|
||||||
|
|
||||||
|
-webkit-transition: opacity 1s ease-in-out;
|
||||||
|
-moz-transition: opacity 1s ease-in-out;
|
||||||
|
-ms-transition: opacity 1s ease-in-out;
|
||||||
|
-o-transition: opacity 1s ease-in-out;
|
||||||
|
transition: opacity 1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teh_matrix span.centered {
|
||||||
|
opacity: 0;
|
||||||
|
display: none;
|
||||||
|
color: #02ff44;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20px;
|
||||||
|
position: absolute;
|
||||||
|
top: 88px;
|
||||||
|
width: 400px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: monospace;
|
||||||
|
word-break: break-word;
|
||||||
|
margin: 20px;
|
||||||
|
text-shadow: black 1px 1px 0;
|
||||||
|
|
||||||
|
-webkit-transition: opacity 1s ease-in-out;
|
||||||
|
-moz-transition: opacity 1s ease-in-out;
|
||||||
|
-ms-transition: opacity 1s ease-in-out;
|
||||||
|
-o-transition: opacity 1s ease-in-out;
|
||||||
|
transition: opacity 1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teh_matrix span.title {
|
||||||
|
opacity: 0;
|
||||||
|
color: #02ff44;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
position: absolute;
|
||||||
|
top: 28px;
|
||||||
|
left: 100px;
|
||||||
|
width: 300px;
|
||||||
|
font-family: monospace;
|
||||||
|
word-break: break-word;
|
||||||
|
text-shadow: black 1px 1px 0;
|
||||||
|
|
||||||
|
-webkit-transition: opacity 1s ease-in-out;
|
||||||
|
-moz-transition: opacity 1s ease-in-out;
|
||||||
|
-ms-transition: opacity 1s ease-in-out;
|
||||||
|
-o-transition: opacity 1s ease-in-out;
|
||||||
|
transition: opacity 1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teh_matrix span.body {
|
||||||
|
position: absolute;;
|
||||||
|
opacity: 0;
|
||||||
|
color: #02ff44;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
top: 70px;
|
||||||
|
left: 100px;
|
||||||
|
width: 300px;
|
||||||
|
font-family: monospace;
|
||||||
|
word-break: break-word;
|
||||||
|
text-shadow: black 1px 1px 0;
|
||||||
|
|
||||||
|
-webkit-transition: opacity 1s ease-in-out;
|
||||||
|
-moz-transition: opacity 1s ease-in-out;
|
||||||
|
-ms-transition: opacity 1s ease-in-out;
|
||||||
|
-o-transition: opacity 1s ease-in-out;
|
||||||
|
transition: opacity 1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
BIN
wowstash/static/img/loading-doge.png
Normal file
BIN
wowstash/static/img/loading-doge.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 216 KiB |
File diff suppressed because one or more lines are too long
|
@ -14,7 +14,11 @@
|
||||||
<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>
|
{% if current_user.wallet_created %}
|
||||||
|
<a href="{{ url_for('wallet.dashboard') }}" class="btn btn-outline btn-xl">Wallet Dashboard</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for('wallet.setup') }}" class="btn btn-outline btn-xl">Setup Wallet</a>
|
||||||
|
{% endif %}
|
||||||
{% 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>
|
||||||
|
|
|
@ -4,6 +4,80 @@
|
||||||
<script src="/static/js/main.js"></script>
|
<script src="/static/js/main.js"></script>
|
||||||
<script src="/static/js/noty.js"></script>
|
<script src="/static/js/noty.js"></script>
|
||||||
|
|
||||||
|
{% if request.path == '/wallet/loading' %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
function check_status(){
|
||||||
|
fetch('/wallet/status')
|
||||||
|
.then((resp) => resp.json())
|
||||||
|
.then(function(data) {
|
||||||
|
// If we've created a wallet and volume, but not connected a container and are not restoring, attempt connecting
|
||||||
|
if(data['created'] && data['volume'] && data['connected'] == false && data['initializing'] == false){
|
||||||
|
fetch('/wallet/connect')
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all of the above and now the wallet is connected, go to dashboard
|
||||||
|
if(data['created'] && data['volume'] && data['connected']){
|
||||||
|
window.setInterval(function(){
|
||||||
|
window.location.href = "{{ url_for('wallet.dashboard') }}"
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
// Check wallet status every few seconds...
|
||||||
|
window.setInterval(function(){
|
||||||
|
check_status();
|
||||||
|
}, 7000);
|
||||||
|
|
||||||
|
// ...but also check on initial page load
|
||||||
|
check_status();
|
||||||
|
|
||||||
|
// enter teh matrix
|
||||||
|
let q = document.getElementById('q');
|
||||||
|
let width = q.width;
|
||||||
|
let height = q.height;
|
||||||
|
let yPositions = Array(300).join(0).split('');
|
||||||
|
let ctx = q.getContext('2d');
|
||||||
|
|
||||||
|
let draw = function () {
|
||||||
|
ctx.fillStyle = 'rgba(0,0,0,.05)';
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
ctx.fillStyle = '#0F0';
|
||||||
|
ctx.font = '10pt Georgia';
|
||||||
|
yPositions.map(function (y, index) {
|
||||||
|
let text = String.fromCharCode(1e2 + Math.random() * 33);
|
||||||
|
let x = (index * 10) + 10;
|
||||||
|
q.getContext('2d').fillText(text, x, y);
|
||||||
|
if (y > 100 + Math.random() * 1e4) {
|
||||||
|
yPositions[index] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yPositions[index] = y + 10;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let matrix_interval = null;
|
||||||
|
|
||||||
|
function RunMatrix() {
|
||||||
|
matrix_interval = setInterval(draw, 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMatrix();
|
||||||
|
|
||||||
|
$('.teh_matrix span').each(function(i, obj){
|
||||||
|
jQuery(obj).css('opacity', '1');
|
||||||
|
});
|
||||||
|
$('.teh_matrix img').each(function(i, obj){
|
||||||
|
jQuery(obj).css('opacity', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if request.path == '/wallet/dashboard' %}
|
{% if request.path == '/wallet/dashboard' %}
|
||||||
<script type="text/javascript" src="/static/js/zxing.js"></script>
|
<script type="text/javascript" src="/static/js/zxing.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
|
@ -154,6 +154,7 @@
|
||||||
<div class="section-heading text-center">
|
<div class="section-heading text-center">
|
||||||
<h2>Delete Account</h2>
|
<h2>Delete Account</h2>
|
||||||
<p>You can and should delete your wallet from the server. Please ensure you have copied the mnemonic seed from the secrets above if there are still funds associated with the keys.</p>
|
<p>You can and should delete your wallet from the server. Please ensure you have copied the mnemonic seed from the secrets above if there are still funds associated with the keys.</p>
|
||||||
|
<p>I highly recommend making a new wallet on your own and transferring funds there to ensure only you have full ownership and visibility into the private keys / seed. Not your keys, not your crypto!</p>
|
||||||
<form method="POST" action="{{ url_for('auth.delete') }}" class="send-form">
|
<form method="POST" action="{{ url_for('auth.delete') }}" class="send-form">
|
||||||
{{ delete_form.csrf_token }}
|
{{ delete_form.csrf_token }}
|
||||||
{% for f in delete_form %}
|
{% for f in delete_form %}
|
||||||
|
@ -168,7 +169,7 @@
|
||||||
{% for field, errors in delete_form.errors.items() %}
|
{% for field, errors in delete_form.errors.items() %}
|
||||||
<li>{{ send_form[field].label }}: {{ ', '.join(errors) }}</li>
|
<li>{{ send_form[field].label }}: {{ ', '.join(errors) }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<input type="submit" value="Delete" class="btn btn-link btn-outline btn-xl">
|
<input type="submit" value="Delete" class="btn btn-link btn-outline btn-xl">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,67 +5,32 @@
|
||||||
|
|
||||||
<body id="page-top">
|
<body id="page-top">
|
||||||
|
|
||||||
{% include 'navbar.html' %}
|
<section class="section1">
|
||||||
|
|
||||||
<section class="section2">
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="section-heading text-center">
|
<div class="section-heading text-center">
|
||||||
{% if current_user.wallet_created == False %}
|
|
||||||
<h2>Your wallet is being created</h2>
|
|
||||||
{% else %}
|
|
||||||
<h2>Your wallet is connecting</h2>
|
<h2>Your wallet is connecting</h2>
|
||||||
{% endif %}
|
<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>
|
||||||
<p>Go smoke a fatty. This page should auto-refresh when it's ready...if not, click the button below</p>
|
<div class="teh_matrix" style="position: relative;border-radius:4px;width:450px;margin-bottom:32px;border:1px solid green;height:250px;overflow:hidden;background-color:black;">
|
||||||
<img src="/static/img/loading-cat.gif" width=300>
|
<canvas id="q" width="450px" height="250px"></canvas>
|
||||||
|
<span class="centered"></span>
|
||||||
|
<img class="doge" width=80px src="/static/img/loading-doge.png"/>
|
||||||
|
<span class="title">Very Secure Login™</span>
|
||||||
|
<span class="body">
|
||||||
|
☑ many encryptions<br>
|
||||||
|
☑ very password<br>
|
||||||
|
☑ NASA certified<br>
|
||||||
|
☑ such login<br>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<span class="dashboard-buttons">
|
<span class="dashboard-buttons">
|
||||||
<div class="col-sm-12 dashboard-button">
|
<div class="col-sm-12 dashboard-button">
|
||||||
<a class="btn btn-lg btn-link btn-outline btn-xl" href="{{ url_for('wallet.dashboard') }}">Check Again</a>
|
<a class="btn-link" href="{{ url_for('wallet.dashboard') }}">Check Again</a>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
|
||||||
function check_wallet_status(attrib) {
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.onreadystatechange = function() {
|
|
||||||
if (xhr.readyState === 4){
|
|
||||||
let res = JSON.parse(xhr.responseText);
|
|
||||||
if (res[attrib] == true) {
|
|
||||||
window.location.href = "{{ url_for('wallet.dashboard') }}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.open('GET', '{{ url_for("wallet.status") }}');
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
{% if current_user.wallet_connected == False and current_user.wallet_created == True %}
|
|
||||||
document.addEventListener("DOMContentLoaded", function(){
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.open('GET', '{{ url_for("wallet.connect") }}');
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if current_user.wallet_connected == False and current_user.wallet_created == False %}
|
|
||||||
document.addEventListener("DOMContentLoaded", function(){
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.open('GET', '{{ url_for("wallet.create") }}');
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
window.setInterval(function(){
|
|
||||||
{% if current_user.wallet_connected == False and current_user.wallet_created == True %}
|
|
||||||
check_wallet_status('connected');
|
|
||||||
{% else %}
|
|
||||||
check_wallet_status('created');
|
|
||||||
{% endif %}
|
|
||||||
}, 6000);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% include 'footer.html' %}
|
{% include 'footer.html' %}
|
||||||
|
|
||||||
{% include 'scripts.html' %}
|
{% include 'scripts.html' %}
|
||||||
|
|
51
wowstash/templates/wallet/setup.html
Normal file
51
wowstash/templates/wallet/setup.html
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<!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>Setup Wallet</h2>
|
||||||
|
<p>Alrighty there hoss, pick an option below...</p>
|
||||||
|
|
||||||
|
<hr><br /><br />
|
||||||
|
|
||||||
|
<a class="btn btn-lg btn-link btn-outline btn-xl" href="{{ url_for('wallet.create') }}">Create new wallet</a>
|
||||||
|
|
||||||
|
<hr><br /><br />
|
||||||
|
|
||||||
|
<form method="POST" action="{{ url_for('wallet.setup') }}" class="send-form">
|
||||||
|
<p><strong>! WARNING !</strong><br /> If you input a mnemonic seed here I could theoretically steal your funds, even without a wallet on my server; so could a hacker if they compromised my server.</p>
|
||||||
|
<p>You <strong>can</strong> and <strong>should</strong> use a <a href="https://wownero.org/#wallets" target="_blank">wallet</a> you can run locally to ensure your funds are safe, especially if there is a lot there. Proceed at your own risk.</p>
|
||||||
|
{{ 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>
|
Loading…
Reference in a new issue