Update README changelog, remove Firebug IT branding, retire dead mobile middleware

README.md: backfill the Changelog with the 2026.9.5, 2026.8.31.1, 2026.8.31,
and v1.2.0 releases that were missing (it jumped straight from 1.0.0 to
1.1.0). Also correct the stale "Mobile App Support"/"Mobile App
Integration" sections - the native Android app is retired, and the
sync protocol they describe now powers the offline PWA instead.

Remove Firebug IT branding/contact info across README.md, API.md, and
the site footer, and drop the stale tasks.firebugit.com fallback from
development.py's ALLOWED_HOSTS/CSRF_TRUSTED_ORIGINS.

AllowMobileAppFramingMiddleware detected the native app via a
'com.firebugit.keepitgoing' User-Agent check to allow WebView iframe
embedding. With that app retired, replaced it with
SecurityHeadersMiddleware, which applies the same X-Frame-Options/CSP
headers unconditionally instead of only for non-mobile requests -
same protection for real users, dead branch and dead branding gone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Keith Smith
2026-09-05 14:12:39 -06:00
co-authored by Claude Sonnet 5
parent 6791f008e9
commit f41939983a
8 changed files with 113 additions and 97 deletions
+2 -2
View File
@@ -1,3 +1,3 @@
from .mobile_app import AllowMobileAppFramingMiddleware
from .security_headers import SecurityHeadersMiddleware
__all__ = ['AllowMobileAppFramingMiddleware']
__all__ = ['SecurityHeadersMiddleware']
-61
View File
@@ -1,61 +0,0 @@
"""
Middleware to allow iframe embedding for the KeepItGoing mobile app.
The mobile app uses Capacitor WebView which embeds the website in an iframe.
This middleware detects requests from the mobile app and removes both
X-Frame-Options and Content-Security-Policy frame-ancestors headers to allow
iframe embedding, while keeping clickjacking protection for regular web browsers.
"""
class AllowMobileAppFramingMiddleware:
"""
Remove frame-blocking headers for requests from KeepItGoing mobile app.
The mobile app uses a Capacitor WebView. We detect these requests via
User-Agent and remove X-Frame-Options and CSP frame-ancestors headers.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
# Check if request is from KeepItGoing mobile app
user_agent = request.META.get('HTTP_USER_AGENT', '')
# Detect Capacitor/Android WebView patterns
is_mobile_app = (
'wv' in user_agent.lower() or # Android WebView
'CapacitorHttp' in user_agent or
'com.firebugit.keepitgoing' in user_agent or
('KeepItGoing' in user_agent and 'Mobile' in user_agent)
)
if is_mobile_app:
# Mobile app: Allow iframe embedding - don't add frame-blocking headers
# Remove any existing frame headers
if 'X-Frame-Options' in response:
del response['X-Frame-Options']
if 'Content-Security-Policy' in response:
del response['Content-Security-Policy']
else:
# Regular browsers: Add security headers for clickjacking protection
if 'X-Frame-Options' not in response:
response['X-Frame-Options'] = 'DENY'
if 'Content-Security-Policy' not in response:
response['Content-Security-Policy'] = (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline'; "
"style-src 'self' 'unsafe-inline'; "
"img-src 'self' data: https:; "
"font-src 'self' data:; "
"connect-src 'self'; "
"frame-ancestors 'none'; "
"base-uri 'self'; "
"form-action 'self';"
)
return response
+35
View File
@@ -0,0 +1,35 @@
"""
Middleware that applies clickjacking protection headers to every response.
Previously also allowed iframe embedding for a native mobile app's WebView
(detected via User-Agent); that app has been retired in favor of the PWA,
so the headers are now applied unconditionally.
"""
class SecurityHeadersMiddleware:
"""Add X-Frame-Options and a CSP frame-ancestors policy to every response."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if 'X-Frame-Options' not in response:
response['X-Frame-Options'] = 'DENY'
if 'Content-Security-Policy' not in response:
response['Content-Security-Policy'] = (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline'; "
"style-src 'self' 'unsafe-inline'; "
"img-src 'self' data: https:; "
"font-src 'self' data:; "
"connect-src 'self'; "
"frame-ancestors 'none'; "
"base-uri 'self'; "
"form-action 'self';"
)
return response