diff --git a/account.py b/account.py index 6316ec1..33b8c53 100644 --- a/account.py +++ b/account.py @@ -196,6 +196,40 @@ def updateNotifications(token, notifications): return True +def updateDomainNotifications(token, domain, notifications): + # Get userID from userToken + if (token.count('$') != 1): + return False + token = token.split('$') + userID = token[0] + token = token[1] + + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("SELECT domains FROM users WHERE id = %s", (userID,)) + user = cursor.fetchall() + cursor.close() + conn.close() + + print(domain) + print(notifications) + + # Read json token from first user + user = user[0][0] + user = json.loads(user) + for userDomain in user: + if (userDomain['name'] == domain): + userDomain['notifications'] = notifications + + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("UPDATE users SET domains = %s WHERE id = %s", (json.dumps(user), userID,)) + conn.commit() + cursor.close() + conn.close() + + return True + def updateNotificationProvider(token, provider,account): # Get userID from userToken if (token.count('$') != 1): diff --git a/domains.py b/domains.py new file mode 100644 index 0000000..f0b0baf --- /dev/null +++ b/domains.py @@ -0,0 +1,253 @@ +import mysql.connector +from mysql.connector import Error +import dotenv +import os +import json +import time +import smtplib +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart +import requests +import re + +dotenv.load_dotenv() + +db_config = { + 'host': os.getenv('DB_HOST'), + 'database': os.getenv('DB_NAME'), + 'user': os.getenv('DB_USER'), + 'password': os.getenv('DB_PASSWORD') +} + +def addDomain(userID:int, domain:str): + # Get user domains + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("SELECT domains FROM users WHERE id = %s", (userID,)) + user = cursor.fetchall() + cursor.close() + conn.close() + + # Read json domains from first user + user = user[0][0] + userDomains = json.loads(user) + + # Check if domain is already in use + for userDomain in userDomains: + if (userDomain['name'] == domain): + return False + + # Add domain to user + userDomains.append({ + "name": domain, + "status": "pending" + }) + + # Update user domains + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("UPDATE users SET domains = %s WHERE id = %s", (json.dumps(userDomains), userID)) + conn.commit() + cursor.close() + conn.close() + return True + + +def verifyDomain(domain:str): + # Remove any trailing slashes + domain = domain.rstrip('/') + # Remove any protocol + domain = domain.replace('https://', '') + domain = domain.replace('http://', '') + domain = domain.lower() + # Verify domain contains only valid characters + if (re.match("^[a-z0-9.-]*$", domain) == None): + return False + return domain + +def deleteDomain(userID:int, domain:str): + # Get user domains + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("SELECT domains FROM users WHERE id = %s", (userID,)) + user = cursor.fetchall() + cursor.close() + conn.close() + + # Read json domains from first user + user = user[0][0] + userDomains = json.loads(user) + + # Check if domain is already in use + for userDomain in userDomains: + if (userDomain['name'] == domain): + userDomains.remove(userDomain) + break + + # Update user domains + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("UPDATE users SET domains = %s WHERE id = %s", (json.dumps(userDomains), userID)) + conn.commit() + cursor.close() + conn.close() + return True + +def syncDomains(): + # Verify connection to HSD node + try: + r = requests.get('http://x:' + os.getenv('HSD_API_KEY') + '@' + os.getenv('HSD_IP') + + ':' + os.getenv('HSD_PORT')) + if (r.status_code != 200): + return "HSD node is not responding" + # Check to make sure the node is synced + data = r.json() + if (data['chain']['progress'] < 0.999): + return "HSD node is not synced" + + except: + return False + + # Get all users + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("SELECT id, domains FROM users") + users = cursor.fetchall() + cursor.close() + conn.close() + + # Loop through users + for user in users: + userID = user[0] + userDomains = json.loads(user[1]) + # Loop through user domains + for userDomain in userDomains: + # Check if domain is pending + if (userDomain['status'] == 'pending'): + try: + print('Importing domain: ' + userDomain['name']) + r = requests.post('http://x:' + os.getenv('HSD_API_KEY') + '@' + os.getenv('HSD_IP') + + ':' + os.getenv('HSD_WALLET_PORT'), json={'method': 'importname', 'params': [userDomain['name']]}) + + if (r.status_code == 200): + # Update domain status + userDomain['status'] = 'added' + + # Set some defaults + userDomain['transfering'] = 0 + userDomain['next'] = 'none' + userDomain['when'] = 0 + + # Update user domains + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("UPDATE users SET domains = %s WHERE id = %s", (json.dumps(userDomains), userID)) + conn.commit() + cursor.close() + conn.close() + + except: + pass + + # Get domain info + r = requests.post('http://x:' + os.getenv('HSD_API_KEY') + '@' + os.getenv('HSD_IP') + + ':' + os.getenv('HSD_PORT'), json={'method': 'getnameinfo', 'params': [userDomain['name']]}) + print(json.dumps(r.json(), indent=4)) + if (r.status_code == 200): + data = r.json() + # Check if domain is registered + info = data['result']['info'] + if (userDomain['transfering'] != info['transfer']): + # Update domain status + alert('transfer', userDomain['name'], userID) + userDomain['transfering'] = info['transfer'] + + if 'stats' in info: + if 'blocksUntilExpire' in info['stats']: + # Update domain status + userDomain['next'] = 'expires' + + previous = userDomain['when'] + userDomain['when'] = info['stats']['blocksUntilExpire'] + + if (crossTimeAlert(userDomain['next'], previous, userDomain['when'])): + alert('expire', userDomain['name'], userID) + + elif 'blocksUntilBidding' in info['stats']: + # Update domain status + userDomain['next'] = 'opens for bidding' + userDomain['when'] = info['stats']['blocksUntilBidding'] + + # Update user domains + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("UPDATE users SET domains = %s WHERE id = %s", (json.dumps(userDomains), userID)) + conn.commit() + cursor.close() + conn.close() + + + + else: + return "Failed to get info about domain: " + userDomain['name'] + "" + str(r.text) + return "Finished syncing domains" + +def alert(event,domain,user): + # TODO this later + pass + +def crossTimeAlert(event,was, now): + # Check for each of these times to see if we should alert + month = 4320 + week = 1008 + + # If the time crossed the month mark + if (was > month and now <= month): + return True + # If the time crossed the week mark + if (was > week and now <= week): + return True + + return False + + + +def getCachedDomainInfo(domain): + # Get domain info from user domains + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + cursor.execute("SELECT domains FROM users") + users = cursor.fetchall() + cursor.close() + conn.close() + + # Loop through users + for user in users: + userDomains = json.loads(user[0]) + # Loop through user domains + for userDomain in userDomains: + if (userDomain['name'] == domain): + return userDomain + return False + + + +def blocksToTime(blocks): + # Get minutes + minutes = blocks * 10 + years, minutes = divmod(minutes, 525600) + days, minutes = divmod(minutes, 1440) + hours, minutes = divmod(minutes, 60) + + # Build the string + time_string = "" + if years: + time_string += f"{years} {'year' if years == 1 else 'years'}, " + if days: + time_string += f"{days} {'day' if days == 1 else 'days'}, " + if hours and not years: + time_string += f"{hours} {'hour' if hours == 1 else 'hours'}, " + if minutes and not years and not days: + time_string += f"{minutes} {'min' if minutes == 1 else 'mins'}" + + return time_string.rstrip(', ') diff --git a/main.py b/main.py index 409b58d..49dca9f 100644 --- a/main.py +++ b/main.py @@ -9,6 +9,7 @@ import time import json import account import threading +import domains dotenv.load_dotenv() @@ -107,7 +108,20 @@ def dashboard(): if (account.verifyUser(request.cookies.get('user_token'))): # Get user data user = account.getUser(request.cookies.get('user_token')) - domains = user['domains'] + error = "" + if (request.args.get('error')): + error = request.args.get('error') + success = "" + if (request.args.get('success')): + success = request.args.get('success') + + + # For each domain in domains get only the name + domains = [] + for domain in user['domains']: + domains.append(domain['name']) + + notifications = user['notifications'] email = user['email'] + ' Test' @@ -140,7 +154,8 @@ def dashboard(): return render_template('dashboard.html', domains=domains, notifications=notifications, email=email, discord=discord, telegram=telegram, - expiry_week=expiry_week,expiry_month=expiry_month) + expiry_week=expiry_week,expiry_month=expiry_month, + error=error,success=success,admin=user['admin']) return redirect('/login') @@ -200,30 +215,161 @@ def notification_options(): if (account.verifyUser(request.cookies.get('user_token'))): # Get user data user = account.getUser(request.cookies.get('user_token')) - notifications = user['notifications'] expiry_week = { - "email": False, - "discord": False, - "telegram": False + "email": False, + "discord": False, + "telegram": False } expiry_month = { "email": False, "discord": False, "telegram": False } - for key in request.form: - if (key.endswith('_week')): - key = key[:-5] - expiry_week[key] = True - elif (key.endswith('_month')): - key = key[:-6] - expiry_month[key] = True - - notifications['expiry_week'] = expiry_week - notifications['expiry_month'] = expiry_month - account.updateNotifications(request.cookies.get('user_token'), notifications) - return redirect('/dashboard') + if not request.form.get('domain'): + notifications = user['notifications'] + for key in request.form: + if (key.endswith('_week')): + key = key[:-5] + expiry_week[key] = True + elif (key.endswith('_month')): + key = key[:-6] + expiry_month[key] = True + + notifications['expiry_week'] = expiry_week + notifications['expiry_month'] = expiry_month + account.updateNotifications(request.cookies.get('user_token'), notifications) + return redirect('/dashboard') + else: + notifications = { + "expiry_week": { + "email": False, + "discord": False, + "telegram": False + }, + "expiry_month": { + "email": False, + "discord": False, + "telegram": False + } + } + domainList = user['domains'] + domain = request.form.get('domain').lower() + + + for key in request.form: + if (key.endswith('_week')): + key = key[:-5] + notifications['expiry_week'][key] = True + elif (key.endswith('_month')): + key = key[:-6] + notifications['expiry_month'][key] = True + + account.updateDomainNotifications(request.cookies.get('user_token'), + domain,notifications) + return redirect('/' + domain + '/info') + + +#region domains +@app.route('/new-domain', methods=['POST']) +def new_domain(): + # Check if user is logged in + if 'user_token' in request.cookies: + if (account.verifyUser(request.cookies.get('user_token'))): + # Get user data + user = account.getUser(request.cookies.get('user_token')) + domain = request.form.get('domain') + # Verify domain + domain = domains.verifyDomain(domain) + if (domain): + # Add domain to user + if (domains.addDomain(user['id'], domain)): + return redirect('/dashboard?success=Domain added') + else: + return redirect('/dashboard?error=Unable to add domain') + else: + return redirect('/dashboard?error=Invalid domain') + + return redirect('/login') + +@app.route('//delete') +def delete_domain(domain): + # Check if user is logged in + if 'user_token' in request.cookies: + if (account.verifyUser(request.cookies.get('user_token'))): + # Get user data + user = account.getUser(request.cookies.get('user_token')) + # Delete domain from user + if (domains.deleteDomain(user['id'], domain)): + return redirect('/dashboard?success=Domain deleted') + else: + return redirect('/dashboard?error=Unable to delete domain') + + return redirect('/login') + +@app.route('/sync') +def sync_domains(): + # Check if user is logged in + if 'user_token' in request.cookies: + if (account.verifyUser(request.cookies.get('user_token'))): + # Get user data + user = account.getUser(request.cookies.get('user_token')) + if (user['admin'] == False): + return redirect('/dashboard?error=You are not an admin') + + # Sync domains + result =domains.syncDomains() + return redirect('/dashboard?error=' + result) + + return redirect('/login') + +@app.route('//info') +def domain(domain): + # Check if user is logged in + if 'user_token' in request.cookies: + if (account.verifyUser(request.cookies.get('user_token'))): + # Get domain info + domainInfo = domains.getCachedDomainInfo(domain) + print(domainInfo) + if (domainInfo): + if (domainInfo['status'] == 'pending'): + return redirect('/dashboard?error=Domain is pendingPlease wait a few minutes') + + + next = domainInfo['next'] + when_blocks = domainInfo['when'] + when_time = domains.blocksToTime(when_blocks) + transfering = domainInfo['transfering'] == 1 + + expiry_week = { + "email": False, + "discord": False, + "telegram": False + } + expiry_month = { + "email": False, + "discord": False, + "telegram": False + } + if ('notifications' in domainInfo): + if ('expiry_week' in domainInfo['notifications']): + expiry_week = domainInfo['notifications']['expiry_week'] + + if ('expiry_month' in domainInfo['notifications']): + expiry_month = domainInfo['notifications']['expiry_month'] + + return render_template('info.html', domain=str(domain).capitalize(), + next=next,when_blocks=when_blocks,when_time=when_time, + transfering=transfering,expiry_week=expiry_week, + expiry_month=expiry_month) + else: + return render_template('info.html', domain=str(domain).capitalize()) + + return redirect('/login') + + + +#endregion @app.route('/assets/') def send_assets(path): diff --git a/templates/dashboard.html b/templates/dashboard.html index 8dbc547..ddd59f2 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -4,7 +4,7 @@ - Products - HNS Alert + Dashboard - HNS Alert @@ -12,25 +12,30 @@ - - - - - - - - - + + + + + + + + + - + - HNS AlertLogout + HNS Alert{%if admin%} +Sync + +{%endif%}Logout + {{error | safe}} + {{success | safe}} Dashboard @@ -77,6 +82,29 @@ + + + + + Domains + + + + + +{% for domain in domains %} + + {{domain}}/ + Info + Delete + + + {% endfor %} + + + + + - - + +