Skip to content
Snippets Groups Projects
main.py 9.32 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jonas Leder's avatar
    Jonas Leder committed
    #!/usr/bin/env python3
    
    Jonas Leder's avatar
    Jonas Leder committed
    #Import of Libraries
    
    Jonas Leder's avatar
    Jonas Leder committed
    from waitress import serve #Used as webserver (Production)
    
    from flask import Flask, request, redirect, make_response, abort #Used to prepare the dynamic pages
    
    Jonas Leder's avatar
    Jonas Leder committed
    from os import environ #Used for getting the enviorement variables
    
    from itsdangerous import URLSafeSerializer #used for signing the cookies
    
    Jonas Leder's avatar
    Jonas Leder committed
    from random import choice#used for signing the cookies
    from string import ascii_lowercase #used for signing the cookies 
    
    Jonas Leder's avatar
    Jonas Leder committed
    from requests import get #used to get the current version on the Server
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    #Import of shorter specific files
    
    from table_check import table_check #import the table check file
    from makeqr import makeQR #Qr code generation tool
    from grecaptcha_verify import grecaptcha_verify #Tool to verify the google recaptcha response
    from newurl import newurl #Script to add the new urls to the database
    from redirectShortenURL import redirectShortenURL #Script to redirect the user to the long site
    from login import login #thandles the login
    from home import home #returns the main page
    from googlecallback import googleCallback #Script to handle the google oauth login
    from githubcallback import githubCallback #Script to handle the Github oauth login
    from userprofile import userProfile #This script handles the overview of the own links
    from deletelink import deleteLink #Script to delete Links of Users, if they want.
    from api import apiGet,apiPost #Scripts to handle the API
    
    Jonas Leder's avatar
    Jonas Leder committed
    domain_to_index = {}
    
    try:
    
    Jonas Leder's avatar
    Jonas Leder committed
        domain = environ["domains"].split(";") #Get the domains from the enviorement variable. If no enviorement variable is set it will be set to 127.0.0.1:5000 (for testing)
    
    Jonas Leder's avatar
    Jonas Leder committed
    except:
    
        domain = ["localhost:5000", "127.0.0.1:5000"]
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    try:
    
    Jonas Leder's avatar
    Jonas Leder committed
        if(environ["show_build_date"] == "1"): #If you want to see the builddate you can enable this enviorement variable
    
    Jonas Leder's avatar
    Jonas Leder committed
            builddate = open("builddate.txt", "r").read()
    
    Jonas Leder's avatar
    Jonas Leder committed
        else:
            builddate = ""
    
    Jonas Leder's avatar
    Jonas Leder committed
    except:
    
    Jonas Leder's avatar
    Jonas Leder committed
        builddate = "" #If the enviorement Variable is not set also skip the builddate
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    
    Jonas Leder's avatar
    Jonas Leder committed
        if(environ["show_version"] == "1"): #If you want to see the builddate you can enable this enviorement variable
    
            version = open("VERSION", "r").read()
    
    Jonas Leder's avatar
    Jonas Leder committed
        else:
            version = ""
    
    Jonas Leder's avatar
    Jonas Leder committed
        version = "" #If the enviorement Variable is not set also skip the version
    
    Jonas Leder's avatar
    Jonas Leder committed
    try:
    
    Jonas Leder's avatar
    Jonas Leder committed
        recaptchaPrivateKey = environ["recaptcha_private"] #Get the recaptcha keys, if not set set skipRecaptcha to true to skip the check. If the publicKey is not set the user also will not get the code needed for recaptcha delivered in the page.
        recaptchaPublicKey = environ["recaptcha_public"]
    
    Jonas Leder's avatar
    Jonas Leder committed
        if(recaptchaPrivateKey != "") and (recaptchaPublicKey != ""): #If the variables are empty also skip the captcha
            skipCaptcha = False
        else:
            skipCaptcha = True
    
    
    Jonas Leder's avatar
    Jonas Leder committed
    except:
        recaptchaPrivateKey = ""
    
        recaptchaPublicKey = ""
    
    Jonas Leder's avatar
    Jonas Leder committed
        skipCaptcha = True
    
    
    Jonas Leder's avatar
    Jonas Leder committed
    try:
    
    Jonas Leder's avatar
    Jonas Leder committed
        if(environ["production"] == "1"): #If you use this in production, please set this to 1, because the Flask Testserver is not very secure (e.g. shows error on Website)
    
    Jonas Leder's avatar
    Jonas Leder committed
            production = True
        else:
            production = False
    except:
        production = False
    
    
    Jonas Leder's avatar
    Jonas Leder committed
    try: #If you use https with a proxy afterwards you can set this to https and internal redirects will be https not http. This is to prevent bugs with modern browsers, bacause they block http content if the main page is loaded via https.
    
    Jonas Leder's avatar
    Jonas Leder committed
        url_scheme = environ["url_scheme"]
    
    Jonas Leder's avatar
    Jonas Leder committed
    except:
        url_scheme = "http"
    
    
    Jonas Leder's avatar
    Jonas Leder committed
        host=environ["host"]
    
    except:
        host="127.0.0.1"
    
    
        if(environ["login"] == "1"): loginEnabled = True
    
        else: loginEnabled = False
    
        loginEnabled = False
    
    
    try:
        if(environ["passwordToShort"] != ""):
            passwordProtected = True
            password = environ["passwordToShort"]
        else:
            passwordProtected = False
    
    except:
        passwordProtected = False
    
    if(loginEnabled):
        try: #Try to get the oauth keys, if it fails, abort and print a message to console
            GITHUB_CLIENT_ID = environ['GITHUB_CLIENT_ID']
            GITHUB_CLIENT_SECRET = environ['GITHUB_CLIENT_SECRET']
            GOOGLE_CLIENT_ID = environ['GOOGLE_CLIENT_ID']
            GOOGLE_CLIENT_SECRET = environ['GOOGLE_CLIENT_SECRET']
        except:
            print("please set the oauth keys and run again.")
            exit()
    
    Jonas Leder's avatar
    Jonas Leder committed
    try: #check, if admin wants to show a cookie notice to the user. 
    
    Jonas Leder's avatar
    Jonas Leder committed
        if(environ["cookieNotice"] == "1"):
    
    Jonas Leder's avatar
    Jonas Leder committed
            cookieNotice = True
        else:
            cookieNotice = False
    except:
        cookieNotice = True
    
    
    Jonas Leder's avatar
    Jonas Leder committed
    try: #The secret key is used to crypt the auth cookie. There will be a seccond key to make the api key.
    
        secretKey = open("db/secretKey.txt", "r").read()
    except:
    
    Jonas Leder's avatar
    Jonas Leder committed
        secretKey = ''.join(choice(ascii_lowercase) for i in range(100)) #If we can't find the secret key(first run) we generate it in this step and write it to a file
    
        print("generated secret Key. Key is: " + secretKey)
        f = open("db/secretKey.txt", "w")
        f.write(secretKey)
        f.close()
        secretKey = open("db/secretKey.txt", "r").read()
    s = URLSafeSerializer(secretKey)
    
    Jonas Leder's avatar
    Jonas Leder committed
    sAPI = URLSafeSerializer("api_key_" + secretKey)
    
    Jonas Leder's avatar
    Jonas Leder committed
    index = 0
    
    Jonas Leder's avatar
    Jonas Leder committed
    domain_prepared = ""
    
    Jonas Leder's avatar
    Jonas Leder committed
    for domains in domain: #Make from every domnain a entry for the select box later
        domain_prepared = domain_prepared + '<option value="' + str(domains) + '">' + str(domains) + '</option>'
        domain_to_index[domains] = str(index)
        index = index + 1
    
    if(index > 1):
        showDomainSelect=True #Show only domain select, if there are more than one available
    else:
    
    Jonas Leder's avatar
    Jonas Leder committed
        showDomainSelect=False
    
        domain_prepared = domain[0]
    
    Jonas Leder's avatar
    Jonas Leder committed
    @app.route('/', methods=['GET'])
    def home_get():
    
        return home(request, builddate, version, domain_prepared, recaptchaPublicKey, showDomainSelect, cookieNotice, domain_to_index, s, loginEnabled, passwordProtected)
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    @app.route('/', methods=['POST']) #This function is used to create a new url
    def home_post():
    
        return newurl(request, skipCaptcha, recaptchaPrivateKey, recaptchaPublicKey, builddate, version, domain_prepared, domain_to_index, showDomainSelect, cookieNotice, s, url_scheme, loginEnabled, passwordProtected, password)
    
    Jonas Leder's avatar
    Jonas Leder committed
    @app.route('/favicon.ico') #Redirect to the static url of the favicon
    def favicon():
    
        return redirect("/static/favicon.ico", code=301)
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    @app.route('/<short_url>')
    def redirect_short_url(short_url):
    
        return redirectShortenURL(request, short_url)
    
    @app.route('/user/login')
    
    def loginPage():
    
        if(loginEnabled): return login(request, GITHUB_CLIENT_ID, cookieNotice, GOOGLE_CLIENT_ID, url_scheme, domain)
        else: abort(404)
    
    
    @app.route("/user/google-callback")
    def authorizeGoogle():
    
        if(loginEnabled): return googleCallback(request, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, url_scheme, domain, s)
        else: abort(404)
    
    @app.route('/user/github-callback') #Github redirects to this link after the user authenticated. Then we use the Token we get from github and request via the github api the username and the userid
    
    def authorizeGithub():
    
        if(loginEnabled): return githubCallback(request, GITHUB_CLIENT_SECRET, GITHUB_CLIENT_ID, s)
        else: abort(404)
    
    @app.route('/user/logout')
    
    Jonas Leder's avatar
    Jonas Leder committed
        resp = make_response('<style>\n@media (prefers-color-scheme: dark) {\nbody {\ncolor: #b3b3b3;\nbackground: #151d28;\n}\n}\n</style>\n<h2>Logout successful. Redirecting you back in 2 sec.</h2>\n<script> window.setTimeout(function(){\nwindow.location.href = "/";\n}, 2000);</script>')
    
        resp.set_cookie('userID', "", max_age=0) #Set the max age of the cookies to 0, this means delete the cookies.
    
        resp.set_cookie('username', "", max_age=0)
        return resp
    
    @app.route('/user/links')#This function gives the user the posibility to see and delete his links
    
    def redirectOwnLinks():
    
        return redirect("/user/links0", code=301)
    
    
    @app.route('/user/links<pageNumber>')#This function gives the user the posibility to see and delete his links
    def ownLinks(pageNumber):
    
        if(loginEnabled): return userProfile(request, cookieNotice, s, pageNumber, url_scheme)
        else: abort(404)
    
    @app.route('/user/delete', methods=['POST']) #This function is called if a user deletes an entrie
    
    Jonas Leder's avatar
    Jonas Leder committed
    def delete():
    
        if(loginEnabled): return deleteLink(request, s)
        else: abort(404)
    
    @app.route('/user/makeqr', methods=['POST'])
    
    Jonas Leder's avatar
    Jonas Leder committed
    def makeQrCode():
    
        link = request.form.get('link')
    
        return "data:image/jpeg;base64," + makeQR(url_scheme + "://" + link)
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    
    Jonas Leder's avatar
    Jonas Leder committed
    @app.route('/user/api', methods=['POST'])
    def api():
    
    Jonas Leder's avatar
    Jonas Leder committed
        return apiPost(request, url_scheme, domain, sAPI, passwordProtected, password)
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    
    @app.route('/user/api', methods=['GET'])
    def apiDocs():
    
    Jonas Leder's avatar
    Jonas Leder committed
        return apiGet(request, url_scheme, s, sAPI, passwordProtected)
    
    Jonas Leder's avatar
    Jonas Leder committed
    
    
    def startup(production):
    
    Jonas Leder's avatar
    Jonas Leder committed
        table_check()# This code checks whether database table is created or not
    
    Jonas Leder's avatar
    Jonas Leder committed
        if production: #Check if production variable is set to true use the waitress webserver, else use the buildin flask webserver, with more debug output
    
    Jonas Leder's avatar
    Jonas Leder committed
            serve(app, host=host, port= 5000, url_scheme=url_scheme) #Start the production Webserver for all users on port 5000
    
    Jonas Leder's avatar
    Jonas Leder committed
        else:
    
            app.run(host=host, port=5000, debug=True) #Start the Webserver in Debug mode. This means, if the script runs in an error, it will show the error message in Browser.
    
    if (__name__ == "__main__"): startup(production) #Only run the startup script, if this file is directly called.