Skip to content

Latest commit

 

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Chrome Extensions for Online Gambling Detection

Ekstensi browser Chromium untuk mendeteksi dan menyoroti konten judi online (judol) pada halaman web mana pun. Proyek ini dibuat untuk memenuhi Tugas Besar 3 IF2211 Strategi Algoritma.

Overview

Promosi judi online ("situs judol") sering muncul tersisip di dalam halaman web di Indonesia sebagai teks, gambar banner, atau disisipkan melalui jaringan iklan pihak ketiga. Ekstensi ini memindai setiap halaman yang dimuat browser yang kemudian:

  • Mendeteksi kata kunci dan frasa terkait judi dalam teks yang terlihat,
  • Menyorot kecocokan yang terdeteksi langsung di DOM halaman,
  • Memblur paragraf yang berisi konten yang terdeteksi,
  • Menjalankan OCR (Optical Character Recognition) pada elemen gambar untuk menangkap teks yang tertanam dalam grafik serta menggantinya dengan gambar penutup, dan
  • Melaporkan statistik berupa jumlah kecocokan, frekuensi kata kunci, dan kinerja per algoritma dalam UI pop-up.

Ekstensi ini berjalan sepenuhnya secara lokal di sisi klien.

Build & Development

Untuk membangun dan menjalankan ekstensi secara lokal, pastikan dependensi berikut terinstal:

  • Node.js (v18+)
  • npm (v8+)
  • Browser Chromium (Chrome, Edge, Brave, dll.)
  1. Di root proyek, jalankan perintah berikut:
# Instalasi dependensi
npm install

# Build ketiga bundle secara berurutan
npm run build
  1. Setelah build selesai, buka browser Chromium dan navigasikan ke chrome://extensions/ atau pengaturan ekstensi di browser lainnya.
  2. Pastikan "Developer mode" diaktifkan pada browser.
  3. Klik "Load unpacked" dan pilih folder dist/ yang baru saja dibangun. Ekstensi akan dimuat ke browser dan siap digunakan.

Antarmuka & Fitur Pengguna

Fitur untuk Pengguna

Fitur Deskripsi
Scan Menjalankan pemindaian DOM penuh pada tab aktif saat ini. Tombol menampilkan "Scanning..." dan dinonaktifkan selama pemindaian; direset saat statistik tiba atau saat terjadi error.
Blur Teks Menambahkan filter blur CSS pada container induk dari setiap elemen yang disorot, mengaburkan konten judi sembari tetap memungkinkan halaman dinavigasi.
OCR Gambar Mengaktifkan pemindaian Tesseract.js pada elemen <img> dan gambar CSS background. Gambar judol yang terdeteksi diganti dengan grafik peringatan (judolss.jpeg).
Tooltip Saat hover di atas highlight <mark>, menampilkan: keyword yang terdeteksi, algoritma yang menemukannya, jumlah kemunculan, dan waktu eksekusi (ms).
Pemilihan Algoritma Checkbox untuk masing-masing AC, KMP, BM, Rabin-Karp, dan Weighted-Levenshtein. Perubahan tersimpan lintas sesi browser dan berlaku pada pemindaian berikutnya. RegEx selalu berjalan tanpa kondisi.
Dashboard Statistik Jumlah total kecocokan, keyword unik yang ditemukan, dan elemen DOM yang disorot. Bar chart untuk 10 keyword teratas berdasarkan frekuensi dan distribusi kecocokan per algoritma. Rincian tabular jumlah kecocokan dan total waktu eksekusi per algoritma.
Auto Rescan MutationObserver memantau halaman untuk perubahan DOM (di-debounce 2.000 ms) dan secara otomatis menjalankan ulang deteksi. Berguna untuk single-page application yang memperbarui konten secara dinamis tanpa navigasi penuh.
Scan Timestamp Header popup menampilkan timestamp relatif ("Baru saja dipindai", "5m lalu") yang dihitung dari timestamp pemindaian yang tersimpan.

Desain Arsitektur

Struktur Proyek

.
├── README.md
├── keywords
│   └── keywords.txt
├── package.json
├── package-lock.json
├── public
│   ├── icons
│   └── manifest.json
├── src
│   ├── algorithms
│   │   ├── ahoCorasick.ts
│   │   ├── boyerMoore.ts
│   │   ├── index.ts
│   │   ├── kmp.ts
│   │   ├── rabinKarp.ts
│   │   ├── regexMatcher.ts
│   │   └── weightedLevenshtein.ts
│   ├── content
│   │   ├── blurManager.ts
│   │   ├── contentScript.ts
│   │   ├── domScanner.ts
│   │   ├── highlighter.ts
│   │   ├── imageReplacer.ts
│   │   ├── ocrScanner.ts
│   │   ├── rescanManager.ts
│   │   └── tooltip.ts
│   ├── core
│   │   ├── detectionEngine.ts
│   │   ├── messageBus.ts
│   │   └── storage.ts
│   ├── popup
│   │   ├── chart.ts
│   │   ├── popup.html
│   │   └── popup.ts
│   ├── styles
│   │   ├── content.css
│   │   ├── judolss.jpeg
│   │   └── popup.css
│   ├── types
│   │   ├── detection.ts
│   │   └── stats.ts
│   ├── utils
│   │   ├── keywordLoader.ts
│   │   ├── textNormalizer.ts
│   │   └── timer.ts
│   ├── main.ts
│   └── vite-env.d.ts
├── test
├── tsconfig.json
└── vite.config.ts

Algoritma

1. Knuth-Morris-Pratt (KMP)

File: src/algorithms/kmp.ts

Pencarian string eksak, single-pattern, dengan kompleksitas linear. Menggunakan tabel LPS (Longest Proper Prefix which is also a Suffix) yang telah dihitung sebelumnya untuk menghindari perbandingan karakter yang redundan.

Properti Nilai
Preprocessing $O(m)$ — membangun array LPS untuk pola sepanjang $m$
Pencarian $O(n)$ — memindai teks sepanjang $n$ dengan paling banyak $2n$ perbandingan
Cache _lpsCache: Map<string, number[]> — dibangun sekali saat startup melalui initKMPCache()
Overlap Didukung — saat cocok, kembali ke lps[j-1] alih-alih mereset ke 0

Array LPS lps[i] menyimpan panjang prefix terpanjang dari pattern[0..i] yang sekaligus merupakan suffix. Ketika terjadi mismatch pada posisi j di pattern, pencarian dilanjutkan dari lps[j-1] alih-alih mengulang dari awal, sehingga memberikan jaminan kompleksitas linear.

2. Boyer-Moore (Bad Character Heuristic)

File: src/algorithms/boyerMoore.ts

Pencarian eksak single-pattern yang memindai pattern dari kanan ke kiri dan menggunakan bad character table untuk melompati sebagian besar teks saat terjadi mismatch.

Properti Nilai
Preprocessing $O(m + |\Sigma|)$ — tabel posisi kemunculan terakhir setiap karakter
Pencarian $O(n/m)$ kasus terbaik, $O(nm)$ kasus terburuk
Cache _badCharCache: Map<string, Map<string, number>> — dibangun sekali melalui initBMCache()

Saat terjadi mismatch pada posisi teks s + j, pattern digeser ke kanan sebesar max(1, j - badChar[text[s+j]]). Jika text[s+j] tidak muncul di pattern, pergeseran menjadi j + 1, melewatkan seluruh jendela saat ini.

3. Aho-Corasick

File: src/algorithms/ahoCorasick.ts

Pencarian eksak multi-pattern yang menemukan semua keyword dalam satu pass $O(n)$ dengan membangun deterministic finite automaton dari trie keyword.

Properti Nilai
Preprocessing $O(\sum m_i \cdot |\Sigma|)$ — konstruksi trie + BFS untuk failure/output link
Pencarian $O(n + k)$$n$ = panjang teks, $k$ = total kecocokan
Cache _cachedAutomaton: TrieNode — dibangun sekali melalui initACCache()

Failure link dihitung bottom-up melalui BFS: untuk node u yang dicapai melalui karakter c dari parent p, failure dari u adalah node yang dicapai dengan mengikuti rantai failure p hingga ditemukan node dengan edge c (atau root). Output link mempercepat pengumpulan semua keyword yang cocok pada setiap posisi dengan menghubungkan ke ancestor terdekat yang memiliki output keyword.

Automaton ini menjadi filter utama dalam pipeline deteksi. KMP dan Boyer-Moore kemudian mengonfirmasi ulang hanya subset keyword yang ditemukan automaton, yang jauh lebih kecil dari daftar penuh pada halaman yang khas.

4. Rabin-Karp

File: src/algorithms/rabinKarp.ts

Pencarian eksak multi-pattern menggunakan polynomial rolling hash. Keyword dikelompokkan berdasarkan panjang; untuk setiap kelompok panjang, rolling hash pada jendela teks dipertahankan dan dibandingkan dengan himpunan hash keyword yang telah dihitung sebelumnya.

Properti Nilai
Hash $H = \sum c_i \cdot \text{BASE}^{m-1-i} \bmod \text{MOD}$, BASE = 31, MOD = 10⁹+7
Rolling update $H_{baru} = (H_{lama} - c_0 \cdot h_{pow}) \cdot \text{BASE} + c_{baru}$
Collision Diverifikasi karakter per karakter saat hash cocok
Cache _rkIndex: RKIndex — dibangun sekali melalui initRKCache()

Aritmetika bigint digunakan di seluruh implementasi untuk menghindari overflow diam-diam pada floating-point 64-bit JavaScript untuk nilai hash yang besar.

5. Regex Matcher

File: src/algorithms/regexMatcher.ts

Pola tetap /[a-z]+\d{2,}/g mendeteksi token alias terkait judi yang menyisipkan angka ke dalam nama situs (misalnya, gacor99, maxwin234, slot777). Ini menangkap nama merek yang dibuat secara dinamis yang tidak dapat dienumerasi dalam daftar keyword.

6. Weighted Levenshtein (Fuzzy Match)

File: src/algorithms/weightedLevenshtein.ts

Pencocokan string aproksimasi berbasis sliding window dengan tabel biaya substitusi yang sadar leet-speak.

Properti Nilai
Ukuran window yang dicoba $m-1$, $m$, $m+1$ (di mana $m$ = panjang keyword)
Ambang batas kesamaan 0.75 — cocok dengan $1 - d / \max(m, w) \geq 0.75$
Pasangan biaya rendah o↔0, a↔4, i↔1, e↔3, s↔5 (biaya 0.5 alih-alih 1.0)
Early exit Jika nilai minimum baris dalam tabel DP melebihi maxDist, loop dihentikan lebih awal
Panjang keyword minimum 4 karakter (keyword lebih pendek menghasilkan terlalu banyak false positive)
Batas panjang teks 300 karakter (sliding window DP adalah $O(n \cdot m)$ per posisi window)

Rekurensi DP adalah:

$$ dp[i][j] = \min\begin{cases} dp[i-1][j] + 1 & \text{(hapus)} \\ dp[i][j-1] + 1 & \text{(sisipkan)} \\ dp[i-1][j-1] + \text{cost}(a_i, b_j) & \text{(ganti)} \end{cases} $$

di mana $\text{cost}(a,b) = 0$ jika $a = b$, $0.5$ untuk pasangan leet-speak, dan $1$ untuk kasus lainnya.

Setelah semua window diberi skor, hasil yang tumpang tindih didedup dengan mempertahankan kecocokan dengan kesamaan tertinggi per kelompok yang overlap.

Modul Inti

detectionEngine.ts

Mengorkestrasikan pipeline deteksi lengkap untuk satu text node:

  1. Mengubah teks menjadi lowercase untuk exact matching (KMP, BM, AC, RK menjaga posisi karakter).
  2. Melakukan normalisasi penuh teks (normalizeText) khusus untuk pass Levenshtein.
  3. Menjalankan Aho-Corasick terlebih dahulu; mencatat keyword yang ditemukannya.
  4. Menjalankan KMP dan Boyer-Moore hanya atas subset keyword yang ditemukan AC.
  5. Menjalankan Rabin-Karp atas semua keyword (pendekatan hash independen).
  6. Selalu menjalankan regex matcher.
  7. Menjalankan fuzzy matching terakhir, dibatasi untuk keyword yang belum ditemukan oleh metode eksak dan teks ≤ 300 karakter.

domScanner.ts

Menelusuri DOM dengan document.createTreeWalker(root, NodeFilter.SHOW_TEXT) dan menyaring elemen:

  • Elemen dengan tag yang ada dalam deny-list (script, style, noscript, textarea, input, select, iframe, code, pre, svg, canvas, video, audio, dll.).
  • Elemen yang sudah memiliki class judol-detector-* (mencegah pemindaian markup yang di-inject oleh ekstensi).
  • Elemen tersembunyi, yang dideteksi melalui API native checkVisibility({ checkOpacity: true, checkVisibilityCSS: true }) (Chrome 105+) dengan fallback getComputedStyle rekursif.

highlighter.ts

Mengganti Text node yang cocok dengan DocumentFragment yang terdiri dari:

  • Node Text biasa untuk segmen yang tidak cocok.
  • Elemen <mark class="judol-detector-highlight"> untuk span yang cocok.

Kecocokan yang tumpang tindih dalam text node yang sama digabung menjadi satu <mark> sebelum penggantian DOM. Setiap <mark> menyimpan metadata kaya sebagai atribut data-* (data-keyword, data-algorithm, data-count, data-execution-time-ms, data-matched-text) yang dikonsumsi oleh tooltip.

ocrScanner.ts

Menggunakan Tesseract.js dengan model bahasa ind (Indonesia) dan eng (Inggris). Langkah pemrosesan:

  1. Mengumpulkan elemen <img> yang terlihat dengan dimensi natural ≥ 50 px; dibatasi 15 gambar per pemindaian.
  2. Mengumpulkan elemen dengan background-image CSS; ukuran render minimum 100 px; dibatasi 10 per pemindaian.
  3. Mencoba menggambar canvas secara langsung untuk gambar same-origin. Saat gagal CORS, meneruskan URL ke background service worker yang mengambilnya dan mengembalikan data URL base64.
  4. Memasukkan data URL ke Tesseract worker; menjalankan runDetection pada teks yang diekstrak.
  5. Jika ditemukan kecocokan, mengganti sumber gambar dengan grafik peringatan judolss.jpeg yang dibundel.

Tesseract worker diinisialisasi secara lazy pada permintaan OCR pertama dan digunakan kembali pada pemindaian berikutnya.

storage.ts

Pembungkus tipis di atas chrome.storage.local dengan fallback in-memory berbasis Map untuk lingkungan non-ekstensi (unit test). Menyimpan:

Key Konten
JUDOL_DETECTOR_RESULTS MatchResult[] dari pemindaian terakhir
JUDOL_DETECTOR_STATS DetectionStats
JUDOL_DETECTOR_LAST_SCAN Unix timestamp (ms)
JUDOL_DETECTOR_SETTINGS DetectionSettings (blur, OCR, tooltip)
JUDOL_DETECTOR_ALGO_PREFS AlgoPrefs

textNormalizer.ts

normalizeText(text):
  trim → lowercase → ratakan whitespace → buang karakter non-printable

Digunakan secara eksklusif untuk pass fuzzy Levenshtein. Algoritma exact-match hanya menerima versi lowercase agar posisi karakter tetap akurat untuk perhitungan offset highlight.

timer.ts

createTimer()  { elapsed(): number }   // menggunakan performance.now()
measureTime(fn)  { result, elapsedMs } // membungkus fungsi sinkron

Setiap algoritma menerima timer saat masuk dan mencap executionTimeMs pada setiap MatchResult yang dikembalikan.

Kontribusi

Kelompok RP17845

Nama NIM Handle
Renuno Yuqa Frinardi 13524080 @renuno-frinardi
Ariel Cornelius Sitorus 13524085 @Sakazu01
Muhammad Akmal 13524099 @m-akma1

IF2211 Strategi Algoritma - Tugas Besar 3
Semester II Tahun Akademik 2025/2026

Program Studi Teknik Informatika
Sekolah Teknik Elektro dan Informatika
Institut Teknologi Bandung

About

Tubes tubes tubest uebst

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages