Files
internet-id/.env.example
Copilot 14014cb784 Production hardening: Remove deprecations, optimize chain queries, enforce explicit configuration (#134)
* Initial plan

* Fix onLimitReached deprecation in rate-limit middleware

- Replace deprecated onLimitReached callback with inline logging in handler
- Update tests to verify logging happens in the rate limit handler
- Remove onLimitReached from exports as it's no longer a separate function

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Fix fromBlock: 0 in event queries for better performance

- Replace fromBlock: 0 with smart default (last 1M blocks)
- Add REGISTRY_START_BLOCK env var for configurable starting block
- Update make-proof.ts, verification-jobs.routes.ts, and verification-queue.service.ts
- Document new env variable in .env.example

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Remove hardcoded testnet RPC fallback for production safety

- Replace testnet fallbacks with proper error handling when RPC_URL is not configured
- Update registry.service.ts, blockchain.service.ts to throw errors if RPC_URL missing
- Update CLI scripts (verify.ts, register.ts, make-proof.ts) to fail fast without RPC_URL
- Update API routes to return 503 error when RPC_URL is not configured
- Update .env.example to emphasize RPC_URL is required

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Add documentation for dual Prisma generators and pin Redis version

- Add comprehensive comments in schema.prisma explaining dual generator setup
- Document why both generators are needed (API vs Next.js web app)
- Pin Redis version to 7.2-alpine in all docker-compose files for reproducibility
- Update docker-compose.yml, docker-compose.production.yml, and docker-compose.staging.yml

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Address code review feedback - add validation for REGISTRY_START_BLOCK

- Add proper validation for parseInt to handle NaN cases
- Ensure REGISTRY_START_BLOCK is validated before use
- Add comment explaining intentional empty catch block
- Prevents invalid block numbers from breaking event queries

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Refactor block range validation into shared utility function

- Create block-range.util.ts with getStartBlock helper
- Extract duplicated validation logic from make-proof.ts, verification-jobs.routes.ts, and verification-queue.service.ts
- Improves code maintainability and ensures consistent validation
- Add comprehensive JSDoc documentation

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Add comprehensive test coverage for block-range utility

- Create test/utils/block-range.util.test.ts following existing test patterns
- Test valid REGISTRY_START_BLOCK values (positive, zero, large numbers)
- Test invalid inputs (NaN, negative, empty string, whitespace)
- Test default fallback behavior (current block - 1M)
- Test edge cases (low block numbers, decimals, provider errors)
- 15 test cases covering all code paths and validation logic

Co-authored-by: PatrickFanella <61631520+PatrickFanella@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>
Co-authored-by: PatrickFanella <61631520+PatrickFanella@users.noreply.github.com>
2026-02-16 19:25:50 -06:00

407 lines
14 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# Internet-ID API Server & Scripts Environment Configuration
# =============================================================================
# Copy this file to .env and fill in your values
# DO NOT commit .env to git (it's in .gitignore)
#
# For web app configuration, see web/.env.example
# See docs/CONTRIBUTOR_ONBOARDING.md for detailed setup instructions
# =============================================================================
# -----------------------------------------------------------------------------
# Blockchain Configuration (REQUIRED)
# -----------------------------------------------------------------------------
# Private key of the deployer/creator account (without 0x prefix or with it)
# REQUIRED for deploying contracts and registering content
# SECURITY: Never commit this value! Keep it secret!
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
PRIVATE_KEY=
# Default RPC URL for blockchain interactions
# REQUIRED: This must be configured for the API server to function
# For production, use a reliable RPC provider (Infura, Alchemy, QuickNode, etc.)
# For development/testing, use a testnet (Base Sepolia recommended)
# See Multi-Chain section below for other networks
RPC_URL=https://sepolia.base.org
# -----------------------------------------------------------------------------
# Multi-Chain RPC Configuration (Optional - defaults provided in config/chains.ts)
# -----------------------------------------------------------------------------
# Ethereum networks
# ETHEREUM_RPC_URL=https://eth.llamarpc.com
# SEPOLIA_RPC_URL=https://ethereum-sepolia-rpc.publicnode.com
# Polygon networks
# POLYGON_RPC_URL=https://polygon-rpc.com
# POLYGON_AMOY_RPC_URL=https://rpc-amoy.polygon.technology
# Base networks (Coinbase L2)
# BASE_RPC_URL=https://mainnet.base.org
# BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
# Arbitrum networks
# ARBITRUM_RPC_URL=https://arb1.arbitrum.io/rpc
# ARBITRUM_SEPOLIA_RPC_URL=https://sepolia-rollup.arbitrum.io/rpc
# Optimism networks
# OPTIMISM_RPC_URL=https://mainnet.optimism.io
# OPTIMISM_SEPOLIA_RPC_URL=https://sepolia.optimism.io
# -----------------------------------------------------------------------------
# SSL/TLS Configuration (Production)
# -----------------------------------------------------------------------------
# Domain name for SSL certificates
DOMAIN=example.com
# Email for Let's Encrypt notifications and alerts
SSL_EMAIL=admin@example.com
SSL_ALERT_EMAIL=ops@example.com
# Certificate monitoring thresholds (days before expiration)
CERT_WARNING_DAYS=14
CERT_CRITICAL_DAYS=7
# Use Let's Encrypt staging environment for testing (0=production, 1=staging)
CERTBOT_STAGING=0
# Application environment
NODE_ENV=production
# -----------------------------------------------------------------------------
# Logging & Observability Configuration
# -----------------------------------------------------------------------------
# Log level (trace, debug, info, warn, error, fatal)
# Default: info
LOG_LEVEL=info
# Log destination configuration for external services
# Uncomment and configure for production deployments
# Logtail (BetterStack) Configuration
# LOGTAIL_SOURCE_TOKEN=your_logtail_source_token
# Datadog Configuration
# DATADOG_API_KEY=your_datadog_api_key
# DATADOG_APP_KEY=your_datadog_app_key
# DATADOG_SITE=datadoghq.com # or datadoghq.eu for EU region
# ELK Stack / Elasticsearch Configuration
# ELASTICSEARCH_URL=https://your-elasticsearch-host:9200
# ELASTICSEARCH_USERNAME=your_username
# ELASTICSEARCH_PASSWORD=your_password
# ELASTICSEARCH_INDEX=internet-id-logs
# -----------------------------------------------------------------------------
# Error Tracking Configuration (Sentry)
# -----------------------------------------------------------------------------
# Sentry DSN for error tracking
# Get this from your Sentry project settings
# Leave empty to disable error tracking
# SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id
# Sentry environment (defaults to NODE_ENV)
# SENTRY_ENVIRONMENT=production
# Sentry release version (for tracking deployments)
# SENTRY_RELEASE=1.0.0
# Performance monitoring sample rate (0.0 to 1.0)
# 1.0 = 100% of transactions, 0.1 = 10% of transactions
# SENTRY_TRACES_SAMPLE_RATE=0.1
# Profiling sample rate (0.0 to 1.0)
# SENTRY_PROFILES_SAMPLE_RATE=0.1
# -----------------------------------------------------------------------------
# IPFS Configuration (REQUIRED - choose one provider)
# -----------------------------------------------------------------------------
# IPFS is used for decentralized storage of content files and manifests
# The uploader automatically falls back between providers on failures
# REQUIRED: Configure at least one provider below
# IPFS provider options (choose one or configure multiple for fallback):
# 1) Infura IPFS
# Create IPFS project, then set:
IPFS_API_URL=https://ipfs.infura.io:5001
# IPFS_PROJECT_ID=your_project_id
# IPFS_PROJECT_SECRET=your_project_secret
# 2) Web3.Storage
# Create an API token at https://web3.storage
# The uploader will use this if set.
# WEB3_STORAGE_TOKEN=your_web3_storage_token
# 3) Pinata (JWT)
# Create a JWT at https://pinata.cloud
# The uploader will use this if set and WEB3_STORAGE_TOKEN is not set.
PINATA_JWT=
#API Key:
#API Secret:
#JWT:
# Optional: Force a specific IPFS provider for uploads
# Allowed values: web3storage | pinata | infura | local
# If not set, the uploader will auto-fallback: Web3.Storage -> Pinata -> Infura (-> Local if configured)
IPFS_PROVIDER=pinata
# Local node override (optional)
LOCAL_RPC_URL=http://127.0.0.1:8545
# Local IPFS node (optional)
# To use a local Kubo node without credentials, run IPFS locally and set:
# IPFS_PROVIDER=local
# IPFS_API_URL=http://127.0.0.1:5001
# -----------------------------------------------------------------------------
# Smart Contract Event Query Configuration (Optional)
# -----------------------------------------------------------------------------
# Starting block number for querying ContentRegistered events
# This avoids scanning the entire blockchain history when searching for registration transactions
# Set this to the block number when the registry contract was deployed
# If not set, defaults to scanning the last 1,000,000 blocks
# Example for Base Sepolia: 14000000 (approximate deployment block)
# REGISTRY_START_BLOCK=14000000
# -----------------------------------------------------------------------------
# API Configuration
# -----------------------------------------------------------------------------
# API key for protected endpoints (optional but recommended)
# If set, the following endpoints require x-api-key header:
# - POST /api/upload (file upload to IPFS)
# - POST /api/manifest (manifest generation)
# - POST /api/register (on-chain registration)
# - POST /api/bind (platform binding)
# Generate with: openssl rand -hex 32
# Leave empty to disable API key protection (not recommended for production)
API_KEY=supersecret
# Rate Limiting (optional)
# Redis URL for distributed rate limiting (if not set, uses in-memory store)
REDIS_URL=redis://localhost:6379
# Optional: API key that exempts from rate limiting (for internal services)
# RATE_LIMIT_EXEMPT_API_KEY=internal_service_key
# -----------------------------------------------------------------------------
# Caching Configuration (optional)
# -----------------------------------------------------------------------------
# Redis is used for both rate limiting and caching
# If REDIS_URL is set, the API will use Redis for:
# 1. Distributed rate limiting across multiple instances
# 2. Caching frequently accessed data (content metadata, manifests, bindings)
#
# Cache TTLs (configured in code):
# - Content metadata: 10 minutes
# - Manifest data: 15 minutes
# - Platform bindings: 3 minutes
# - Verification status: 5 minutes
# - IPFS gateway URLs: 30 minutes
#
# Redis configuration (automatically set by cache service):
# - Eviction policy: allkeys-lru (evicts least recently used keys)
# - Max memory: 256MB (configurable in cache.service.ts)
#
# To disable caching, simply don't set REDIS_URL (API will use database fallback)
# -----------------------------------------------------------------------------
# Database Configuration (REQUIRED)
# -----------------------------------------------------------------------------
# Database connection URL for Prisma ORM
# The web app shares the same database, so web/.env.local must have the same value
# REQUIRED: Choose one option below
# Option 1: SQLite (Recommended for development)
# Easiest setup, no separate database server needed
# Creates dev.db file in the root directory
DATABASE_URL="file:./dev.db"
# Option 2: PostgreSQL (Recommended for production)
# Better performance and features for production deployments
# Start with: docker compose up -d
# Uncomment the lines below and comment out the SQLite option above
# POSTGRES_USER=internetid
# POSTGRES_PASSWORD=internetid
# POSTGRES_DB=internetid
# DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?schema=public"
# -----------------------------------------------------------------------------
# Database Seed Data (Development Only)
# -----------------------------------------------------------------------------
# The seed script populates the database with test data for local development:
# - 5 test creator accounts
# - 5 sample content entries (video, image, audio, document)
# - 10 platform bindings (YouTube, TikTok, GitHub, Instagram, Discord, LinkedIn)
# - 3 verification records
#
# Usage:
# npm run db:seed - Populate test data
# npm run db:reset - Clear database and reseed
#
# ⚠️ NEVER use seed data in production! All test accounts use publicly known keys.
# See prisma/SEED_DATA.md for detailed documentation.
# -----------------------------------------------------------------------------
# Authentication (Auth.js / NextAuth recommended)
# -----------------------------------------------------------------------------
# Base app URL (used for callback URLs)
APP_BASE_URL=http://localhost:3000
# NextAuth core
# If using NextAuth/Auth.js, set these:
NEXTAUTH_URL=${APP_BASE_URL}
NEXTAUTH_SECRET=supersupersecret
# Optional: Cookie/session hints if your auth needs them
SESSION_SECRET=change_me
COOKIE_NAME=internet-id.session
COOKIE_SECURE=false
# Generic OIDC (works with any standards-compliant provider)
# OIDC_ISSUER=https://your-issuer.example.com
# OIDC_CLIENT_ID=your_oidc_client_id
# OIDC_CLIENT_SECRET=your_oidc_client_secret
# OIDC_REDIRECT_URI=${APP_BASE_URL}/api/auth/callback/oidc
# OIDC_SCOPES="openid profile email"
# Optional overrides if discovery isnt available:
# OIDC_AUTHORIZATION_URL=
# OIDC_TOKEN_URL=
# OIDC_USERINFO_URL=
# OIDC_END_SESSION_URL=
# Provider-specific examples (Auth.js/NextAuth)
# Callback for all providers will be: ${APP_BASE_URL}/api/auth/callback/<provider>
# GitHub
# GITHUB_ID=your_github_client_id
# GITHUB_SECRET=your_github_client_secret
# Google
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Auth0 (as an OIDC provider)
# AUTH0_ISSUER=https://your-tenant.us.auth0.com
# AUTH0_CLIENT_ID=your_auth0_client_id
# AUTH0_CLIENT_SECRET=your_auth0_client_secret
# Discord
# DISCORD_CLIENT_ID=your_discord_client_id
# DISCORD_CLIENT_SECRET=your_discord_client_secret
# Twitter (X) - OAuth2
TWITTER_CLIENT_ID=
TWITTER_CLIENT_SECRET=
# Apple
# APPLE_ID=your_service_id
# APPLE_TEAM_ID=your_team_id
# APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
# APPLE_KEY_ID=your_key_id
# LinkedIn
# LINKEDIN_CLIENT_ID=your_linkedin_client_id
# LINKEDIN_CLIENT_SECRET=your_linkedin_client_secret
# Slack
# SLACK_CLIENT_ID=your_slack_client_id
# SLACK_CLIENT_SECRET=your_slack_client_secret
# Microsoft (Azure AD)
# AZURE_AD_CLIENT_ID=your_azure_client_id
# AZURE_AD_CLIENT_SECRET=your_azure_client_secret
# AZURE_AD_TENANT_ID=common
# Reddit
# REDDIT_CLIENT_ID=your_reddit_client_id
# REDDIT_CLIENT_SECRET=your_reddit_client_secret
# Coinbase
# COINBASE_CLIENT_ID=your_coinbase_client_id
# COINBASE_CLIENT_SECRET=your_coinbase_client_secret
# TikTok
TIKTOK_CLIENT_ID=
TIKTOK_CLIENT_SECRET=
# Optional: CORS
# -----------------------------------------------------------------------------
# Alerting Configuration
# -----------------------------------------------------------------------------
# PagerDuty Integration
# Get these from your PagerDuty account settings
# PAGERDUTY_SERVICE_KEY=your_pagerduty_service_key
# PAGERDUTY_ROUTING_KEY=your_pagerduty_routing_key
# PAGERDUTY_DATABASE_KEY=your_pagerduty_database_key
# PAGERDUTY_DBA_ROUTING_KEY=your_pagerduty_dba_routing_key
# Slack Integration
# Create a webhook at https://api.slack.com/messaging/webhooks
# SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
# SLACK_CRITICAL_CHANNEL=#alerts-critical
# SLACK_WARNINGS_CHANNEL=#alerts-warnings
# Email Alerting
# ALERT_EMAIL=ops@example.com
# INFO_EMAIL=team@example.com
# ALERT_FROM_EMAIL=alerts@internet-id.com
# SMTP Configuration for Email Alerts
# SMTP_HOST=smtp.gmail.com
# SMTP_PORT=587
# SMTP_USERNAME=your_smtp_username
# SMTP_PASSWORD=your_smtp_password
# -----------------------------------------------------------------------------
# Email Notification System (Optional)
# -----------------------------------------------------------------------------
# Email service provider (sendgrid, postmark, ses, smtp)
# If not set, email notifications will be disabled
# EMAIL_PROVIDER=sendgrid
# SendGrid Configuration
# SENDGRID_API_KEY=your_sendgrid_api_key_here
# Postmark Configuration
# POSTMARK_SERVER_TOKEN=your_postmark_server_token_here
# AWS SES Configuration
# AWS_SES_REGION=us-east-1
# AWS_SES_ACCESS_KEY_ID=your_aws_access_key_id
# AWS_SES_SECRET_ACCESS_KEY=your_aws_secret_access_key
# SMTP Configuration (fallback provider)
# SMTP_HOST=smtp.example.com
# SMTP_PORT=587
# SMTP_SECURE=false
# SMTP_USER=your_smtp_username
# SMTP_PASS=your_smtp_password
# Email settings
# EMAIL_FROM=noreply@internet-id.com
# EMAIL_FROM_NAME=Internet ID
# EMAIL_REPLY_TO=support@internet-id.com
# Email notification base URL (for links in emails)
# EMAIL_BASE_URL=https://internet-id.com
# Grafana Configuration
# GRAFANA_ADMIN_USER=admin
# GRAFANA_ADMIN_PASSWORD=changeme
# GRAFANA_ROOT_URL=http://localhost:3000
# GRAFANA_ANONYMOUS_ENABLED=false