thevoidforge 21.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/vault-read.d.ts +11 -0
- package/dist/scripts/vault-read.js +89 -0
- package/dist/scripts/voidforge.d.ts +20 -0
- package/dist/scripts/voidforge.js +404 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/wizard/api/auth.d.ts +5 -0
- package/dist/wizard/api/auth.js +133 -0
- package/dist/wizard/api/blueprint.d.ts +45 -0
- package/dist/wizard/api/blueprint.js +184 -0
- package/dist/wizard/api/cloud-providers.d.ts +16 -0
- package/dist/wizard/api/cloud-providers.js +363 -0
- package/dist/wizard/api/credentials.d.ts +1 -0
- package/dist/wizard/api/credentials.js +258 -0
- package/dist/wizard/api/danger-room.d.ts +18 -0
- package/dist/wizard/api/danger-room.js +401 -0
- package/dist/wizard/api/deploy.d.ts +4 -0
- package/dist/wizard/api/deploy.js +164 -0
- package/dist/wizard/api/prd.d.ts +1 -0
- package/dist/wizard/api/prd.js +363 -0
- package/dist/wizard/api/project.d.ts +1 -0
- package/dist/wizard/api/project.js +239 -0
- package/dist/wizard/api/projects.d.ts +6 -0
- package/dist/wizard/api/projects.js +648 -0
- package/dist/wizard/api/provision.d.ts +4 -0
- package/dist/wizard/api/provision.js +535 -0
- package/dist/wizard/api/terminal.d.ts +25 -0
- package/dist/wizard/api/terminal.js +241 -0
- package/dist/wizard/api/users.d.ts +6 -0
- package/dist/wizard/api/users.js +244 -0
- package/dist/wizard/api/war-room.d.ts +14 -0
- package/dist/wizard/api/war-room.js +45 -0
- package/dist/wizard/lib/ad-platform-core.d.ts +6 -0
- package/dist/wizard/lib/ad-platform-core.js +1 -0
- package/dist/wizard/lib/adapters/index.d.ts +52 -0
- package/dist/wizard/lib/adapters/index.js +38 -0
- package/dist/wizard/lib/adapters/sandbox-bank.d.ts +17 -0
- package/dist/wizard/lib/adapters/sandbox-bank.js +77 -0
- package/dist/wizard/lib/adapters/sandbox.d.ts +39 -0
- package/dist/wizard/lib/adapters/sandbox.js +174 -0
- package/dist/wizard/lib/adapters/stripe.d.ts +19 -0
- package/dist/wizard/lib/adapters/stripe.js +143 -0
- package/dist/wizard/lib/adapters/types.d.ts +9 -0
- package/dist/wizard/lib/adapters/types.js +10 -0
- package/dist/wizard/lib/agent-memory.d.ts +36 -0
- package/dist/wizard/lib/agent-memory.js +114 -0
- package/dist/wizard/lib/anomaly-detection.d.ts +59 -0
- package/dist/wizard/lib/anomaly-detection.js +122 -0
- package/dist/wizard/lib/anthropic.d.ts +21 -0
- package/dist/wizard/lib/anthropic.js +105 -0
- package/dist/wizard/lib/asset-scanner.d.ts +23 -0
- package/dist/wizard/lib/asset-scanner.js +107 -0
- package/dist/wizard/lib/audit-log.d.ts +23 -0
- package/dist/wizard/lib/audit-log.js +70 -0
- package/dist/wizard/lib/autonomy-controller.d.ts +76 -0
- package/dist/wizard/lib/autonomy-controller.js +183 -0
- package/dist/wizard/lib/body-parser.d.ts +2 -0
- package/dist/wizard/lib/body-parser.js +36 -0
- package/dist/wizard/lib/build-analytics.d.ts +39 -0
- package/dist/wizard/lib/build-analytics.js +91 -0
- package/dist/wizard/lib/build-step.d.ts +21 -0
- package/dist/wizard/lib/build-step.js +104 -0
- package/dist/wizard/lib/campaign-proposer.d.ts +39 -0
- package/dist/wizard/lib/campaign-proposer.js +180 -0
- package/dist/wizard/lib/campaign-state-machine.d.ts +63 -0
- package/dist/wizard/lib/campaign-state-machine.js +114 -0
- package/dist/wizard/lib/ci-generator.d.ts +14 -0
- package/dist/wizard/lib/ci-generator.js +187 -0
- package/dist/wizard/lib/claude-merge.d.ts +38 -0
- package/dist/wizard/lib/claude-merge.js +115 -0
- package/dist/wizard/lib/codegen/erd-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/erd-gen.js +98 -0
- package/dist/wizard/lib/codegen/integrations.d.ts +18 -0
- package/dist/wizard/lib/codegen/integrations.js +189 -0
- package/dist/wizard/lib/codegen/openapi-gen.d.ts +15 -0
- package/dist/wizard/lib/codegen/openapi-gen.js +79 -0
- package/dist/wizard/lib/codegen/prisma-types.d.ts +15 -0
- package/dist/wizard/lib/codegen/prisma-types.js +44 -0
- package/dist/wizard/lib/codegen/seed-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/seed-gen.js +128 -0
- package/dist/wizard/lib/compliance.d.ts +51 -0
- package/dist/wizard/lib/compliance.js +112 -0
- package/dist/wizard/lib/correlation-engine.d.ts +59 -0
- package/dist/wizard/lib/correlation-engine.js +151 -0
- package/dist/wizard/lib/cost-estimator.d.ts +22 -0
- package/dist/wizard/lib/cost-estimator.js +72 -0
- package/dist/wizard/lib/cost-tracker.d.ts +27 -0
- package/dist/wizard/lib/cost-tracker.js +37 -0
- package/dist/wizard/lib/daemon-aggregator.d.ts +71 -0
- package/dist/wizard/lib/daemon-aggregator.js +204 -0
- package/dist/wizard/lib/daemon-core.d.ts +6 -0
- package/dist/wizard/lib/daemon-core.js +5 -0
- package/dist/wizard/lib/dashboard-data.d.ts +132 -0
- package/dist/wizard/lib/dashboard-data.js +336 -0
- package/dist/wizard/lib/dashboard-ws.d.ts +25 -0
- package/dist/wizard/lib/dashboard-ws.js +91 -0
- package/dist/wizard/lib/deep-current.d.ts +77 -0
- package/dist/wizard/lib/deep-current.js +234 -0
- package/dist/wizard/lib/deploy-coordinator.d.ts +40 -0
- package/dist/wizard/lib/deploy-coordinator.js +86 -0
- package/dist/wizard/lib/deploy-log.d.ts +28 -0
- package/dist/wizard/lib/deploy-log.js +52 -0
- package/dist/wizard/lib/desktop-notify.d.ts +27 -0
- package/dist/wizard/lib/desktop-notify.js +98 -0
- package/dist/wizard/lib/dns/cloudflare-dns.d.ts +35 -0
- package/dist/wizard/lib/dns/cloudflare-dns.js +216 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.d.ts +31 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.js +148 -0
- package/dist/wizard/lib/dns/types.d.ts +22 -0
- package/dist/wizard/lib/dns/types.js +4 -0
- package/dist/wizard/lib/document-discovery.d.ts +33 -0
- package/dist/wizard/lib/document-discovery.js +145 -0
- package/dist/wizard/lib/env-validator.d.ts +14 -0
- package/dist/wizard/lib/env-validator.js +205 -0
- package/dist/wizard/lib/env-writer.d.ts +13 -0
- package/dist/wizard/lib/env-writer.js +26 -0
- package/dist/wizard/lib/exec.d.ts +30 -0
- package/dist/wizard/lib/exec.js +52 -0
- package/dist/wizard/lib/experiment.d.ts +70 -0
- package/dist/wizard/lib/experiment.js +169 -0
- package/dist/wizard/lib/extensions.d.ts +20 -0
- package/dist/wizard/lib/extensions.js +183 -0
- package/dist/wizard/lib/financial/adapter-factory.d.ts +47 -0
- package/dist/wizard/lib/financial/adapter-factory.js +225 -0
- package/dist/wizard/lib/financial/billing/base.d.ts +6 -0
- package/dist/wizard/lib/financial/billing/base.js +1 -0
- package/dist/wizard/lib/financial/billing/google-billing.d.ts +56 -0
- package/dist/wizard/lib/financial/billing/google-billing.js +298 -0
- package/dist/wizard/lib/financial/billing/meta-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/meta-billing.js +243 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.js +260 -0
- package/dist/wizard/lib/financial/campaign/base.d.ts +13 -0
- package/dist/wizard/lib/financial/campaign/base.js +1 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.d.ts +42 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.js +388 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.d.ts +41 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.js +311 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.d.ts +45 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.js +261 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.d.ts +40 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.js +350 -0
- package/dist/wizard/lib/financial/funding-auto.d.ts +44 -0
- package/dist/wizard/lib/financial/funding-auto.js +52 -0
- package/dist/wizard/lib/financial/funding-policy.d.ts +60 -0
- package/dist/wizard/lib/financial/funding-policy.js +179 -0
- package/dist/wizard/lib/financial/platform-planner.d.ts +47 -0
- package/dist/wizard/lib/financial/platform-planner.js +134 -0
- package/dist/wizard/lib/financial/reconciliation-engine.d.ts +78 -0
- package/dist/wizard/lib/financial/reconciliation-engine.js +193 -0
- package/dist/wizard/lib/financial/registry.d.ts +22 -0
- package/dist/wizard/lib/financial/registry.js +26 -0
- package/dist/wizard/lib/financial/reporting.d.ts +96 -0
- package/dist/wizard/lib/financial/reporting.js +198 -0
- package/dist/wizard/lib/financial/stablecoin/base.d.ts +6 -0
- package/dist/wizard/lib/financial/stablecoin/base.js +1 -0
- package/dist/wizard/lib/financial/stablecoin/circle.d.ts +54 -0
- package/dist/wizard/lib/financial/stablecoin/circle.js +367 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.d.ts +24 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.js +171 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.d.ts +47 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.js +202 -0
- package/dist/wizard/lib/financial/treasury-planner.d.ts +52 -0
- package/dist/wizard/lib/financial/treasury-planner.js +128 -0
- package/dist/wizard/lib/financial-core.d.ts +6 -0
- package/dist/wizard/lib/financial-core.js +5 -0
- package/dist/wizard/lib/financial-vault.d.ts +34 -0
- package/dist/wizard/lib/financial-vault.js +199 -0
- package/dist/wizard/lib/frontmatter.d.ts +30 -0
- package/dist/wizard/lib/frontmatter.js +96 -0
- package/dist/wizard/lib/gap-analysis.d.ts +37 -0
- package/dist/wizard/lib/gap-analysis.js +218 -0
- package/dist/wizard/lib/github.d.ts +22 -0
- package/dist/wizard/lib/github.js +261 -0
- package/dist/wizard/lib/headless-deploy.d.ts +14 -0
- package/dist/wizard/lib/headless-deploy.js +452 -0
- package/dist/wizard/lib/health-monitor.d.ts +15 -0
- package/dist/wizard/lib/health-monitor.js +91 -0
- package/dist/wizard/lib/health-poller.d.ts +9 -0
- package/dist/wizard/lib/health-poller.js +123 -0
- package/dist/wizard/lib/heartbeat.d.ts +15 -0
- package/dist/wizard/lib/heartbeat.js +827 -0
- package/dist/wizard/lib/http-helpers.d.ts +9 -0
- package/dist/wizard/lib/http-helpers.js +24 -0
- package/dist/wizard/lib/image-gen.d.ts +56 -0
- package/dist/wizard/lib/image-gen.js +159 -0
- package/dist/wizard/lib/instance-sizing.d.ts +26 -0
- package/dist/wizard/lib/instance-sizing.js +51 -0
- package/dist/wizard/lib/kongo/analytics.d.ts +29 -0
- package/dist/wizard/lib/kongo/analytics.js +179 -0
- package/dist/wizard/lib/kongo/campaigns.d.ts +52 -0
- package/dist/wizard/lib/kongo/campaigns.js +91 -0
- package/dist/wizard/lib/kongo/client.d.ts +58 -0
- package/dist/wizard/lib/kongo/client.js +221 -0
- package/dist/wizard/lib/kongo/jobs.d.ts +57 -0
- package/dist/wizard/lib/kongo/jobs.js +122 -0
- package/dist/wizard/lib/kongo/pages.d.ts +60 -0
- package/dist/wizard/lib/kongo/pages.js +150 -0
- package/dist/wizard/lib/kongo/provisioner.d.ts +64 -0
- package/dist/wizard/lib/kongo/provisioner.js +116 -0
- package/dist/wizard/lib/kongo/seed.d.ts +49 -0
- package/dist/wizard/lib/kongo/seed.js +237 -0
- package/dist/wizard/lib/kongo/types.d.ts +323 -0
- package/dist/wizard/lib/kongo/types.js +11 -0
- package/dist/wizard/lib/kongo/variants.d.ts +57 -0
- package/dist/wizard/lib/kongo/variants.js +88 -0
- package/dist/wizard/lib/kongo/webhooks.d.ts +41 -0
- package/dist/wizard/lib/kongo/webhooks.js +112 -0
- package/dist/wizard/lib/marker.d.ts +28 -0
- package/dist/wizard/lib/marker.js +79 -0
- package/dist/wizard/lib/migrator.d.ts +35 -0
- package/dist/wizard/lib/migrator.js +190 -0
- package/dist/wizard/lib/natural-language-deploy.d.ts +30 -0
- package/dist/wizard/lib/natural-language-deploy.js +186 -0
- package/dist/wizard/lib/network.d.ts +22 -0
- package/dist/wizard/lib/network.js +72 -0
- package/dist/wizard/lib/oauth-core.d.ts +6 -0
- package/dist/wizard/lib/oauth-core.js +5 -0
- package/dist/wizard/lib/open-browser.d.ts +1 -0
- package/dist/wizard/lib/open-browser.js +26 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.d.ts +209 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.js +269 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.d.ts +200 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.js +212 -0
- package/dist/wizard/lib/patterns/daemon-process.d.ts +88 -0
- package/dist/wizard/lib/patterns/daemon-process.js +271 -0
- package/dist/wizard/lib/patterns/financial-transaction.d.ts +161 -0
- package/dist/wizard/lib/patterns/financial-transaction.js +132 -0
- package/dist/wizard/lib/patterns/funding-plan.d.ts +136 -0
- package/dist/wizard/lib/patterns/funding-plan.js +200 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.d.ts +94 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.js +139 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.d.ts +67 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.js +216 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.d.ts +96 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.js +182 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.d.ts +218 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.js +264 -0
- package/dist/wizard/lib/prd-validator.d.ts +39 -0
- package/dist/wizard/lib/prd-validator.js +137 -0
- package/dist/wizard/lib/project-init.d.ts +24 -0
- package/dist/wizard/lib/project-init.js +193 -0
- package/dist/wizard/lib/project-registry.d.ts +86 -0
- package/dist/wizard/lib/project-registry.js +359 -0
- package/dist/wizard/lib/provision-manifest.d.ts +44 -0
- package/dist/wizard/lib/provision-manifest.js +164 -0
- package/dist/wizard/lib/provisioner-registry.d.ts +15 -0
- package/dist/wizard/lib/provisioner-registry.js +34 -0
- package/dist/wizard/lib/provisioners/aws-vps.d.ts +6 -0
- package/dist/wizard/lib/provisioners/aws-vps.js +643 -0
- package/dist/wizard/lib/provisioners/cloudflare.d.ts +6 -0
- package/dist/wizard/lib/provisioners/cloudflare.js +300 -0
- package/dist/wizard/lib/provisioners/docker.d.ts +6 -0
- package/dist/wizard/lib/provisioners/docker.js +75 -0
- package/dist/wizard/lib/provisioners/http-client.d.ts +20 -0
- package/dist/wizard/lib/provisioners/http-client.js +79 -0
- package/dist/wizard/lib/provisioners/railway.d.ts +6 -0
- package/dist/wizard/lib/provisioners/railway.js +413 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.js +54 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.js +112 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.d.ts +11 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.js +91 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.d.ts +5 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.js +185 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.js +36 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.d.ts +14 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.js +202 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.js +67 -0
- package/dist/wizard/lib/provisioners/self-deploy.d.ts +41 -0
- package/dist/wizard/lib/provisioners/self-deploy.js +185 -0
- package/dist/wizard/lib/provisioners/static-s3.d.ts +6 -0
- package/dist/wizard/lib/provisioners/static-s3.js +235 -0
- package/dist/wizard/lib/provisioners/types.d.ts +40 -0
- package/dist/wizard/lib/provisioners/types.js +4 -0
- package/dist/wizard/lib/provisioners/vercel.d.ts +6 -0
- package/dist/wizard/lib/provisioners/vercel.js +287 -0
- package/dist/wizard/lib/pty-manager.d.ts +42 -0
- package/dist/wizard/lib/pty-manager.js +231 -0
- package/dist/wizard/lib/rate-limiter-core.d.ts +5 -0
- package/dist/wizard/lib/rate-limiter-core.js +5 -0
- package/dist/wizard/lib/reconciliation.d.ts +43 -0
- package/dist/wizard/lib/reconciliation.js +173 -0
- package/dist/wizard/lib/revenue-types.d.ts +5 -0
- package/dist/wizard/lib/revenue-types.js +1 -0
- package/dist/wizard/lib/route-optimizer.d.ts +28 -0
- package/dist/wizard/lib/route-optimizer.js +93 -0
- package/dist/wizard/lib/s3-deploy.d.ts +19 -0
- package/dist/wizard/lib/s3-deploy.js +156 -0
- package/dist/wizard/lib/safety-tiers.d.ts +76 -0
- package/dist/wizard/lib/safety-tiers.js +134 -0
- package/dist/wizard/lib/sentry-generator.d.ts +15 -0
- package/dist/wizard/lib/sentry-generator.js +116 -0
- package/dist/wizard/lib/server-config.d.ts +13 -0
- package/dist/wizard/lib/server-config.js +23 -0
- package/dist/wizard/lib/service-install.d.ts +18 -0
- package/dist/wizard/lib/service-install.js +182 -0
- package/dist/wizard/lib/site-scanner.d.ts +80 -0
- package/dist/wizard/lib/site-scanner.js +262 -0
- package/dist/wizard/lib/ssh-deploy.d.ts +25 -0
- package/dist/wizard/lib/ssh-deploy.js +225 -0
- package/dist/wizard/lib/templates.d.ts +24 -0
- package/dist/wizard/lib/templates.js +219 -0
- package/dist/wizard/lib/totp.d.ts +35 -0
- package/dist/wizard/lib/totp.js +276 -0
- package/dist/wizard/lib/tower-auth.d.ts +43 -0
- package/dist/wizard/lib/tower-auth.js +352 -0
- package/dist/wizard/lib/tower-rate-limit.d.ts +14 -0
- package/dist/wizard/lib/tower-rate-limit.js +61 -0
- package/dist/wizard/lib/tower-session.d.ts +28 -0
- package/dist/wizard/lib/tower-session.js +119 -0
- package/dist/wizard/lib/treasury-backup.d.ts +23 -0
- package/dist/wizard/lib/treasury-backup.js +126 -0
- package/dist/wizard/lib/treasury-heartbeat.d.ts +82 -0
- package/dist/wizard/lib/treasury-heartbeat.js +1104 -0
- package/dist/wizard/lib/updater.d.ts +29 -0
- package/dist/wizard/lib/updater.js +190 -0
- package/dist/wizard/lib/user-manager.d.ts +39 -0
- package/dist/wizard/lib/user-manager.js +182 -0
- package/dist/wizard/lib/vault.d.ts +26 -0
- package/dist/wizard/lib/vault.js +161 -0
- package/dist/wizard/router.d.ts +5 -0
- package/dist/wizard/router.js +15 -0
- package/dist/wizard/server.d.ts +18 -0
- package/dist/wizard/server.js +436 -0
- package/package.json +59 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project templates — curated starters with pre-filled PRD frontmatter,
|
|
3
|
+
* recommended integrations, and seed configuration.
|
|
4
|
+
*
|
|
5
|
+
* Usage: `npx voidforge init --template saas`
|
|
6
|
+
* Or selected in Gandalf wizard Step 4 (PRD tab: "Start from a template")
|
|
7
|
+
*/
|
|
8
|
+
export const TEMPLATES = [
|
|
9
|
+
{
|
|
10
|
+
id: 'saas',
|
|
11
|
+
name: 'SaaS Application',
|
|
12
|
+
description: 'Multi-tenant SaaS with auth, billing, teams, and admin dashboard. Next.js + Postgres + Stripe.',
|
|
13
|
+
frontmatter: {
|
|
14
|
+
type: 'full-stack',
|
|
15
|
+
framework: 'next.js',
|
|
16
|
+
database: 'postgres',
|
|
17
|
+
cache: 'redis',
|
|
18
|
+
styling: 'tailwind',
|
|
19
|
+
auth: 'yes',
|
|
20
|
+
payments: 'stripe',
|
|
21
|
+
workers: 'yes',
|
|
22
|
+
admin: 'yes',
|
|
23
|
+
marketing: 'yes',
|
|
24
|
+
email: 'resend',
|
|
25
|
+
deploy: 'vps',
|
|
26
|
+
},
|
|
27
|
+
suggestedIntegrations: ['Stripe', 'Resend', 'S3'],
|
|
28
|
+
prdSections: `## 1. Product Vision
|
|
29
|
+
|
|
30
|
+
**Name:** [PROJECT_NAME]
|
|
31
|
+
**One-liner:** [Describe your SaaS in one sentence]
|
|
32
|
+
**Who it's for:** [Target audience]
|
|
33
|
+
|
|
34
|
+
## 2. System Architecture
|
|
35
|
+
|
|
36
|
+
Multi-tenant SaaS with workspace isolation. Each tenant has their own data, billing, and team management.
|
|
37
|
+
|
|
38
|
+
## 3. Tech Stack
|
|
39
|
+
|
|
40
|
+
Next.js 14 (App Router), PostgreSQL, Redis, Tailwind + shadcn/ui, Prisma ORM, BullMQ workers.
|
|
41
|
+
|
|
42
|
+
## 4. Core Features
|
|
43
|
+
|
|
44
|
+
### 4.1 Authentication & Teams
|
|
45
|
+
- Email + password signup/login (or OAuth: Google, GitHub)
|
|
46
|
+
- Workspace creation on signup
|
|
47
|
+
- Team invites with role-based access (owner, admin, member)
|
|
48
|
+
- Session management with iron-session
|
|
49
|
+
|
|
50
|
+
### 4.2 [Your Core Feature]
|
|
51
|
+
[Describe the primary value proposition — the thing users pay for]
|
|
52
|
+
|
|
53
|
+
### 4.3 Billing
|
|
54
|
+
- Stripe Checkout for subscription creation
|
|
55
|
+
- Customer portal for plan management
|
|
56
|
+
- Webhook handling for subscription lifecycle (created, updated, cancelled, payment failed)
|
|
57
|
+
- Free trial: 14 days, no credit card required
|
|
58
|
+
- Plans: Free, Pro ($X/mo), Team ($X/mo)
|
|
59
|
+
|
|
60
|
+
### 4.4 Admin Dashboard
|
|
61
|
+
- User management (view, deactivate, change plan)
|
|
62
|
+
- Metrics: MRR, active subscriptions, churn rate
|
|
63
|
+
- Audit log of admin actions
|
|
64
|
+
|
|
65
|
+
## 5. Authentication & Accounts
|
|
66
|
+
[Detail auth flows, session management, OAuth providers]
|
|
67
|
+
|
|
68
|
+
## 6. Database Schema
|
|
69
|
+
[Prisma schema with User, Workspace, WorkspaceMember, Subscription tables]
|
|
70
|
+
|
|
71
|
+
## 7. API Design
|
|
72
|
+
[List all API routes with auth requirements]
|
|
73
|
+
|
|
74
|
+
## 15. Deployment
|
|
75
|
+
VPS with PostgreSQL, Redis, Caddy. PM2 cluster mode.`,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'api',
|
|
79
|
+
name: 'REST API',
|
|
80
|
+
description: 'Production API with auth, rate limiting, and documentation. Express + Postgres.',
|
|
81
|
+
frontmatter: {
|
|
82
|
+
type: 'api-only',
|
|
83
|
+
framework: 'express',
|
|
84
|
+
database: 'postgres',
|
|
85
|
+
cache: 'redis',
|
|
86
|
+
styling: 'none',
|
|
87
|
+
auth: 'yes',
|
|
88
|
+
payments: 'none',
|
|
89
|
+
workers: 'no',
|
|
90
|
+
admin: 'no',
|
|
91
|
+
marketing: 'no',
|
|
92
|
+
email: 'none',
|
|
93
|
+
deploy: 'vps',
|
|
94
|
+
},
|
|
95
|
+
suggestedIntegrations: [],
|
|
96
|
+
prdSections: `## 1. Product Vision
|
|
97
|
+
|
|
98
|
+
**Name:** [PROJECT_NAME]
|
|
99
|
+
**One-liner:** [What does this API do?]
|
|
100
|
+
**Who it's for:** [Frontend apps, mobile apps, third-party integrations]
|
|
101
|
+
|
|
102
|
+
## 3. Tech Stack
|
|
103
|
+
|
|
104
|
+
Express + TypeScript, PostgreSQL, Redis (caching + rate limiting), Prisma ORM.
|
|
105
|
+
|
|
106
|
+
## 4. Core Features
|
|
107
|
+
|
|
108
|
+
### 4.1 [Primary Resource]
|
|
109
|
+
[CRUD operations for the main entity]
|
|
110
|
+
|
|
111
|
+
### 4.2 Authentication
|
|
112
|
+
- API key auth for server-to-server
|
|
113
|
+
- JWT for user-facing clients
|
|
114
|
+
- Rate limiting per key/user
|
|
115
|
+
|
|
116
|
+
## 7. API Design
|
|
117
|
+
[List all endpoints with methods, auth, input/output schemas]
|
|
118
|
+
|
|
119
|
+
## 15. Deployment
|
|
120
|
+
VPS or Docker. Caddy reverse proxy. PM2 process management.`,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'marketing',
|
|
124
|
+
name: 'Marketing Site',
|
|
125
|
+
description: 'Fast, SEO-optimized marketing site with CMS-ready content. Next.js + Tailwind.',
|
|
126
|
+
frontmatter: {
|
|
127
|
+
type: 'static-site',
|
|
128
|
+
framework: 'next.js',
|
|
129
|
+
database: 'none',
|
|
130
|
+
cache: 'none',
|
|
131
|
+
styling: 'tailwind',
|
|
132
|
+
auth: 'no',
|
|
133
|
+
payments: 'none',
|
|
134
|
+
workers: 'no',
|
|
135
|
+
admin: 'no',
|
|
136
|
+
marketing: 'yes',
|
|
137
|
+
email: 'none',
|
|
138
|
+
deploy: 'vercel',
|
|
139
|
+
},
|
|
140
|
+
suggestedIntegrations: [],
|
|
141
|
+
prdSections: `## 1. Product Vision
|
|
142
|
+
|
|
143
|
+
**Name:** [PROJECT_NAME]
|
|
144
|
+
**One-liner:** [What does this site promote?]
|
|
145
|
+
|
|
146
|
+
## 4. Core Features
|
|
147
|
+
|
|
148
|
+
### Pages
|
|
149
|
+
- Homepage (hero, features, testimonials, CTA)
|
|
150
|
+
- Features / Product page
|
|
151
|
+
- Pricing page (if applicable)
|
|
152
|
+
- About page
|
|
153
|
+
- Blog (optional — MDX or CMS)
|
|
154
|
+
- Legal (privacy, terms)
|
|
155
|
+
|
|
156
|
+
### SEO
|
|
157
|
+
- Meta tags, Open Graph, JSON-LD
|
|
158
|
+
- Sitemap, robots.txt
|
|
159
|
+
- Performance: Lighthouse > 95
|
|
160
|
+
|
|
161
|
+
## 14. Brand Voice
|
|
162
|
+
[Tone, microcopy guidelines, visual style]
|
|
163
|
+
|
|
164
|
+
## 15. Deployment
|
|
165
|
+
Vercel (automatic from GitHub push).`,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: 'admin',
|
|
169
|
+
name: 'Admin Dashboard',
|
|
170
|
+
description: 'Internal tool with data tables, charts, and CRUD. Next.js + Postgres + shadcn/ui.',
|
|
171
|
+
frontmatter: {
|
|
172
|
+
type: 'full-stack',
|
|
173
|
+
framework: 'next.js',
|
|
174
|
+
database: 'postgres',
|
|
175
|
+
cache: 'none',
|
|
176
|
+
styling: 'tailwind',
|
|
177
|
+
auth: 'yes',
|
|
178
|
+
payments: 'none',
|
|
179
|
+
workers: 'no',
|
|
180
|
+
admin: 'yes',
|
|
181
|
+
marketing: 'no',
|
|
182
|
+
email: 'none',
|
|
183
|
+
deploy: 'docker',
|
|
184
|
+
},
|
|
185
|
+
suggestedIntegrations: [],
|
|
186
|
+
prdSections: `## 1. Product Vision
|
|
187
|
+
|
|
188
|
+
**Name:** [PROJECT_NAME]
|
|
189
|
+
**One-liner:** Internal admin dashboard for [what data/operations]
|
|
190
|
+
**Who it's for:** Internal team (not public-facing)
|
|
191
|
+
|
|
192
|
+
## 4. Core Features
|
|
193
|
+
|
|
194
|
+
### 4.1 Authentication
|
|
195
|
+
- Email + password login (internal users only)
|
|
196
|
+
- Role-based access: admin, viewer
|
|
197
|
+
|
|
198
|
+
### 4.2 Data Management
|
|
199
|
+
[List the entities this dashboard manages — users, orders, content, etc.]
|
|
200
|
+
|
|
201
|
+
### 4.3 Analytics
|
|
202
|
+
- Overview dashboard with key metrics
|
|
203
|
+
- Charts: line (trends), bar (comparisons), stat cards
|
|
204
|
+
|
|
205
|
+
## 6. Database Schema
|
|
206
|
+
[Prisma schema for the data this dashboard manages]
|
|
207
|
+
|
|
208
|
+
## 15. Deployment
|
|
209
|
+
Docker (internal network). Or VPS with Caddy + IP allowlist.`,
|
|
210
|
+
},
|
|
211
|
+
];
|
|
212
|
+
/** Get a template by ID. Returns null if not found. */
|
|
213
|
+
export function getTemplate(id) {
|
|
214
|
+
return TEMPLATES.find((t) => t.id === id) ?? null;
|
|
215
|
+
}
|
|
216
|
+
/** List all available template IDs with descriptions. */
|
|
217
|
+
export function listTemplates() {
|
|
218
|
+
return TEMPLATES.map((t) => ({ id: t.id, name: t.name, description: t.description }));
|
|
219
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TOTP 2FA for financial operations.
|
|
3
|
+
*
|
|
4
|
+
* - Secret stored in system keychain (macOS Keychain / Linux Secret Service) per ADR-4
|
|
5
|
+
* - Fallback: separate encrypted file (totp.enc) with different password from vault
|
|
6
|
+
* - TOTP verification valid for 5 minutes, per-operation
|
|
7
|
+
* - Stored in process memory only (never on disk)
|
|
8
|
+
* - Replay protection: reject reuse of the same code within 30-second window
|
|
9
|
+
*
|
|
10
|
+
* PRD Reference: §9.11 (TOTP setup), ADR-4 (§9.16), §9.18 (session management)
|
|
11
|
+
*
|
|
12
|
+
* Zero dependencies — uses Node.js built-in crypto for HMAC-SHA1 (RFC 6238).
|
|
13
|
+
*/
|
|
14
|
+
/** Generate a new TOTP secret (160 bits per RFC 4226) */
|
|
15
|
+
export declare function generateSecret(): Buffer;
|
|
16
|
+
/** Encode secret as base32 for authenticator apps */
|
|
17
|
+
export declare function encodeBase32(buffer: Buffer): string;
|
|
18
|
+
/** Generate the otpauth:// URI for QR code / manual entry */
|
|
19
|
+
export declare function generateOtpauthUri(secret: Buffer, issuer?: string, account?: string): string;
|
|
20
|
+
/** Set up TOTP — generates secret, stores in keychain, returns URI for QR display */
|
|
21
|
+
export declare function totpSetup(fallbackPassword?: string): Promise<{
|
|
22
|
+
uri: string;
|
|
23
|
+
secret: string;
|
|
24
|
+
stored: 'keychain' | 'file';
|
|
25
|
+
}>;
|
|
26
|
+
/** Verify a TOTP code. Returns true if valid, false if invalid or replay. */
|
|
27
|
+
export declare function totpVerify(code: string, fallbackPassword?: string): Promise<boolean>;
|
|
28
|
+
/** Check if a TOTP session is still valid (5 min TTL, 2 min idle) */
|
|
29
|
+
export declare function totpSessionValid(): boolean;
|
|
30
|
+
/** Invalidate the TOTP session */
|
|
31
|
+
export declare function totpSessionInvalidate(): void;
|
|
32
|
+
/** Check if TOTP is configured (keychain or file) */
|
|
33
|
+
export declare function totpIsConfigured(fallbackPassword?: string): Promise<boolean>;
|
|
34
|
+
/** Remove TOTP configuration */
|
|
35
|
+
export declare function totpRemove(): Promise<void>;
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TOTP 2FA for financial operations.
|
|
3
|
+
*
|
|
4
|
+
* - Secret stored in system keychain (macOS Keychain / Linux Secret Service) per ADR-4
|
|
5
|
+
* - Fallback: separate encrypted file (totp.enc) with different password from vault
|
|
6
|
+
* - TOTP verification valid for 5 minutes, per-operation
|
|
7
|
+
* - Stored in process memory only (never on disk)
|
|
8
|
+
* - Replay protection: reject reuse of the same code within 30-second window
|
|
9
|
+
*
|
|
10
|
+
* PRD Reference: §9.11 (TOTP setup), ADR-4 (§9.16), §9.18 (session management)
|
|
11
|
+
*
|
|
12
|
+
* Zero dependencies — uses Node.js built-in crypto for HMAC-SHA1 (RFC 6238).
|
|
13
|
+
*/
|
|
14
|
+
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
15
|
+
import { readFile, open, rename, mkdir } from 'node:fs/promises';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { homedir, platform } from 'node:os';
|
|
19
|
+
import { execSync } from 'node:child_process';
|
|
20
|
+
const TREASURY_DIR = join(homedir(), '.voidforge', 'treasury');
|
|
21
|
+
const TOTP_FALLBACK_PATH = join(TREASURY_DIR, 'totp.enc');
|
|
22
|
+
const KEYCHAIN_SERVICE = 'com.voidforge.totp';
|
|
23
|
+
const KEYCHAIN_ACCOUNT = 'totp-secret';
|
|
24
|
+
// TOTP parameters (RFC 6238)
|
|
25
|
+
const TOTP_PERIOD = 30; // seconds
|
|
26
|
+
const TOTP_DIGITS = 6;
|
|
27
|
+
const TOTP_ALGORITHM = 'sha1'; // per RFC 6238
|
|
28
|
+
// Session management (§9.18)
|
|
29
|
+
const TOTP_SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
30
|
+
const TOTP_IDLE_TTL_MS = 2 * 60 * 1000; // 2 minutes idle → invalidate
|
|
31
|
+
const TOTP_WINDOW = 1; // accept ±1 time step (30s tolerance)
|
|
32
|
+
let session = null;
|
|
33
|
+
// ── TOTP Generation (RFC 6238) ────────────────────────
|
|
34
|
+
function generateTotpCode(secret, timeStep) {
|
|
35
|
+
const timeBuffer = Buffer.alloc(8);
|
|
36
|
+
timeBuffer.writeBigInt64BE(BigInt(timeStep));
|
|
37
|
+
const hmac = createHmac(TOTP_ALGORITHM, secret);
|
|
38
|
+
hmac.update(timeBuffer);
|
|
39
|
+
const hash = hmac.digest();
|
|
40
|
+
// Dynamic truncation (RFC 4226 §5.4)
|
|
41
|
+
const offset = hash[hash.length - 1] & 0x0f;
|
|
42
|
+
const binary = ((hash[offset] & 0x7f) << 24) |
|
|
43
|
+
((hash[offset + 1] & 0xff) << 16) |
|
|
44
|
+
((hash[offset + 2] & 0xff) << 8) |
|
|
45
|
+
(hash[offset + 3] & 0xff);
|
|
46
|
+
const otp = binary % Math.pow(10, TOTP_DIGITS);
|
|
47
|
+
return otp.toString().padStart(TOTP_DIGITS, '0');
|
|
48
|
+
}
|
|
49
|
+
function getCurrentStep() {
|
|
50
|
+
return Math.floor(Date.now() / 1000 / TOTP_PERIOD);
|
|
51
|
+
}
|
|
52
|
+
// ── Secret Management ─────────────────────────────────
|
|
53
|
+
/** Generate a new TOTP secret (160 bits per RFC 4226) */
|
|
54
|
+
export function generateSecret() {
|
|
55
|
+
return randomBytes(20); // 160 bits
|
|
56
|
+
}
|
|
57
|
+
/** Encode secret as base32 for authenticator apps */
|
|
58
|
+
export function encodeBase32(buffer) {
|
|
59
|
+
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
60
|
+
let bits = '';
|
|
61
|
+
for (const byte of buffer) {
|
|
62
|
+
bits += byte.toString(2).padStart(8, '0');
|
|
63
|
+
}
|
|
64
|
+
let result = '';
|
|
65
|
+
for (let i = 0; i < bits.length; i += 5) {
|
|
66
|
+
const chunk = bits.substring(i, i + 5).padEnd(5, '0');
|
|
67
|
+
result += alphabet[parseInt(chunk, 2)];
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
/** Generate the otpauth:// URI for QR code / manual entry */
|
|
72
|
+
export function generateOtpauthUri(secret, issuer = 'VoidForge', account = 'treasury') {
|
|
73
|
+
const b32 = encodeBase32(secret);
|
|
74
|
+
return `otpauth://totp/${encodeURIComponent(issuer)}:${encodeURIComponent(account)}?secret=${b32}&issuer=${encodeURIComponent(issuer)}&algorithm=SHA1&digits=${TOTP_DIGITS}&period=${TOTP_PERIOD}`;
|
|
75
|
+
}
|
|
76
|
+
// ── Keychain Storage (ADR-4) ──────────────────────────
|
|
77
|
+
/** Store TOTP secret in system keychain (macOS) */
|
|
78
|
+
async function storeInKeychain(secret) {
|
|
79
|
+
if (platform() !== 'darwin')
|
|
80
|
+
return false;
|
|
81
|
+
try {
|
|
82
|
+
// Delete existing entry if present
|
|
83
|
+
try {
|
|
84
|
+
execSync(`security delete-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" 2>/dev/null`);
|
|
85
|
+
}
|
|
86
|
+
catch { /* not found — fine */ }
|
|
87
|
+
const hex = secret.toString('hex');
|
|
88
|
+
execSync(`security add-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" -w "${hex}" -T ""`);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Read TOTP secret from system keychain (macOS) */
|
|
96
|
+
async function readFromKeychain() {
|
|
97
|
+
if (platform() !== 'darwin')
|
|
98
|
+
return null;
|
|
99
|
+
try {
|
|
100
|
+
const hex = execSync(`security find-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" -w 2>/dev/null`, { encoding: 'utf-8' }).trim();
|
|
101
|
+
return Buffer.from(hex, 'hex');
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Delete TOTP secret from system keychain */
|
|
108
|
+
async function deleteFromKeychain() {
|
|
109
|
+
if (platform() !== 'darwin')
|
|
110
|
+
return;
|
|
111
|
+
try {
|
|
112
|
+
execSync(`security delete-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" 2>/dev/null`);
|
|
113
|
+
}
|
|
114
|
+
catch { /* not found — fine */ }
|
|
115
|
+
}
|
|
116
|
+
// ── Fallback: Encrypted File ──────────────────────────
|
|
117
|
+
// Used when system keychain is unavailable (Linux without Secret Service, etc.)
|
|
118
|
+
// Encrypted with a DIFFERENT password from the financial vault (§9.11)
|
|
119
|
+
async function storeInFile(secret, totpPassword) {
|
|
120
|
+
// Re-use the financial vault's encrypt pattern but with a separate password
|
|
121
|
+
const { createCipheriv, scrypt: scryptCb } = await import('node:crypto');
|
|
122
|
+
const salt = randomBytes(32);
|
|
123
|
+
const iv = randomBytes(16);
|
|
124
|
+
const key = await new Promise((resolve, reject) => {
|
|
125
|
+
scryptCb(totpPassword.slice(0, 256), salt, 32, { N: 131072, r: 8, p: 1 }, (err, k) => {
|
|
126
|
+
if (err)
|
|
127
|
+
reject(err);
|
|
128
|
+
else
|
|
129
|
+
resolve(k);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
133
|
+
const encrypted = Buffer.concat([cipher.update(secret), cipher.final()]);
|
|
134
|
+
const tag = cipher.getAuthTag();
|
|
135
|
+
await mkdir(TREASURY_DIR, { recursive: true });
|
|
136
|
+
const tmpPath = TOTP_FALLBACK_PATH + '.tmp.' + process.pid;
|
|
137
|
+
const fh = await open(tmpPath, 'w', 0o600);
|
|
138
|
+
try {
|
|
139
|
+
await fh.writeFile(Buffer.concat([salt, iv, tag, encrypted]));
|
|
140
|
+
await fh.sync();
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
await fh.close();
|
|
144
|
+
}
|
|
145
|
+
await rename(tmpPath, TOTP_FALLBACK_PATH);
|
|
146
|
+
}
|
|
147
|
+
async function readFromFile(totpPassword) {
|
|
148
|
+
if (!existsSync(TOTP_FALLBACK_PATH))
|
|
149
|
+
return null;
|
|
150
|
+
try {
|
|
151
|
+
const raw = await readFile(TOTP_FALLBACK_PATH);
|
|
152
|
+
const salt = raw.subarray(0, 32);
|
|
153
|
+
const iv = raw.subarray(32, 48);
|
|
154
|
+
const tag = raw.subarray(48, 64);
|
|
155
|
+
const ciphertext = raw.subarray(64);
|
|
156
|
+
const { createDecipheriv, scrypt: scryptCb } = await import('node:crypto');
|
|
157
|
+
const key = await new Promise((resolve, reject) => {
|
|
158
|
+
scryptCb(totpPassword.slice(0, 256), salt, 32, { N: 131072, r: 8, p: 1 }, (err, k) => {
|
|
159
|
+
if (err)
|
|
160
|
+
reject(err);
|
|
161
|
+
else
|
|
162
|
+
resolve(k);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
const decipher = createDecipheriv('aes-256-gcm', key, iv);
|
|
166
|
+
decipher.setAuthTag(tag);
|
|
167
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// ── Public API ────────────────────────────────────────
|
|
174
|
+
/** Set up TOTP — generates secret, stores in keychain, returns URI for QR display */
|
|
175
|
+
export async function totpSetup(fallbackPassword) {
|
|
176
|
+
const secret = generateSecret();
|
|
177
|
+
const uri = generateOtpauthUri(secret);
|
|
178
|
+
const b32 = encodeBase32(secret);
|
|
179
|
+
// Try keychain first (ADR-4)
|
|
180
|
+
const keychainOk = await storeInKeychain(secret);
|
|
181
|
+
if (keychainOk) {
|
|
182
|
+
return { uri, secret: b32, stored: 'keychain' };
|
|
183
|
+
}
|
|
184
|
+
// Fallback to encrypted file
|
|
185
|
+
if (!fallbackPassword) {
|
|
186
|
+
throw new Error('System keychain unavailable. Provide a TOTP encryption password (must differ from vault password).');
|
|
187
|
+
}
|
|
188
|
+
await storeInFile(secret, fallbackPassword);
|
|
189
|
+
return { uri, secret: b32, stored: 'file' };
|
|
190
|
+
}
|
|
191
|
+
/** Verify a TOTP code. Returns true if valid, false if invalid or replay. */
|
|
192
|
+
export async function totpVerify(code, fallbackPassword) {
|
|
193
|
+
// Read secret from keychain or file
|
|
194
|
+
let secret = await readFromKeychain();
|
|
195
|
+
if (!secret && fallbackPassword) {
|
|
196
|
+
secret = await readFromFile(fallbackPassword);
|
|
197
|
+
}
|
|
198
|
+
if (!secret) {
|
|
199
|
+
throw new Error('TOTP not configured. Run /cultivation install or voidforge treasury --setup-2fa.');
|
|
200
|
+
}
|
|
201
|
+
const currentStep = getCurrentStep();
|
|
202
|
+
// Check current step ± window
|
|
203
|
+
for (let offset = -TOTP_WINDOW; offset <= TOTP_WINDOW; offset++) {
|
|
204
|
+
const step = currentStep + offset;
|
|
205
|
+
const expected = generateTotpCode(secret, step);
|
|
206
|
+
// SEC-003: Use constant-time comparison for TOTP codes
|
|
207
|
+
const codeMatch = code.length === expected.length &&
|
|
208
|
+
timingSafeEqual(Buffer.from(code), Buffer.from(expected));
|
|
209
|
+
if (codeMatch) {
|
|
210
|
+
// VG-003: Replay protection — reject reuse of ANY code within the window period
|
|
211
|
+
const codeKey = code + ':' + step;
|
|
212
|
+
if (session && session.usedCodes.has(codeKey)) {
|
|
213
|
+
return false; // Replay detected
|
|
214
|
+
}
|
|
215
|
+
// Set or update session, tracking all used codes
|
|
216
|
+
if (!session) {
|
|
217
|
+
session = { verifiedAt: Date.now(), lastUsedAt: Date.now(), usedCodes: new Set() };
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
session.lastUsedAt = Date.now();
|
|
221
|
+
}
|
|
222
|
+
session.usedCodes.add(codeKey);
|
|
223
|
+
// Prune codes older than 3 TOTP periods (90 seconds)
|
|
224
|
+
// LOKI-005: If clock jumped (step difference > 10), clear all used codes to prevent lockout
|
|
225
|
+
const toDelete = [];
|
|
226
|
+
for (const key of session.usedCodes) {
|
|
227
|
+
const keyStep = parseInt(key.split(':')[1]);
|
|
228
|
+
const drift = currentStep - keyStep;
|
|
229
|
+
if (drift > 3 || drift < -3)
|
|
230
|
+
toDelete.push(key);
|
|
231
|
+
}
|
|
232
|
+
for (const key of toDelete)
|
|
233
|
+
session.usedCodes.delete(key);
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
/** Check if a TOTP session is still valid (5 min TTL, 2 min idle) */
|
|
240
|
+
export function totpSessionValid() {
|
|
241
|
+
if (!session)
|
|
242
|
+
return false;
|
|
243
|
+
const now = Date.now();
|
|
244
|
+
if (now - session.verifiedAt > TOTP_SESSION_TTL_MS) {
|
|
245
|
+
session = null;
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
if (now - session.lastUsedAt > TOTP_IDLE_TTL_MS) {
|
|
249
|
+
session = null;
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
session.lastUsedAt = now; // Touch
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
/** Invalidate the TOTP session */
|
|
256
|
+
export function totpSessionInvalidate() {
|
|
257
|
+
session = null;
|
|
258
|
+
}
|
|
259
|
+
/** Check if TOTP is configured (keychain or file) */
|
|
260
|
+
export async function totpIsConfigured(fallbackPassword) {
|
|
261
|
+
const secret = await readFromKeychain();
|
|
262
|
+
if (secret)
|
|
263
|
+
return true;
|
|
264
|
+
if (fallbackPassword) {
|
|
265
|
+
const fileSecret = await readFromFile(fallbackPassword);
|
|
266
|
+
if (fileSecret)
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
return existsSync(TOTP_FALLBACK_PATH);
|
|
270
|
+
}
|
|
271
|
+
/** Remove TOTP configuration */
|
|
272
|
+
export async function totpRemove() {
|
|
273
|
+
await deleteFromKeychain();
|
|
274
|
+
// Don't delete the file — user may want to keep the backup
|
|
275
|
+
totpSessionInvalidate();
|
|
276
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tower Auth — Authentication engine for remote mode.
|
|
3
|
+
*
|
|
4
|
+
* 5-layer security: this module handles Layer 2 (Authentication).
|
|
5
|
+
* Two-password architecture: login password ≠ vault password.
|
|
6
|
+
*
|
|
7
|
+
* TOTP: RFC 6238, 30-second rotation, replay protection.
|
|
8
|
+
* ARCH-R2-003: Split into tower-auth + tower-session + tower-rate-limit.
|
|
9
|
+
*/
|
|
10
|
+
export { type UserRole, type SessionInfo, createSession, validateSession, logout, invalidateUserSessions, updateSessionRole, cleanupExpiredSessions, getSessionCookieName, parseSessionCookie, buildSessionCookie, clearSessionCookie, isAuthExempt, } from './tower-session.js';
|
|
11
|
+
export { checkRateLimit, recordFailure, clearFailures, cleanupStaleEntries, } from './tower-rate-limit.js';
|
|
12
|
+
import type { UserRole } from './tower-session.js';
|
|
13
|
+
export declare function setRemoteMode(enabled: boolean): void;
|
|
14
|
+
export declare function isRemoteMode(): boolean;
|
|
15
|
+
export declare function setLanMode(enabled: boolean): void;
|
|
16
|
+
export declare function isLanMode(): boolean;
|
|
17
|
+
/** Get client IP — delegates to rate-limit module but passes remoteMode state. */
|
|
18
|
+
export declare function getClientIp(req: {
|
|
19
|
+
headers: Record<string, string | string[] | undefined>;
|
|
20
|
+
socket: {
|
|
21
|
+
remoteAddress?: string;
|
|
22
|
+
};
|
|
23
|
+
}): string;
|
|
24
|
+
export declare function isValidUsername(username: string): boolean;
|
|
25
|
+
export declare function hasUsers(): Promise<boolean>;
|
|
26
|
+
export declare function createUser(username: string, password: string, role?: UserRole): Promise<{
|
|
27
|
+
totpSecret: string;
|
|
28
|
+
totpUri: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function removeUser(targetUsername: string): Promise<void>;
|
|
31
|
+
export declare function updateUserRole(targetUsername: string, newRole: UserRole): Promise<void>;
|
|
32
|
+
export declare function listUsers(): Promise<Array<{
|
|
33
|
+
username: string;
|
|
34
|
+
role: UserRole;
|
|
35
|
+
createdAt: string;
|
|
36
|
+
}>>;
|
|
37
|
+
export declare function getUserRole(username: string): Promise<UserRole | null>;
|
|
38
|
+
export declare function login(username: string, password: string, totpCode: string, ip: string): Promise<{
|
|
39
|
+
token: string;
|
|
40
|
+
} | {
|
|
41
|
+
error: string;
|
|
42
|
+
retryAfterMs?: number;
|
|
43
|
+
}>;
|