コード例 #1
0
def before_request() -> None:
    """ Runs before each request. """
    try:
        vote = cube.load_file("vote")
    except:
        #sometimes fails, not sure why
        app.logger.warning("Error in parsing JSON file")
    else:
        if time.time() > cube.short_date(vote["ends_at"]):
            vote["vote_active"] = False
            cube.dump_file(vote, "vote")

    # record number of times each page has been visted
    path = flask.request.path
    if path.split("/")[1] != "static" and path.split("/")[1] != "_uploads":
        vists = cube.load_file("vists")
        date = cube.unix_to_date(time.time())
        vists[path] = vists.get(path, {})
        vists[path][date] = vists[path].get(date, 0) + 1

        # more than one day
        if time.time() - vists["time"] > 60 * 60 * 24:
            cube.graph_vists()
            vists["time"] = time.time()

        cube.dump_file(vists, "vists")
コード例 #2
0
def GLOBALS() -> dict:
    """ Returns all the global variables passed to every template. """
    user = cube.load_file("users").get(flask.session.get("account", None), {})
    vars = {
        "vote_active": cube.load_file("vote")["vote_active"],
        "user": user,
        "btnform": forms.FlaskForm(),
        "searchForm": forms.SearchForm(),
    }
    return cube.add_dict(GLOBAL, vars)
コード例 #3
0
def settings() -> dict:
    """ Adjusts a user's profile. """
    if "account" not in flask.session:
        return flask.redirect("profile")

    users = cube.load_file("users")
    user = users[flask.session["account"]]
    gpgForm = forms.GPGForm()
    photoForm = forms.PhotoForm()
    secret = ""

    if gpgForm.validate_on_submit():
        key = cube.gpg.import_keys(gpgForm.gpgkey.data)
        user["keys"] += cube.gpg.list_keys(keys=[key.fingerprints[0]])
        curr = user["keys"][-1]
        curr["fuids"] = ", ".join(
            [uid.split()[-1][1:-1] for uid in curr["uids"]])
        cube.dump_file(users, "users")
        return alert("GPG key added.", "success", "meta")

    elif photoForm.validate_on_submit():
        users = cube.load_file("users")
        delete_photo()  #old profile picture not necessary anymore
        filename = forms.photos.save(photoForm.photo.data)
        users[flask.session["account"]]["pfp"] = forms.photos.url(filename)
        users[flask.session["account"]]["pfpfilename"] = filename
        cube.dump_file(users, "users")
        return alert("Profile photo changed.", "success", "profile")

    if flask.request.method == "POST":
        if "remove" in flask.request.form:
            delete_photo()
            return alert("Profile picture removed.", "success", "profile")

        if "delete" in flask.request.form:
            del user["keys"][int(flask.request.form["delete"])]
            cube.dump_file(users, "users")

        if "enable_2fa" in flask.request.form:
            secret = cube.pyotp.random_base32()
            user["2fa"] = secret
            cube.dump_file(users, "users")

        if "disable_2fa" in flask.request.form:
            del user["2fa"]
            cube.dump_file(users, "users")

        if "disable_yubi" in flask.request.form:
            del user["yubi"]
            cube.dump_file(users, "users")

    return {"gpgForm": gpgForm, "photoForm": photoForm, "secret": secret}
コード例 #4
0
def email() -> Response:
    """ After requesting to be added to the email list, see if nonce matches. """
    emails = cube.load_file("emails")
    requests = emails["requests"]
    nonce = flask.request.args.get("nonce", None)
    # subscribing
    if nonce in requests:
        email = requests[nonce]
        # Remove previous attempts
        emails["requests"] = {
            nonce: value
            for nonce, value in requests.items() if value != email
        }
        cube.dump_file(emails, "emails")
        cube.register_email(email)
        return alert("You have been added to the email list.", "success")
    requests = emails["unsubscribe-requests"]
    # unsubscribing
    if nonce in requests:
        email = requests[nonce]
        # Remove previous attempts
        emails["unsubscribe-requests"] = {
            nonce: value
            for nonce, value in requests.items() if value != email
        }
        cube.dump_file(emails, "emails")
        cube.remove_email(email)
        return alert("You have been removed from the email list.", "success")

    return alert("Wrong nonce. Try registering again?", "danger")
コード例 #5
0
def records() -> dict:
    """ Displays TJ's all time bests. """
    records = cube.load_file("records")
    times, people = records["records"], records["people"]
    refresh = False
    if "wca_token" in flask.session and "ion_token" in flask.session:
        me = cube.api_call("wca", "me")["me"]
        year = cube.api_call("ion", "profile")["graduation_year"]

        if [me["url"], me["name"], year] not in people:
            records["people"].append([me["url"], me["name"], year])
            # New person added
            refresh = True
            cube.dump_file(records, "records")

    if refresh or time.time() - records["time"] > cube.CONFIG["time"]:
        cube.update_records()
        (sing_rank, avg_rank), kinch_rank = cube.get_ranks()
        cube.dump_file(
            {
                "sor_single": sing_rank,
                "sor_average": avg_rank,
                "kinch": kinch_rank
            }, "wca/ranks")

    return {
        "times": times,
        "events": cube.EVENTS,
        "icons": cube.ICONS,
        "DNF": statistics.DNF,
        "ranks": cube.RANKS
    }
コード例 #6
0
def wca_stats() -> dict:
    """ Computes WCA summary statistics for TJ. """
    ranks = cube.load_file("wca/ranks")
    return {
        "events": [cube.ICONS[event][6:] for event in cube.EVENTS],
        "sor": cube.get_sor(),
        "sor_rank": (ranks["sor_single"], ranks["sor_average"]),
        "kinch": cube.get_kinch(),
        "kinch_rank": ranks["kinch"]
    }
コード例 #7
0
def cookie() -> dict:
    """ Returns the user's cookies. """
    data = dict(flask.session)
    users = cube.load_file("users")
    if "account" in flask.session:
        user = users[flask.session["account"]]
        if len(user["keys"]) > 0:
            return str(
                cube.gpg.encrypt(flask.json.dumps(data),
                                 [k["fingerprint"] for k in user["keys"]],
                                 always_trust=True))
    return data
コード例 #8
0
def competitions() -> dict:
    """ Gets the cached competitions, but will refresh if not updated recently. """
    c = cube.load_file("comps")
    last, comps = c["time"], c["comps"]
    if time.time() - last > cube.CONFIG["time"]:
        comps = cube.get_comps()

    return {
        "comps": comps,
        "last": cube.unix_to_human(last),
        "icons": cube.ICONS
    }
コード例 #9
0
def delete_photo() -> None:
    """ Deletes a photo from the server. """
    users = cube.load_file("users")
    user = users[flask.session["account"]]
    try:
        del user["pfp"]
    except KeyError:
        pass

    try:
        os.remove(forms.photos.path(user["pfpfilename"]))
        del user["pfpfilename"]
    except (KeyError, FileNotFoundError):
        pass

    cube.dump_file(users, "users")
コード例 #10
0
def vote_requirements():
    """ Checks if the user can view the vote/run pages. """
    if not cube.test_token("ion"):
        flask.session["action"] = flask.request.path
        return flask.redirect(flask.url_for("ion_login"))

    vote = cube.load_file("vote")

    if not cube.valid_voter():
        return alert(
            "You do not fullfill the requirements to be able to vote.",
            "warning")

    if not vote["vote_active"]:
        return alert("Stop trying to subvert democracy!", "danger")

    return vote
コード例 #11
0
def register_complete():
    data = cbor.decode(flask.request.get_data())
    client_data = ClientData(data["clientDataJSON"])
    att_obj = AttestationObject(data["attestationObject"])
    # print("clientData", client_data)
    # print("AttestationObject:", att_obj)

    auth_data = server.register_complete(flask.session["state"], client_data,
                                         att_obj)

    flask.session["credentials"].append(auth_data.credential_data)
    encoded = websafe_encode(auth_data.credential_data)
    users = cube.load_file("users")
    users[flask.session["account"]]["yubi"] = encoded
    cube.dump_file(users, "users")

    # print("REGISTERED CREDENTIAL:", auth_data.credential_data)
    return cbor.encode({"status": "OK"})
コード例 #12
0
def check(club_id):
    """ Checks the signups for a user on ION. """
    # may be subject to change, check: https://ion.tjhsst.edu/api/activities
    # 152 - Rubik's cube club, 198 - Computer vision, 204 - SCT
    if not cube.test_token("ion"):
        flask.session["action"] = flask.request.path
        return flask.redirect(flask.url_for("ion_login"))

    club_name = cube.api_call("ion", f"activities/{club_id}")["name"]
    fname = f"signups_{club_id}"
    record = cube.load_file(fname)

    username = cube.api_call("ion", "profile")["ion_username"]
    signups = cube.get_signups(club_id)
    number = cube.count_meetings(signups)
    record[username] = number

    cube.dump_file(record, fname)

    return alert(
        f"Recorded for {username} {number} attendances at {club_name}")
コード例 #13
0
def rankings() -> dict:
    """ Shows the rankings of all TJ students signed up. """
    return {
        "records": cube.load_file("records")["records"],
        "events": cube.EVENTS
    }
コード例 #14
0
csp = {
    "default-src": "'self'",
}
Talisman(app, content_security_policy=None)
# explicit CSRF protection for all forms
CSRFProtect(app)

# generate sitemap
# ext = Sitemap(app=app)

flask_uploads.configure_uploads(app, (forms.times, forms.photos))
# Strange glitch with TJ servers - if you look at the source code this *should* happen already...
app.register_blueprint(flask_uploads.uploads_mod)

rp = PublicKeyCredentialRpEntity(
    cube.load_file("site")["domain"], "2fa server")
server = Fido2Server(rp)


def alert(msg: str, category: str = "success", loc: str = "index") -> Response:
    """ Redirects the user with an alert. """
    flask.flash(msg, category)
    dest = {"self": flask.request.path, "meta": flask.request.full_path}
    return flask.redirect(flask.url_for(dest.get(loc, loc)))


@app.before_request
def before_request() -> None:
    """ Runs before each request. """
    try:
        vote = cube.load_file("vote")
コード例 #15
0
def profile() -> dict:
    """ Allows the user to login as well as register a new account. """
    loginForm = forms.LoginForm()
    codeForm = forms.TFAForm()
    signupForm = forms.SignupForm()
    mailForm = forms.MailForm()
    httpForm = forms.HTTPForm()
    ionForm, wcaForm = forms.APIForm(prefix="ion"), forms.APIForm(prefix="wca")
    rtn = {
        "loginForm": loginForm,
        "codeForm": codeForm,
        "signupForm": signupForm,
        "mailForm": mailForm,
        "httpForm": httpForm,
        "ionForm": ionForm,
        "wcaForm": wcaForm
    }

    users = cube.load_file("users")

    if "account" in flask.session:
        tabs = [["overview", "API"], ["email", "refresh", "develop"], ["edit"]]
        scopes = {"default": 0, "privileged": 1, "admin": 2}
        tab = flask.request.args.get('tab', 'overview')
        scope = scopes[flask.session["scope"]]

        i = None
        for j, group in enumerate(tabs):
            if tab in group:
                i = j
        if i is None:
            return alert("Invalid tab!", "info", "self")
        if i > scope:
            return alert(
                "User does not have the valid scope. This incident will be logged.",
                "danger", "self")

        rtn = cube.add_dict(
            {
                "tabs": tabs,
                "scopes": scopes,
                "clubmailpassword":
                cube.load_file("secrets")["clubmailpassword"],
                "emails": cube.load_file("emails")["emails"],
            }, rtn)
    else:
        scope = 0

    if scope >= 0:
        if "confirm" in flask.request.form and signupForm.validate_on_submit():
            username, password = signupForm.username.data, signupForm.password.data
            if username in cube.load_file("users"):
                return alert("Username is taken.", "info", "meta")
            if password != signupForm.confirm.data:
                return alert("Passwords do not match.", "info", "meta")

            cube.register(username, password)
            return alert("Account registered!", "success", "self")

        elif "login" in flask.request.form and loginForm.validate_on_submit():
            username, password = loginForm.username.data, loginForm.password.data
            if not cube.check(username, password):
                return alert("Username or password is incorrect.", "info",
                             "self")

            # Save login to cookies if 2fa is not enabled, otherwise don't
            if "2fa" not in users[username] and "yubi" not in users[username]:
                flask.session["account"] = username
                flask.session["scope"] = users[username]["scope"]
            else:
                if "2fa" in users[username]:
                    flask.session["2fa"] = True
                flask.session["username"] = username

            # load U2F challenge if it exists
            if "yubi" in users[username]:
                flask.session["yubi"] = websafe_decode(users[username]["yubi"])

            return flask.redirect(flask.url_for("profile"))

        elif "yubi_check" in flask.session or (
                "login_2fa" in flask.request.form
                and codeForm.validate_on_submit()):
            username = flask.session["username"]
            if "yubi_check" not in flask.session and not cube.check_2fa(
                    username, str(codeForm.code.data)):
                return alert("2FA code is incorrect.", "info", "self")

            if "yubi_check" in flask.session:
                del flask.session["yubi_check"]

            # actually login
            flask.session["account"] = username
            flask.session["scope"] = users[username]["scope"]
            return flask.redirect(flask.url_for("profile"))

        elif "cancel_2fa" in flask.request.form and "2fa" in flask.session:
            del flask.session["2fa"]

        elif "cancel_yubi" in flask.request.form and "yubi" in flask.session:
            del flask.session["yubi"]

        elif ionForm.validate_on_submit():
            rtn = cube.add_dict(
                {"data": cube.api_call("ion", ionForm.call.data)}, rtn)

        elif wcaForm.validate_on_submit():
            rtn = cube.add_dict(
                {"data": cube.api_call("wca", wcaForm.call.data)}, rtn)

    if scope >= 1:
        if mailForm.validate_on_submit():
            recipients = mailForm.recipients.data.split(
                ", ") if mailForm.recipients.data != "" else cube.load_file(
                    "emails")["emails"]
            # add footer with unsubscribe information
            body = mailForm.email.data.replace("\n", "") + \
f"""

--
If you're tired of seeing these emails, unsubscribe [here]({cube.TJ}).
"""
            body = cube.markdown2.markdown(body)
            cube.send_email(recipients, mailForm.subject.data, body)
            if mailForm.log.data:
                cube.save_email(mailForm.subject.data, mailForm.email.data)
            return alert("Mail sent.", "success", "meta")

        elif httpForm.validate_on_submit():
            flask.abort(int(httpForm.http.data))

    if scope >= 2:
        pass

    if flask.request.method == "POST":

        if "logout" in flask.request.form:
            del flask.session["account"]
            if "2fa" in flask.session:
                del flask.session["2fa"]
            if "yubi" in flask.session:
                del flask.session["yubi"]

        if "delete" in flask.request.form:
            del users[flask.session["account"]]
            del flask.session["account"]
            cube.dump_file(users, "users")
            return alert("Account deleted!", "success", "self")

        if "clear" in flask.request.form:
            # Save CSRF token
            csrf = flask.session["csrf_token"]
            flask.session.clear()
            flask.session["csrf_token"] = csrf

        if "fb" in flask.request.form:
            cube.get_pfps(cube.CONFIG["officers"])
            alert("Updated the profile pictures!")

        if "comps" in flask.request.form:
            cube.get_comps()
            alert("Updated the competitions!")

        if "records" in flask.request.form:
            cube.update_records()
            alert("Updated the records!")

        if "history" in flask.request.form:
            cube.save_club_history()
            cube.graph_capacity()
            cube.graph_blocks("by_x")
            cube.graph_blocks("by_y")
            alert("Updated the club history!")

        if "heatmap" in flask.request.form:
            cube.graph_vists()
            alert("Updated the heatmap!")

    return rtn
コード例 #16
0
def result() -> dict:
    """ Displays the result of the election. """
    return {"result": cube.get_winner(), "vote": cube.load_file("vote")}
コード例 #17
0
def profile() -> dict:
    """ Allows the user to login as well as register a new account. """
    loginForm = forms.LoginForm()
    signupForm = forms.SignupForm()
    mailForm = forms.MailForm()
    httpForm = forms.HTTPForm()
    ionForm, wcaForm = forms.APIForm(prefix="ion"), forms.APIForm(prefix="wca")
    rtn = {
        "loginForm": loginForm,
        "signupForm": signupForm,
        "mailForm": mailForm,
        "httpForm": httpForm,
        "ionForm": ionForm,
        "wcaForm": wcaForm
    }

    users = cube.load_file("users")

    if "account" in flask.session:
        tabs = [["overview", "API"], ["email", "refresh", "develop"], ["edit"]]
        scopes = {"default": 0, "privileged": 1, "admin": 2}
        tab = flask.request.args.get('tab', 'overview')
        scope = scopes[flask.session["scope"]]

        i = None
        for j, group in enumerate(tabs):
            if tab in group:
                i = j
        if i is None:
            return alert("Invalid tab!", "info", "self")
        if i > scope:
            return alert(
                "User does not have the valid scope. This incident will be logged.",
                "danger", "self")

        rtn = cube.add_dict(
            {
                "tabs": tabs,
                "scopes": scopes,
                "clubmailpassword":
                cube.load_file("secrets")["clubmailpassword"],
                "emails": cube.load_file("emails")["emails"],
            }, rtn)
    else:
        scope = 0

    if scope >= 0:
        if "confirm" in flask.request.form and signupForm.validate_on_submit():
            username, password = signupForm.username.data, signupForm.password.data
            if username in cube.load_file("users"):
                return alert("Username is taken.", "info", "meta")
            if password != signupForm.confirm.data:
                return alert("Passwords do not match.", "info", "meta")

            cube.register(username, password)
            return alert("Account registered!", "success", "self")

        elif "login" in flask.request.form and loginForm.validate_on_submit():
            username, password = loginForm.username.data, loginForm.password.data
            if not cube.check(username, password):
                return alert("Username or password is incorrect.", "info",
                             "self")

            # Save login to cookies
            flask.session["account"] = username
            flask.session["scope"] = users[username]["scope"]
            return flask.redirect(flask.url_for("profile"))

        elif ionForm.validate_on_submit():
            rtn = cube.add_dict(
                {"data": cube.api_call("ion", ionForm.call.data)}, rtn)

        elif wcaForm.validate_on_submit():
            rtn = cube.add_dict(
                {"data": cube.api_call("wca", wcaForm.call.data)}, rtn)

    if scope >= 1:
        if mailForm.validate_on_submit():
            recipients = mailForm.recipients.data.split(
                ", ") if mailForm.recipients.data != "" else cube.load_file(
                    "emails")["emails"]
            body = cube.markdown2.markdown(mailForm.email.data).replace(
                "\n", "")
            cube.send_email(recipients, mailForm.subject.data, body)
            if mailForm.log.data:
                cube.save_email(mailForm.subject.data, mailForm.email.data)
            return alert("Mail sent.", "success", "meta")

        elif httpForm.validate_on_submit():
            flask.abort(int(httpForm.http.data))

    if scope >= 2:
        pass

    if flask.request.method == "POST":

        if "logout" in flask.request.form:
            del flask.session["account"]

        if "delete" in flask.request.form:
            del users[flask.session["account"]]
            del flask.session["account"]
            cube.dump_file(users, "users")
            return alert("Account deleted!", "success", "self")

        if "clear" in flask.request.form:
            # Save CSRF token
            csrf = flask.session["csrf_token"]
            flask.session.clear()
            flask.session["csrf_token"] = csrf

        if "fb" in flask.request.form:
            cube.get_pfps(cube.CONFIG["officers"])

        if "comps" in flask.request.form:
            cube.get_comps()

        if "records" in flask.request.form:
            cube.update_records()

    return rtn
コード例 #18
0
ファイル: freeze.py プロジェクト: stephen-huan/TJCubing
import time, os
from flask_frozen import Freezer
import cube

OUT = "rendered_templates"

#Change URL format to end with a tailing slash
site = cube.load_file("site")
site["tailing_slash"] = True
cube.dump_file(site, "site")

from app import app

app.config['FREEZER_IGNORE_MIMETYPE_WARNINGS'] = True
app.config['FREEZER_REDIRECT_POLICY'] = 'ignore'

freezer = Freezer(app)

# if __name__ == '__main__':
#     freezer.freeze()

#Undo changes
site["tailing_slash"] = False
cube.dump_file(site, "site")

try:
    os.mkdir(OUT)
except FileExistsError:
    pass

コード例 #19
0
def convert(order: list, prefix: str = "", new: list = []) -> list:
    """ Converts an order specification into a parsable (path, name) format by the nav header. """
    for name in order:
        if isinstance(name, list):
            addition, sublist = name
            new.append(
                ("*" + addition, convert(sublist, "{}".format(prefix), [])))
        else:
            new.append(
                ("{}{}".format(prefix,
                               name if name != "" else "index"), NAMES[name]))
    return new


params = cube.load_file("site")
TSLASH = "/" if params["tailing_slash"] else ""
NAMES = params["names"]
NAV = convert(params["order"])

PAGES = {
    "": (index, ["POST", "GET"]),
    "competitions": competitions,
    "algorithms": None,
    "weekly": {
        "lectures": lectures,
        "inhouse": (in_house, ["POST", "GET"]),
    },
    "contact": lambda: {
        "fb": cube.load_file("fb")
    },