Esempio n. 1
0
def load(name, skip_auth=False):
    """Loads the paste text for given name

    :param name: name associated with the paste text
    :type name: str
    :param skip_auth: a flag to skip the authentication for the user;
        ``False`` by default
    :type skip_auth: bool

    :return: a string representing the paste text for this user
    """
    out = None
    with connect_db() as db:
        data = db(
            "SELECT data FROM pastes WHERE name=%s AND private=FALSE",
            [name],
        ).fetchone()
        if data:
            out = data[0]
    if out is None:
        if not skip_auth and not is_staff("cs61a"):
            return login()
        with connect_db() as db:
            data = db(
                "SELECT data FROM pastes WHERE name=%s",
                [name],
            ).fetchone()
            if data:
                out = data[0]
    if out is None:
        abort(404)
    elif isinstance(out, bytes):
        return out.decode("utf-8")
    else:
        return out
Esempio n. 2
0
def db_lock(active_db, username):
    try:
        with connect_db() as db:
            locked = db(f"SELECT locked FROM {active_db} WHERE username=%s",
                        [username]).fetchone()
            if locked is None:
                # environment does not exist
                db(
                    f"INSERT INTO {active_db} (username, initialized, locked) VALUES (%s, FALSE, TRUE)",
                    [username],
                )
                yield
            else:
                [locked] = locked
                if locked:
                    # TODO: Some way to force an unlock from the CLI
                    raise BlockingIOError(
                        f"Another operation is currently taking place on {active_db}"
                    )
                else:
                    db(
                        f"UPDATE {active_db} SET locked=TRUE WHERE username=%s",
                        [username],
                    )
                    yield

    finally:
        with connect_db() as db:
            db(f"UPDATE {active_db} SET locked=FALSE WHERE username=%s",
               [username])
Esempio n. 3
0
def validate(data, timeout):
    for participation in data["participations"]:
        if participation["course"]["offering"] == get_endpoint("cs61a"):
            break
    else:
        abort(
            401,
            "You are not enrolled in CS 61A, and so are not authorized to submit."
        )

    email = data["email"]

    with connect_db() as db:
        ret = db("SELECT last_access FROM accesses WHERE email=(%s)",
                 [email]).fetchone()

    now = int(time.time())
    if ret and now - ret[0] < timeout:
        abort(
            429,
            "You have made many requests in a short amount of time. Please wait a bit and try again.",
        )

    with connect_db() as db:
        db("DELETE FROM accesses WHERE email=(%s)", [email])
        db("INSERT INTO accesses VALUES (%s, %s)", [email, now])
Esempio n. 4
0
    def submitRegradeRequest():
        if not is_logged_in():
            return dict(success=False)
        if request.method == "GET":
            return dict(success=False)
        email = request.get_json().get("email")
        assignment = request.get_json().get("assignment")

        with connect_db() as db:
            status = db(
                "SELECT status FROM regrade_requests WHERE courseCode=%s AND email=%s AND assignment=%s",
                [get_course(), email, assignment],
            ).fetchone()
            if status:
                status = status[0]
        if status and status not in ("needs followup"):
            return dict(success=False)

        backup_id = request.get_json().get("backup_id")
        description = request.get_json().get("description")
        ta = request.form.get("ta")
        status = "requested"
        with connect_db() as db:
            db(
                """INSERT INTO regrade_requests (
                courseCode, email, assignment, backup_id, description, assigned_to, status
                ) VALUES (%s, %s, %s, %s, %s, %s, %s)""",
                [
                    get_course(), email, assignment, backup_id, description,
                    ta, status
                ],
            )
        return dict(success=True)
Esempio n. 5
0
def load(name, skip_auth=False):
    out = None
    with connect_db() as db:
        data = db(
            "SELECT data FROM pastes WHERE name=%s AND private=FALSE",
            [name],
        ).fetchone()
        if data:
            out = data[0]
    if out is None:
        if not skip_auth and not is_staff("cs61a"):
            return login()
        with connect_db() as db:
            data = db(
                "SELECT data FROM pastes WHERE name=%s",
                [name],
            ).fetchone()
            if data:
                out = data[0]
    if out is None:
        abort(404)
    elif isinstance(out, bytes):
        return out.decode("utf-8")
    else:
        return out
Esempio n. 6
0
def refresh():
    with connect_db() as db:
        db("DELETE FROM shortlinks WHERE course=%s", [get_course()])
        sheets = db(
            "SELECT url, sheet, secure FROM sources WHERE course=(%s)", [get_course()]
        ).fetchall()
    data = []
    for url, sheet, secure in sheets:
        try:
            csvr = read_spreadsheet(url=url, sheet_name=sheet)
        except:
            return error(f"Failed to read spreadsheet {url} (Sheet: {sheet})")
        headers = [x.lower() for x in csvr[0]]
        for row in csvr[1:]:
            row = row + [""] * 5
            shortlink = row[headers.index("shortlink")]
            url = row[headers.index("url")]
            creator = row[headers.index("creator")]
            data.append([shortlink, url, creator, secure, get_course()])
    with connect_db() as db:
        db(
            "INSERT INTO shortlinks (shortlink, url, creator, secure, course) VALUES (%s, %s, %s, %s, %s)",
            data,
        )
    return html("Links updated")
Esempio n. 7
0
    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"))
Esempio n. 8
0
    def query():
        try:
            if is_logged_in():
                user = get_user()

                email = user["email"]

                target = request.args.get("target", None)

                if is_staff(get_course()):
                    if target:
                        email = target
                    else:
                        all_students = []
                        with connect_db() as db:
                            lookup = db(
                                "SELECT shortData FROM students WHERE courseCode=%s",
                                [get_course()],
                            ).fetchall()
                            for row in lookup:
                                parsed = json.loads(row[0])
                                all_students.append(parsed)
                        return jsonify({
                            "success": True,
                            "isStaff": True,
                            "allStudents": all_students,
                            "email": user["email"],
                            "name": user["name"],
                            "lastUpdated": last_updated(),
                        })

                with connect_db() as db:
                    [short_data, data] = db(
                        "SELECT shortData, data FROM students WHERE courseCode=%s AND email=%s",
                        [get_course(), email],
                    ).fetchone()
                    [header
                     ] = db("SELECT header FROM headers WHERE courseCode=%s",
                            [get_course()]).fetchone()
                    short_data = json.loads(short_data)
                    data = json.loads(data)
                    header = json.loads(header)
                    return jsonify({
                        "success": True,
                        "header": header,
                        "data": data,
                        "email": short_data["Email"],
                        "name": short_data["Name"],
                        "SID": short_data["SID"],
                        "lastUpdated": last_updated(),
                    })
            else:
                return jsonify({"success": False, "retry": True})

        except Exception:
            pass
        return jsonify({"success": False, "retry": False})
Esempio n. 9
0
def add_domain(app, is_staging, course, domain):
    try:
        if app != "auth":
            abort(401)

        app = APP_LOOKUP[domain.split(".")[0]]

        with connect_db() as db:
            status = db("SELECT status FROM hosted_apps WHERE domain=(%s)",
                        [domain]).fetchone()
            if status is not None and status[0] == Status.SUCCESS:
                return ""  # domain already provisioned
            db("DELETE FROM hosted_apps WHERE domain=(%s)", [domain])

        with connect_db() as db:
            db(
                "INSERT INTO hosted_apps (domain, course, app, status) VALUES (%s, %s, %s, %s)",
                [domain, course, app, Status.VALIDATING.value],
            )

        try:
            ip = socket.gethostbyname(domain)
        except socket.gaierror:
            ip = None
        if ip != socket.gethostbyname("proxy.cs61a.org"):
            set_status(domain, Status.DNS_INVALID)
            return

        set_status(domain, Status.PROVISIONING)

        try:
            requests.post(
                "https://proxy.cs61a.org/create_domain",
                json=dict(
                    app=app,
                    domain=domain,
                    target=get_base_hostname(target_app=app),
                    secret=get_secret(secret_name="DOMAIN_WEBHOOK_SECRET"),
                ),
            ).raise_for_status()
        except requests.exceptions.ConnectionError:
            pass  # nginx restarts so the connection crashes

        sleep(5)

        if not requests.get(f"https://{domain}/").ok:
            set_status(domain, Status.PROVISIONING_FAILED)
            return

        set_status(domain, Status.UPDATING_OAUTH)
        # TODO
        set_status(domain, Status.SUCCESS)
        return
    except:
        set_status(domain, Status.INTERNAL_ERROR)
        raise
Esempio n. 10
0
 def oauth():
     if not request.args["code"]:
         return jsonify({"Error": "sadcat"}), 500
     resp = requests.post(
         "https://slack.com/api/oauth.v2.access",
         {
             "code": request.args["code"],
             "client_id": get_secret(secret_name="CLIENT_ID"),
             "client_secret": get_secret(secret_name="CLIENT_SECRET"),
         },
     )
     if resp.status_code == 200:
         data = resp.json()
         bot_token = data["access_token"]
         workspace_data = requests.post(
             "https://slack.com/api/auth.test",
             headers={"Authorization": "Bearer {}".format(bot_token)},
         ).json()
         workspace_url = workspace_data["url"]
         workspace = re.match(
             r"https://([a-zA-Z\-0-9]+)\.slack\.com", workspace_url
         ).group(1)
         store_bot_token(get_course(workspace), data["team"]["id"], bot_token)
         store_user_token(
             data["authed_user"]["id"], data["authed_user"]["access_token"]
         )
         with connect_db() as db:
             db(
                 "DELETE FROM silenced_users WHERE user = (%s)",
                 [data["authed_user"]["id"]],
             )
         return redirect(workspace_url)
     return jsonify({"Error": "sadcat"}), 500
Esempio n. 11
0
    def handler():
        payload = json.loads(request.form["payload"])
        if "actions" not in payload or "value" not in payload["actions"][0]:
            return ""
        action = payload["actions"][0]["value"]
        user_id = payload["user"]["id"]
        if action == "activate":
            requests.post(
                payload["response_url"],
                json={
                    "text": ":robot_face: Activated! While we can't update your previous message (:crying_cat_face:), all your future messages will be made awesome!",
                    "replace_original": "true",
                },
            )
        elif action == "maybe_later":
            requests.post(
                payload["response_url"],
                json={
                    "text": "Alright, I'll ask you again later. Or visit slack.apps.cs61a.org to activate this bot manually!!",
                    "replace_original": "true",
                },
            )
        elif action == "never_ask_again":
            with connect_db() as db:
                db("INSERT INTO silenced_users VALUES (%s)", (user_id,))
            requests.post(
                payload["response_url"],
                json={
                    "text": "Understood. If you ever change your mind, visit slack.apps.cs61a.org to activate this bot!",
                    "replace_original": "true",
                },
            )

        return ""
Esempio n. 12
0
def index():
    if not is_staff("cs61a"):
        return login()
    with connect_db() as db:
        secrets: List[Tuple[str, str, str, str]] = db(
            "SELECT app, name, public_value, staging_value FROM secrets"
        ).fetchall()
    return """
    <h1>Secrets Tool</h1>
    <p>
        Add a secret: 
        <form action="/create_secret" method="POST">
            <input name="app" placeholder="App name" /> 
            <input name="name" placeholder="Secret name" /> 
            <input name="public" placeholder="Public value" /> 
            <input name="staging" placeholder="Staging value" />
            <button type="submit">Submit</button>
        </form>
    </p>
    <p>
        You should assume that the staging value is visible to any member of 61A staff.
        For instance, for Auth keys, provide a 61A-specific key for the staging value,
        and a super key only for the public value, to avoid leaking information. That said,
        staging values are not directly exposed and access will be logged in deploy logs,
        so don't worry about it too much, just be careful.
    </p>
    """ + "".join(f"""<p>
            <form 
                style="display: inline" 
                action="{url_for("delete_secret", app_name=app, secret_name=name)}" 
                method="post"
            >
                {app}/{name} - {display_hash(public_value)} (staging: {display_hash(staging_value)})
                <input type="submit" value="Remove">
        </form>""" for app, name, public_value, staging_value in secrets)
Esempio n. 13
0
 def wrapped(**kwargs):
     kwargs.pop("client_name", None)  # legacy argument
     secret = kwargs.pop("secret")
     with connect_db() as db:
         ret_regular = db(
             "SELECT client_name, course FROM auth_keys WHERE auth_key = (%s)",
             [secret],
         ).fetchone()
         ret_super = db(
             "SELECT client_name FROM super_auth_keys WHERE auth_key = (%s)",
             [secret],
         ).fetchone()
         if ret_regular:
             client_name = ret_regular[0]
             course = ret_regular[1]
             db(
                 "UPDATE auth_keys SET unused = FALSE WHERE client_name=(%s)",
                 [client_name],
             )
             # the course might still be passed in, but should be ignored
             kwargs.pop("course", None)
         elif ret_super:
             client_name = ret_super[0]
             db(
                 "UPDATE super_auth_keys SET unused = FALSE WHERE client_name=(%s)",
                 [client_name],
             )
             course = kwargs.pop("course")
         else:
             abort(401)
     return route(**kwargs, course=course)
Esempio n. 14
0
def lookup(path):
    with connect_db() as db:
        target = db(
            "SELECT url, creator, secure FROM shortlinks WHERE shortlink=%s AND course=%s",
            [path, get_course()],
        ).fetchone()
    return list(target) if target else (None, None, None)
Esempio n. 15
0
 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)
Esempio n. 16
0
 def workspace_name(course):
     with connect_db() as db:
         workspace = db(
             "SELECT workspace FROM slack_config WHERE course=(%s)",
             [course]).fetchone()
     if workspace:
         return workspace[0]
Esempio n. 17
0
def teardown():
    conn = connect_db()
    cursor = conn.cursor()

    cursor.execute("DELETE FROM `users` WHERE `username` LIKE 'test%'")
    conn.commit()
    conn.close()
Esempio n. 18
0
def index():
    if not is_staff("cs61a"):
        return login()
    email = get_user()["email"]
    if not is_admin(course="cs61a", email=email):
        abort(401)
    with connect_db() as db:
        apps = db("SELECT app FROM services WHERE pr_number=0", []).fetchall()
        pr_apps = db(
            "SELECT app, pr_number FROM services WHERE pr_number>0 ORDER BY pr_number DESC",
            [],
        ).fetchall()
    return html(
        f"""
        This service manages the deployment of the 61A website and various apps.
        {"".join(f'''
        <form action="/deploy_prod_app">
            <input type="submit" name="app" value="{app}" />
        </form>
        ''' for [app] in apps)}
        {"".join(f'''
        <form action="/trigger_build">
            <input type="hidden" name="app" value="{app}" />
            <input type="hidden" name="pr_number" value="{pr_number}" />
            <input type="submit" value="{app + "-pr" + str(pr_number)}" />
        </form>
        ''' for [app, pr_number] in pr_apps)}
        <form action="/delete_unused_services" method="post">
            <input type="submit" value="Delete unused services" />
       </form>
    """
    )
Esempio n. 19
0
 def load_stored_file(file_name):
     with connect_db() as db:
         out = db("SELECT * FROM stored_files WHERE file_name=%s;",
                  [file_name]).fetchone()
         if out:
             return out[1]
     abort(404)
def attempt_generated_shortlink(path, app):
    with connect_db() as db:
        try:
            ret = db("SELECT * FROM staffLinks WHERE link=%s;", [path]).fetchone()
            if ret is not None:
                return ServerFile(
                    ret["link"],
                    ret["fileName"],
                    "",
                    ret["fileContent"].decode(),
                    ret["shareRef"],
                    False,
                )._asdict()

            ret = db("SELECT * FROM studentLinks WHERE link=%s;", [path]).fetchone()

            if ret is None:
                return NOT_FOUND

            if check_auth(app):
                return ServerFile(
                    ret["link"],
                    ret["fileName"],
                    "",
                    ret["fileContent"].decode(),
                    ret["shareRef"],
                    False,
                )._asdict()
            else:
                return NOT_AUTHORIZED
        except Exception:
            return NOT_LOGGED_IN
Esempio n. 21
0
def init_db():
    with connect_db() as db:
        db("""CREATE TABLE IF NOT EXISTS auth_keys (
                client_name varchar(128), 
                auth_key varchar(128),
                creator varchar(128),
                course varchar(128),
                service varchar(128),
                unused BOOLEAN
             )""")
        db("""CREATE TABLE IF NOT EXISTS super_auth_keys (
                client_name varchar(128), 
                auth_key varchar(128),
                creator varchar(128),
                unused BOOLEAN
             )""")
        db("""CREATE TABLE IF NOT EXISTS courses (
                course varchar(128),
                endpoint varchar(128),
                endpoint_id INTEGER
            )""")
        ret = db("SELECT * FROM courses WHERE course=(%s)",
                 [MASTER_COURSE]).fetchone()
        if not ret:
            db(
                "INSERT INTO courses (course, endpoint, endpoint_id) VALUES (%s, %s, %s)",
                ["cs61a", "cal/cs61a/sp20", 151],
            )
Esempio n. 22
0
 def handle_get_endpoint_id(course):
     with connect_db() as db:
         endpoint = db(
             "SELECT endpoint_id FROM courses WHERE course = (%s)",
             [course]).fetchone()
     if endpoint:
         return endpoint[0]
Esempio n. 23
0
    def course_config(course):
        with connect_db() as db:
            endpoint, endpoint_id = db(
                "SELECT endpoint, endpoint_id FROM courses WHERE course=(%s)",
                [course]).fetchone()

            user_data = get_user()
            for participation in user_data["participations"]:
                if participation["course"]["offering"] == endpoint:
                    endpoint_id = participation["course_id"]

            db(
                "UPDATE courses SET endpoint_id=(%s) WHERE endpoint=(%s)",
                [[endpoint_id, endpoint]],
            )

            return """
                <h3>Config</h3>
                <p>
                Current endpoint: {} (id: {})
                </p>
                Set new endpoint:
                <form action="/api/{}/set_endpoint" method="post">
                    <input name="endpoint" type="text" placeholder="OKPy endpoint">
                    <input type="submit">
                </form>
            """.format(endpoint, endpoint_id, course)
Esempio n. 24
0
def delete_secret(app_name, secret_name):
    if not is_admin(get_user()["email"], "cs61a"):
        return login()
    with connect_db() as db:
        db("DELETE FROM secrets WHERE app=%s AND name=%s",
           [app_name, secret_name])
    return redirect(url_for("index"))
Esempio n. 25
0
 def handle_get_course(domain, **_kwargs):
     # note: deliberately not secured, not sensitive data
     with connect_db() as db:
         [course
          ] = db("SELECT course FROM domains_config WHERE domain = (%s)",
                 [domain]).fetchone()
     return course
Esempio n. 26
0
    def register_channel(course):
        purpose = request.form["purpose"]
        channel_name = request.form["channel"]

        channel_data = list_channels(course=course)

        for channel in channel_data:
            if channel["name"] == channel_name:
                channel_id = channel["id"]
                break
        else:
            return "Channel not found.", 404

        with connect_db() as db:
            ret = db(
                "SELECT * FROM slack_channels WHERE course = (%s) AND purpose = (%s)",
                [course, purpose],
            ).fetchone()
            if ret:
                return "Channel with same purpose already registered", 409
            db(
                "INSERT INTO slack_channels VALUES (%s, %s, %s, %s)",
                [course, purpose, channel_name, channel_id],
            )

        return redirect("/")
Esempio n. 27
0
def record_strat(name, group, received_strat):
    if not isinstance(name, str):
        abort(400, "Name is not a string!")
    name = base64.encodebytes(bytes(name, "utf-8"))
    if len(name) >= 1024:
        abort(400, "Strategy name is too long!")
    name = name.decode("utf-8")
    extracted_strat = validate_strat(received_strat)
    # extracted_strat probably OK
    email = group[0]
    encoded_strat = json.dumps(extracted_strat)
    hashed = hashlib.md5(bytes(encoded_strat, "utf-8")).hexdigest()

    # time to load it into the database
    with connect_db() as db:
        dupes = db(
            "SELECT email FROM cached_strategies WHERE name = (%s)", [name]
        ).fetchall()
        for dupe in dupes:
            if dupe["email"] not in group:
                abort(
                    409,
                    "Another strategy has already been submitted with the same name.",
                )
        for member in group:
            db("DELETE FROM cached_strategies WHERE email=(%s)", [member])
        db(
            "INSERT INTO cached_strategies VALUES (%s, %s, %s, %s)",
            [email, name, hashed, encoded_strat],
        )

    return hashed
Esempio n. 28
0
    def perform_action(action,
                       course,
                       as_staff=False,
                       is_test=None,
                       kwargs=None):
        with connect_db() as db:
            if as_staff:
                user, pw = db(
                    "SELECT staff_user, staff_pw FROM piazza_config WHERE course = (%s)",
                    [course],
                ).fetchone()
            else:
                user, pw = db(
                    "SELECT student_user, student_pw FROM piazza_config WHERE course = (%s)",
                    [course],
                ).fetchone()
            if is_test:
                (course_id, ) = db(
                    "SELECT test_course_id FROM piazza_config WHERE course = (%s)",
                    [course],
                ).fetchone()
            else:
                (course_id, ) = db(
                    "SELECT course_id FROM piazza_config WHERE course = (%s)",
                    [course]).fetchone()

        p = Piazza()
        p.user_login(user, pw)
        course = p.network(course_id)
        if kwargs is None:
            kwargs = {}
        try:
            return getattr(course, action)(**kwargs)
        except Exception as e:
            return str(e), 400
Esempio n. 29
0
def clear():
    email = session.get("email")
    if not email:
        abort(401)
    with connect_db() as db:
        db("DELETE FROM saves WHERE email=%s", [email])
    return dict(success=True)
Esempio n. 30
0
 def handle_list_admins(course):
     with connect_db() as db:
         return [
             list(x) for x in db(
                 "SELECT email, name FROM course_admins WHERE course=(%s)",
                 [course]).fetchall()
         ]
Esempio n. 31
0
 def handle_list_courses(**_kwargs):
     # note: deliberately not secured, not sensitive data
     with connect_db() as db:
         return [
             list(x)
             for x in db("SELECT course, endpoint FROM courses").fetchall()
         ]
Esempio n. 32
0
def setUp():
    conn = connect_db()
    cursor = conn.cursor()

    salt = bcrypt.gensalt(8)
    pwhash = bcrypt.hashpw('test', salt)
    cursor.executemany("""INSERT INTO `users`
        (`username`, `salt`, `pwhash`) VALUES (%s, %s, %s)""",
        [('test', salt, pwhash), ('test2', salt, pwhash)])
    conn.commit()
    conn.close()

    app.testing = True
Esempio n. 33
0
def init_db():
    g.conn = connect_db()
    g.cursor = g.conn.cursor()