mirror of
https://git.wownero.com/lza_menace/wowstash.git
synced 2024-08-15 00:33:15 +00:00
add user wallet deletion
This commit is contained in:
parent
86fd1ecbcc
commit
c379ae9bc9
7 changed files with 72 additions and 21 deletions
|
@ -1,9 +1,8 @@
|
||||||
from os import kill
|
from os import kill
|
||||||
from flask import request, render_template, session, redirect, url_for, flash
|
from flask import request, render_template, session, redirect, url_for, flash
|
||||||
from flask_login import login_user, logout_user, current_user
|
from flask_login import login_user, logout_user, current_user, login_required
|
||||||
from secrets import token_urlsafe
|
|
||||||
from wowstash.blueprints.auth import auth_bp
|
from wowstash.blueprints.auth import auth_bp
|
||||||
from wowstash.forms import Register, Login
|
from wowstash.forms import Register, Login, Delete
|
||||||
from wowstash.models import User
|
from wowstash.models import User
|
||||||
from wowstash.factory import db, bcrypt
|
from wowstash.factory import db, bcrypt
|
||||||
from wowstash.library.docker import docker
|
from wowstash.library.docker import docker
|
||||||
|
@ -28,7 +27,6 @@ def register():
|
||||||
user = User(
|
user = User(
|
||||||
email=form.email.data,
|
email=form.email.data,
|
||||||
password=bcrypt.generate_password_hash(form.password.data).decode('utf8'),
|
password=bcrypt.generate_password_hash(form.password.data).decode('utf8'),
|
||||||
wallet_password=token_urlsafe(16),
|
|
||||||
)
|
)
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -76,6 +74,22 @@ def logout():
|
||||||
docker.stop_container(current_user.wallet_container)
|
docker.stop_container(current_user.wallet_container)
|
||||||
send_es({'type': 'stop_container', 'user': current_user.email})
|
send_es({'type': 'stop_container', 'user': current_user.email})
|
||||||
current_user.clear_wallet_data()
|
current_user.clear_wallet_data()
|
||||||
send_es({'type': 'logout', 'user': current_user.email})
|
send_es({'type': 'logout', 'user': current_user.email})
|
||||||
logout_user()
|
logout_user()
|
||||||
return redirect(url_for('meta.index'))
|
return redirect(url_for('meta.index'))
|
||||||
|
|
||||||
|
@auth_bp.route("/delete", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
def delete():
|
||||||
|
form = Delete()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
docker.stop_container(current_user.wallet_container)
|
||||||
|
send_es({'type': 'stop_container', 'user': current_user.email})
|
||||||
|
docker.delete_wallet_data(current_user.id)
|
||||||
|
send_es({'type': 'delete_wallet', 'user': current_user.email})
|
||||||
|
current_user.clear_wallet_data(reset_password=True, reset_wallet=True)
|
||||||
|
flash('Successfully deleted wallet data')
|
||||||
|
return redirect(url_for('meta.index'))
|
||||||
|
else:
|
||||||
|
flash('Please confirm deletion of the account')
|
||||||
|
return redirect(url_for('wallet.dashboard'))
|
||||||
|
|
|
@ -13,7 +13,7 @@ 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
|
from wowstash.forms import Send, Delete
|
||||||
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
|
||||||
|
@ -31,6 +31,7 @@ def loading():
|
||||||
@login_required
|
@login_required
|
||||||
def dashboard():
|
def dashboard():
|
||||||
send_form = Send()
|
send_form = Send()
|
||||||
|
delete_form = Delete()
|
||||||
_address_qr = BytesIO()
|
_address_qr = BytesIO()
|
||||||
all_transfers = list()
|
all_transfers = list()
|
||||||
wallet = Wallet(
|
wallet = Wallet(
|
||||||
|
@ -67,6 +68,7 @@ def dashboard():
|
||||||
address=address,
|
address=address,
|
||||||
qrcode=qrcode,
|
qrcode=qrcode,
|
||||||
send_form=send_form,
|
send_form=send_form,
|
||||||
|
delete_form=delete_form,
|
||||||
user=current_user,
|
user=current_user,
|
||||||
seed=seed,
|
seed=seed,
|
||||||
spend_key=spend_key,
|
spend_key=spend_key,
|
||||||
|
|
|
@ -17,3 +17,6 @@ class Login(FlaskForm):
|
||||||
class Send(FlaskForm):
|
class Send(FlaskForm):
|
||||||
address = StringField('Destination Address:', validators=[DataRequired()], render_kw={"placeholder": "Wownero address", "class": "form-control"})
|
address = StringField('Destination Address:', validators=[DataRequired()], render_kw={"placeholder": "Wownero address", "class": "form-control"})
|
||||||
amount = StringField('Amount:', validators=[DataRequired()], render_kw={"placeholder": "Amount to send or \"all\"", "class": "form-control"})
|
amount = StringField('Amount:', validators=[DataRequired()], render_kw={"placeholder": "Amount to send or \"all\"", "class": "form-control"})
|
||||||
|
|
||||||
|
class Delete(FlaskForm):
|
||||||
|
confirm = BooleanField('Confirm Account and Wallet Deletion:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
from docker import from_env, APIClient
|
from docker import from_env, APIClient
|
||||||
from docker.errors import NotFound, NullResource, APIError
|
from docker.errors import NotFound, NullResource, APIError
|
||||||
from socket import socket
|
from socket import socket
|
||||||
|
from shutil import rmtree
|
||||||
|
from os.path import expanduser
|
||||||
|
from secrets import token_urlsafe
|
||||||
from wowstash import config
|
from wowstash import config
|
||||||
from wowstash.models import User
|
from wowstash.models import User
|
||||||
|
from wowstash.factory import db
|
||||||
from wowstash.library.jsonrpc import daemon
|
from wowstash.library.jsonrpc import daemon
|
||||||
from wowstash.library.elasticsearch import send_es
|
from wowstash.library.elasticsearch import send_es
|
||||||
|
|
||||||
|
@ -11,11 +15,13 @@ class Docker(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.client = from_env()
|
self.client = from_env()
|
||||||
self.wownero_image = getattr(config, 'WOWNERO_IMAGE', 'lalanza808/wownero')
|
self.wownero_image = getattr(config, 'WOWNERO_IMAGE', 'lalanza808/wownero')
|
||||||
self.wallet_dir = getattr(config, 'WALLET_DIR', '/tmp/wallets')
|
self.wallet_dir = expanduser(getattr(config, 'WALLET_DIR', '~/data/wallets'))
|
||||||
self.listen_port = 34569
|
self.listen_port = 8888
|
||||||
|
|
||||||
def create_wallet(self, user_id):
|
def create_wallet(self, user_id):
|
||||||
u = User.query.get(user_id)
|
u = User.query.get(user_id)
|
||||||
|
u.wallet_password = token_urlsafe(12)
|
||||||
|
db.session.commit()
|
||||||
command = f"""wownero-wallet-cli \
|
command = f"""wownero-wallet-cli \
|
||||||
--generate-new-wallet /wallet/{u.id}.wallet \
|
--generate-new-wallet /wallet/{u.id}.wallet \
|
||||||
--restore-height {daemon.info()['height']} \
|
--restore-height {daemon.info()['height']} \
|
||||||
|
@ -103,6 +109,11 @@ class Docker(object):
|
||||||
c = self.client.containers.get(container_id)
|
c = self.client.containers.get(container_id)
|
||||||
c.stop()
|
c.stop()
|
||||||
|
|
||||||
|
def delete_wallet_data(self, user_id):
|
||||||
|
user_dir = f'{self.wallet_dir}/{user_id}'
|
||||||
|
res = rmtree(user_dir)
|
||||||
|
return res
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
users = User.query.all()
|
users = User.query.all()
|
||||||
for u in users:
|
for u in users:
|
||||||
|
|
|
@ -14,7 +14,7 @@ class User(db.Model):
|
||||||
email = db.Column(db.String(50), unique=True, index=True)
|
email = db.Column(db.String(50), unique=True, index=True)
|
||||||
password = db.Column(db.String(120))
|
password = db.Column(db.String(120))
|
||||||
register_date = db.Column(db.DateTime, server_default=func.now())
|
register_date = db.Column(db.DateTime, server_default=func.now())
|
||||||
wallet_password = db.Column(db.String(120))
|
wallet_password = db.Column(db.String(120), nullable=True)
|
||||||
wallet_created = db.Column(db.Boolean, default=False)
|
wallet_created = db.Column(db.Boolean, default=False)
|
||||||
wallet_connected = db.Column(db.Boolean, default=False)
|
wallet_connected = db.Column(db.Boolean, default=False)
|
||||||
wallet_port = db.Column(db.Integer, nullable=True)
|
wallet_port = db.Column(db.Integer, nullable=True)
|
||||||
|
@ -39,10 +39,14 @@ class User(db.Model):
|
||||||
def get_id(self):
|
def get_id(self):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
def clear_wallet_data(self):
|
def clear_wallet_data(self, reset_password=False, reset_wallet=False):
|
||||||
self.wallet_connected = False
|
self.wallet_connected = False
|
||||||
self.wallet_port = None
|
self.wallet_port = None
|
||||||
self.wallet_container = None
|
self.wallet_container = None
|
||||||
|
if reset_password:
|
||||||
|
self.wallet_password = None
|
||||||
|
if reset_wallet:
|
||||||
|
self.wallet_created = False
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
|
@ -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">Wallet Dashboard</a>
|
<a href="{{ url_for('wallet.dashboard') }}" class="btn btn-outline btn-xl">{% if current_user.wallet_created %}Wallet Dashboard{% else %}Create 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>
|
||||||
|
|
|
@ -69,14 +69,6 @@
|
||||||
<div class="container-slim">
|
<div class="container-slim">
|
||||||
<div class="section-heading text-center">
|
<div class="section-heading text-center">
|
||||||
<h2>Send</h2>
|
<h2>Send</h2>
|
||||||
{% if current_user.funds_locked %}
|
|
||||||
<p>Sending funds is currently locked due to a transfer already in progress. Please try again in a few minutes. Pending transfers:</p>
|
|
||||||
<ul>
|
|
||||||
{% for tx in txs_queued %}
|
|
||||||
<li class="slim small">{{ tx.amount | from_atomic }} - {{ tx.address }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
<form method="POST" action="{{ url_for('wallet.send') }}" class="send-form">
|
<form method="POST" action="{{ url_for('wallet.send') }}" class="send-form">
|
||||||
{{ send_form.csrf_token }}
|
{{ send_form.csrf_token }}
|
||||||
{% for f in send_form %}
|
{% for f in send_form %}
|
||||||
|
@ -94,7 +86,6 @@
|
||||||
</ul>
|
</ul>
|
||||||
<input type="submit" value="Send" class="btn btn-link btn-outline btn-xl">
|
<input type="submit" value="Send" class="btn btn-link btn-outline btn-xl">
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -117,6 +108,32 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="section2" id="send">
|
||||||
|
<div class="container-slim">
|
||||||
|
<div class="section-heading text-center">
|
||||||
|
<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>
|
||||||
|
<form method="POST" action="{{ url_for('auth.delete') }}" class="send-form">
|
||||||
|
{{ delete_form.csrf_token }}
|
||||||
|
{% for f in delete_form %}
|
||||||
|
{% if f.name != 'csrf_token' %}
|
||||||
|
<div class="form-group">
|
||||||
|
{{ f.label }}
|
||||||
|
{{ f }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<ul>
|
||||||
|
{% for field, errors in delete_form.errors.items() %}
|
||||||
|
<li>{{ send_form[field].label }}: {{ ', '.join(errors) }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<input type="submit" value="Delete" class="btn btn-link btn-outline btn-xl">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{% include 'footer.html' %}
|
{% include 'footer.html' %}
|
||||||
|
|
||||||
{% include 'scripts.html' %}
|
{% include 'scripts.html' %}
|
||||||
|
|
Loading…
Reference in a new issue