Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RipoDoc

Secure, interactive client reports for managed service providers.

Send a normal PDF where a reader can click an approved figure and inspect the precise evidence behind it. Delivery is recipient-bound, time-bound, revocable, and auditable.

RipoDoc preserves the client reporting workflow MSPs already use while adding a defensible evidence layer. It supports two complementary paths: render a report from a validated manifest, or overlay link annotations onto an existing PDF without redrawing its pages.

Capability What RipoDoc provides
Familiar client experience A standard PDF that opens in common viewers and keeps the report format your clients know.
Evidence on demand One click opens only the rows and provenance approved for that figure.
Controlled delivery Signed evidence claims bind the report, version, recipient hash, expiry, and revocation identifier.
Accountable publication Report manifests validate before storage; every figure has approved provenance.
Auditability Granted and denied access can be recorded in a SHA-256 hash chain.
MSP-ready workspace A customer dashboard, security-control view, downloadable report registry, and private administrator workspace.

Product routes

Route Audience Purpose
/ Prospects and MSP teams Outcome-led product page with an interactive sample report backed by real fixture data.
/upload Verified self-hosted operators Propose overlays and create a downloadable clickable PDF through the same-origin authoring gateway and a private RipoDoc worker.
/api/health Deployment monitoring No-store operational health response with safe configuration indicators only; never returns tenants, reports, recipients, sessions, or secrets.
/dashboard Verified MSP workspace users Review only reports owned by the authenticated tenant; report manifests require tenant-scoped session authorization.
/signup, /login, /verify-email, /forgot-password, /reset-password MSP workspace users Complete account lifecycle with email activation, one-time codes, private sessions, rate limits, and CAPTCHA protection.
/security Operators and security reviewers Inspect safe, live operational posture without exposing secrets, recipient identities, or audit records.
/e/[token]/[elementId] Intended report recipient Open the evidence authorized by a signed link.
/admin Private operators only Protected report and recipient operations workspace. It is intentionally excluded from public navigation.

Quick start

RipoDoc requires Node.js 22.6 or newer because the toolchain uses native TypeScript stripping. The following sequence runs the public app and produces a locally clickable sample report.

git clone https://github.com/thecelestialmismatch/RipoDoc.git
cd RipoDoc

# Install the frontend and project dependencies.
npm install
npm install --prefix web/frontend

# Use a strong server-only signing secret for evidence links.
export RIPODOC_EVIDENCE_SECRET="$(openssl rand -base64 32)"

# Start the customer-facing application.
npm --prefix web/frontend run dev

# In a second terminal, generate a PDF whose evidence links point at localhost.
npm run build:pdf:local

Open build/demo-report.local.pdf and select a report figure. The local application will show the approved evidence rows, provenance, and review metadata for that figure.

Download and self-host the complete platform

RipoDoc is downloadable as a complete MSP deployment bundle, not merely a public marketing site. The bundle starts PostgreSQL, the protected workspace application, and a loopback-only PDF worker together. Copy the repository, create the required environment values, then run:

git clone https://github.com/thecelestialmismatch/RipoDoc.git
cd RipoDoc
export POSTGRES_PASSWORD="$(openssl rand -base64 32)"
export RIPODOC_AUTH_SECRET="$(openssl rand -base64 32)"
export RIPODOC_EVIDENCE_SECRET="$(openssl rand -base64 32)"
export RIPODOC_WORKER_AUTH_SECRET="$(openssl rand -base64 32)"
# Set RIPODOC_APP_ORIGIN, RIPODOC_RESEND_API_KEY, RIPODOC_EMAIL_FROM,
# RIPODOC_TURNSTILE_SECRET, and NEXT_PUBLIC_RIPODOC_TURNSTILE_SITE_KEY.
docker compose -f docker-compose.selfhost.yml up --build

The browser-facing app listens on ${RIPODOC_PORT:-3000}. PostgreSQL remains internal to the compose network, while the PDF worker binds its host port to 127.0.0.1 and accepts only short-lived server-issued authoring capabilities. The browser never receives a worker credential or direct worker URL. The bundle runs the web and worker containers as non-root with read-only root filesystems, temporary tmpfs mounts, dropped Linux capabilities, health checks, and conservative CPU/memory limits. Deploy the web service behind an HTTPS reverse proxy using the canonical origin configured in RIPODOC_APP_ORIGIN.

Self-hosted report authoring

The /upload route intentionally uses a private self-hosted processing worker. A public Vercel site must not receive an MSP's client report by default. Every upload, proposal download, review, publish, and artifact download starts with a verified workspace session. The web server issues a single-use, short-lived, tenant-bound capability to the worker; browser CORS and draft IDs are never treated as authorization. The authoring sequence is explicit: select a validated RipoDoc manifest, upload its matching PDF, review the proposed click zones, record a server-bound reviewer decision, then publish the downloadable PDF. Publication rechecks the exact source PDF, manifest, and reviewed-proposal digests.

# The worker signs evidence links and verifies a separate server-only
# authoring credential. Do not place either value in NEXT_PUBLIC_ variables.
export RIPODOC_EVIDENCE_SECRET="$(openssl rand -base64 32)"
export RIPODOC_WORKER_AUTH_SECRET="$(openssl rand -base64 32)"
export RIPODOC_LOCAL_WORKER_URL="http://127.0.0.1:4000/api/local"

# Start the private PDF worker, then run the Next.js app with the same
# RIPODOC_WORKER_AUTH_SECRET and RIPODOC_LOCAL_WORKER_URL values.
npm run dev:local-server
npm --prefix web/frontend run dev

The upload page uses same-origin /api/authoring/* routes. Configure RIPODOC_LOCAL_WORKER_URL only in the trusted web-server environment; never publish it as NEXT_PUBLIC_*, and never expose RIPODOC_WORKER_AUTH_SECRET to the browser. The worker rejects browser-originated requests, unsigned requests, expired/replayed capabilities, wrong-purpose capabilities, and cross-tenant draft access.

Mode Use it when Command
Overlay You want to retain the existing PDF your MSP already sends. npm run overlay:propose then npm run overlay:sample
Generate You want RipoDoc to render a complete PDF from a report manifest. npm run build:pdf or npm run build:pdf:local
Local authoring UI You want a browser interface connected to your self-hosted worker. npm run docker:run and npm --prefix web/frontend run dev

Environment configuration

Store all values below in the relevant server environment. Do not expose RIPODOC_EVIDENCE_SECRET, RIPODOC_AUTH_SECRET, or RIPODOC_WORKER_AUTH_SECRET to the browser.

Variable Required Purpose
RIPODOC_EVIDENCE_SECRET Yes for evidence delivery A 32-character-or-longer secret used to sign recipient-bound evidence claims.
RIPODOC_DATABASE_URL Yes for workspace authentication PostgreSQL connection URL for tenant users, opaque sessions, one-time codes, rate-limit counters, and tenant report records.
RIPODOC_AUTH_SECRET Yes for workspace authentication A separate 32-character-or-longer server-only HMAC secret for session, privacy, and one-time-code hashing.
RIPODOC_APP_ORIGIN Yes for workspace authentication Canonical HTTPS application origin used in email messages and CSRF checks.
RIPODOC_RESEND_API_KEY Yes for workspace authentication Server-only Resend API key used for verification, reset, and recipient-proof codes.
RIPODOC_EMAIL_FROM Yes for workspace authentication Verified sender address for security notices.
RIPODOC_TURNSTILE_SECRET Yes in production Server-only Cloudflare Turnstile secret used by every authentication action.
NEXT_PUBLIC_RIPODOC_TURNSTILE_SITE_KEY Yes in production Public Cloudflare Turnstile site key for the authentication forms.
RIPODOC_AUDIT_LOG Recommended on durable infrastructure File path for a persisted, locally verifiable hash-chained audit log. Without it, events are emitted as structured stdout.
RIPODOC_REVOKED_JTIS Optional Comma-separated claim identifiers that must no longer authorize evidence access.
RIPODOC_ALLOW_EXPORT Optional Set to false to disable evidence CSV export. The default is enabled.
RIPODOC_CONTENT_ROOT Optional Filesystem root for published report manifests in a self-hosted runtime. Defaults to content/reports under the active working directory.
RIPODOC_LOCAL_WORKER_URL Yes for private authoring Server-only URL for the private worker. Compose sets this to http://worker:4000/api/local; local development may use http://127.0.0.1:4000/api/local.
RIPODOC_WORKER_AUTH_SECRET Yes for private authoring A separate 32-character-or-longer server-only HMAC secret shared only by the web service and worker to issue and verify single-use, 90-second authoring capabilities.
RIPODOC_WORKER_MAX_CONCURRENT_JOBS Optional Private worker concurrency cap. Defaults to 2 and is constrained to a maximum of 4.

Security model

RipoDoc does not treat possession of a PDF URL as permanent authorization. Its evidence token contains the report identifier, version, recipient email hash, expiry, and revocation identifier; the email address itself is not embedded in the token. Before rendering scoped evidence, the recipient must complete a one-time code challenge delivered to the address whose hash is embedded in the signed claim. One-time codes are stored only as keyed hashes, expire quickly, are consumed atomically, and are never placed in links or audit logs.

Authentication technology stack

The workspace identity service is deliberately implemented as a small, server-side TypeScript boundary rather than a browser-side identity shim. Next.js 16 App Router supplies the request and response surfaces; Node.js crypto provides random generation, HMAC, constant-time comparison, and scrypt; PostgreSQL is the durable authority for users, sessions, one-time codes, rate limits, audit events, tenants, and report ownership; the pg client uses parameterized statements and transactions; Resend delivers verification, recovery, and recipient-proof codes through HTTPS; and Cloudflare Turnstile is verified server-side for production anti-automation. The Next.js middleware sets the browser security headers and CSRF cookie.

Required authentication control Shipped implementation Primary source
Enumeration-resistant lifecycle Signup and recovery return one generic message, and login performs a dummy scrypt verification for unknown accounts before a fixed 900 ms response floor. service.ts, primitives.ts
Rate limiting and CAPTCHA PostgreSQL rate-limit buckets enforce address and IP limits; every production auth action verifies Turnstile before it invokes the auth service. service.ts, captcha.ts, [action]/route.ts
Verified account activation New tenants are inactive until a one-time verification code is consumed; sign-in excludes unverified or disabled users. service.ts
Slow password hashing Passwords use Node.js scrypt with a random 16-byte salt and a 64-byte derived key; no plaintext, MD5, or raw SHA-256 password storage is used. primitives.ts
Secure reset and proof codes Codes are cryptographically random, HMAC-hashed before storage, single-use through an atomic transaction, delivered outside URLs, and expire after 30 minutes. service.ts, recipient-proof.ts
Session and CSRF controls Opaque session secrets are stored only as keyed hashes; session cookies use HttpOnly, strict same-site handling, and production-only Secure; state-changing actions require same-origin plus double-submit CSRF validation. server.ts, middleware.ts

A deeper test and control inventory is maintained in docs/05-security/authentication-and-test-coverage.md. The historical read-only 20-control assessment is maintained in docs/05-security/self-hosted-deployment-and-read-only-audit.md. The current private-worker threat model is maintained in docs/05-security/worker-hardening-threat-model.md, and the complete self-hosted operational procedure is maintained in docs/05-engineering/self-hosted-operations-runbook.md. PR #9 supply-chain evidence, reproducible final-image scanning instructions, and CycloneDX SBOM files are maintained in docs/05-security/container-sbom-and-vulnerability-scan.md; customer-facing self-hosted upgrade instructions are maintained in docs/05-security/pr9-self-hosted-security-advisory-and-migration-guide.md.

RipoDoc fails closed for hosted account actions until PostgreSQL, Resend, the canonical app origin, an authentication secret, and the production Turnstile configuration are present. It never substitutes ephemeral Vercel filesystem state or silent email failure for a durable identity deployment.

The evidence rows are not embedded in the PDF. Forwarding the document does not automatically forward the underlying dataset.

Published manifests are schema-validated and immutable at the file-store boundary. When a durable RIPODOC_AUDIT_LOG is configured, audit events can be verified with:

npm run audit:verify -- --path /secure/audit/evidence-access.jsonl

The /security page provides operator-safe indicators for this posture. It never displays signing secrets, token identifiers, recipient identities, or audit-log contents.

Verification

The repository uses the built-in Node.js test runner for evidence and application-runtime boundaries. The current regression suite completes 135 tests with no failures, including an end-to-end local worker test that verifies the manifest requirement, review gate, signed publication, and PDF download, plus dashboard/download route-contract coverage, followed by clean linting, type checking, and a production build. See docs/05-security/authentication-and-test-coverage.md for the full file-by-file coverage map.

npm test              # evidence, audit, runtime-posture, and admin-key tests
npm run lint          # ESLint for the Next.js frontend
npm run typecheck     # strict TypeScript checks for web and tools
npm run verify        # typecheck + test + production frontend build

Deployment

The public product site is designed for Vercel deployment from the main branch. Before enabling workspace accounts on Vercel, provision PostgreSQL and configure RIPODOC_DATABASE_URL, RIPODOC_AUTH_SECRET, RIPODOC_APP_ORIGIN, Resend, and Turnstile variables listed above. The application fails closed for account actions until that durable authentication configuration exists.

The document processor is intentionally not bundled into the public Vercel application. Deploy the worker on infrastructure you control and configure its URL only through server-side RIPODOC_LOCAL_WORKER_URL, paired with RIPODOC_WORKER_AUTH_SECRET. This separation prevents report files from being silently routed through a public marketing deployment and prevents a browser from directly calling the worker.

Release gate Required result
Automated checks npm run verify exits successfully.
Public route review /, /upload, /dashboard, /security, and the safe /api/health deployment probe render without broken navigation.
Private operations review /admin redirects unauthenticated visitors to /login; verified owner and admin users see only their tenant-scoped operational summary.
Worker review A verified tenant session completes upload, review, and publication through /api/authoring; direct browser, unsigned, replayed, wrong-purpose, and cross-tenant worker requests fail without disclosing artifacts.
Environment review Server-only variables are present in the deployment environment and never committed.

Project structure

web/frontend/                 Next.js App Router application
  src/app/                    Public, customer, evidence, and admin routes
  src/lib/evidence/           Manifest validation, tokens, audit, storage, posture
  src/lib/admin/              HMAC session helpers for private operations
  content/reports/            Validated published report manifests

tools/evidence-pdf/           PDF generator, overlay engine, fixtures, and tests
docker/local/                 Local self-hosted authoring worker
var/msp_pitch_deck/           12-slide MSP sales and marketing pitch deck
DESIGN.md                     RipoDoc visual system and interface standards

Sales and product materials

The MSP sales deck is maintained in var/msp_pitch_deck/. It explains the reporting problem, the RipoDoc evidence workflow, integration posture, security approach, onboarding path, and commercial positioning.

The product design system is maintained in DESIGN.md. It documents the RipoDoc navy, blue, and teal visual language; layout principles; component behavior; accessibility expectations; and responsive constraints.

Contributing

Keep trust boundaries explicit. Any change that affects evidence authorization, recipient binding, link expiry, revocation, report manifest validation, or audit behavior must include focused tests. Keep the public website truthful about deployment capabilities: a public preview is not a substitute for an explicitly configured self-hosted document processor.

License

See LICENSE for the repository license terms.

About

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages