from functools import cache import json from flask import ( Flask, make_response, redirect, request, jsonify, render_template, send_from_directory, send_file, ) import os import json import requests from datetime import datetime import dotenv import sales dotenv.load_dotenv() app = Flask(__name__) def find(name, path): for root, dirs, files in os.walk(path): if name in files: return os.path.join(root, name) # Assets routes @app.route("/assets/") def send_assets(path): if path.endswith(".json"): return send_from_directory( "templates/assets", path, mimetype="application/json" ) if os.path.isfile("templates/assets/" + path): return send_from_directory("templates/assets", path) # Try looking in one of the directories filename: str = path.split("/")[-1] if ( filename.endswith(".png") or filename.endswith(".jpg") or filename.endswith(".jpeg") or filename.endswith(".svg") ): if os.path.isfile("templates/assets/img/" + filename): return send_from_directory("templates/assets/img", filename) if os.path.isfile("templates/assets/img/favicon/" + filename): return send_from_directory("templates/assets/img/favicon", filename) return render_template("404.html"), 404 # region Special routes @app.route("/favicon.png") def faviconPNG(): return send_from_directory("templates/assets/img", "favicon.png") @app.route("/.well-known/") def wellknown(path): # Try to proxy to https://nathan.woodburn.au/.well-known/ req = requests.get(f"https://nathan.woodburn.au/.well-known/{path}") return make_response( req.content, 200, {"Content-Type": req.headers["Content-Type"]} ) # endregion # region Main routes @app.route("/") def index(): listings = sales.get_listings_rendered() return render_template("index.html", listings=listings) @app.route("/view/") def view(domain: str): listing = sales.search_listings(domain) if not listing: return render_template("404.html"), 404 return render_template("view.html", listing=listing) @app.route("/list", methods=["POST"]) def list_form(): # Get form data data = request.form domain = data['domain'] price = data['price'] description = data['description'] contact = data['contact'] signature = data['signature'] listing = sales.Listing(domain=domain,price=price,description=description,contact=contact,signature=signature) if not listing.signed(): return render_template("list.html", domain=domain, price=price, description=description, contact=contact, signature=signature, error="Signature is not valid") status = sales.add_listing(listing) if status != True: return render_template("list.html", domain=domain, price=price, description=description, contact=contact, signature=signature, error="Failed to add listing") return render_template("list.html", success="Successfully added listing") @app.route("/delete/") def delete_web(domain: str): message = f"FS: {domain}" return render_template("delete.html", domain=domain, message=message) @app.route("/delete/", methods=["POST"]) def delete_form(domain:str): data = request.form signature = data['signature'] if not sales.validate_cancel_signature(domain,signature): return render_template("delete.html", domain=domain, error="Invalid signature") sales.remove_listing(domain) return redirect("/") @app.route("/view/", methods=["POST"]) def post_offer(domain: str): data = request.form # Convert to JSON data = json.loads(json.dumps(data)) offer = sales.send_offer(domain, data) listing = sales.search_listings(domain) return render_template("view.html", listing=listing,message=offer['message']) @app.route("/report/") def report(domain: str): listing = sales.search_listings(domain) if not listing: return render_template("404.html"), 404 return redirect("https://l.woodburn.au/contact") @app.route("/verify/") def verify(domain: str): listing = sales.search_listings(domain) if not listing: return render_template("404.html"), 404 return render_template("verify.html", domain=domain, string=str(listing).replace('\n','
'), message=listing.getMessage(), signature=listing.signature) #region API Routes def validate_data(data,required): for key in required: if key not in data: return jsonify({'error': f'Missing {key}','success': False}),400 return True @app.route("/api/v1/listing-message", methods=["GET"]) def listingMessage(): # Create listing valid = validate_data(request.args,['domain','description','price','contact']) if valid != True: return valid listing = sales.Listing(**request.args) return { 'message': listing.getMessage(), 'success': True } @app.route("/api/v1/list", methods=["POST"]) def list(): data = request.get_json() # Validate data has domain,description,price,contact valid = validate_data(data,['domain','description','price','contact']) if valid != True: return valid listing = sales.Listing(**data) if not listing.signed(): return jsonify({'error': 'Not signed','success': False,'message': f'Sign this message to post listing: {listing.getMessage()}'}) status = sales.add_listing(listing) if status != True: return jsonify({'error': 'Failed to add listing','success': False,'message': status}) return jsonify({'success': True,'error': None}) @app.route("/api/v1/delete", methods=["POST"]) def delete(): data = request.get_json() # Validate data has domain if not 'domain' in data: return jsonify({'error': 'Domain is required','success': False}) if 'tx' in data: if not sales.validate_buy_tx(data['domain'],data['tx']): return jsonify({'error': 'Invalid tx','success': False}) sales.remove_listing(data['domain']) return jsonify({'success': True,'error': None}) if 'signature' in data: if not sales.validate_cancel_signature(data['domain'],data['signature']): return jsonify({'error': 'Invalid signature','success': False,'message': f"FS: {data['domain']}"}) sales.remove_listing(data['domain']) return jsonify({'success': True,'error': None}) return jsonify({'error': 'Signature or tx is required','success': False}) #endregion @app.route("/plugin") def plugin(): return redirect('https://git.woodburn.au/nathanwoodburn/firesales-plugin') @app.route("/docs") def docs(): return redirect('https://git.woodburn.au/nathanwoodburn/FireSales/wiki/Home') @app.route("/") def catch_all(path: str): if os.path.isfile("templates/" + path): return render_template(path) # Try with .html if os.path.isfile("templates/" + path + ".html"): return render_template(path + ".html") if os.path.isfile("templates/" + path.strip("/") + ".html"): return render_template(path.strip("/") + ".html") # Try to find a file matching if path.count("/") < 1: # Try to find a file matching filename = find(path, "templates") if filename: return send_file(filename) return render_template("404.html"), 404 # endregion # region Error Catching # 404 catch all @app.errorhandler(404) def not_found(e): return render_template("404.html"), 404 # endregion if __name__ == "__main__": app.run(debug=True, port=5000, host="0.0.0.0")