All notable changes to Bookgram will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Optional Password Protection for Private Articles
templates/edit.php:71-91)templates/password-prompt.php)/verify-password route for password verification (index.php:161-197)Navigation Enhancement
templates/page.php:81)Data Model Updates
password_hash (string) - BCrypt/Argon2 hash of the optional passwordsave_page_content() function signature to accept $password parameter (app/core/functions.php:367)can_view_private_page() to check password authentication (app/core/functions.php:199-238)verify_page_password() function for secure password verification (app/core/functions.php:246-267)User Experience Improvements
Password Hashing
password_hash() with PASSWORD_DEFAULT (currently Argon2id or BCrypt)password_verify() to prevent timing attacksAccess Control Flow
$_SESSION['authenticated_pages'] array/app/core/functions.php - Password hashing and verification functions
/templates/edit.php - Password input field with toggle (lines 71-103)
/templates/page.php - Password protection indicators (lines 45-56)
/templates/password-prompt.php - Password entry form (NEW)
/index.php - Password handling in save and verify routes
/CHANGELOG.md - This file (UPDATED)
/VERSION.txt - Version number update
For existing pages, the password field will be automatically initialized:
password_hash: '' (empty string = no password)Setting up a password-protected page:
Accessing a password-protected page:
Private Articles with Share Links
templates/edit.php:62-68)templates/edit.php:70-83)templates/page.php:43-62)Code Block Rendering Fix
<pre> elements with white-space: pre (public/css/style.css:239-254)Data Model Updates
is_private (boolean) - privacy status flagshare_token (string) - unique 32-character hex token for private accesssave_page_content() function signature to accept $is_private parameter (app/core/functions.php:367)app/core/functions.php:891)Function Enhancements
get_directory_contents() - Now filters private pages based on user permissions (app/core/functions.php:571-574)search_pages() - Excludes private pages from search unless user has permission (app/core/functions.php:929-932)get_all_pages_sorted_by_date() - Filters private pages from RSS/listings (app/core/functions.php:990-993)can_view_private_page() helper function (app/core/functions.php:199-226)generate_share_token() utility function (app/core/functions.php:190-192)bin2hex(random_bytes(16)) for cryptographic securityhash_equals() to prevent timing attacks?token={32-char-hex}/public/css/style.css - Code block styling (lines 239-254)
/app/core/functions.php - Privacy functions and data filtering
/templates/edit.php - Privacy checkbox and share link UI
/templates/page.php - Private page notice and share link display
/index.php - Privacy parameter handling in save route (line 120)
/CHANGELOG.md - This file (NEW)
No database migrations required (file-based storage).
For existing pages, the privacy fields will be automatically initialized to default values:
is_private: falseshare_token: '' (empty string)Initial release of v2.06 with: