Compare commits

..

7 Commits

@ -10,16 +10,15 @@ export FLASK_ENV=production
mkdir -p $BASE
kill $(cat $BASE/gunicorn.pid) 2>&1
pgrep -F $BASE/gunicorn.pid
gunicorn \
if [[ $? != 0 ]]; then
gunicorn \
--bind 127.0.0.1:4001 "wowstash.app:app" \
--daemon \
--log-file $BASE/gunicorn.log \
--pid $BASE/gunicorn.pid \
--access-logfile $BASE/access.log \
--reload
sleep 1
echo "Starting gunicorn with pid $(cat $BASE/gunicorn.pid)"
sleep 1
echo "Starting gunicorn with pid $(cat $BASE/gunicorn.pid)"
fi

@ -4,8 +4,14 @@ from wowstash.library.jsonrpc import daemon
from wowstash.library.cache import cache
from wowstash.library.db import Database
from wowstash.library.docker import Docker
from wowstash.library.helpers import post_discord_webhook
@meta_bp.errorhandler(500)
def internal_error(error):
post_discord_webhook(f'500 error: {error.original_exception}')
return render_template('meta/500.html', error=error)
@meta_bp.route('/')
def index():
return render_template('meta/index.html', node=daemon.info(), info=cache.get_coin_info())
@ -30,8 +36,6 @@ def health():
'docker': Docker().client.ping()
}), 200)
# @app.errorhandler(404)
# def not_found(error):
# return make_response(jsonify({
# 'error': 'Page not found'
# }), 404)
@meta_bp.route('/donate')
def donate():
return render_template('meta/donate.html')

@ -15,7 +15,7 @@ from wowstash.library.jsonrpc import Wallet, daemon, to_atomic
from wowstash.library.cache import cache
from wowstash.forms import Send, Delete, Restore
from wowstash.factory import db
from wowstash.models import User, ServerMessage
from wowstash.models import User, DonatePrompt
from wowstash import config
@ -70,6 +70,25 @@ def dashboard():
sleep(1.5)
return redirect(url_for('wallet.loading'))
# Redirect to donate page if user isnt prompted for a bit
dp = DonatePrompt.query.filter(
DonatePrompt.user == current_user.id
).order_by(
DonatePrompt.date.desc()
).first()
if not dp:
d = DonatePrompt(user=current_user.id)
db.session.add(d)
db.session.commit()
return redirect(url_for('meta.donate'))
# If havent seen donate page in some time, show again
if dp.hours_elapsed() > 168:
d = DonatePrompt(user=current_user.id)
db.session.add(d)
db.session.commit()
return redirect(url_for('meta.donate'))
address = wallet.get_address()
transfers = wallet.get_transfers()
for type in transfers:
@ -83,9 +102,6 @@ def dashboard():
spend_key = wallet.spend_key()
view_key = wallet.view_key()
capture_event(current_user.id, 'load_dashboard')
sm = ServerMessage.query.all()
if sm:
flash(f'Server message from admin: <a href="https://google.com">yo</a>')
return render_template(
'wallet/dashboard.html',
transfers=all_transfers,
@ -211,7 +227,7 @@ def send():
msg = tx['message'].capitalize()
msg_lower = tx['message'].replace(' ', '_').lower()
flash(f'There was a problem sending the transaction: {msg}')
capture_event(user.id, f'tx_fail_{msg_lower}')
capture_event(user.id, f'tx_fail_{msg_lower[0:50]}')
else:
flash('Successfully sent transfer.')
capture_event(user.id, 'tx_success')

@ -3,7 +3,7 @@ from flask import Blueprint, url_for
import wowstash.models
from wowstash.library.docker import docker
from wowstash.models import User, PasswordReset, ServerMessage
from wowstash.models import User, PasswordReset, Event
from wowstash.factory import db, bcrypt
@ -25,6 +25,29 @@ def reset_wallet(user_id):
def init():
db.create_all()
@bp.cli.command('list_users')
def list_users():
users = User.query.all()
for i in users:
print(f'{i.id} - {i.email}')
@bp.cli.command('wipe_user')
@click.argument('user_id')
def wipe_user(user_id):
user = User.query.get(user_id)
if user:
events = Event.query.filter(Event.user == user.id)
for i in events:
print(f'[+] Deleting event {i.id} for user {user.id}')
db.session.delete(i)
print(f'[+] Deleting user {user.id}')
db.session.delete(user)
db.session.commit()
return True
else:
print('That user id does not exist')
return False
@bp.cli.command('reset_password')
@click.argument('user_email')
@click.argument('duration')
@ -42,16 +65,3 @@ def reset_password(user_email, duration):
db.session.add(pwr)
db.session.commit()
click.echo(f'[+] Password reset link #{pwr.id} for {user_email} expires in {duration} hours: {url_for("auth.reset", hash=pwr.hash)}')
@bp.cli.command('set_message')
@click.argument('msg_content')
def set_message(msg_content):
s = ServerMessage.query.all()
if s:
db.session.delete(s.first())
db.session.commit()
_s = ServerMessage(
content=msg_content
)
db.session.add(_s)
db.session.commit()

@ -1,4 +1,6 @@
from re import match as re_match
from re import fullmatch as re_fullmatch
from re import compile as re_compile
from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired, ValidationError
@ -11,6 +13,12 @@ class Register(FlaskForm):
terms_reviewed = BooleanField('Terms Reviewed:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
privacy_reviewed = BooleanField('Privacy Policy Reviewed:', validators=[DataRequired()], render_kw={"class": "form-control-span"})
def validate_email(self, email):
regex = re_compile(r'([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+')
if not re_fullmatch(regex, self.email.data):
raise ValidationError('This appears to be an invalid email. Contact admins if you feel this is incorrect.')
class Login(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"})

@ -31,6 +31,7 @@ class Docker(object):
--password {u.wallet_password} \
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \
--trusted-daemon \
--electrum-seed '{seed}' \
--log-file /wallet/{u.id}-init.log \
--command refresh"
@ -43,6 +44,7 @@ class Docker(object):
--mnemonic-language English \
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \
--trusted-daemon \
--log-file /wallet/{u.id}-init.log \
--command version
"""
@ -81,6 +83,7 @@ class Docker(object):
--password {u.wallet_password} \
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \
--trusted-daemon \
--log-file /wallet/{u.id}-rpc.log
"""
try:

@ -1,5 +1,8 @@
import requests
from wowstash.models import Event
from wowstash.factory import db
from wowstash import config
def capture_event(user_id, event_type):
@ -10,3 +13,11 @@ def capture_event(user_id, event_type):
db.session.add(event)
db.session.commit()
return
def post_discord_webhook(text):
try:
r = requests.post(config.DISCORD_URL, data={"content": text})
r.raise_for_status()
return True
except:
return False

@ -90,12 +90,18 @@ class PasswordReset(db.Model):
def __repr__(self):
return self.id
class ServerMessage(db.Model):
__tablename__ = 'server_message'
class DonatePrompt(db.Model):
__tablename__ = 'donate_prompts'
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text)
user = db.Column(db.Integer, db.ForeignKey(User.id))
date = db.Column(db.DateTime, server_default=func.now())
def hours_elapsed(self):
now = datetime.utcnow()
diff = now - self.date
return diff.total_seconds() / 60 / 60
def __repr__(self):
return self.id
return str(f'donate-prompt-{self.id}')

@ -0,0 +1,30 @@
<!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-sm mx-auto">
<h2 class="mb-4">Error</h2>
<p>There was an error - an administrator has been notified.</p>
<p>Error: <code style="background-color: white;">{{ error.original_exception }}</code></p>
</div>
</div>
</div>
</div>
</header>
{% include 'footer.html' %}
{% include 'scripts.html' %}
</body>
</html>

@ -0,0 +1,33 @@
<!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">
<h1 class="mb-4">Donate</h1>
<p>Hey, this service is provided to you for free, please consider donating some WOW since I both donate my time and money keeping the service alive and paying for hosting.</p>
<p>lza_menace: <code style="background-color: white;">Wo59kvcHiDd48sstysDqGgBAN1fECLKALKw2bPUJhS4UjX9wj2SK4e4GH6HvrBmot6cBrWNE1T65UR6a5SLbzh882c1SXEhiK</code></p>
<a href="{{ url_for('wallet.dashboard') }}?to_addr=Wo59kvcHiDd48sstysDqGgBAN1fECLKALKw2bPUJhS4UjX9wj2SK4e4GH6HvrBmot6cBrWNE1T65UR6a5SLbzh882c1SXEhiK#send" class="btn btn-outline btn-xl js-scroll-trigger">Ok, take me to my wallet</a>
<br/><br/>
<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target=_blank class="btn btn-outline btn-xl js-scroll-trigger">Nah, fuck you menace.</a>
</div>
</div>
</div>
</div>
</header>
{% include 'footer.html' %}
{% include 'scripts.html' %}
</body>
</html>

@ -1,35 +0,0 @@
<!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">
<h1 class="mb-4">Privacy Policy</h1>
<p>Here is the information I will collect from you:</p>
<ul>
<li>Web server access logs (Source IP address, browser user-agent, page requests, etc)</li>
<li>Email address and salted/hashed password (registration)</li>
<li>Application events and metrics (function execution and the user who triggered)</li>
</ul>
<p>I check logs and capture events for troubleshooting purposes only. None of this data is shared with any third parties because I'm not a fucking lame.</p>
</div>
</div>
</div>
</div>
</header>
{% include 'footer.html' %}
{% include 'scripts.html' %}
</body>
</html>

@ -117,7 +117,7 @@
{{ send_form.csrf_token }}
<div class="form-group">
{{ send_form.address.label }}
{{ send_form.address }}
<input class="form-control" id="address" name="address" placeholder="Wownero address" required="" type="text" value="{{ request.args.to_addr }}">
</div>
<div class="form-group">
{{ send_form.amount.label }}
@ -130,6 +130,7 @@
</ul>
<input type="submit" value="Send" class="btn btn-link btn-outline btn-xl">
</form>
<a href="{{ url_for('meta.donate') }}" style="padding-top: 1em; display: block;">Donation Info</a>
</div>
</div>
</section>

Loading…
Cancel
Save