Skip to content

About

A lightweight Chrome extension + Flask backend that blocks distracting websites using a Bloom Filter for O(k) domain lookups. Built as a DSA course project.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

💻😣 Digital Detox Filter — Bloom Filter Focus Mode 🫷🛑

A lightweight website blocker that enforces "focus mode" in the browser, using a Bloom Filter for O(k) domain membership checks instead of a linear list lookup.

This was built as a practical implementation of Bloom filters for a Data Structures & Algorithms course. A companion project applying the same data structure to a different problem — network-level packet filtering for a game server — is linked at the bottom of this README.


🤔 How It Works

A naive blocker checks every visited domain against a blocklist stored as an array or hash set. As the list grows, so does lookup cost (or memory). This project swaps that lookup for a Bloom filter: a probabilistic set membership structure that answers "definitely not blocked" or "probably blocked" in constant time, using a fraction of the memory a full domain set would need — at the cost of a small, tunable false-positive rate.

Because a browser extension's service worker can't reliably read local files or run native C extensions (like the mmh3 hashing library), the system is split across two cooperating processes:

┌─────────────────────────────┐         ┌──────────────────────────────┐
│   BROWSER                    │         │   LOCAL MACHINE               │
│                               │         │                                │
│   background.js               │         │   server.py                   │
│   • Chrome extension           │         │   • Flask backend              │
│     (Manifest V3)              │  HTTP   │   • Owns the "real" Bloom     │
│   • Watches navigation via     │◄──────►│     filter (bloom.py)          │
│     webNavigation API          │ request │   • Loads blocklist from       │
│   • Queries the local server   │         │     blocked_urls.txt           │
│   • Injects blocking overlay   │         │   • Answers /check/<url>       │
└─────────────────────────────┘         └──────────────────────────────┘
              │                                          ▲
              └──────────── GET /check/<hostname> ───────┘

The two processes don't share memory — the extension calls the server over localhost for every navigation, and the server is the single source of truth for what's blocked.


📂 Files

File Runs On Role
bloom.py Local machine (Python) Core Bloom filter ADT (create_bloom_filter, add_item, check_item) plus a standalone test harness
server.py Local machine (Python/Flask) Initializes the Bloom filter on startup and exposes it over HTTP via /check/<url>, with CORS enabled for the extension
background.js Browser (Chrome extension) Service worker that hooks navigation, queries the local server, and injects the blocking overlay
manifest.json Browser (Chrome extension) Manifest V3 config declaring permissions (webNavigation, scripting) and registering the service worker
blocked_urls.txt Shared file The blocklist — read by server.py on startup to build the Bloom filter

👨‍👩‍👧‍👦 Prerequisites

  • Python 3.8+ and pip
  • Google Chrome (or any Chromium-based browser supporting Manifest V3)

🔢 Step-by-Step Setup

1. Install backend dependencies

pip install flask flask-cors mmh3 bitarray

2. Configure the blocklist

Edit blocked_urls.txt — one domain per line, no http://, no www.:

facebook.com
instagram.com
tiktok.com

If this file doesn't exist yet, server.py will create it automatically with a default sample list on first run.

3. Start the backend

python server.py

You should see:

=== Initializing Python Backend ===
[*] Blocklist loaded from blocked_urls.txt
 * Running on http://127.0.0.1:5000

Leave this running — the extension needs it active on localhost:5000 to check URLs.

Want to see the Bloom filter tested standalone (without the server or extension)? Run:

python bloom.py

This runs a small built-in test suite that checks sample IPs and URLs against two independent filters.

4. Load the Chrome extension

  1. Open Chrome and go to chrome://extensions.
  2. Enable Developer mode (toggle in the top-right corner).
  3. Click Load unpacked.
  4. Select this repository's folder (the one containing manifest.json).
  5. "Digital Detox Blocker" should now appear in your extensions list and be active.

🧪 Interactive Testing

With the backend running and the extension loaded:

  1. Navigate to a site not in the blocklist (e.g. wikipedia.org) — it should load normally.
  2. Navigate to a site that is in the blocklist (e.g. instagram.com) — a full-screen "Get Back To Work" overlay should appear, hiding the page.
  3. Click the Redirect to Canvas button on the overlay to confirm the redirect works.
  4. Add a new domain to blocked_urls.txt, restart server.py, and confirm it's now blocked too.
  5. Watch the terminal running server.py — every check logs a line like [SERVER] Checked instagram.com - Blocked: True, useful for confirming requests are actually reaching the backend.

🧹 Cleanup

To stop enforcing focus mode:

  1. Stop the server.py process (Ctrl+C). With the server down, the extension fails open — sites load normally rather than being blocked.
  2. Optionally, disable or remove the extension from chrome://extensions.

📓 Design Notes & Limitations

  • Two independent Bloom filter implementations. bloom.py (Python, using mmh3) is the source of truth, queried through the Flask server. background.js also contains a JavaScript reimplementation (using a custom hash function in place of mmh3, since native C extensions aren't available in a browser service worker) — but it's currently initialized without being used for the actual blocking decision, since the real check happens via the server. This is a candidate for cleanup in a future iteration.
  • No deletions. Bloom filters don't natively support removing an item without a more complex structure (e.g. a counting Bloom filter), so removing a domain currently requires editing blocked_urls.txt and restarting the server to rebuild the filter.
  • False positives are possible, false negatives are not. With fp_rate=0.05, a small percentage of legitimate domains could — in rare cases — be mistakenly flagged, but a domain that's actually in the blocklist will never slip through.
  • Server dependency. The extension's blocking decision depends entirely on the local Flask server running — if it's stopped, the extension fails open rather than blocking.
  • Hostname-level only. The filter currently blocks by hostname, not by full path or subdomain-specific rules.

🖇️ Companion Project

This is one of two Bloom filter implementations built for the same DSA coursework. The second project, Network Security Filter, applies the same underlying data structure to network-level packet filtering — intercepting inbound traffic on a game server VM using iptables + NetfilterQueue and checking source IPs against a Bloom filter to allow or drop connections:

🔗 Network Security Filter


🤝 Team

Name Contribution
Abbas Dar Worked on the Network Security Filter including the VM setup
Muhammad Saad Masood Worked on the Digital Detox including the custom browser extension setup
Syed Aayan Rizvi Coordinated with both the teammates and worked on documentations and presentations

About

A lightweight Chrome extension + Flask backend that blocks distracting websites using a Bloom Filter for O(k) domain lookups. Built as a DSA course project.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages