npm package: @iron-stack/security
Description: Server-side security middleware for Fastify and Socket.IO -- rate limiting, CORS, security headers, input sanitization, and WebSocket protection.
Latest version: 1.0.0

# @iron-stack/security

Server-side security middleware for Fastify and Socket.IO -- rate limiting, CORS, security headers, input sanitization, and WebSocket protection.

## Installation

```bash
npm install @iron-stack/security
```

## Quick Start

```ts
import {
  registerSecurityHeaders,
  registerCors,
  registerRateLimit,
  createAuthRateLimit,
  createSocketRateLimit,
  sanitizeUserInput,
} from '@iron-stack/security';

// Security headers (helmet-like)
registerSecurityHeaders(fastify);

// CORS
registerCors(fastify, {
  origins: ['https://app.yourdomain.com'],
  credentials: true,
});

// Global rate limiting
registerRateLimit(fastify, { max: 100, windowMs: 60_000 });

// Stricter rate limiting for auth endpoints
createAuthRateLimit(fastify, { maxAttempts: 5 });

// Socket.IO rate limiting
io.use(createSocketRateLimit({ maxEvents: 30, windowMs: 10_000 }));

// Sanitize user input
const clean = sanitizeUserInput('<script>alert("xss")</script> Hello world');
// => "Hello world"
```

## API Reference

### Rate Limiting

| Export | Description |
|---|---|
| `registerRateLimit(fastify, config?)` | In-memory rate limiter for Fastify. Sets `X-RateLimit-*` response headers |
| `createAuthRateLimit(fastify, options?)` | Stricter rate limiter for auth route prefixes |
| `RateLimitConfig` | Configuration interface for `registerRateLimit` |

### Security Headers

| Export | Description |
|---|---|
| `registerSecurityHeaders(fastify, config?)` | Adds security headers to all responses (CSP, HSTS, X-Frame-Options, etc.) |
| `SecurityHeadersConfig` | Configuration interface for header customization |

### CORS

| Export | Description |
|---|---|
| `registerCors(fastify, config)` | Registers strict CORS with preflight handling |
| `CorsConfig` | Configuration interface for CORS |

### Input Sanitization

| Export | Description |
|---|---|
| `sanitizeUserInput(input)` | Strips HTML tags, normalizes whitespace, and trims |
| `stripHtml(input)` | Removes all HTML tags from a string |
| `escapeHtml(input)` | Escapes `&`, `<`, `>`, `"`, `'` for safe HTML rendering |
| `normalizeString(input)` | Trims and collapses whitespace |
| `isSafeUrl(url)` | Returns `true` if URL uses `http:` or `https:` protocol |

### Socket.IO Security

| Export | Description |
|---|---|
| `createSocketRateLimit(config?)` | Socket.IO middleware that rate-limits events per connection |
| `validatePayloadSize(data, maxBytes?)` | Returns `true` if serialized payload is within size limit |
| `SocketRateLimitConfig` | Configuration for socket rate limiting |
| `SocketPayloadConfig` | Configuration for payload size validation |

## Configuration

### `RateLimitConfig`

| Option | Type | Default | Description |
|---|---|---|---|
| `max` | `number` | `100` | Max requests per window |
| `windowMs` | `number` | `60000` | Window size in milliseconds |
| `keyExtractor` | `(req) => string` | IP address | Determines rate limit grouping |
| `skipPaths` | `string[]` | `[]` | URL prefixes to exclude from limiting |
| `message` | `string` | `"Too many requests..."` | Error message on limit exceeded |

### `SecurityHeadersConfig`

| Option | Type | Default | Description |
|---|---|---|---|
| `contentSecurityPolicy` | `string \| false` | `"default-src 'self'"` | CSP header value |
| `frameOptions` | `"DENY" \| "SAMEORIGIN" \| false` | `"DENY"` | X-Frame-Options |
| `hstsMaxAge` | `number \| false` | `31536000` | HSTS max-age in seconds (1 year) |
| `noSniff` | `boolean` | `true` | X-Content-Type-Options: nosniff |
| `xssProtection` | `string \| false` | `"0"` | X-XSS-Protection (CSP preferred) |
| `referrerPolicy` | `string \| false` | `"strict-origin-when-cross-origin"` | Referrer-Policy |
| `permissionsPolicy` | `string \| false` | `"camera=(), microphone=(), geolocation=()"` | Permissions-Policy |

### `CorsConfig`

| Option | Type | Default | Description |
|---|---|---|---|
| `origins` | `string[] \| "*"` | **required** | Allowed origins (use `"*"` only in dev) |
| `methods` | `string[]` | `["GET","POST","PUT","DELETE","OPTIONS"]` | Allowed HTTP methods |
| `allowedHeaders` | `string[]` | `["Content-Type","Authorization","trpc-accept","x-trpc-source"]` | Allowed request headers |
| `credentials` | `boolean` | `true` | Allow credentials |
| `maxAge` | `number` | `86400` | Preflight cache duration in seconds |

### `SocketRateLimitConfig`

| Option | Type | Default | Description |
|---|---|---|---|
| `maxEvents` | `number` | `50` | Max events per window per socket |
| `windowMs` | `number` | `10000` | Window size in milliseconds |
| `events` | `string[]` | all events | Specific events to rate limit |

## License

MIT