Spaces:
Runtime error
Runtime error
Security: remove auto-login demo endpoint, require password for demo_user
Browse files- app.py +0 -35
- auth.py +3 -2
- static/index.html +2 -2
- static/login.html +2 -35
- static/map.html +2 -2
- static/sw.js +1 -1
- version.json +1 -1
app.py
CHANGED
|
@@ -373,41 +373,6 @@ async def login(login_data: LoginRequest, response: Response):
|
|
| 373 |
pass
|
| 374 |
return result
|
| 375 |
|
| 376 |
-
@app.get("/api/auth/demo-login", response_model=DemoLoginResponse, tags=["Authentication"])
|
| 377 |
-
async def demo_login(response: Response):
|
| 378 |
-
"""Auto-login for demo mode"""
|
| 379 |
-
# Always allow demo login - no settings check needed
|
| 380 |
-
|
| 381 |
-
# Create a new demo session
|
| 382 |
-
result = auth_manager.create_demo_session()
|
| 383 |
-
if not result:
|
| 384 |
-
raise HTTPException(
|
| 385 |
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
| 386 |
-
detail="Could not create demo session"
|
| 387 |
-
)
|
| 388 |
-
|
| 389 |
-
# Set authentication cookie for web page requests (12 hour expiry)
|
| 390 |
-
response.set_cookie(
|
| 391 |
-
key="auth_token",
|
| 392 |
-
value=result["token"],
|
| 393 |
-
max_age=12*60*60, # 12 hours for demo duration
|
| 394 |
-
httponly=True,
|
| 395 |
-
secure=True,
|
| 396 |
-
samesite="lax"
|
| 397 |
-
)
|
| 398 |
-
|
| 399 |
-
logger.info("Demo user logged in via demo button")
|
| 400 |
-
|
| 401 |
-
return DemoLoginResponse(
|
| 402 |
-
token=result["token"],
|
| 403 |
-
user={
|
| 404 |
-
"username": result["user"]["username"],
|
| 405 |
-
"role": result["user"]["role"],
|
| 406 |
-
"full_name": result["user"]["full_name"],
|
| 407 |
-
"permissions": result["user"]["permissions"]
|
| 408 |
-
},
|
| 409 |
-
is_demo_mode=True
|
| 410 |
-
)
|
| 411 |
|
| 412 |
@app.get("/api/auth/validate", tags=["Authentication"])
|
| 413 |
async def validate_session(user: Dict[str, Any] = Depends(require_auth)):
|
|
|
|
| 373 |
pass
|
| 374 |
return result
|
| 375 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 376 |
|
| 377 |
@app.get("/api/auth/validate", tags=["Authentication"])
|
| 378 |
async def validate_session(user: Dict[str, Any] = Depends(require_auth)):
|
auth.py
CHANGED
|
@@ -28,9 +28,10 @@ class AuthManager:
|
|
| 28 |
admin_password = os.getenv('ADMIN_PASSWORD', DEV_PASSWORDS['ADMIN_PASSWORD'])
|
| 29 |
ishita_password = os.getenv('ISHITA_PASSWORD', DEV_PASSWORDS['ISHITA_PASSWORD'])
|
| 30 |
jeeb_password = os.getenv('JEEB_PASSWORD', DEV_PASSWORDS['JEEB_PASSWORD'])
|
|
|
|
| 31 |
|
| 32 |
# Warn if using development passwords
|
| 33 |
-
env_vars = ['AALEKH_PASSWORD', 'ADMIN_PASSWORD', 'ISHITA_PASSWORD', 'JEEB_PASSWORD']
|
| 34 |
missing_vars = [var for var in env_vars if not os.getenv(var)]
|
| 35 |
if missing_vars:
|
| 36 |
logger.warning(f"Using default development passwords for: {', '.join(missing_vars)}. Set these environment variables for production!")
|
|
@@ -70,7 +71,7 @@ class AuthManager:
|
|
| 70 |
|
| 71 |
# Demo account for public demonstrations
|
| 72 |
"demo_user": {
|
| 73 |
-
"password_hash": self._hash_password(
|
| 74 |
"role": "demo_user",
|
| 75 |
"full_name": "Demo Account",
|
| 76 |
"permissions": ["read", "demo_view", "demo_interact", "map_view", "demo_navigation"]
|
|
|
|
| 28 |
admin_password = os.getenv('ADMIN_PASSWORD', DEV_PASSWORDS['ADMIN_PASSWORD'])
|
| 29 |
ishita_password = os.getenv('ISHITA_PASSWORD', DEV_PASSWORDS['ISHITA_PASSWORD'])
|
| 30 |
jeeb_password = os.getenv('JEEB_PASSWORD', DEV_PASSWORDS['JEEB_PASSWORD'])
|
| 31 |
+
demo_password = os.getenv('DEMO_PASSWORD', DEV_PASSWORDS.get('DEMO_PASSWORD'))
|
| 32 |
|
| 33 |
# Warn if using development passwords
|
| 34 |
+
env_vars = ['AALEKH_PASSWORD', 'ADMIN_PASSWORD', 'ISHITA_PASSWORD', 'JEEB_PASSWORD', 'DEMO_PASSWORD']
|
| 35 |
missing_vars = [var for var in env_vars if not os.getenv(var)]
|
| 36 |
if missing_vars:
|
| 37 |
logger.warning(f"Using default development passwords for: {', '.join(missing_vars)}. Set these environment variables for production!")
|
|
|
|
| 71 |
|
| 72 |
# Demo account for public demonstrations
|
| 73 |
"demo_user": {
|
| 74 |
+
"password_hash": self._hash_password(demo_password),
|
| 75 |
"role": "demo_user",
|
| 76 |
"full_name": "Demo Account",
|
| 77 |
"permissions": ["read", "demo_view", "demo_interact", "map_view", "demo_navigation"]
|
static/index.html
CHANGED
|
@@ -947,7 +947,7 @@
|
|
| 947 |
// Force refresh if we detect cached version
|
| 948 |
(function() {
|
| 949 |
const currentVersion = '5.1.1';
|
| 950 |
-
const timestamp = '
|
| 951 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
| 952 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
| 953 |
|
|
@@ -1193,7 +1193,7 @@
|
|
| 1193 |
</div>
|
| 1194 |
</div>
|
| 1195 |
|
| 1196 |
-
<script type="module" src="/static/js/tree-track-app.js?v=5.1.1&t=
|
| 1197 |
|
| 1198 |
<script>
|
| 1199 |
// Idle-time prefetch of map assets to speed up first navigation
|
|
|
|
| 947 |
// Force refresh if we detect cached version
|
| 948 |
(function() {
|
| 949 |
const currentVersion = '5.1.1';
|
| 950 |
+
const timestamp = '1762281551'; // Cache-busting bump
|
| 951 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
| 952 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
| 953 |
|
|
|
|
| 1193 |
</div>
|
| 1194 |
</div>
|
| 1195 |
|
| 1196 |
+
<script type="module" src="/static/js/tree-track-app.js?v=5.1.1&t=1762281551"></script>
|
| 1197 |
|
| 1198 |
<script>
|
| 1199 |
// Idle-time prefetch of map assets to speed up first navigation
|
static/login.html
CHANGED
|
@@ -358,9 +358,9 @@
|
|
| 358 |
</button>
|
| 359 |
|
| 360 |
<div class="accounts-dropdown" id="accountsDropdown">
|
| 361 |
-
<button class="account-item demo-account" onclick="
|
| 362 |
<div class="account-role">Demo Account</div>
|
| 363 |
-
<div class="account-username">
|
| 364 |
</button>
|
| 365 |
<button class="account-item" onclick="selectAccount('aalekh', event)">
|
| 366 |
<div class="account-role">Aalekh (Admin)</div>
|
|
@@ -400,39 +400,6 @@
|
|
| 400 |
}
|
| 401 |
}
|
| 402 |
|
| 403 |
-
function selectDemoAccount(event) {
|
| 404 |
-
// Directly log in to demo account
|
| 405 |
-
event.preventDefault();
|
| 406 |
-
|
| 407 |
-
setLoading(true);
|
| 408 |
-
|
| 409 |
-
// Call demo login API
|
| 410 |
-
fetch('/api/auth/demo-login', {
|
| 411 |
-
method: 'GET'
|
| 412 |
-
})
|
| 413 |
-
.then(response => response.json())
|
| 414 |
-
.then(result => {
|
| 415 |
-
if (result.token) {
|
| 416 |
-
// Store authentication token
|
| 417 |
-
localStorage.setItem('auth_token', result.token);
|
| 418 |
-
localStorage.setItem('user_info', JSON.stringify(result.user));
|
| 419 |
-
|
| 420 |
-
showMessage('Demo access granted! Redirecting...', 'success');
|
| 421 |
-
|
| 422 |
-
// Redirect to welcome screen for demo users
|
| 423 |
-
setTimeout(() => {
|
| 424 |
-
window.location.href = '/welcome';
|
| 425 |
-
}, 1500);
|
| 426 |
-
} else {
|
| 427 |
-
throw new Error('Demo mode not available');
|
| 428 |
-
}
|
| 429 |
-
})
|
| 430 |
-
.catch(error => {
|
| 431 |
-
console.error('Demo login error:', error);
|
| 432 |
-
showMessage('Demo mode is not currently available. Please try again later.');
|
| 433 |
-
setLoading(false);
|
| 434 |
-
});
|
| 435 |
-
}
|
| 436 |
|
| 437 |
function selectAccount(username, event) {
|
| 438 |
document.getElementById('username').value = username;
|
|
|
|
| 358 |
</button>
|
| 359 |
|
| 360 |
<div class="accounts-dropdown" id="accountsDropdown">
|
| 361 |
+
<button class="account-item demo-account" onclick="selectAccount('demo_user', event)">
|
| 362 |
<div class="account-role">Demo Account</div>
|
| 363 |
+
<div class="account-username">demo_user (requires password)</div>
|
| 364 |
</button>
|
| 365 |
<button class="account-item" onclick="selectAccount('aalekh', event)">
|
| 366 |
<div class="account-role">Aalekh (Admin)</div>
|
|
|
|
| 400 |
}
|
| 401 |
}
|
| 402 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 403 |
|
| 404 |
function selectAccount(username, event) {
|
| 405 |
document.getElementById('username').value = username;
|
static/map.html
CHANGED
|
@@ -968,7 +968,7 @@
|
|
| 968 |
// Force refresh if we detect cached version
|
| 969 |
(function() {
|
| 970 |
const currentVersion = '5.1.1';
|
| 971 |
-
const timestamp = '
|
| 972 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
| 973 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
| 974 |
|
|
@@ -1137,7 +1137,7 @@ const timestamp = '1762281121'; // Current timestamp for cache busting
|
|
| 1137 |
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
| 1138 |
<!-- Leaflet MarkerCluster JS for performance and grouping -->
|
| 1139 |
<script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script>
|
| 1140 |
-
<script src="/static/map.js?v=5.1.1&t=
|
| 1141 |
<script>
|
| 1142 |
console.log('🗺️ Map script loaded successfully');
|
| 1143 |
</script>
|
|
|
|
| 968 |
// Force refresh if we detect cached version
|
| 969 |
(function() {
|
| 970 |
const currentVersion = '5.1.1';
|
| 971 |
+
const timestamp = '1762281551'; // Current timestamp for cache busting
|
| 972 |
const lastVersion = sessionStorage.getItem('treetrack_version');
|
| 973 |
const lastTimestamp = sessionStorage.getItem('treetrack_timestamp');
|
| 974 |
|
|
|
|
| 1137 |
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
| 1138 |
<!-- Leaflet MarkerCluster JS for performance and grouping -->
|
| 1139 |
<script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script>
|
| 1140 |
+
<script src="/static/map.js?v=5.1.1&t=1762281551"></script>
|
| 1141 |
<script>
|
| 1142 |
console.log('🗺️ Map script loaded successfully');
|
| 1143 |
</script>
|
static/sw.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
// TreeTrack Service Worker - PWA and Offline Support
|
| 2 |
-
const VERSION =
|
| 3 |
const CACHE_NAME = `treetrack-v${VERSION}`;
|
| 4 |
const STATIC_CACHE = `static-v${VERSION}`;
|
| 5 |
const API_CACHE = `api-v${VERSION}`;
|
|
|
|
| 1 |
// TreeTrack Service Worker - PWA and Offline Support
|
| 2 |
+
const VERSION = 1762281551; // Cache busting bump - force clients to fetch new static assets and header image change
|
| 3 |
const CACHE_NAME = `treetrack-v${VERSION}`;
|
| 4 |
const STATIC_CACHE = `static-v${VERSION}`;
|
| 5 |
const API_CACHE = `api-v${VERSION}`;
|
version.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
{
|
| 2 |
"version": "5.1.1",
|
| 3 |
-
"timestamp":
|
| 4 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"version": "5.1.1",
|
| 3 |
+
"timestamp": 1762281551
|
| 4 |
}
|