def login(): if app.debug: response = remote.authorize( callback=url_for("authorized", _external=True)) else: response = remote.authorize( url_for("authorized", _external=True, _scheme="https")) return response
def toggle_recovery(): if not is_staff("cs61a"): return redirect(url_for("config")) with connect_db() as db: was_enabled = is_recovery_enabled() db('DELETE FROM config WHERE conf_key="recovery"') if not was_enabled: db('INSERT INTO config VALUES ("recovery", "true")') return redirect(url_for("config"))
def sudo(username): if not is_software_ta(get_user()["email"]): return redirect(url_for("index")) out = "<h1>61A Sandbox IDE</h1>\n" out += f"Hi {get_user()['name'].split()[0]}! {username}'s IDE is " session[SK_RETURN_TO] = url_for("sudo", username=username) return gen_index_html(out, username, True)
def config(): auth_result = authenticate(app) if not (isinstance(auth_result, str) and auth_result == "Authorized!"): return auth_result with connect_db() as db: gscope: List[Tuple[str, str]] = db( "SELECT name, gs_code FROM gscope", [], ).fetchall() adjustments: List[Tuple[str, str, str]] = db( "SELECT hashed, url, sheet FROM adjustments", [], ).fetchall() return html( """ <h1>Grade Display Config</h1> <p> Add a Gradescope assignment: """ + make_row( """<input name="name" placeholder="Shortname (no spaces!)" /> <input name="gs_code" placeholder="Gradescope code" /> """, url_for("create_assign"), "Submit", ) + """ </p> <p> Add an adjustments sheet: """ + make_row( """<input name="url" placeholder="Full URL" /> <input name="sheet" placeholder="Sheet Name" /> """, url_for("add_adjustments"), "Submit", ) + """ </p> """ + "".join( "<p>" + make_row(f"{name} ({gs_code})", url_for("delete_assign", name=name)) for name, gs_code in gscope ) + "".join( "<p>" + make_row( f"Adjustments: {url} ({sheet})", url_for("delete_adjustments", hashed=hashed), ) for hashed, url, sheet in adjustments ) )
def add_adjustments(): if not is_staff("cs61a"): return redirect(url_for("config")) url = request.form["url"] sheet = request.form["sheet"] hashed = hashlib.sha512(url.encode("utf-8") + sheet.encode("utf-8")).hexdigest() with connect_db() as db: db( "INSERT INTO adjustments (hashed, url, sheet) VALUES (%s, %s, %s)", [hashed, url, sheet], ) return redirect(url_for("config"))
def set_acadh(): if not is_staff("cs61a"): return redirect(url_for("config")) url = request.form["url"] sheet = request.form["sheet"] with connect_db() as db: db("DELETE FROM acadh") db( "INSERT INTO acadh (url, sheet) VALUES (%s, %s)", [url, sheet], ) return redirect(url_for("config"))
def authorized(): from common.course_config import get_endpoint message = request.args.get("error") if message: message = "Ok OAuth error: %s" % (message) return redirect(url_for("error", message=message)) try: auth_resp = auth.ok_auth.authorized_response() if auth_resp is None: message = "Invalid Ok response: %s" % (message) return redirect(url_for("error", message=message)) except OAuthException as ex: message = str(ex) return redirect(url_for("error", message=message)) token = auth_resp["access_token"] session["access_token"] = (token, "") # (access_token, secret) info = auth.ok_auth.get("user").data["data"] email = info["email"] name = info["name"] if not name: name = email if ", " in name: last, first = name.split(", ") name = first + " " + last is_staff = False offering = get_endpoint() for p in info["participations"]: if p["course"]["offering"] == offering: if p["role"] != "student": is_staff = True else: is_staff = False break else: if ( ConfigEntry.query.filter_by( course=get_course(), key="only_registered_students" ) .one() .value == "true" ): return redirect( url_for( "error", message="Only registered students can log in", ) ) user = user_from_email(name, email, is_staff) return authorize_user(user)
def create_assign(): if not is_staff("cs61a"): return redirect(url_for("config")) name = request.form["name"] gs_code = request.form["gs_code"] with connect_db() as db: existing = db("SELECT * FROM gscope WHERE name=%s", [name]).fetchall() if existing: abort(409) db( "INSERT INTO gscope (name, gs_code) VALUES (%s, %s)", [name, gs_code], ) return redirect(url_for("config"))
def load_file(path): try: out = send_from_directory(STATIC_FOLDER, path.replace("//", "/")) except NotFound: pass else: return out raw = load_shortlink_file(path) if raw is NOT_LOGGED_IN: response = redirect(url_for("login")) response.set_cookie(COOKIE_SHORTLINK_REDIRECT, value=path) return response elif raw is NOT_AUTHORIZED: return "This file is only visible to staff." if raw is NOT_FOUND: return "File not found", 404 data = { "fileName": raw["full_name"], "data": raw["data"], "shareRef": raw["share_ref"], } return render_template("index.html", initData={"loadFile": data})
def add_admin(course): email = request.form["email"] with connect_db() as db: check = db( "SELECT * FROM course_admins WHERE email=(%s) AND course=(%s)", [email, course], ).fetchone() if check: return error("User is already an admin"), 409 with connect_db() as db: db( "INSERT INTO course_admins VALUES (%s, %s, %s, %s)", [email, "Unknown", course, get_name()], ) # make sure that you can't accidentally lock yourself out with connect_db() as db: check = db( "SELECT * FROM course_admins WHERE email=(%s) AND course=(%s)", [get_email(), course], ).fetchone() if not check: db( "INSERT INTO course_admins VALUES (%s, %s, %s, %s)", [get_email(), get_name(), course, get_name()], ) return redirect(url_for("index"))
def super_clients(): if not is_staff(MASTER_COURSE): return "" with connect_db() as db: ret = db("SELECT client_name, creator, unused FROM super_auth_keys" ).fetchall() super_client_names = [ make_row( f'{client_name}, created by {creator} {"(unused)" if unused else ""} ', url_for("revoke_super_key", client_name=client_name), ) for client_name, creator, unused in ret ] return f""" <h3>Super-Clients</h3> <p> Warning - the API keys for these clients are extremely sensitive, as they can access <i>any</i> course's data. Only use them for 61A-hosted apps, and reset them whenever a head TA leaves course staff. </p> Create new super-client and obtain secret key: <form action="{url_for("create_super_key")}" method="post"> <input name="client_name" type="text" placeholder="client_name"> <input type="submit"> </form> """ + "<p>".join(super_client_names)
def delete_unused_services_handler(): if not is_staff("cs61a"): return login() email = get_user()["email"] if not is_admin(course="cs61a", email=email): return login() delete_unused_services() return redirect(url_for("index"))
def kill(): username = request.form.get("username") pid = get_server_pid(username) if pid: sh("kill", pid.decode("utf-8")[:-1]) sh("sleep", "2") # give the server a couple of seconds to shutdown return redirect(session.pop(SK_RETURN_TO, url_for("index")))
def index(): username = get_username() out = "<h1>61A Sandbox IDE</h1>\n" out += f"Hi {get_user()['name'].split()[0]}! Your IDE is " session[SK_RETURN_TO] = url_for("index") return gen_index_html(out, username, is_software_ta(get_user()["email"]))
def remove_admin(course): email = request.args["email"] with connect_db() as db: db( "DELETE FROM course_admins WHERE email=(%s) AND course=(%s)", [email, course], ) return redirect(url_for("index"))
def login(): """Store the current URL as the redirect target on success, then redirect to the login endpoint for the current app. :return: a :func:`~flask.redirect` to the login endpoint for the current :class:`~flask.Flask` app. """ session[REDIRECT_KEY] = urlparse(request.url)._replace(netloc=get_host()).geturl() return redirect(url_for("login"))
def set_granular_spreadsheet(course): url = request.form["url"] sheet = request.form["sheet"] with connect_db() as db: db("DELETE FROM course_permissions WHERE course=(%s)", [course]) db( "INSERT INTO course_permissions (course, url, sheet) VALUES (%s, %s, %s)", [course, url, sheet], ) return redirect(url_for("index"))
def admin_data(course): with connect_db() as db: ret = db( "SELECT email, name, course, creator FROM course_admins WHERE course=(%s)", [course], ).fetchall() admin_names = [ make_row( f'{name} (<a href="mailto:{email}">{email}</a>), added by {creator} ', url_for("remove_admin", course=course, email=email), ) for email, name, course, creator in ret ] add_admin = f""" Add new course administrator: <form action="{url_for("add_admin", course=course)}" method="post"> <input name="email" type="email" placeholder="Email address"> <input type="submit"> </form> """ with connect_db() as db: ret = db( "SELECT url, sheet FROM course_permissions WHERE course=(%s)", [course]).fetchall() perms_sheet = [ make_row( f'<a href="{url}">{sheet} ({url})</a>', url_for("unset_granular_spreadsheet", course=course), ) for url, sheet in ret ] # there should only be 0-1 perms sheets add_perms_sheet = f""" Add granular permissions sheet (first column should be email, the rest should be permission names): <form action="{url_for("set_granular_spreadsheet", course=course)}" method="post"> <input name="url" placeholder="URL"> <input name="sheet" placeholder="Sheet Name"> <input type="submit"> </form> """ return ("<h3>Admins</h3>" + add_admin + "<p>".join(admin_names) + "<br>" + "<h3>Granular Permissions</h3>" + add_perms_sheet + "<p>".join(perms_sheet))
def remove_source(): if not is_staff(get_course()): return login() url = request.form["url"] sheet = request.form["sheet"] with connect_db() as db: db( "DELETE FROM sources WHERE url=%s AND sheet=%s AND course=%s", [url, sheet, get_course()], ) return redirect(url_for("index"))
def add_source(): if not is_staff(get_course()): return login() url = request.form["url"] sheet = request.form["sheet"] secure = True if request.form.get("secure", False) else False with connect_db() as db: db( "INSERT INTO sources VALUES (%s, %s, %s, %s)", [url, sheet, secure, get_course()], ) return redirect(url_for("index"))
def authenticate(app): """Returns an OAuth token that can be passed to the server for identification. If FORCE is False, it will attempt to use a cached token or refresh the OAuth token. If NOINTERACT is true, it will return None rather than prompting the user. """ try: access_token = refresh_local_token() except Exception: print("Performing authentication.") if not is_staff("cs61a"): return redirect(url_for("login")) return "Authorized!"
def authorized(): resp = remote.authorized_response() if resp is None: return "Access denied: error=%s" % (request.args["error"]) if isinstance(resp, dict) and "access_token" in resp: session["access_token"] = (resp["access_token"], "") if return_response: return_response(resp) if success_callback: success_callback() target = session.get(REDIRECT_KEY) if target: session.pop(REDIRECT_KEY) return redirect(target) return redirect(url_for("index"))
def slack_help(course): with connect_db() as db: workspace = db( "SELECT workspace FROM slack_config WHERE course=(%s)", [course]).fetchone() workspace = workspace[0] if workspace else "" registered_channels = db( "SELECT purpose, channel, channel_id FROM slack_channels WHERE course=(%s)", [course], ).fetchall() try: channels = list_channels(course=course) except: registration = """ To register Slack channels, first go to <a href="https://slack.cs61a.org">slack.cs61a.org</a> to add the bot to your workspace. """ else: channels = [ f"<option value=\"{channel['name']}\">{channel['name']}</option>" for channel in channels ] registration = f""" Register a new Slack channel. <form action="/slack/{course}/register_channel" method="post"> <input name="purpose" type="text" placeholder="Purpose"> <select name="channel"> {channels} </select> <input type="submit"> </form> """ registered_channels_list = "<p>".join( make_row( f"{purpose} associated with #{channel} (id: {channel_id})", url_for("remove_channel", course=course, purpose=purpose), ) for purpose, channel, channel_id in registered_channels) return f"""
def view_course(course=None): if not course: course = request.form["course"] return redirect(url_for("canonical_view_course", course=course)) if not is_logged_in(): return login() email = get_user()["email"] if not is_admin(email, course): abort(403) with connect_db() as db: apps = db( "SELECT domain, app, status FROM hosted_apps WHERE course=(%s)", [course]).fetchall() return html(f""" <h2>Hosted Apps for {format_coursecode(course)}</h2> {"<p>".join(f"<code>{domain}</code> ({app}) - {status}" for domain, app, status in apps)} """)
def index(): if not is_staff(get_course()): return login() with connect_db() as db: sources = db( "SELECT url, sheet, secure FROM sources WHERE course=%s", [get_course()] ).fetchall() insert_fields = """<input placeholder="Spreadsheet URL" name="url"></input> <input placeholder="Sheet Name" name="sheet"></input> <label> <input type="checkbox" name="secure"></input> Require Authentication </label>""" sources = "<br/>".join( make_row( f'<a href="{url}">{url}</a> {sheet} (Secure: {secure})' f'<input name="url" type="hidden" value="{url}"></input>' f'<input name="sheet" type="hidden" value="{sheet}"></input>', url_for("remove_source"), ) for url, sheet, secure in sources ) return html( f""" <h2>Course: <code>{get_course()}</code></h2> Each spreadsheet should be shared with the 61A service account <a href="mailto:[email protected]"> [email protected]</a>. They should have three columns with the headers: "URL", "Shortlink", and "Creator". <p> Visit <a href="{url_for("refresh")}">{url_for("refresh")}</a> (no auth required) after adding a link to synchronize with the spreadsheets. <h3>Sources</h3> {sources} <h3>Add Sources</h3> {make_row(insert_fields, url_for("add_source"), "Add")} """ )
def client_data(course): with connect_db() as db: ret = db( "SELECT email, name, course, creator FROM course_admins WHERE course=(%s)", [course], ).fetchall() admin_names = [ make_row( f'{name} (<a href="mailto:{email}">{email}</a>), added by {creator} ', url_for("remove_admin", course=course, email=email), ) for email, name, course, creator in ret ] create_client = f""" Add new course administrator: <form action="{url_for("add_admin", course=course)}" method="post"> <input name="email" type="email" placeholder="Email address"> <input type="submit"> </form> """ return "<h3>Admins</h3>" + create_client + "<p>".join(admin_names)
def client_data(course): with connect_db() as db: ret = db( "SELECT client_name, creator, unused FROM auth_keys WHERE course=(%s)", [course], ).fetchall() client_names = [ make_row( f'{client_name}, created by {creator} {"(unused)" if unused else ""} ', url_for("revoke_key", course=course, client_name=client_name), ) for client_name, creator, unused in ret ] create_client = f""" Create new client and obtain secret key: <form action="{url_for("create_key", course=course)}" method="post"> <input name="client_name" type="text" placeholder="client_name"> <input type="submit"> </form> """ return "<h3>Clients</h3>" + create_client + "<p>".join(client_names)
def domains_help(course): with connect_db() as db: ret = db("SELECT domain FROM domains_config WHERE course=(%s)", [course]).fetchall() client_names = [ make_row(domain, url_for("remove_domain", domain=domain, course=course)) for domain, in ret ] register_domain = f""" Register new domain: <form action="/domains/{course}/register_domain" method="post"> <input name="domain_name" type="text" placeholder="seating.cs61a.org"> <input type="submit"> </form> View the status of your domain setup at <a href="https://domains.cs61a.org/">domains.cs61a.org</a> <br /> """ return "<h3>Domains</h3>" + register_domain + "<p>".join(client_names)
def add_course(): if not is_staff(MASTER_COURSE): return "" with connect_db() as db: courses = db("SELECT course, endpoint FROM courses").fetchall() courses = [ make_row( "{} ({}), at endpoint {}".format(prettify(course), course, endpoint), url_for("remove_course", course=course), ) for course, endpoint in courses ] return """ <h2>Admin</h2> <h3>Courses</h3> Activate Auth for a new course (method only available to 61A admins): <form action="/api/add_course" method="post"> <input name="course" type="text" placeholder="course name"> <input name="endpoint" type="text" placeholder="OKPy endpoint"> <input type="submit"> </form> """ + "<p>".join(courses)
def submit(): if not is_staff("cs61a"): return login() data = request.form["data"] return redirect(url_for("load_formatted", name=paste_worker(data)))