Skip to content

Latest commit

 

History

History
173 lines (153 loc) · 8.48 KB

File metadata and controls

173 lines (153 loc) · 8.48 KB

AGENTS.md

Purpose

This repository builds a personal ShareX hosting app defined in PLAN.md. Implement the project end-to-end using PLAN.md as the source of truth.

Scope

  • Single-user personal deployment.
  • Blazor Server (.NET 10) app in Docker.
  • Self-hosted Convex backend (TypeScript) for storage + metadata.
  • ShareX upload routes for image/file/text.
  • Public view/download routes by slug.
  • Admin area with:
    • Overview page (/admin/dashboard) with real-time stats and cross-type top records
    • Per-type pages (/admin/images, /admin/files, /admin/texts) with real-time updates
    • Tools page (/admin/tools) for credential hash generation and ShareX uploader config
  • Security: rate limiting, security headers, upload validation, session hardening, proxy trust model.

Non-Goals

  • Multi-user auth, RBAC, or account recovery.
  • Enterprise-grade abuse controls beyond basic correctness.
  • Running Convex inside the .NET Docker image.

Source of Truth

  • Primary spec: PLAN.md
  • If implementation and plan conflict, update implementation to match plan unless user says otherwise.
  • If plan ambiguity is discovered, ask user once with a concrete recommendation, then proceed.

Required Environment Variables

  • CONVEX_URL
  • CONVEX_ADMIN_KEY (HTTP API auth header: Authorization: Convex <key>)
  • INTERNAL_API_SECRET (shared secret injected into Convex mutation args for function-level auth)
  • PUBLIC_BASE_URL
  • ADMIN_PASSWORD_HASH (PBKDF2-SHA256; random temporary password generated at startup if missing)
  • SHAREX_AUTH_KEY_HASH (PBKDF2-SHA256; random temporary key generated at startup if missing)

PUBLIC_BASE_URL must be normalized by trimming trailing slash before generating returned URLs.

Optional Security Environment Variables

  • TRUSTED_PROXY_IPS (comma-separated IPs/CIDRs for trusted reverse proxies)
  • ADMIN_IP_ALLOWLIST (comma-separated IPs/CIDRs allowed to access /admin*)
  • RATE_LIMIT_UPLOAD_PER_MINUTE (default 20)
  • RATE_LIMIT_VIEW_PER_MINUTE_PER_SLUG (default 60)
  • RATE_LIMIT_DOWNLOAD_PER_MINUTE_PER_SLUG (default 30)
  • RATE_LIMIT_ADMIN_LOGIN_PER_15MIN (default 5)
  • MAX_IMAGE_MB (default 20)
  • MAX_FILE_MB (default 100)
  • MAX_TEXT_KB (default 1024)

Required Contracts

Upload endpoints (auth required)

  • POST /i/ multipart image upload (magic-byte validated)
  • POST /f/ multipart file upload
  • POST /t/ form post with text field (fallback to content field; ShareX FormURLEncoded)

Upload return format:

  • Image: { "url": "{PUBLIC_BASE_URL}/i/{slug}" }
  • File: { "url": "{PUBLIC_BASE_URL}/f/{slug}" }
  • Text: { "url": "{PUBLIC_BASE_URL}/t/{slug}" }

Content endpoints (public, cached)

  • GET /content/i/{slug} - streams image with original content type, 1-year immutable cache, ETag, range requests

Download endpoints (public)

  • GET /download/i/{slug}
  • GET /download/f/{slug}
  • GET /download/t/{slug}

Behavior:

  • Lookup slug.
  • If found, increment downloads once.
  • Serve/redirect content (forced application/octet-stream to prevent stored XSS).

View behavior (public pages)

  • /i/{slug}, /f/{slug}, /t/{slug}:
    • Load by slug.
    • If found, increment views once per request.
    • If not found, render 404 component.

Text filename behavior

  • Text uploads do not accept client filename.
  • texts:create generates/stores filename as text-{slug}.txt.

Data Integrity and Rollback (Required)

Upload flow must be rollback-safe:

  1. Generate upload URL.
  2. Upload bytes and get storageId.
  3. Call {type}:create.
  4. If create fails: call storage:deleteStorageObject(storageId), then return error.
  5. If partial success then later failure: call {type}:deleteById(id) and storage:deleteStorageObject(storageId), then return error.
  6. Cleanup is best-effort. If cleanup also fails, log details and return HTTP 500.

Convex Backend Requirements

  • Functions live in convex/functions/ (configured via convex/convex.json).
  • schema.ts with tables: images, files, texts, counters.
  • Upload table shared fields: slug, storageId, fileName, contentType, fileSize, views, downloads.
  • counters table fields: table, count, views, downloads, storageBytes (pre-aggregated stats).
  • by_slug index on each upload table; by_table index on counters.
  • auth.ts - requireApiSecret() validates INTERNAL_API_SECRET env var (called by all mutations and admin-facing queries).
  • crud.ts - buildCrud(table) returns shared CRUD implementations:
    • getBySlug (query)
    • incrementViews (mutation, adjusts counter)
    • incrementDownloads (mutation, adjusts counter)
    • list (query, cursor pagination, default 50, max 50)
    • deleteById (mutation, cleans up storage object, adjusts counter)
  • helpers.ts - slug generation (8-char alphanumeric, collision check), type/table mapping, limit normalization.
  • Per-type module (images.ts, files.ts, texts.ts):
    • create mutation (generates slug, inserts record, adjusts counter)
    • Re-exports shared CRUD from buildCrud()
  • counters.ts:
    • adjustCounter (internal helper for atomic counter updates)
    • getCounter (internal helper for reading counter values)
  • storage.ts:
    • generateUploadUrl (requires API secret)
    • deleteStorageObject (requires API secret)
  • stats.ts:
    • getOverviewStats (dashboard callouts from counters + cross-type top records)
    • getTypeStats(type, cursor, limit) (per-type totals from counters + paginated records)
    • getImageStatsLive / getFileStatsLive / getTextStatsLive (queries accepting apiSecret for WebSocket subscriptions)

Blazor App Requirements

  • Services:
    • ConvexService.cs for query/mutation/upload operations (HTTP wrapper with Authorization: Convex <key> + apiSecret arg injection for mutations).
    • AuthService.cs for ShareX key and admin password validation (PBKDF2-SHA256 hashes only; generates random temporary secrets if env vars missing).
    • UploadService.cs orchestrating rollback-safe upload flow.
    • ShareXUploaderService.cs for generating ShareX .sxcu configuration files.
  • Features (vertical slice):
    • Features/Uploads/UploadEndpoints.cs - upload route handlers with magic-byte validation for images.
    • Features/Downloads/DownloadEndpoints.cs - download + content route handlers.
    • Features/Admin/AdminAuthEndpoints.cs - admin login/logout with anti-forgery.
    • Features/Admin/AdminAccessMiddleware.cs - admin access control (session + IP allowlist).
    • Features/Public/NotFoundRedirectMiddleware.cs - 404 redirect handling.
  • Minimal API endpoints in Program.cs for upload/download/admin login/logout + OpenAPI/Scalar UI.
  • Admin session auth via server-side session (single-instance assumptions are acceptable), with:
    • PBKDF2-SHA256 password validation
    • anti-forgery validation on admin login/logout
    • login rate limiting
    • optional admin IP allowlist
    • session hardening (HttpOnly, SameSite=Strict, Secure, path-restricted, absolute 8-hour timeout)
  • Security middleware:
    • Rate limiting (per-route partitions: upload, view, download, admin login)
    • Security headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, CSP)
    • Configurable upload size limits per type
    • Proxy trust model via TRUSTED_PROXY_IPS
  • UI pages:
    • Home, ImageView, FileView, TextView, NotFound, Error
    • AdminLogin, AdminDashboard, AdminImages, AdminFiles, AdminTexts, AdminTools
  • Shared components:
    • AdminRecordList.razor - reusable record list with staggered row animation
    • AdminNavigation.razor - admin navigation

Verification Checklist (Must Pass)

  • Convex deploy works.
  • Upload tests for /i/, /f/, and /t/ return valid URLs.
  • Public view pages render expected content.
  • Download routes work and increment counters.
  • Abuse/rate-limit checks return HTTP 429 after threshold for upload and admin login routes.
  • Auth checks:
    • Missing upload auth returns 401.
    • Unauthenticated admin route redirects to login.
  • Admin overview shows callouts, top records, and links.
  • Per-type admin pages show totals + paginated records with live updates.
  • Pagination loads older records.
  • Rollback test: create failure after upload does not orphan storage.
  • Cleanup-failure test: logs failure and returns 500.
  • docker build && docker run works with end-to-end checks.
  • dotnet test passes all unit tests.

Delivery Expectations

  • Implement, run tests, and report exact pass/fail outcomes.
  • If blocked, state blocker clearly with the smallest required user input.
  • Keep changes minimal, coherent, and aligned to PLAN.md.