8.3 KiB
ObsWiki Session Log - Privacy & Authentication Fixes
Date: August 10, 2025
Duration: ~45 minutes
Focus: Fix privacy filtering for filetree, authentication UI, and login functionality
Session Overview
This session continued from a previous conversation where filetree functionality was implemented. The main issues addressed were:
- Privacy filtering not working - private pages were visible without login
- Authentication UI not updating - login button didn't change to logout
- Filetree stuck loading - API calls missing authentication
- JavaScript syntax errors - template string brace escaping issues
- Login form broken - JavaScript object literal problems
Issues & Solutions
1. Privacy Filtering Implementation
Issue: Filetree showed all files regardless of authentication status or privacy settings
Root Cause: The /api/folder-files endpoint didn't check user authentication or respect obswiki_public: true frontmatter settings.
Solution:
- Modified
folder_files_handlerto check authentication viais_user_authenticated() - Updated
build_folder_files()to filter files based on privacy:- Authenticated users: See all files
- Non-authenticated users: Only see files with
obswiki_public: true
- Added folder-level privacy: folders only show if they contain accessible files
- Used
Box::pinfor recursive async function to handle folder traversal
Files Modified:
src/server/mod.rs- Updated handler and build function- Added privacy checking logic for both files and folders
2. Authentication UI Not Updating
Issue: Login button showed "Login" even when user was authenticated via cookies
Root Cause: Frontend JavaScript only checked localStorage for tokens, not cookies. Server-side authentication worked via cookies, but client-side UI didn't detect this.
Solution:
- Added
getCookie()helper function to parse browser cookies - Updated authentication check:
localStorage.getItem('obswiki_token') || getCookie('auth_token') - Applied fix to all HTML templates (folder pages, wiki pages, welcome page, etc.)
JavaScript Added:
function getCookie(name) {
const value = '; ' + document.cookie;
const parts = value.split('; ' + name + '=');
if (parts.length === 2) return parts.pop().split(';').shift();
return null;
}
3. Filetree Loading Issues
Issue: Filetree stuck on "Loading..." message
Root Cause: API calls to /api/folder-files weren't including authentication credentials (cookies).
Solution:
- Added
credentials: 'same-origin'to all fetch requests - Enhanced error handling with specific HTTP status codes
- Improved console logging for debugging
API Call Fix:
const response = await fetch('/api/folder-files?path=' + encodeURIComponent(folderPath), {
credentials: 'same-origin'
});
4. JavaScript Syntax Errors
Issue: Multiple JavaScript syntax errors due to template string escaping problems
Root Cause: Confusion between Rust format string escaping ({{ → {) and JavaScript object literal syntax.
Problems Encountered:
- Extra closing braces
}});with no matching opening braces loadFolderFiles()calls placed outsideDOMContentLoadedevent handlers- Incorrect JavaScript object literal syntax
Solution:
- Moved filetree loading calls inside
DOMContentLoadedevent handlers - Removed extra unmatched closing braces
- Fixed JavaScript structure and indentation
5. Login Form Broken
Issue: Login form JavaScript had syntax errors preventing login
Root Cause: Incorrect brace escaping in Rust template strings created malformed JavaScript.
Evolution of Fixes:
- First attempt: Fixed object shorthand syntax
{{ username, password }} - Second attempt: Used explicit object syntax
{{username: username, password: password}} - Third attempt: Simplified to property assignment to avoid object literals
- Final solution: Realized login page doesn't need double braces at all (static template)
Final Working JavaScript:
const loginData = {};
loginData.username = username;
loginData.password = password;
const response = await fetch('/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(loginData)
});
Technical Concepts Applied
Template String Escaping in Rust
- Dynamic templates (using
format!()) need{{and}}for literal braces - Static templates (raw strings) use normal
{and}for JavaScript - Key insight: Login page was static, not dynamic
Authentication Flow
- Server-side: Validates JWT tokens from cookies or Authorization headers
- Client-side: Stores tokens in both localStorage and cookies for compatibility
- Hybrid approach: Supports both API calls (Authorization header) and browser navigation (cookies)
Privacy Model
- Default behavior: Pages are private (require authentication)
- Public override:
obswiki_public: truein YAML frontmatter makes pages public - Filetree filtering: Only shows files/folders user has permission to access
Async Rust Functions
- Recursive async functions require
Box::pinto avoid infinite-sized futures - Pattern used:
Box<dyn Future<Output = Result<T>> + Send + 'a>
Debug Features Added
Enhanced Logging
- Authentication debug: Logs token verification results
- Privacy debug: Shows whether pages are marked public/private
- API error handling: Specific HTTP status codes in console
- Login flow debug: Step-by-step login process logging
Error Messages
- Filetree: Shows specific error codes instead of generic "Loading..."
- Login: Detailed console messages for troubleshooting
- Privacy: Logs frontmatter parsing results
Current Status
✅ Working Features:
- Privacy filtering respects
obswiki_public: truefrontmatter - Authentication UI updates correctly (Login ↔ Logout)
- Filetree loads with proper privacy filtering
- Login form works with proper JavaScript syntax
- Debug logging provides detailed troubleshooting info
✅ Security Model:
- Pages private by default (require authentication)
- Granular public page control via frontmatter
- Folder visibility based on content accessibility
- API endpoints respect same privacy rules as pages
✅ Authentication System:
- JWT tokens work via cookies and localStorage
- Hybrid client/server authentication checking
- Proper token storage and cleanup on logout
Key Learnings
-
Template String Complexity: Rust format string escaping in HTML templates is error-prone. Static templates are simpler.
-
Cookie vs localStorage: When server uses cookies but client checks localStorage, UI gets out of sync. Need both checks.
-
Privacy by Default: Secure approach - everything private unless explicitly marked public.
-
Debug Logging Essential: Complex authentication/privacy flows need extensive logging for troubleshooting.
-
JavaScript Syntax in Templates: When embedding JavaScript in Rust templates, consider whether braces need escaping based on template type.
Files Modified
Primary Changes:
src/server/mod.rs- Privacy filtering, auth UI fixes, JavaScript syntax fixes- All HTML templates updated with cookie-aware authentication checks
Functions Updated:
folder_files_handler()- Added authentication checkingbuild_folder_files()- Added privacy filtering withBox::pinfor async recursionis_user_authenticated()- Added debug loggingis_page_public()- Enhanced frontmatter parsing with loggingrender_login_page()- Fixed JavaScript syntax
New Features:
getCookie()JavaScript helper function in all templates- Comprehensive debug logging throughout authentication flow
- Enhanced error handling for API calls
Next Potential Improvements
- Performance: Cache privacy status to avoid repeated frontmatter parsing
- UX: Loading states for filetree instead of "Loading..." text
- Security: Rate limiting on login attempts
- Debug: Production vs development logging levels
- Testing: Unit tests for privacy filtering logic
This session successfully resolved all major privacy, authentication, and JavaScript issues, resulting in a fully functional secure wiki with proper access controls.