npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@neabyte/express-shield

v1.0.1

Published

Express Middleware With Rate-Limit And Security Headers

Readme

🛡️ @neabyte/express-shield

release npm version CI coverage

Lightweight Express middleware for rate limiting, unique client fingerprinting, Cloudflare-aware IP trust, and essential security headers 🛡️
Now with auto-updated Cloudflare IP lists, hot-reload without restart, and zero dependency design for production-grade security and flexibility.


✨ Features

  • 🔁 Auto-updated Cloudflare IPs: Automatically keeps the IP whitelist in sync with Cloudflare’s official ranges (IPv4/IPv6) and hot-reloads without restart.
  • 🚦 Rate Limiting: Configurable time window and maximum requests per IP address (with Cloudflare trusted IP logic).
  • 🔒 Fingerprinting: Generates a unique, consistent client fingerprint for better request tracking.
  • 🛡️ Security Headers: Automatically applies crucial HTTP security headers (X-Content-Type-Options, Strict-Transport-Security, X-Frame-Options, Referrer-Policy, and more).
  • 🎨 Custom Error Responses: Override default 429 (Too Many Requests) handler with custom logic/format.
  • 📦 Modular Design: Redis is optional; rate limiting is skipped if no Redis is supplied.
  • ⚙️ TypeScript Support: Built-in .d.ts types, fully typed exports.
  • 🔄 Zero External Dependency: No deps except Express and (optionally) ioredis for rate-limit.

🚀 Installation

npm install @neabyte/express-shield

Requires Node.js >=18.20.8

  • After install, Cloudflare IPs are fetched to data/ folder.
  • To update manually: node ./script/update-cloudflare-ip.js

🛠️ Quick Start

With Redis (Enables Rate Limiting)

const express = require('express')
const Redis = require('ioredis')
const { createExpressShield } = require('@neabyte/express-shield')

const app = express()
const redisClient = new Redis()

app.use(
  createExpressShield(
    redisClient,
    {
      app,
      windowSec: 60,
      maxRequests: 10,
      showHeader: true,
      showLog: false,
      applySecurity: true,
      customErrorResponse: (req, res, ttl) => {
        res.status(429).json({
          error: 'Too many requests',
          ip: req.fingerprint.ip,
          retryAfterSec: ttl
        })
      }
    }
  )
)

app.get('/', (req, res) => {
  res.send('Hello, world! 🎉 This route is protected with rate limiting and security headers.')
})

app.listen(3000, () => console.log('Server running on port 3000 🚀'))

Without Redis (Skips Rate Limiting)

const express = require('express')
const { createExpressShield } = require('@neabyte/express-shield')

const app = express()

app.use(
  createExpressShield(
    null,
    {
      app,
      applySecurity: true
    }
  )
)

app.get('/', (req, res) => {
  res.send('Hello, world! 🎉 This route is protected with security headers.')
})

app.listen(3000, () => console.log('Server running on port 3000 🚀'))

⚡ Cloudflare IP Support

  • The IP whitelist used for trusting cf-connecting-ip is auto-updated using Cloudflare’s published range.

  • After install, files data/cloudflare_ipv4.json and data/cloudflare_ipv6.json are created/updated.

  • IPs are hot-reloaded at runtime (no restart needed).

  • To force reload in app code:

    const { reloadCloudflareIpList } = require('@neabyte/express-shield')
    reloadCloudflareIpList()

🧩 Parameters & Defaults

| Parameter | Type | Default | Description | | ----------------------------- | --------- | -------------------- | -------------------------------------------------------------- | | redisClient | object? | null | Optional ioredis instance. If falsy, disables rate limiting. | | options.app | Express | null | Express app instance for header patching. | | options.windowSec | number | 60 | Duration of the rate limit window (seconds). | | options.maxRequests | number | 10 | Max allowed requests per IP within the window. | | options.showHeader | boolean | true | Show X-Fingerprint-Id header. | | options.showLog | boolean | false | Enable debug console logging. | | options.applySecurity | boolean | true | Apply HTTP security headers. | | options.customErrorResponse | function | default 429 JSON | Custom 429 handler. (req, res, ttl) => void | | options.whitelist | string[] | [] | Skip rate-limit for these IPs. | | options.ipResolver | function | getClientIpAddress | Custom IP resolver (rarely needed). |


📖 API Reference

  • createExpressShield(redisClient, options)
    Creates the Express middleware. Handles security headers, fingerprinting, rate limit (if Redis provided).

  • getClientIpAddress(req)
    Returns the trusted client IP. Automatically checks cf-connecting-ip if request comes from Cloudflare IP range.

  • generateFingerprintHash(req)
    Returns a SHA256 hash of client IP + headers (used for fingerprinting).

  • reloadCloudflareIpList()
    Forces reload of Cloudflare IPv4 + IPv6 lists from data/ folder. Useful for manual reload or custom schedulers.

  • watchCloudflareIpList()
    Starts file watcher. Automatically reloads Cloudflare IPs when data/cloudflare_ipv4.json or data/cloudflare_ipv6.json change.

  • CLOUDFLARE_IPV4 / CLOUDFLARE_IPV6
    Exposes current trusted Cloudflare IP lists (arrays of CIDR).

  • checkIpInCidrList(ip, cidrList)
    Utility to check if an IP (IPv4/IPv6) is within any CIDR in the list.

  • checkIpv4InCidr(ip, cidr) / checkIpv6InCidr(ip, cidr)
    Low-level CIDR match utilities for IPv4 / IPv6.

  • convertIpv4ToNumber(ip) / convertIpv6ToBigint(ip)
    Internal helpers to convert IP addresses for CIDR math (exposed for testability).

Note: All utility functions are exposed primarily for testing and advanced use cases.
Typical users only need createExpressShield and optionally reloadCloudflareIpList.


✅ Running Tests Locally

npm install
npm test

❤️ Contributing

  1. Fork the repo 🔱
  2. Create your feature branch (git checkout -b feature/your-feature-name)
  3. Commit your changes (git commit -am 'Add some your-feature-name')
  4. Push to the branch (git push origin feature/your-feature-name)
  5. Open a Pull Request 📬

📬 Questions / Support

For questions, issues or feature requests, please open an issue or start a discussion.


🗒️ Changelog

See CHANGELOG.md for all updates.


📜 License

MIT License © 2025 NeaByteLab