commit e3b4fbdebec9462f7f468c876f7502c0de2b56b2
parent aafc0a115249f47840e276f853454d13bb0cf467
Author: Damian Myrda <damian@prime8.dev>
Date: Wed, 18 Feb 2026 14:42:48 -0600
Fix critical bugs and security issues
- Fix Python 3 relative imports in models/__init__.py
- Fix Jinja2 macro call in events.html template
- Fix authors parsing in add_project route (comma-separated)
- Replace insecure pickle with JSON in database
- Use secure random SECRET_KEY instead of DOMAIN
- Only allow insecure OAuth transport in development mode
- Update README with new environment variables
Diffstat:
5 files changed, 26 insertions(+), 23 deletions(-)
diff --git a/README.md b/README.md
@@ -10,13 +10,15 @@ A website for Computer Science Club made during a mini-hackathon.
The following environment variables are required:
-| Variable | Description |
-|----------|-------------|
-| `DOMAIN` | The URL where this app is hosted |
-| `GROUP_ID` | Schoology group ID (found in the URL after `/group/`) |
-| `SCHOOLOGY_DOMAIN` | Your Schoology instance domain (e.g., `schoology.example.com`) |
-| `SCHOOLOGY_API_KEY` | Schoology API key |
-| `SCHOOLOGY_API_SECRET` | Schoology API secret |
+| Variable | Description | Required |
+|----------|-------------|----------|
+| `DOMAIN` | The URL where this app is hosted | Yes |
+| `SECRET_KEY` | Flask session secret key (auto-generated if not set) | No |
+| `GROUP_ID` | Schoology group ID (found in the URL after `/group/`) | Yes |
+| `SCHOOLOGY_DOMAIN` | Your Schoology instance domain (e.g., `schoology.example.com`) | Yes |
+| `SCHOOLOGY_API_KEY` | Schoology API key | Yes |
+| `SCHOOLOGY_API_SECRET` | Schoology API secret | Yes |
+| `FLASK_ENV` | Set to `development` to allow HTTP OAuth (insecure) | No |
### Schoology
diff --git a/database.py b/database.py
@@ -1,6 +1,6 @@
from models import Project
import sqlite3
-import pickle
+import json
class Database:
@@ -29,7 +29,7 @@ class Database:
for data in self.cursor.fetchall():
name = data[0]
description = data[1]
- authors = pickle.loads(data[2])
+ authors = json.loads(data[2])
source = data[3]
project = Project(name, description, authors, source)
self.projects.append(project)
@@ -43,7 +43,7 @@ class Database:
data = (
project.name,
project.description,
- pickle.dumps(project.authors),
+ json.dumps(project.authors),
project.source,
)
self.cursor.execute("INSERT INTO projects VALUES (?, ?, ?, ?)", data)
diff --git a/main.py b/main.py
@@ -12,8 +12,10 @@ from schoology import group
from flask import Flask, request, redirect, abort, render_template, session
from cachecontrol import CacheControl
+import secrets
+
app = Flask(__name__)
-app.secret_key = DOMAIN
+app.secret_key = os.environ.get("SECRET_KEY", secrets.token_hex(32))
@app.route("/")
@@ -53,13 +55,11 @@ def add_project():
description = request.form["description"].rstrip()
if description == "":
description = None
- authors = request.form["authors"]
- for author in authors:
- author = author.rstrip()
+ authors = [a.strip() for a in request.form["authors"].split(",") if a.strip()]
source = request.form["source"].rstrip()
if source == "":
source = None
- project = Project(name, description, [authors], source)
+ project = Project(name, description, authors, source)
database.add(project)
return redirect("/projects")
return render_template(
@@ -88,7 +88,8 @@ GOOGLE_AUTH_SCOPES = [
"https://www.googleapis.com/auth/userinfo.email",
"openid",
]
-os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
+if os.environ.get("FLASK_ENV") == "development":
+ os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
flow = Flow.from_client_secrets_file(
client_secrets_file=GOOGLE_CLIENT_SECRETS_FILE,
diff --git a/models/__init__.py b/models/__init__.py
@@ -1,6 +1,6 @@
-from discussion import Discussion
-from event import Event
-from group import Group
-from member import Member
-from project import Project
-from update import Update
+from .discussion import Discussion
+from .event import Event
+from .group import Group
+from .member import Member
+from .project import Project
+from .update import Update
diff --git a/templates/elements/events.html b/templates/elements/events.html
@@ -18,6 +18,6 @@
{% macro upcoming(events) -%}
{% for event in events %}
-<div>view(event)</div>
+<div>{{ view(event) }}</div>
{% endfor %}
{%- endmacro %}