DownloadPublic File Areas
> Draft ? generated by AI, may not have been reviewed for accuracy.
Overview
This proposal adds an is_public flag to individual file areas. When enabled,
the area's file listing and file downloads are accessible to unauthenticated
visitors without requiring a BBS account. Comments, uploads, and all other
interactive features remain login-gated. This is a registered (premium) feature.
Motivation
Sysops running public shareware libraries, FTN file echo mirrors, or community
software archives may want to allow anonymous visitors to browse and download
files without requiring registration. The existing gemini_public flag already
exposes file areas over the Gemini protocol; this proposal extends the same
concept to the web interface.
Scope
What anonymous visitors can do on a public area
-
Browse the file listing for the area (filename, description, size, date)
-
Download individual files
-
View the file preview modal (images, text/NFO, ANSI, ZIP browser, etc.)
What anonymous visitors cannot do
-
Post, view, or interact with file comments
-
Upload files
-
Access private file areas (`is_private = true`)
-
Access any area that does not have `is_public = true`
Implementation Status
Implemented in migration v1.11.0.33_public_file_areas.sql.
Admin Configuration
Per-area flag
A Public File Area checkbox is added to the file area editor in
Admin ? Area Management ? File Areas, following the same pattern as the
existing Gemini Public checkbox (#fileareaGeminiPublic in fileareas.twig).
-
HTML ID: `fileareaIsPublic`
-
Loaded from `area.is_public` in JS (same pattern as `gemini_public`, line ~592 of `fileareas.twig`)
-
Saved in the `PUT /api/fileareas/{id}` request body
-
Default: `false` (no change to existing behaviour)
-
Wrapped in `{% if license_valid %}...{% else %}<lock notice>{% endif %}`
Public file area index page
A new BBS setting Enable Public Files Index controls whether public areas are
listed on a discoverable index page (/public-files). Options:
-
Disabled (default) ? public areas are only reachable via direct URL
-
Enabled ? a `/public-files` page lists all public areas and is linked
from the guest navigation bar
This setting is stored as features.public_files_index in config/bbs.json
and toggled via Admin ? BBS Settings ? BBS Features. Requires a registered
license to enable.
Database Change
New boolean column on file_areas (migration v1.11.0.33_public_file_areas.sql):
ALTER TABLE file_areas ADD COLUMN IF NOT EXISTS is_public BOOLEAN NOT NULL DEFAULT FALSE;
CREATE INDEX IF NOT EXISTS idx_file_areas_is_public ON file_areas(is_public) WHERE is_public = TRUE;
Backend Changes
FileAreaManager ? access control (src/FileAreaManager.php:133)
canAccessFileArea() now allows $userId = null (guest) when the area has
is_public = true and is_private = false:
// Areas flagged is_public allow unauthenticated (guest) access
if (!empty($area['is_public'])) {
return true;
}
// Non-public areas require a logged-in user
if ($userId === null) {
return false;
}
return true;
FileAreaManager ? save is_public (updateFileArea())
$isPublic is saved alongside gemini_public:
$isPublic = \BinktermPHP\License::isValid() ? (bool)($data['is_public'] ?? false) : false;
Stored as string 'true'/'false' for PostgreSQL compatibility.
Web route ? /files/{tag} (routes/web-routes.php)
If is_public = true and is_private = false: skips requireAuth(), gets
optional user via getCurrentUser(), passes is_public_area and initial_area
to files.twig.
Web route ? /public-files
New route, no auth required. Returns 404 when public_files_index feature is
disabled. Queries `file_areas WHERE is_public = TRUE AND is_private = FALSE AND
is_active = TRUE. Renderstemplates/public_files.twig`.
API ? GET /api/files
Guest access allowed when the requested area has is_public = true. Credits and
activity tracking are skipped for guests.
API ? GET /api/files/{id}/download
Guest access allowed for public areas. All credit deduction/reward logic is
skipped for unauthenticated requests.
API ? GET /api/files/{id}/preview
Extended to allow unauthenticated access when the file belongs to a public area
(viaPublicArea = true), alongside the existing share-token bypass.
API ? GET /api/files/{id}/comments
No change ? still requires auth. Frontend simply does not call this endpoint for
guest sessions.
API ? GET /api/fileareas
No change ? remains login-required. Public area metadata for /files/{tag} is
resolved server-side in the web route handler.
Frontend Changes
files.twig
A is_public_area Twig variable (boolean) and initial_area (area record) are
passed from the route. When true and no user is logged in:
-
Sidebar (file area list, search, stats) is hidden via Twig conditional
-
JS `document.ready` loads files directly for `guestPublicArea` without calling
`loadFileAreas()` or `loadStats()`
-
Upload button remains hidden (JS `selectFileArea()` is not called for guests)
-
Comments section shows the existing "log in to comment" alert
-
Open Graph meta tags are added via `{% block meta_tags %}`
public_files.twig
New template listing public file areas in a card grid. Each area shows tag,
description, and file count, linked to /files/AREATAG.
Navigation (templates/base.twig, templates/shells/web/base.twig)
-
The Files nav link is now only shown to authenticated users
-
A Public Files nav link appears for guests when `public_files_index` is enabled
Security Considerations
-
`is_private = true` areas are never served publicly. `canAccessFileArea()` checks
`empty($area['is_private'])` before allowing guest access.
-
File downloads are served via API (no storage path exposed to client).
-
Private areas (tag format `PRIVATE_USER_{id}`) always have `is_private = true`.
-
`updateFileArea()` forces `is_public = false` when `License::isValid()` is false,
preventing manipulation via direct API call.
Premium Gating
This feature requires a valid license (License::isValid()).
-
The Public checkbox in the file area editor is wrapped in `{% if license_valid %}`.
-
The Public Files Index toggle in BBS Settings is wrapped in `{% if license_valid %}`.
-
`updateFileArea()` forces `is_public = false` when no valid license is present.
-
The area access check at serve time does not re-check the license ? once set,
the area stays public even if the license lapses, to avoid service disruption.
See docs/proposals/PremiumFeatures.md for the premium features table.
|