diff --git a/wowstash/blueprints/auth/routes.py b/wowstash/blueprints/auth/routes.py index bd8f409..df7b2af 100644 --- a/wowstash/blueprints/auth/routes.py +++ b/wowstash/blueprints/auth/routes.py @@ -1,9 +1,8 @@ from os import kill from flask import request, render_template, session, redirect, url_for, flash -from flask_login import login_user, logout_user, current_user -from secrets import token_urlsafe +from flask_login import login_user, logout_user, current_user, login_required 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.factory import db, bcrypt from wowstash.library.docker import docker @@ -28,7 +27,6 @@ def register(): user = User( email=form.email.data, password=bcrypt.generate_password_hash(form.password.data).decode('utf8'), - wallet_password=token_urlsafe(16), ) db.session.add(user) db.session.commit() @@ -76,6 +74,22 @@ def logout(): docker.stop_container(current_user.wallet_container) send_es({'type': 'stop_container', 'user': current_user.email}) current_user.clear_wallet_data() - send_es({'type': 'logout', 'user': current_user.email}) - logout_user() + send_es({'type': 'logout', 'user': current_user.email}) + logout_user() 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')) diff --git a/wowstash/blueprints/wallet/routes.py b/wowstash/blueprints/wallet/routes.py index 8d1fc36..ed3c1a8 100644 --- a/wowstash/blueprints/wallet/routes.py +++ b/wowstash/blueprints/wallet/routes.py @@ -13,7 +13,7 @@ from wowstash.library.docker import docker from wowstash.library.elasticsearch import send_es from wowstash.library.jsonrpc import Wallet, to_atomic from wowstash.library.cache import cache -from wowstash.forms import Send +from wowstash.forms import Send, Delete from wowstash.factory import db from wowstash.models import User from wowstash import config @@ -31,6 +31,7 @@ def loading(): @login_required def dashboard(): send_form = Send() + delete_form = Delete() _address_qr = BytesIO() all_transfers = list() wallet = Wallet( @@ -67,6 +68,7 @@ def dashboard(): address=address, qrcode=qrcode, send_form=send_form, + delete_form=delete_form, user=current_user, seed=seed, spend_key=spend_key, diff --git a/wowstash/forms.py b/wowstash/forms.py index 0765bd6..65578fa 100644 --- a/wowstash/forms.py +++ b/wowstash/forms.py @@ -17,3 +17,6 @@ class Login(FlaskForm): class Send(FlaskForm): 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"}) + +class Delete(FlaskForm): + confirm = BooleanField('Confirm Account and Wallet Deletion:', validators=[DataRequired()], render_kw={"class": "form-control-span"}) diff --git a/wowstash/library/docker.py b/wowstash/library/docker.py index a7c5694..fbaaacc 100644 --- a/wowstash/library/docker.py +++ b/wowstash/library/docker.py @@ -1,8 +1,12 @@ from docker import from_env, APIClient from docker.errors import NotFound, NullResource, APIError from socket import socket +from shutil import rmtree +from os.path import expanduser +from secrets import token_urlsafe from wowstash import config from wowstash.models import User +from wowstash.factory import db from wowstash.library.jsonrpc import daemon from wowstash.library.elasticsearch import send_es @@ -11,11 +15,13 @@ class Docker(object): def __init__(self): self.client = from_env() self.wownero_image = getattr(config, 'WOWNERO_IMAGE', 'lalanza808/wownero') - self.wallet_dir = getattr(config, 'WALLET_DIR', '/tmp/wallets') - self.listen_port = 34569 + self.wallet_dir = expanduser(getattr(config, 'WALLET_DIR', '~/data/wallets')) + self.listen_port = 8888 def create_wallet(self, user_id): u = User.query.get(user_id) + u.wallet_password = token_urlsafe(12) + db.session.commit() command = f"""wownero-wallet-cli \ --generate-new-wallet /wallet/{u.id}.wallet \ --restore-height {daemon.info()['height']} \ @@ -103,6 +109,11 @@ class Docker(object): c = self.client.containers.get(container_id) 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): users = User.query.all() for u in users: diff --git a/wowstash/models.py b/wowstash/models.py index 7c3c9af..ac634b8 100644 --- a/wowstash/models.py +++ b/wowstash/models.py @@ -14,7 +14,7 @@ class User(db.Model): email = db.Column(db.String(50), unique=True, index=True) password = db.Column(db.String(120)) 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_connected = db.Column(db.Boolean, default=False) wallet_port = db.Column(db.Integer, nullable=True) @@ -39,10 +39,14 @@ class User(db.Model): def get_id(self): 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_port = None self.wallet_container = None + if reset_password: + self.wallet_password = None + if reset_wallet: + self.wallet_created = False db.session.commit() def __repr__(self): diff --git a/wowstash/templates/meta/index.html b/wowstash/templates/meta/index.html index 8c227bd..edb0f2b 100644 --- a/wowstash/templates/meta/index.html +++ b/wowstash/templates/meta/index.html @@ -14,7 +14,7 @@

Manage your Wownero funds securely and anonymously.

{% if current_user.is_authenticated %} - Wallet Dashboard + {% if current_user.wallet_created %}Wallet Dashboard{% else %}Create Wallet{% endif %} {% else %} Register Login diff --git a/wowstash/templates/wallet/dashboard.html b/wowstash/templates/wallet/dashboard.html index 4db0235..74e1f91 100644 --- a/wowstash/templates/wallet/dashboard.html +++ b/wowstash/templates/wallet/dashboard.html @@ -69,14 +69,6 @@

Send

- {% if current_user.funds_locked %} -

Sending funds is currently locked due to a transfer already in progress. Please try again in a few minutes. Pending transfers:

-
    - {% for tx in txs_queued %} -
  • {{ tx.amount | from_atomic }} - {{ tx.address }}
  • - {% endfor %} -
- {% else %}
{{ send_form.csrf_token }} {% for f in send_form %} @@ -94,7 +86,6 @@
- {% endif %}
@@ -117,6 +108,32 @@
+
+
+
+

Delete Account

+

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.

+
+ {{ delete_form.csrf_token }} + {% for f in delete_form %} + {% if f.name != 'csrf_token' %} +
+ {{ f.label }} + {{ f }} +
+ {% endif %} + {% endfor %} +
    + {% for field, errors in delete_form.errors.items() %} +
  • {{ send_form[field].label }}: {{ ', '.join(errors) }}
  • + {% endfor %} +
+ +
+
+
+
+ {% include 'footer.html' %} {% include 'scripts.html' %}