A Firefox Manifest V3 extension for Pi-hole v6 integration. Monitor DNS blocking statistics, control blocking status, and manage domains directly from your browser.
- Real-time Statistics - View blocked queries, block rate, and active clients
- Blocking Control - Toggle DNS blocking with optional timer (30s to indefinite)
- Multi-Instance Support - Manage multiple Pi-hole servers from a single extension
- Domain Tracking - See all domains loaded by each tab, categorized as first-party or third-party
- Quick Actions - Add domains to allowlist/denylist with one click
- Query Log - Browse recent DNS queries with blocked/allowed filtering
- 2FA Support - Full TOTP authentication support for secured Pi-hole instances
| Settings | Domain Sidebar |
|---|---|
![]() |
![]() |
- Firefox 142 or later
- Pi-hole v6 with the new REST API
Before installing, ensure you have:
- Node.js 20.x or later (LTS recommended)
- Bun 1.x or later
Verify your installation:
node --version # Should output v20.x.x or higher
bun --version # Should output 1.x.x or higherInstall directly from the official Firefox Add-ons store:
-
Clone the repository
git clone https://github.com/linx-systems/pi-sentinel cd pi-sentinel # Optional: Go to release version ( the version soon to be uploaded ) git checkout release
-
Install dependencies
npm install # or bun install -
Build the extension
npm run build # or bun run build -
Load in Firefox
- Open Firefox and navigate to
about:debugging - Click "This Firefox" in the sidebar
- Click "Load Temporary Add-on..."
- Select the
dist/firefox-mv3/manifest.jsonfile
- Open Firefox and navigate to
# Install dependencies
bun install
# Development mode with hot reload
bun run devThen:
- Open Firefox and navigate to
about:debugging - Click "This Firefox" in the sidebar
- Click "Load Temporary Add-on..."
- Select the
dist/firefox-mv3/manifest.jsonfile
To package the extension for Firefox:
bun run packageThe unsigned .xpi file will be created in the web-ext-artifacts/ directory.
- Go to
about:debugging#/runtime/this-firefox - Find PiSentinel and click "Inspect"
- This opens DevTools for the background script where you can:
- View console logs
- Set breakpoints
- Inspect network requests to Pi-hole API
- Right-click inside the popup/sidebar/options page
- Select "Inspect" to open DevTools for that specific UI
The extension uses console.log/warn/error for logging. In development mode, useful logs include:
- API calls: Check the Network tab in background script DevTools
- State changes: Add
console.logstatements inbackground/state/ - Message passing: Log in
entrypoints/background.tsmessage handlers
To add temporary debug logging:
// In any source file
console.log("[PiSentinel]", "Debug message", { data });| Command | Description |
|---|---|
bun run dev |
Development mode with hot reload |
bun run build |
Production build to dist/firefox-mv3/ |
bun run lint |
Run ESLint on TypeScript files |
bun run lint:fix |
ESLint with auto-fix |
bun run format |
Prettier formatting |
bun run test |
Run unit tests (Vitest) |
bun run test:watch |
Unit tests in watch mode |
bun run test:coverage |
Unit tests with coverage |
bun run test:e2e |
E2E tests (Playwright) |
bun run package |
Build and create unsigned .xpi for distribution |
bun run sign |
Build and sign extension with Mozilla (requires AMO credentials) |
bun run sign:channel |
Build and sign as unlisted (for self-distribution) |
To distribute your extension outside of development, you'll need to sign it with Mozilla:
-
Get API credentials from Mozilla Add-ons Developer Hub
- Sign in to your Mozilla account
- Navigate to API Key Management
- Generate new credentials (API Key + Secret)
-
Configure environment variables
# Copy the example file cp .env.example .env # Edit .env and add your credentials AMO_API_KEY=your_api_key_here AMO_API_SECRET=your_api_secret_here
-
Sign the extension
# For public distribution (listed on AMO) bun run sign # For self-distribution (unlisted) bun run sign:channel
The signed .xpi file will be created in the web-ext-artifacts/ directory.
For testing without signing:
- Firefox Developer/Nightly Edition: Load temporary add-on via
about:debugging - Firefox Release: Must disable signature verification in
about:config(setxpinstall.signatures.requiredtofalse)
/
├── background/ # Background modules
│ ├── api/ # Pi-hole v6 REST client
│ ├── crypto/ # PBKDF2 + AES-256-GCM encryption
│ ├── services/ # Badge, notifications, domain tracker
│ └── state/ # Central state store
├── components/ # Shared UI components
├── entrypoints/ # WXT entry points
│ ├── background.ts # Background script
│ ├── popup/ # Popup UI (Preact)
│ ├── sidebar/ # Sidebar UI (Preact)
│ └── options/ # Options page (Preact)
├── public/ # Static assets (icons)
├── tests/ # Unit + E2E tests
└── utils/ # Shared utilities
- TypeScript - Type-safe JavaScript with strict mode
- Preact - Lightweight React alternative (~3KB gzipped)
- WXT + Vite - Modern web extension toolkit with hot reload
- webextension-polyfill - Cross-browser WebExtensions API compatibility
- Vitest - Unit testing framework
- Playwright - E2E testing framework
Run the test suite:
# Unit tests
bun run test
# Unit tests in watch mode
bun run test:watch
# Unit tests with coverage
bun run test:coverage
# E2E tests
bun run test:e2e- Click the PiSentinel icon in your toolbar
- If not configured, click "Configure Pi-hole"
- Enter your Pi-hole server URL (e.g.,
http://pi.holeorhttp://192.168.1.100) - Enter your Pi-hole web interface password
- Click "Test Connection" to verify, then "Save & Connect"
- If 2FA is enabled, enter your TOTP code when prompted
Click the toolbar icon to view:
- Connection status
- Total queries and blocked count
- Block rate percentage
- Active clients
- Toggle blocking on/off with optional timer
Open the sidebar (View → Sidebar → PiSentinel Domains) to see:
- Domains tab: All domains loaded by the current page
- First-party domains (green)
- Third-party domains (orange)
- Quick actions to allow/block each domain
- Query Log tab: Recent DNS queries with filtering
The toolbar badge shows:
- Number: Blocked query count
- Green background: Blocking active
- Red background: Blocking disabled
- Gray background: Not connected
- Credentials are encrypted using PBKDF2 (100,000 iterations) + AES-256-GCM
- Session tokens stored in
browser.storage.session(cleared on browser close) - All API calls routed through background script (CORS bypass)
- No credentials or tokens exposed to content scripts
| Endpoint | Purpose |
|---|---|
POST /api/auth |
Authenticate and get session |
DELETE /api/auth |
Logout |
GET /api/stats/summary |
Fetch statistics |
GET/POST /api/dns/blocking |
Check/toggle blocking |
GET /api/queries |
Query log |
POST /api/domains/allow/exact |
Add to allowlist |
POST /api/domains/deny/exact |
Add to denylist |
GET /api/search/{domain} |
Search domain status |
- Verify Pi-hole URL is correct (no
/adminsuffix needed) - Ensure Pi-hole v6 is running
- Check if Pi-hole is accessible from your browser
- The extension automatically refreshes sessions every 4 minutes
- If issues persist, check Pi-hole's session timeout settings
- Ensure
bun run devis running and shows successful rebuilds - Click "Reload" in
about:debuggingafter each change - For popup changes, close and reopen the popup
- Background script logs: Inspect via
about:debugging - Popup/sidebar logs: Right-click → Inspect within the UI
- Recent macOS versions may require granting Firefox "Local Network" permission in System Preferences → Privacy & Security
Contributions are welcome! Here's how to get started:
- Fork the repository and clone your fork
- Create a feature branch:
git checkout -b feature/your-feature-name - Make your changes following the existing code style
- Run linting:
bun run lintand fix any issues - Test manually in Firefox using the development workflow above
- Commit your changes with a descriptive message
- Push to your fork and open a Pull Request
- Use TypeScript strict mode
- Follow existing patterns in the codebase
- Keep components small and focused
- Use meaningful variable and function names
See LICENSE for details.

