from flask import Flask, Response, redirect, url_for, request, session, abort, render_template, send_file from flask_login import LoginManager, UserMixin, login_required, login_user, logout_user, current_user from PIL import Image, ImageFont, ImageDraw import qrcode from io import BytesIO import json, random, re, string, hashlib, base64 app = Flask(__name__) systemURL = 'http://192.168.0.11:5000/' #FULL URL with a '/' at the end systemURL = 'http://10.0.1.115:5000/' randomchars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789' #note the lack of zero # flask-login login_manager = LoginManager() login_manager.init_app(app) login_manager.login_view = "login" admins={} class Admin(UserMixin): def __init__(self, name, password): self.id = name self.password = password admins[name] = self with open('links.json', 'r') as infile: links = json.load(infile) with open('admins.json', 'r') as infile: adminfile = json.load(infile) for key, value in adminfile.items(): if key=='secret_key': app.secret_key = value elif key=='secret_cookie': secret_cookie = value.encode('utf-8') else: a = Admin(key, value['password']) def saveFile(): with open('links.json', 'w') as outfile: json.dump(links, outfile) def randomToken(): code = "" for i in range(0,6): code += random.choice(randomchars) return code def codeValidation(code): if len(code) not in range (3,10): return False if re.match('^[\w-]+$', code) is None: return False return True def codeLink(code): global links if code not in links: return False if len(links[code]['url'])==0: return None return links[code]['url'] def createNewCode(): code=randomToken() while code in links: #danger! code=randomToken() links[code]={'url':''} return code def serveImage(img): img_io = BytesIO() img.save(img_io, 'PNG') img_io.seek(0) return send_file(img_io, mimetype='image/png') @app.route('/code/') def serveCode(code): code = code[:code.find('.')] if codeValidation(code) is False: return send_file('static/invalid.png', mimetype='image/png') qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_M, box_size=8, border=3, ) qr.add_data(systemURL + code) qr.make(fit=True) img = qr.make_image(fill_color="black", back_color="white") return serveImage(img) @app.route("/edit", methods=['GET', 'POST']) def edit(): code = request.form.get("code") if request.form.get("code") is not None else request.args.get("code") url = request.form.get("url") if codeLink(code) is False: return render_template('invalid.html', code=code) if current_user.is_authenticated: if url==None: return render_template('editlink.html', code=code, url=codeLink(code), admin=current_user.is_authenticated) else: if url=='remove': url = '' links[code]['url']=url saveFile() return render_template('message.html', message="Done Mr. Admin person") else: if codeLink(code) is not None: return render_template('cantedit.html', url=codeLink(code)) if url is None: return render_template('editlink.html', code=code, url='', admin=current_user.is_authenticated) #Saving the link: if url.lower().startswith('https://') is False and url.lower().startswith('http://') is False: return render_template('message.html', message="Only http:// and https:// links alowed. Plz fix your link!") if len(url)>1000: return render_template('message.html', message="This link is too long! It probably contains tracking data or other crap. Please find a shorter link.") links[code]['url']=url saveFile() return render_template('success.html') @app.route("/admin") @login_required def admin(): return render_template('admin.html') # somewhere to login @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] hasher = hashlib.sha256() hasher.update(password.encode('utf-8')) hasher.update(secret_cookie) hashedpassword = base64.b64encode(hasher.digest()).decode('utf-8') if admins[username].password == hashedpassword: login_user(admins[username]) return redirect(request.args.get("next")) return abort(401) else: return render_template('login.html') @app.route("/logout") @login_required def logout(): logout_user() return redirect('/') # callback to reload the user object @login_manager.user_loader def load_user(userid): return admins[userid] @app.route("/generate", methods=['GET', 'POST']) def generate(): howmany = request.form.get("howmany") if howmany is None: return render_template('generate.html') codes = [] for i in range(0, int(howmany)): codes.append(createNewCode()) columns = 4 codesarray = [codes[i:i+columns] for i in range(0, len(codes), columns)] saveFile() humanSystemURL = systemURL[systemURL.find('//')+2:] return render_template("printlabels.html", codes=codesarray, systemURL=humanSystemURL, codegenURL=systemURL+'code/', format='.png') @app.route("/list") @login_required def list(): linklist = [] for key, value in links.items(): if len(value['url'])>0: linklist.append({'code':key, 'url':value['url']}) return render_template('list.html', linklist=linklist, count=len(linklist)) @app.route("/empty") @login_required def showEmptyCodes(): linklist = [] for key, value in links.items(): if value['url']=='': linklist.append({'code':key, 'url':value['url']}) return render_template('listempty.html', linklist=linklist, count=len(linklist)) @app.route('/', defaults={'path': ''}) @app.route('/') def catch_all(path): if len(path)==0: return render_template('welcome.html') if path in links: if codeLink(path) is not None: return redirect(links[path]['url'], code=302) else: return render_template('newcode.html', code=path) else: return render_template('invalid.html', code=path)