Screenshots Worker Service
Relevant source files
The following files were used as context for generating this wiki page:
The Screenshots Worker Service is an isolated component responsible for generating visual previews of member homepages. It operates as a separate service that interacts with the main PuppyPad application via an internal API. The worker renders untrusted member HTML using headless Chromium and produces JPEG images used in the site directory and user profiles.
Sources: shots/worker.js:1-5, PLAN.md:15-30
Architecture and Component Interaction
The service runs in a dedicated container to isolate the untrusted rendering environment from the main application and sensitive member data. It communicates with the backend through a polling mechanism and specific internal endpoints.
The diagram shows the polling and rendering flow between the isolated worker and the core application server.
Sources: shots/worker.js:80-95, PLAN.md:15-30
Communication Workflow
- Polling: The worker continuously polls
/internal/shots/nextto find sites marked as "dirty" (requiring a new screenshot). - Selection: The server selects the oldest site where
shot_dirty = 1and returns its name and URL. - Rendering: The worker uses Playwright to open the URL in a sandboxed browser context.
- Submission: The worker posts the generated JPEG buffer back to
/internal/shots/:name. - Finalization: The server saves the image to disk and resets the
shot_dirtyflag.
Sources: shots/worker.js:84-100, src/server.js:296-310
Security and Guardrails
Rendering member-controlled JavaScript and HTML presents security risks. The worker implements multiple layers of protection to prevent SSRF (Server-Side Request Forgery) and unauthorized access.
URL and Network Filtering
The worker validates every request made by the browser. It prevents the browser from accessing internal network resources or metadata services.
| Feature | Logic / Action |
|---|---|
| Protocol Allowlist | Permits only http:, https:, data:, and blob:. |
| Hostname Validation | Rejects hostnames without dots (e.g., app, db) or containing localhost/internal. |
| IP Resolution Check | Resolves hostnames and rejects any that point to private or reserved IP ranges. |
| Egress Blocking | Aborts Chromium requests to any IP classified as non-public. |
Sources: shots/worker.js:14-55, README.md:153-157
Request Authentication
The main application protects internal screenshot endpoints using a SHOT_TOKEN. The worker must include this token in the x-shot-token header for every request. If the token is missing or mismatched, the server returns a 403 Forbidden status.
Sources: src/server.js:291-295, shots/worker.js:85
Browser Configuration
The worker utilizes Playwright to manage the Chromium instance with specific parameters tailored for static site previews.
- Viewport: Fixed at 1024x768 pixels.
- Scale Factor: Set to 0.5 to produce compact previews.
- Timeouts: 15-second page load timeout and 10-second screenshot timeout.
- Wait Period: Pauses for 1.5 seconds after loading to allow animated GIFs and fonts to settle.
- Media: Audio is muted via browser arguments.
Sources: shots/worker.js:58-77, shots/worker.js:82
API Endpoints
The core application provides the following endpoints specifically for the worker service. These are restricted to internal network access and require token authentication.
| Endpoint | Method | Purpose |
|---|---|---|
/internal/shots/next | GET | Returns { name, url } for the next site needing a screenshot. |
/internal/shots/:name | POST | Accepts a raw binary buffer (JPEG) and updates the site's shot_at timestamp. |
Sources: src/server.js:296-307
Implementation Details
Dirty Flag Logic
The system marks a site as needing a screenshot (shot_dirty = 1) whenever:
- A member saves a file in the editor.
- A member uploads files or imports a ZIP.
- A member renames their site.
- A site is restored from a banned state.
Sources: src/server.js:63-65, src/server.js:464, src/server.js:635
Image Validation
The server performs basic JPEG validation before saving the worker's output. It checks for the JPEG magic bytes (0xff 0xd8) and ensures the buffer length is greater than 100 bytes. This prevents corrupted or malicious uploads from overwriting existing previews.
Sources: src/server.js:303-305, test/app.test.js:614-618
Summary
The Screenshots Worker Service provides an automated, secure way to generate site previews. By isolating the rendering logic in a separate container and enforcing strict network filtering, PuppyPad mitigates the risks associated with executing untrusted member code during the screenshot process. This component is essential for maintaining the visual directory of the "Dog Park" while ensuring platform stability.