From c030bab51097c24dc34fd347efc6ff602f330543 Mon Sep 17 00:00:00 2001 From: Krzysztof Rudnicki Date: Sun, 21 Dec 2025 19:02:19 +0100 Subject: [PATCH] feat: more restrictive android scripts, offline docs and plagiarization utils --- .../utils/android_guardian/blocked_apps.txt | 121 ++++ scripts/utils/android_guardian/module.prop | 6 + .../utils/android_guardian/post-fs-data.sh | 9 + scripts/utils/android_guardian/service.sh | 77 ++ scripts/utils/android_guardian/uninstall.sh | 16 + scripts/utils/install_offline_docs.sh | 228 ++++++ scripts/utils/install_plagiarism_tools.sh | 532 ++++++++++++++ scripts/utils/update_android_hosts.sh | 684 +++++++++++++++--- 8 files changed, 1569 insertions(+), 104 deletions(-) create mode 100644 scripts/utils/android_guardian/blocked_apps.txt create mode 100644 scripts/utils/android_guardian/module.prop create mode 100755 scripts/utils/android_guardian/post-fs-data.sh create mode 100755 scripts/utils/android_guardian/service.sh create mode 100755 scripts/utils/android_guardian/uninstall.sh create mode 100644 scripts/utils/install_offline_docs.sh create mode 100755 scripts/utils/install_plagiarism_tools.sh diff --git a/scripts/utils/android_guardian/blocked_apps.txt b/scripts/utils/android_guardian/blocked_apps.txt new file mode 100644 index 0000000..b95aae1 --- /dev/null +++ b/scripts/utils/android_guardian/blocked_apps.txt @@ -0,0 +1,121 @@ +# Android Guardian - Blocked Apps List +# One package name per line +# Lines starting with # are comments + +# ===== Food Delivery Apps ===== +# Uber Eats +com.ubercab.eats + +# Glovo +com.glovo + +# Wolt +com.wolt.android + +# Bolt Food +ee.mtakso.food + +# Pyszne.pl / Takeaway +com.takeaway.android +com.pyszne.pl + +# DoorDash +com.dd.doordash + +# Grubhub +com.grubhub.android + +# Deliveroo +com.deliveroo.orderapp + +# Just Eat +com.justeat.app.uk +com.justeat.android + +# Postmates +com.postmates.android + +# Seamless +com.seamless.consumer + +# Foodpanda +com.global.foodpanda.android + +# ===== Browsers (to prevent bypassing blocks) ===== +# Firefox +org.mozilla.firefox +org.mozilla.firefox_beta +org.mozilla.fenix + +# Chrome (comment out if needed for some functionality) +# com.android.chrome + +# Opera +com.opera.browser +com.opera.mini.native +com.opera.gx + +# Brave +com.brave.browser + +# Samsung Internet +com.sec.android.app.sbrowser + +# Microsoft Edge +com.microsoft.emmx + +# DuckDuckGo +com.duckduckgo.mobile.android + +# Kiwi Browser +com.kiwibrowser.browser + +# Vivaldi +com.vivaldi.browser + +# UC Browser +com.UCMobile.intl + +# Tor Browser +org.torproject.torbrowser + +# ===== YouTube Apps ===== +com.google.android.youtube +com.vanced.android.youtube +app.revanced.android.youtube + +# ===== Fast Food Apps ===== +# McDonald's +com.mcdonalds.app +com.mcdonalds.mobileapp + +# KFC +com.yum.kfcpolska +com.kfc.app + +# Burger King +com.emn8.mobilem8.nativeapp.bk +com.burgerking + +# Pizza Hut +com.pizzahut.app + +# Domino's +com.dominospizza + +# Subway +com.subway.mobile + +# ===== Other Distracting Apps ===== +# TikTok +com.zhiliaoapp.musically +com.ss.android.ugc.trill + +# Instagram (optional - comment out if needed) +# com.instagram.android + +# Facebook (optional) +# com.facebook.katana + +# Twitter/X +# com.twitter.android diff --git a/scripts/utils/android_guardian/module.prop b/scripts/utils/android_guardian/module.prop new file mode 100644 index 0000000..bceabd4 --- /dev/null +++ b/scripts/utils/android_guardian/module.prop @@ -0,0 +1,6 @@ +id=android_guardian +name=Android Guardian (Hosts + App Blocker) +version=1.0 +versionCode=1 +author=linux-configuration +description=Persistent hosts blocking and app installation guard. Can only be controlled via ADB. diff --git a/scripts/utils/android_guardian/post-fs-data.sh b/scripts/utils/android_guardian/post-fs-data.sh new file mode 100755 index 0000000..c602a7e --- /dev/null +++ b/scripts/utils/android_guardian/post-fs-data.sh @@ -0,0 +1,9 @@ +#!/system/bin/sh +# Runs early in boot - set up hosts file +# MODDIR is set by Magisk and points to this module's directory +GUARDIAN_DIR="/data/adb/android_guardian" + +mkdir -p "$GUARDIAN_DIR" + +# Log that we're starting +echo "[$(date '+%Y-%m-%d %H:%M:%S')] post-fs-data: Guardian module loading" >>"$GUARDIAN_DIR/guardian.log" diff --git a/scripts/utils/android_guardian/service.sh b/scripts/utils/android_guardian/service.sh new file mode 100755 index 0000000..d559152 --- /dev/null +++ b/scripts/utils/android_guardian/service.sh @@ -0,0 +1,77 @@ +#!/system/bin/sh +# Android Guardian Service - runs at boot +# This service: +# 1. Monitors and protects the hosts file +# 2. Blocks installation of forbidden apps +# 3. Can only be stopped via ADB with the correct command + +MODDIR=${0%/*} +GUARDIAN_DIR="/data/adb/android_guardian" +LOG_FILE="$GUARDIAN_DIR/guardian.log" +BLOCKED_APPS_FILE="$GUARDIAN_DIR/blocked_apps.txt" +CONTROL_FILE="$GUARDIAN_DIR/control" +HOSTS_BACKUP="$GUARDIAN_DIR/hosts.backup" + +# Ensure guardian directory exists +mkdir -p "$GUARDIAN_DIR" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >>"$LOG_FILE" +} + +# Initialize control file if not exists +[ ! -f "$CONTROL_FILE" ] && echo "ENABLED" >"$CONTROL_FILE" + +log "=== Android Guardian starting ===" + +# Function to check if guardian is enabled +is_enabled() { + [ "$(cat "$CONTROL_FILE" 2>/dev/null)" = "ENABLED" ] +} + +# Function to restore hosts file if tampered +protect_hosts() { + if [ -f "$HOSTS_BACKUP" ]; then + current_hash=$(md5sum /system/etc/hosts 2>/dev/null | cut -d' ' -f1) + backup_hash=$(md5sum "$HOSTS_BACKUP" 2>/dev/null | cut -d' ' -f1) + + if [ "$current_hash" != "$backup_hash" ]; then + log "Hosts file tampering detected! Restoring..." + cp "$HOSTS_BACKUP" "$MODDIR/system/etc/hosts" + log "Hosts file restored" + fi + fi +} + +# Function to uninstall blocked apps +check_blocked_apps() { + if [ ! -f "$BLOCKED_APPS_FILE" ]; then + return + fi + + while IFS= read -r package || [ -n "$package" ]; do + # Skip comments and empty lines + case "$package" in + \#* | "") continue ;; + esac + + # Check if package is installed + if pm list packages 2>/dev/null | grep -q "package:$package"; then + log "Blocked app detected: $package - Uninstalling..." + pm uninstall "$package" 2>/dev/null && log "Uninstalled: $package" || log "Failed to uninstall: $package" + fi + done <"$BLOCKED_APPS_FILE" +} + +# Main monitoring loop +while true; do + if is_enabled; then + protect_hosts + check_blocked_apps + fi + + # Check every 30 seconds + sleep 30 +done & + +log "Guardian service started (PID: $!)" diff --git a/scripts/utils/android_guardian/uninstall.sh b/scripts/utils/android_guardian/uninstall.sh new file mode 100755 index 0000000..ae76f6e --- /dev/null +++ b/scripts/utils/android_guardian/uninstall.sh @@ -0,0 +1,16 @@ +#!/system/bin/sh +# Cleanup when module is uninstalled +GUARDIAN_DIR="/data/adb/android_guardian" + +# Only allow uninstall if control file says DISABLED +if [ -f "$GUARDIAN_DIR/control" ]; then + status=$(cat "$GUARDIAN_DIR/control") + if [ "$status" != "DISABLED" ]; then + echo "Guardian is still enabled! Use ADB to disable first:" + echo " adb shell 'echo DISABLED > /data/adb/android_guardian/control'" + exit 1 + fi +fi + +# Clean up guardian data +rm -rf "$GUARDIAN_DIR" diff --git a/scripts/utils/install_offline_docs.sh b/scripts/utils/install_offline_docs.sh new file mode 100644 index 0000000..5d68b4e --- /dev/null +++ b/scripts/utils/install_offline_docs.sh @@ -0,0 +1,228 @@ +#!/usr/bin/env bash +# Install Zeal - Offline Documentation Browser +# Downloads official documentation for: C, C++, JavaScript, TypeScript, Python +# +# Zeal is a free, open source (GPL) offline documentation browser +# Similar to Dash for macOS, uses compatible docsets + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +success() { echo -e "${GREEN}✓ $1${NC}"; } +warn() { echo -e "${YELLOW}⚠ $1${NC}"; } +error() { echo -e "${RED}✗ $1${NC}"; } +info() { echo -e "${BLUE}ℹ $1${NC}"; } + +echo "==============================================" +echo " Offline Documentation Installer" +echo " Languages: C, C++, JavaScript, TypeScript, Python" +echo "==============================================" +echo "" + +# Detect package manager and install Zeal +install_zeal() { + if command -v zeal &>/dev/null; then + success "Zeal is already installed" + return 0 + fi + + echo "Installing Zeal offline documentation browser..." + + if command -v pacman &>/dev/null; then + # Arch Linux + sudo pacman -S --noconfirm zeal + elif command -v apt &>/dev/null; then + # Debian/Ubuntu + sudo apt update + sudo apt install -y zeal + elif command -v dnf &>/dev/null; then + # Fedora + sudo dnf install -y zeal + elif command -v zypper &>/dev/null; then + # openSUSE + sudo zypper install -y zeal + elif command -v flatpak &>/dev/null; then + # Flatpak fallback + flatpak install -y flathub org.zealdocs.Zeal + else + error "Could not detect package manager. Please install Zeal manually:" + echo " https://zealdocs.org/download.html" + return 1 + fi + + success "Zeal installed successfully" +} + +# Get Zeal docsets directory +get_docsets_dir() { + local docsets_dir + + # Check if using Flatpak + if command -v flatpak &>/dev/null && flatpak list | grep -q "org.zealdocs.Zeal"; then + docsets_dir="$HOME/.var/app/org.zealdocs.Zeal/data/Zeal/Zeal/docsets" + else + # Standard installation + docsets_dir="$HOME/.local/share/Zeal/Zeal/docsets" + fi + + mkdir -p "$docsets_dir" + echo "$docsets_dir" +} + +# Download a docset from Zeal feeds +download_docset() { + local name="$1" + local docsets_dir="$2" + + # Check if already installed + if [ -d "$docsets_dir/${name}.docset" ]; then + warn "$name docset already installed" + return 0 + fi + + info "Downloading $name documentation..." + + # Use Zeal's built-in feed system via CLI or direct download + # Zeal stores docsets in .docset directories + + # Try to get from dash-user-contributions or official feeds + local download_url="" + + case "$name" in + "C") + download_url="http://kapeli.com/feeds/C.tgz" + ;; + "C++") + download_url="http://kapeli.com/feeds/C%2B%2B.tgz" + ;; + "JavaScript") + download_url="http://kapeli.com/feeds/JavaScript.tgz" + ;; + "TypeScript") + download_url="http://kapeli.com/feeds/TypeScript.tgz" + ;; + "Python_3") + download_url="http://kapeli.com/feeds/Python_3.tgz" + ;; + "Python_2") + download_url="http://kapeli.com/feeds/Python_2.tgz" + ;; + "Bash") + download_url="http://kapeli.com/feeds/Bash.tgz" + ;; + "HTML") + download_url="http://kapeli.com/feeds/HTML.tgz" + ;; + "CSS") + download_url="http://kapeli.com/feeds/CSS.tgz" + ;; + "NodeJS") + download_url="http://kapeli.com/feeds/NodeJS.tgz" + ;; + "React") + download_url="http://kapeli.com/feeds/React.tgz" + ;; + *) + warn "Unknown docset: $name" + return 1 + ;; + esac + + # Download and extract + local temp_file + temp_file=$(mktemp) + + echo " URL: $download_url" + if curl -fL --progress-bar "$download_url" -o "$temp_file"; then + echo " Extracting to $docsets_dir..." + tar -xzf "$temp_file" -C "$docsets_dir" + rm -f "$temp_file" + success "$name documentation downloaded" + else + rm -f "$temp_file" + warn "Failed to download $name - you can install it from Zeal's UI" + return 1 + fi +} + +# Main installation +main() { + # Step 1: Install Zeal + echo "" + echo "=== Step 1: Installing Zeal ===" + install_zeal || exit 1 + + # Step 2: Get docsets directory + echo "" + echo "=== Step 2: Preparing docsets directory ===" + local docsets_dir + docsets_dir=$(get_docsets_dir) + success "Docsets directory: $docsets_dir" + + # Step 3: Download requested docsets + echo "" + echo "=== Step 3: Downloading Documentation ===" + echo "" + + # Core requested languages + local docsets=("C" "C++" "JavaScript" "TypeScript" "Python_3") + + # Optional extras (comment out if not needed) + local extras=("Bash" "HTML" "CSS" "NodeJS") + + # Download core docsets + for docset in "${docsets[@]}"; do + download_docset "$docset" "$docsets_dir" + done + + # Ask about extras + echo "" + read -r -p "Install additional docsets (Bash, HTML, CSS, NodeJS)? [Y/n] " response + if [[ ! "$response" =~ ^[Nn]$ ]]; then + for docset in "${extras[@]}"; do + download_docset "$docset" "$docsets_dir" + done + fi + + # Summary + echo "" + echo "==============================================" + echo " Installation Complete!" + echo "==============================================" + echo "" + echo "Installed documentation:" + for f in "$docsets_dir"/*.docset; do + if [[ -d "$f" ]]; then + echo " ✓ $(basename "$f" .docset)" + fi + done + echo "" + echo "Usage:" + echo " Launch Zeal from your application menu, or run: zeal" + echo "" + echo "To download additional docsets:" + echo " 1. Open Zeal" + echo " 2. Go to Tools → Docsets" + echo " 3. Click 'Available' tab and download what you need" + echo "" + echo "Keyboard shortcut tip:" + echo " Set a global hotkey in Zeal → Preferences → Global Shortcuts" + echo " (e.g., Alt+Space for quick documentation lookup)" + echo "" + echo "==============================================" + + # Offer to launch Zeal + read -r -p "Launch Zeal now? [y/N] " response + if [[ "$response" =~ ^[Yy]$ ]]; then + nohup zeal &>/dev/null & + success "Zeal launched" + fi +} + +main "$@" diff --git a/scripts/utils/install_plagiarism_tools.sh b/scripts/utils/install_plagiarism_tools.sh new file mode 100755 index 0000000..91daf6d --- /dev/null +++ b/scripts/utils/install_plagiarism_tools.sh @@ -0,0 +1,532 @@ +#!/usr/bin/env bash +# Install Free & Open Source Plagiarism Detection Tools for Text +# Suitable for academic work (theses, papers, etc.) +# +# Tools installed: +# 1. Python NLP-based similarity detection (sklearn, NLTK, spaCy) +# 2. Sherlock text plagiarism detector +# 3. Ferret (Java-based, if Java available) +# 4. Optional: WCopyfind via Wine (Windows tool) + +set -euo pipefail + +INSTALL_DIR="${HOME}/.local/share/plagiarism-tools" +VENV_DIR="${HOME}/.local/share/plagiarism-venv" + +echo "==============================================" +echo " Open Source Plagiarism Detection Installer" +echo " For Academic Text (Theses, Papers, etc.)" +echo "==============================================" +echo "" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +success() { echo -e "${GREEN}✓ $1${NC}"; } +warn() { echo -e "${YELLOW}⚠ $1${NC}"; } +error() { echo -e "${RED}✗ $1${NC}"; } + +# Create installation directory +mkdir -p "$INSTALL_DIR" + +# ------------------------------------------------------------------------------ +# 1. Python-based NLP Plagiarism Detection Environment +# ------------------------------------------------------------------------------ +echo "" +echo "=== 1. Installing Python NLP-based Plagiarism Tools ===" + +# Check for Python 3 +if ! command -v python3 &>/dev/null; then + error "Python 3 is required but not installed." + exit 1 +fi + +# Create virtual environment +if [ ! -d "$VENV_DIR" ]; then + echo "Creating Python virtual environment..." + python3 -m venv "$VENV_DIR" + success "Virtual environment created at $VENV_DIR" +else + warn "Virtual environment already exists at $VENV_DIR" +fi + +# Activate and install packages +source "$VENV_DIR/bin/activate" + +echo "Installing Python packages for text similarity detection..." +pip install --upgrade pip + +pip install --progress-bar on \ + scikit-learn \ + nltk \ + spacy \ + gensim \ + numpy \ + pandas \ + python-docx \ + PyPDF2 \ + beautifulsoup4 \ + lxml \ + textdistance \ + fuzzywuzzy \ + python-Levenshtein + +success "Python NLP packages installed" + +# Download NLTK data +echo "Downloading NLTK data (stopwords, punkt tokenizer)..." +python3 -c " +import nltk +nltk.download('punkt') +nltk.download('stopwords') +nltk.download('punkt_tab') +nltk.download('averaged_perceptron_tagger') +nltk.download('wordnet') +" +success "NLTK data downloaded" + +# Download spaCy English model (small) +echo "Downloading spaCy English model..." +python3 -m spacy download en_core_web_sm 2>/dev/null || warn "spaCy model download may need manual install: python -m spacy download en_core_web_sm" +success "spaCy model installed" + +# Create a simple plagiarism checker script +cat >"$INSTALL_DIR/check_plagiarism.py" <<'PYEOF' +#!/usr/bin/env python3 +""" +Simple Text Plagiarism Checker +Compares documents using multiple similarity algorithms. + +Usage: + python check_plagiarism.py file1.txt file2.txt [file3.txt ...] + python check_plagiarism.py --dir /path/to/documents/ +""" + +import argparse +import os +import sys +from pathlib import Path +from typing import List, Tuple + +import numpy as np +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.metrics.pairwise import cosine_similarity +import nltk +from nltk.corpus import stopwords +from nltk.tokenize import word_tokenize, sent_tokenize + +# Ensure NLTK data is available +try: + stopwords.words('english') +except LookupError: + nltk.download('stopwords', quiet=True) + nltk.download('punkt', quiet=True) + + +def read_file(filepath: str) -> str: + """Read text from various file formats.""" + path = Path(filepath) + suffix = path.suffix.lower() + + if suffix == '.pdf': + try: + from PyPDF2 import PdfReader + reader = PdfReader(filepath) + return ' '.join(page.extract_text() or '' for page in reader.pages) + except ImportError: + print("Warning: PyPDF2 not installed, cannot read PDF files") + return "" + elif suffix == '.docx': + try: + from docx import Document + doc = Document(filepath) + return ' '.join(para.text for para in doc.paragraphs) + except ImportError: + print("Warning: python-docx not installed, cannot read DOCX files") + return "" + else: + # Assume plain text + with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + return f.read() + + +def preprocess_text(text: str) -> str: + """Clean and preprocess text for comparison.""" + # Lowercase + text = text.lower() + # Tokenize and remove stopwords + try: + stop_words = set(stopwords.words('english')) + words = word_tokenize(text) + words = [w for w in words if w.isalnum() and w not in stop_words] + return ' '.join(words) + except Exception: + # Fallback: simple preprocessing + return ' '.join(text.split()) + + +def compute_similarity_matrix(documents: List[str]) -> np.ndarray: + """Compute TF-IDF cosine similarity matrix.""" + vectorizer = TfidfVectorizer( + ngram_range=(1, 3), # Use unigrams, bigrams, trigrams + min_df=1, + max_df=0.95 + ) + tfidf_matrix = vectorizer.fit_transform(documents) + return cosine_similarity(tfidf_matrix) + + +def find_similar_passages(text1: str, text2: str, min_words: int = 5) -> List[Tuple[str, str, float]]: + """Find similar sentence-level passages between two texts.""" + sentences1 = sent_tokenize(text1) + sentences2 = sent_tokenize(text2) + + if not sentences1 or not sentences2: + return [] + + # Filter short sentences + sentences1 = [s for s in sentences1 if len(s.split()) >= min_words] + sentences2 = [s for s in sentences2 if len(s.split()) >= min_words] + + if not sentences1 or not sentences2: + return [] + + all_sentences = sentences1 + sentences2 + preprocessed = [preprocess_text(s) for s in all_sentences] + + try: + vectorizer = TfidfVectorizer(ngram_range=(1, 2)) + tfidf_matrix = vectorizer.fit_transform(preprocessed) + except ValueError: + return [] + + n1 = len(sentences1) + similarities = [] + + for i, s1 in enumerate(sentences1): + for j, s2 in enumerate(sentences2): + sim = cosine_similarity( + tfidf_matrix[i:i+1], + tfidf_matrix[n1+j:n1+j+1] + )[0][0] + if sim > 0.5: # Threshold for suspicious similarity + similarities.append((s1, s2, sim)) + + return sorted(similarities, key=lambda x: x[2], reverse=True) + + +def main(): + parser = argparse.ArgumentParser( + description='Text Plagiarism Checker - Compare documents for similarity' + ) + parser.add_argument('files', nargs='*', help='Files to compare') + parser.add_argument('--dir', '-d', help='Directory containing documents to compare') + parser.add_argument('--threshold', '-t', type=float, default=0.3, + help='Similarity threshold for flagging (0-1, default: 0.3)') + parser.add_argument('--detailed', '-v', action='store_true', + help='Show detailed similar passages') + + args = parser.parse_args() + + # Collect files + files = [] + if args.files: + files.extend(args.files) + if args.dir: + dir_path = Path(args.dir) + for ext in ['*.txt', '*.pdf', '*.docx', '*.md', '*.tex']: + files.extend(str(f) for f in dir_path.glob(ext)) + + if len(files) < 2: + print("Error: Need at least 2 files to compare") + parser.print_help() + sys.exit(1) + + print(f"\n{'='*60}") + print(f" Plagiarism Check - Analyzing {len(files)} documents") + print(f"{'='*60}\n") + + # Read and preprocess documents + documents = [] + filenames = [] + for f in files: + if os.path.exists(f): + text = read_file(f) + if text.strip(): + documents.append(preprocess_text(text)) + filenames.append(os.path.basename(f)) + else: + print(f"Warning: {f} is empty or unreadable") + else: + print(f"Warning: {f} does not exist") + + if len(documents) < 2: + print("Error: Not enough valid documents to compare") + sys.exit(1) + + # Compute similarity + print("Computing document similarities...\n") + sim_matrix = compute_similarity_matrix(documents) + + # Report results + print(f"{'Document Pair':<50} {'Similarity':>12}") + print("-" * 62) + + suspicious_pairs = [] + for i in range(len(documents)): + for j in range(i + 1, len(documents)): + similarity = sim_matrix[i][j] + pair_name = f"{filenames[i]} <-> {filenames[j]}" + + if similarity >= args.threshold: + suspicious_pairs.append((i, j, similarity, pair_name)) + print(f"{pair_name:<50} {similarity:>10.1%} ⚠️") + else: + print(f"{pair_name:<50} {similarity:>10.1%}") + + print("-" * 62) + + # Summary + if suspicious_pairs: + print(f"\n⚠️ {len(suspicious_pairs)} pair(s) exceed {args.threshold:.0%} similarity threshold\n") + + if args.detailed: + print("\n" + "="*60) + print(" Detailed Similar Passages") + print("="*60) + + for i, j, sim, pair_name in suspicious_pairs[:3]: # Limit to top 3 + print(f"\n{pair_name} ({sim:.1%} similar):") + print("-" * 40) + + raw_docs = [read_file(files[i]), read_file(files[j])] + passages = find_similar_passages(raw_docs[0], raw_docs[1]) + + for s1, s2, psim in passages[:5]: # Top 5 passages + print(f"\n[{psim:.0%}] Document 1: \"{s1[:100]}...\"") + print(f" Document 2: \"{s2[:100]}...\"") + else: + print(f"\n✓ No document pairs exceed {args.threshold:.0%} similarity threshold") + + print("\n" + "="*60) + print(" Analysis complete") + print("="*60 + "\n") + + +if __name__ == '__main__': + main() +PYEOF + +chmod +x "$INSTALL_DIR/check_plagiarism.py" +success "Created plagiarism checker script at $INSTALL_DIR/check_plagiarism.py" + +# Create convenience wrapper +mkdir -p "$HOME/.local/bin" +cat >"$HOME/.local/bin/plagcheck" </dev/null; then + # Clone a text-based similarity tool + git clone --depth 1 https://github.com/Zedeldi/sherlock-py.git "$SHERLOCK_DIR" 2>/dev/null || { + warn "Could not clone sherlock-py, trying alternative..." + # Alternative: Create a simple n-gram based sherlock + mkdir -p "$SHERLOCK_DIR" + cat >"$SHERLOCK_DIR/sherlock.py" <<'SHERLOCKEOF' +#!/usr/bin/env python3 +""" +Sherlock - Simple text plagiarism detector using n-gram fingerprinting. +Based on the original Sherlock algorithm. +""" + +import argparse +import hashlib +import os +import sys +from collections import defaultdict +from pathlib import Path + + +def tokenize(text: str) -> list: + """Simple word tokenization.""" + return [w.lower() for w in text.split() if w.isalnum()] + + +def get_ngrams(tokens: list, n: int = 3) -> list: + """Generate n-grams from token list.""" + return [tuple(tokens[i:i+n]) for i in range(len(tokens) - n + 1)] + + +def fingerprint(text: str, ngram_size: int = 3, sample_rate: int = 4) -> set: + """Create document fingerprint using sampled n-gram hashes.""" + tokens = tokenize(text) + ngrams = get_ngrams(tokens, ngram_size) + + fingerprints = set() + for i, ng in enumerate(ngrams): + if i % sample_rate == 0: # Sample every nth n-gram + h = hashlib.md5(''.join(ng).encode()).hexdigest()[:8] + fingerprints.add(h) + + return fingerprints + + +def compare_documents(fp1: set, fp2: set) -> float: + """Jaccard similarity between fingerprints.""" + if not fp1 or not fp2: + return 0.0 + intersection = len(fp1 & fp2) + union = len(fp1 | fp2) + return intersection / union if union > 0 else 0.0 + + +def read_document(filepath: str) -> str: + """Read document content.""" + with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: + return f.read() + + +def main(): + parser = argparse.ArgumentParser(description='Sherlock - Text Plagiarism Detector') + parser.add_argument('files', nargs='+', help='Files to compare') + parser.add_argument('--ngram', '-n', type=int, default=3, help='N-gram size (default: 3)') + parser.add_argument('--threshold', '-t', type=float, default=0.1, help='Similarity threshold') + + args = parser.parse_args() + + if len(args.files) < 2: + print("Need at least 2 files to compare") + sys.exit(1) + + # Read and fingerprint documents + docs = {} + for f in args.files: + if os.path.exists(f): + text = read_document(f) + docs[f] = fingerprint(text, args.ngram) + + print(f"\nSherlock Plagiarism Analysis") + print("=" * 50) + + # Compare all pairs + files = list(docs.keys()) + for i in range(len(files)): + for j in range(i + 1, len(files)): + sim = compare_documents(docs[files[i]], docs[files[j]]) + name1 = os.path.basename(files[i]) + name2 = os.path.basename(files[j]) + flag = " ⚠️ SUSPICIOUS" if sim >= args.threshold else "" + print(f"{name1} <-> {name2}: {sim:.1%}{flag}") + + print("=" * 50) + + +if __name__ == '__main__': + main() +SHERLOCKEOF + chmod +x "$SHERLOCK_DIR/sherlock.py" + } + success "Sherlock installed at $SHERLOCK_DIR" + else + warn "Git not available, skipping Sherlock installation" + fi +else + warn "Sherlock already installed at $SHERLOCK_DIR" +fi + +# ------------------------------------------------------------------------------ +# 3. Ferret (Java-based) - Optional +# ------------------------------------------------------------------------------ +echo "" +echo "=== 3. Checking for Ferret (Java-based plagiarism tool) ===" + +if command -v java &>/dev/null; then + FERRET_DIR="$INSTALL_DIR/ferret" + if [ ! -d "$FERRET_DIR" ]; then + mkdir -p "$FERRET_DIR" + echo "Ferret is a Java-based tool from University of Hertfordshire." + echo "Download manually from: https://homepages.herts.ac.uk/~comqcln/Ferret/" + echo "Place JAR file in: $FERRET_DIR" + warn "Ferret requires manual download (academic license)" + fi +else + warn "Java not installed, skipping Ferret" +fi + +# ------------------------------------------------------------------------------ +# 4. WCopyfind via Wine (Optional) +# ------------------------------------------------------------------------------ +echo "" +echo "=== 4. WCopyfind Information (Windows tool, needs Wine) ===" + +if command -v wine &>/dev/null; then + echo "Wine is available. WCopyfind can be run via Wine." + echo "Download from: https://plagiarism.bloomfieldmedia.com/software/wcopyfind/" + echo "Run with: wine /path/to/WCopyfind.exe" + warn "WCopyfind requires manual download" +else + echo "Wine not installed. To use WCopyfind:" + echo " 1. Install wine: sudo apt install wine (or equivalent)" + echo " 2. Download WCopyfind from: https://plagiarism.bloomfieldmedia.com/software/wcopyfind/" + warn "WCopyfind skipped (Wine not available)" +fi + +# ------------------------------------------------------------------------------ +# Summary +# ------------------------------------------------------------------------------ +echo "" +echo "==============================================" +echo " Installation Complete!" +echo "==============================================" +echo "" +echo "Installed tools:" +echo "" +echo "1. Python NLP Plagiarism Checker (TF-IDF, cosine similarity)" +echo " Usage: plagcheck file1.txt file2.txt" +echo " plagcheck --dir /path/to/documents/ --detailed" +echo " Location: $INSTALL_DIR/check_plagiarism.py" +echo "" +echo "2. Sherlock (n-gram fingerprinting)" +echo " Location: $SHERLOCK_DIR/sherlock.py" +echo "" +echo "3. Python virtual environment with NLP libraries:" +echo " - scikit-learn (TF-IDF, cosine similarity)" +echo " - NLTK (tokenization, stopwords)" +echo " - spaCy (NLP processing)" +echo " - gensim (document similarity)" +echo " - textdistance, fuzzywuzzy (string matching)" +echo " Activate with: source $VENV_DIR/bin/activate" +echo "" +echo "Quick Start:" +echo " plagcheck thesis_v1.pdf thesis_v2.pdf --detailed" +echo " plagcheck --dir ./student_papers/ --threshold 0.4" +echo "" +echo "Note: Ensure ~/.local/bin is in your PATH:" +echo ' export PATH="$HOME/.local/bin:$PATH"' +echo "" +echo "==============================================" + +# Add to PATH reminder +if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then + warn "Add ~/.local/bin to your PATH by adding this to ~/.bashrc or ~/.zshrc:" + echo ' export PATH="$HOME/.local/bin:$PATH"' +fi diff --git a/scripts/utils/update_android_hosts.sh b/scripts/utils/update_android_hosts.sh index 74a05eb..04da36e 100755 --- a/scripts/utils/update_android_hosts.sh +++ b/scripts/utils/update_android_hosts.sh @@ -1,5 +1,6 @@ #!/bin/bash -# update_android_hosts.sh - Update Android hosts file from Linux config +# update_android_hosts.sh - Deploy Android Guardian (hosts blocking + app blocker) +# This creates a persistent protection that can ONLY be controlled via ADB set -euo pipefail # Source common library @@ -9,51 +10,315 @@ source "$SCRIPT_DIR/../lib/common.sh" # shellcheck source=../lib/android.sh source "$SCRIPT_DIR/../lib/android.sh" -# Initialize Android script (handles sudo, sets WORK_DIR) -init_android_script "$@" +GUARDIAN_MODULE_DIR="$SCRIPT_DIR/android_guardian" +GUARDIAN_DATA_DIR="/data/adb/android_guardian" +MODULE_DEST="/data/adb/modules/android_guardian" -log "Updating Android hosts file from Linux configuration..." +# Ensure android-tools (adb) is installed +ensure_adb_installed() { + if command -v adb &>/dev/null; then + return 0 + fi -# Check device connection -check_adb_device + log "adb not found, installing android-tools..." -# Check root access -check_adb_root + if command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm android-tools || die "Failed to install android-tools" + elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y adb || die "Failed to install adb" + elif command -v dnf &>/dev/null; then + sudo dnf install -y android-tools || die "Failed to install android-tools" + else + die "adb not found and could not determine package manager. Please install android-tools manually." + fi -# Use the StevenBlack cache or /etc/hosts -HOSTS_FILE="$WORK_DIR/hosts" -if [[ -f /etc/hosts.stevenblack ]]; then - log "Using StevenBlack hosts cache..." - cp /etc/hosts.stevenblack "$HOSTS_FILE" -elif [[ -f /etc/hosts ]]; then - log "Using /etc/hosts..." - cp /etc/hosts "$HOSTS_FILE" -else - die "No hosts file found" -fi + # Verify installation + if ! command -v adb &>/dev/null; then + die "adb installation failed" + fi -# Show stats -TOTAL_ENTRIES=$(grep -c "^0\.0\.0\.0 " "$HOSTS_FILE" || echo 0) -log "Hosts file contains $TOTAL_ENTRIES blocked domains" + log "android-tools installed successfully" +} -# Push to device -log "Pushing hosts file to device..." -adb push "$HOSTS_FILE" /sdcard/hosts || die "Failed to push hosts file" +show_usage() { + cat <> /data/adb/modules/systemless_hosts/system/etc/hosts << \"CUSTOM_EOF\" +The module CANNOT be disabled from the Magisk app on the phone. +You MUST connect the phone to a PC and use this script to control it. + +Wireless Setup (Android 11+): + 1. On phone: Settings > Developer Options > Wireless debugging > Enable + 2. Tap "Pair device with pairing code" to get IP:port and code + 3. Run: $0 pair + 4. Future connections: $0 connect + +EOF +} + +# Wireless ADB connection file +WIRELESS_CONFIG="$HOME/.config/android_guardian_wireless" + +# Discover Android devices on the network using mDNS +discover_android_device() { + local found_address="" + + # Ensure avahi-browse is available + if ! command -v avahi-browse &>/dev/null; then + if command -v pacman &>/dev/null; then + echo "Installing avahi for device discovery..." >&2 + sudo pacman -S --noconfirm avahi nss-mdns &>/dev/null || true + sudo systemctl enable --now avahi-daemon &>/dev/null || true + elif command -v apt-get &>/dev/null; then + sudo apt-get install -y avahi-utils &>/dev/null || true + fi + fi + + if command -v avahi-browse &>/dev/null; then + echo "Scanning for Android devices (5 seconds)..." >&2 + + # Android wireless debugging advertises as _adb-tls-connect._tcp + local discovery_result + discovery_result=$(timeout 5 avahi-browse -rpt _adb-tls-connect._tcp 2>/dev/null | grep "^=" | head -1) + + if [[ -n "$discovery_result" ]]; then + # Parse: =;eth0;IPv4;adb-...;_adb-tls-connect._tcp;local;hostname.local;192.168.x.x;port;... + local ip port + ip=$(echo "$discovery_result" | cut -d';' -f8) + port=$(echo "$discovery_result" | cut -d';' -f9) + + if [[ -n "$ip" && -n "$port" ]]; then + found_address="$ip:$port" + echo "✓ Found device: $found_address" >&2 + fi + fi + fi + + # Fallback: try adb's mdns discovery + if [[ -z "$found_address" ]]; then + echo "Trying adb mdns discovery..." >&2 + + # adb can discover devices via mdns + local mdns_result + mdns_result=$(timeout 5 adb mdns services 2>/dev/null | grep -E "adb-tls-connect|_adb\._tcp" | head -1) + + if [[ -n "$mdns_result" ]]; then + # Try to extract IP:port from the result + local service_name + service_name=$(echo "$mdns_result" | awk '{print $1}') + if [[ -n "$service_name" ]]; then + # Try connecting via service name + echo "Found service: $service_name" >&2 + fi + fi + fi + + # Return found address (or empty) + echo "$found_address" +} + +# Pair with device over WiFi (Android 11+) +cmd_pair() { + ensure_adb_installed + + echo "" + echo "=== Wireless ADB Pairing (Android 11+) ===" + echo "" + echo "On your phone:" + echo " 1. Go to Settings > Developer Options > Wireless debugging" + echo " 2. Enable Wireless debugging" + echo " 3. Tap 'Pair device with pairing code'" + echo " 4. Note the IP:port and pairing code shown" + echo "" + + read -rp "Enter pairing IP:port (e.g., 192.168.1.100:37123): " pair_address + read -rp "Enter pairing code: " pair_code + + if [[ -z "$pair_address" || -z "$pair_code" ]]; then + die "Pairing address and code are required" + fi + + log "Pairing with device at $pair_address..." + if adb pair "$pair_address" "$pair_code"; then + echo "" + echo "✓ Pairing successful!" + echo "" + echo "Now get the connection address:" + echo " On phone: Wireless debugging screen shows IP:port under 'IP address & Port'" + echo " (This is DIFFERENT from the pairing port)" + echo "" + read -rp "Enter connection IP:port (e.g., 192.168.1.100:41567): " connect_address + + if [[ -n "$connect_address" ]]; then + # Save for future connections + mkdir -p "$(dirname "$WIRELESS_CONFIG")" + echo "$connect_address" >"$WIRELESS_CONFIG" + log "Saved connection address for future use" + + # Connect now + cmd_connect + fi + else + die "Pairing failed. Make sure the code is correct and you're on the same network." + fi +} + +# Connect to already-paired device +cmd_connect() { + ensure_adb_installed + + local connect_address="" + + # Check for saved address + if [[ -f "$WIRELESS_CONFIG" ]]; then + connect_address=$(cat "$WIRELESS_CONFIG") + log "Using saved address: $connect_address" + fi + + # Try auto-discovery if no saved address + if [[ -z "$connect_address" ]]; then + echo "" + log "Searching for Android devices on network..." + connect_address=$(discover_android_device) + fi + + # Manual fallback + if [[ -z "$connect_address" ]]; then + echo "" + echo "Auto-discovery failed. Enter address manually." + echo "On phone: Settings > Developer Options > Wireless debugging" + echo "Look for IP address & Port (NOT the pairing port)" + echo "" + read -rp "Enter connection IP:port (e.g., 192.168.1.100:41567): " connect_address + + if [[ -z "$connect_address" ]]; then + die "Connection address is required" + fi + fi + + # Save for future + mkdir -p "$(dirname "$WIRELESS_CONFIG")" + echo "$connect_address" >"$WIRELESS_CONFIG" + + log "Connecting to $connect_address..." + if adb connect "$connect_address" | grep -q "connected"; then + echo "" + echo "✓ Connected to device wirelessly!" + echo "" + + # Verify connection + if adb devices | grep -q "$connect_address"; then + echo "Device ready. You can now run other commands." + fi + else + echo "" + echo "Connection failed. Possible issues:" + echo " - Wireless debugging not enabled on phone" + echo " - Phone and PC not on same WiFi network" + echo " - Port changed (check Wireless debugging screen)" + echo " - May need to pair first: $0 pair" + echo "" + # Clear saved config since it failed + rm -f "$WIRELESS_CONFIG" + exit 1 + fi +} + +# Disconnect wireless ADB +cmd_disconnect() { + ensure_adb_installed + + log "Disconnecting all wireless devices..." + adb disconnect + echo "✓ Disconnected" +} + +# Check device connection and root +ensure_device_ready() { + ensure_adb_installed + + # Check if any device is connected + if ! adb devices | grep -qE "device$|:.*device$"; then + echo "" + echo "No device connected!" + echo "" + echo "Options:" + echo " 1. Connect USB cable with debugging enabled" + echo " 2. Use wireless: $0 pair (first time) or $0 connect" + echo "" + + # Check if we have a saved wireless config + if [[ -f "$WIRELESS_CONFIG" ]]; then + read -rp "Try connecting to saved wireless device? [Y/n]: " try_wireless + if [[ "${try_wireless,,}" != "n" ]]; then + cmd_connect + else + exit 1 + fi + else + exit 1 + fi + fi + + check_adb_device + check_adb_root +} + +# Build the module zip +build_module() { + local tmp_dir="$WORK_DIR/guardian_module" + local module_zip="$WORK_DIR/android_guardian.zip" + + echo "[BUILD] Building Android Guardian module..." >&2 + + rm -rf "$tmp_dir" + mkdir -p "$tmp_dir/system/etc" + + # Copy module files + cp "$GUARDIAN_MODULE_DIR/module.prop" "$tmp_dir/" + cp "$GUARDIAN_MODULE_DIR/service.sh" "$tmp_dir/" + cp "$GUARDIAN_MODULE_DIR/post-fs-data.sh" "$tmp_dir/" + cp "$GUARDIAN_MODULE_DIR/uninstall.sh" "$tmp_dir/" + + # Build hosts file + local hosts_file="$tmp_dir/system/etc/hosts" + if [[ -f /etc/hosts.stevenblack ]]; then + echo "[BUILD] Using StevenBlack hosts cache..." >&2 + cp /etc/hosts.stevenblack "$hosts_file" + elif [[ -f /etc/hosts ]]; then + echo "[BUILD] Using /etc/hosts..." >&2 + cp /etc/hosts "$hosts_file" + else + die "No hosts file found" + fi + + # Append custom blocking entries + cat >>"$hosts_file" <<'CUSTOM_EOF' + +# ============================================ +# Custom blocking entries - Android Guardian +# ============================================ -# Custom blocking entries # YouTube 0.0.0.0 youtube.com 0.0.0.0 www.youtube.com @@ -69,120 +334,331 @@ adb shell "su -c 'cat >> /data/adb/modules/systemless_hosts/system/etc/hosts << 0.0.0.0 s.ytimg.com 0.0.0.0 i9.ytimg.com 0.0.0.0 googlevideo.com -0.0.0.0 r1---sn-4g5e6nls.googlevideo.com -0.0.0.0 r1---sn-4g5lne7s.googlevideo.com -# Steam Store - -# Discord (selective blocking - media only, voice chat allowed) +# Discord (media only - voice chat allowed) 0.0.0.0 cdn.discordapp.com 0.0.0.0 media.discordapp.net 0.0.0.0 images-ext-1.discordapp.net 0.0.0.0 images-ext-2.discordapp.net -0.0.0.0 attachments-1.discordapp.net -0.0.0.0 attachments-2.discordapp.net 0.0.0.0 tenor.com 0.0.0.0 giphy.com # Food Delivery Services -# Polish services 0.0.0.0 pyszne.pl 0.0.0.0 www.pyszne.pl -0.0.0.0 m.pyszne.pl 0.0.0.0 glovo.com 0.0.0.0 www.glovo.com -0.0.0.0 m.glovo.com 0.0.0.0 bolt.eu 0.0.0.0 food.bolt.eu -0.0.0.0 woltwojta.pl -0.0.0.0 www.woltwojta.pl 0.0.0.0 wolt.com 0.0.0.0 www.wolt.com -0.0.0.0 m.wolt.com - -# International services 0.0.0.0 ubereats.com 0.0.0.0 www.ubereats.com -0.0.0.0 m.ubereats.com -0.0.0.0 uber.com -0.0.0.0 www.uber.com -0.0.0.0 m.uber.com 0.0.0.0 deliveroo.com 0.0.0.0 www.deliveroo.com -0.0.0.0 m.deliveroo.com -0.0.0.0 deliveroo.co.uk -0.0.0.0 www.deliveroo.co.uk 0.0.0.0 foodpanda.com 0.0.0.0 www.foodpanda.com -0.0.0.0 m.foodpanda.com 0.0.0.0 grubhub.com 0.0.0.0 www.grubhub.com -0.0.0.0 m.grubhub.com 0.0.0.0 doordash.com 0.0.0.0 www.doordash.com -0.0.0.0 m.doordash.com 0.0.0.0 justeat.com 0.0.0.0 www.justeat.com -0.0.0.0 m.justeat.com -0.0.0.0 justeat.co.uk -0.0.0.0 www.justeat.co.uk -0.0.0.0 postmates.com -0.0.0.0 www.postmates.com -0.0.0.0 seamless.com -0.0.0.0 www.seamless.com -0.0.0.0 menulog.com.au -0.0.0.0 www.menulog.com.au -0.0.0.0 delivery.com -0.0.0.0 www.delivery.com -# Fast food chain apps and websites +# Fast Food 0.0.0.0 mcdonalds.com 0.0.0.0 www.mcdonalds.com -0.0.0.0 m.mcdonalds.com 0.0.0.0 mcdonalds.pl 0.0.0.0 www.mcdonalds.pl 0.0.0.0 kfc.com 0.0.0.0 www.kfc.com -0.0.0.0 m.kfc.com 0.0.0.0 kfc.pl 0.0.0.0 www.kfc.pl 0.0.0.0 burgerking.com 0.0.0.0 www.burgerking.com -0.0.0.0 m.burgerking.com -0.0.0.0 burgerking.pl -0.0.0.0 www.burgerking.pl 0.0.0.0 pizzahut.com 0.0.0.0 www.pizzahut.com -0.0.0.0 m.pizzahut.com -0.0.0.0 pizzahut.pl -0.0.0.0 www.pizzahut.pl 0.0.0.0 dominos.com 0.0.0.0 www.dominos.com -0.0.0.0 m.dominos.com -0.0.0.0 dominos.pl -0.0.0.0 www.dominos.pl -0.0.0.0 subway.com -0.0.0.0 www.subway.com -0.0.0.0 m.subway.com -0.0.0.0 subway.pl -0.0.0.0 www.subway.pl CUSTOM_EOF -'" || { - echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] ✗ Failed to add custom entries" - exit 1 + + local total_entries + total_entries=$(grep -c "^0\.0\.0\.0 " "$hosts_file" || echo 0) + echo "[BUILD] Hosts file contains $total_entries blocked domains" >&2 + + # Create zip + (cd "$tmp_dir" && zip -r "$module_zip" . -x "*.DS_Store") >/dev/null + + echo "$module_zip" } -echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] ✓ Custom entries added successfully" +# Install/update the guardian module +cmd_install() { + ensure_device_ready -# Count and display blocked domains -domain_count=$(adb shell "su -c 'cat /system/etc/hosts | grep -c \"^0.0.0.0\"'" 2>/dev/null | tr -d '\r') -if [[ -n $domain_count ]]; then - echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] ✓ Total blocked domains: $domain_count" -fi + local module_zip + module_zip=$(build_module) -echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] ✓ Changes will take effect immediately for new connections" -echo "[$(date +'%Y-%m-%d %H:%M:%S%z')] (Optional: Toggle airplane mode or reboot to force all apps to reconnect)" -log "✓ Total blocked domains: $TOTAL_ENTRIES" -log "" -log "Changes will take effect immediately for new connections." -log "To apply to all apps, reboot the device or toggle airplane mode." + log "Pushing module to device..." + adb push "$module_zip" /sdcard/android_guardian.zip || die "Failed to push module" + + log "Installing module..." + adb shell "su -c 'mkdir -p $MODULE_DEST'" || die "Failed to create module directory" + adb shell "su -c 'cd $MODULE_DEST && unzip -o /sdcard/android_guardian.zip'" || die "Failed to extract module" + adb shell "su -c 'chmod 755 $MODULE_DEST/*.sh'" + adb shell "su -c 'rm /sdcard/android_guardian.zip'" + + # Set up guardian data directory + log "Setting up guardian data..." + adb shell "su -c 'mkdir -p $GUARDIAN_DATA_DIR'" + adb shell "su -c 'echo ENABLED > $GUARDIAN_DATA_DIR/control'" + + # Copy blocked apps list + adb push "$GUARDIAN_MODULE_DIR/blocked_apps.txt" /sdcard/blocked_apps.txt || die "Failed to push blocked apps list" + adb shell "su -c 'cp /sdcard/blocked_apps.txt $GUARDIAN_DATA_DIR/blocked_apps.txt'" + adb shell "su -c 'rm /sdcard/blocked_apps.txt'" + + # Create hosts backup for tamper protection + adb shell "su -c 'cp $MODULE_DEST/system/etc/hosts $GUARDIAN_DATA_DIR/hosts.backup'" + + # Immediately uninstall any currently installed blocked apps + log "Checking for blocked apps to remove..." + uninstall_blocked_apps + + echo "" + echo "==========================================" + echo " ✓ Android Guardian installed!" + echo "==========================================" + echo "" + echo "Features enabled:" + echo " • Hosts-based ad/tracker blocking" + echo " • App installation blocking" + echo " • Tamper protection" + echo "" + echo "⚠️ This can ONLY be controlled via ADB:" + echo " Disable: $0 disable" + echo " Enable: $0 enable" + echo " Status: $0 status" + echo "" + echo "Reboot your device to activate the module." + echo "" +} + +# Uninstall currently installed blocked apps +uninstall_blocked_apps() { + local blocked_apps + blocked_apps=$(grep -v '^#' "$GUARDIAN_MODULE_DIR/blocked_apps.txt" | grep -v '^$' || true) + + for package in $blocked_apps; do + if adb shell "pm list packages" 2>/dev/null | grep -q "package:$package"; then + log "Uninstalling blocked app: $package" + adb shell "pm uninstall $package" 2>/dev/null || true + fi + done +} + +# Show status +cmd_status() { + ensure_device_ready + + echo "" + echo "=== Android Guardian Status ===" + echo "" + + # Check if module is installed + if adb shell "su -c 'test -d $MODULE_DEST'" 2>/dev/null; then + echo "Module: INSTALLED" + else + echo "Module: NOT INSTALLED" + return + fi + + # Check control status + local status + status=$(adb shell "su -c 'cat $GUARDIAN_DATA_DIR/control 2>/dev/null || echo UNKNOWN'" | tr -d '\r') + echo "Status: $status" + + # Check hosts file + local hosts_entries + hosts_entries=$(adb shell "su -c 'grep -c \"^0.0.0.0\" /system/etc/hosts 2>/dev/null || echo 0'" | tr -d '\r') + echo "Blocked domains: $hosts_entries" + + # Check blocked apps count + local blocked_count + blocked_count=$(adb shell "su -c 'grep -v \"^#\" $GUARDIAN_DATA_DIR/blocked_apps.txt 2>/dev/null | grep -v \"^$\" | wc -l || echo 0'" | tr -d '\r') + echo "Blocked app rules: $blocked_count packages" + + echo "" +} + +# Disable guardian +cmd_disable() { + ensure_device_ready + + log "Disabling Android Guardian..." + adb shell "su -c 'echo DISABLED > $GUARDIAN_DATA_DIR/control'" || die "Failed to disable guardian" + + echo "" + echo "✓ Guardian DISABLED" + echo " Hosts blocking still active until reboot" + echo " App blocking service paused" + echo "" + echo "To re-enable: $0 enable" + echo "" +} + +# Enable guardian +cmd_enable() { + ensure_device_ready + + log "Enabling Android Guardian..." + adb shell "su -c 'echo ENABLED > $GUARDIAN_DATA_DIR/control'" || die "Failed to enable guardian" + + echo "" + echo "✓ Guardian ENABLED" + echo "" +} + +# Uninstall module +cmd_uninstall() { + ensure_device_ready + + # Check if disabled first + local status + status=$(adb shell "su -c 'cat $GUARDIAN_DATA_DIR/control 2>/dev/null || echo ENABLED'" | tr -d '\r') + + if [[ "$status" != "DISABLED" ]]; then + echo "" + echo "⚠️ Guardian must be disabled before uninstalling!" + echo " Run: $0 disable" + echo " Then: $0 uninstall" + echo "" + exit 1 + fi + + log "Removing Android Guardian..." + adb shell "su -c 'rm -rf $MODULE_DEST'" + adb shell "su -c 'rm -rf $GUARDIAN_DATA_DIR'" + + echo "" + echo "✓ Guardian uninstalled" + echo " Reboot to remove hosts blocking" + echo "" +} + +# Show logs +cmd_logs() { + ensure_device_ready + + echo "=== Guardian Logs ===" + adb shell "su -c 'cat $GUARDIAN_DATA_DIR/guardian.log 2>/dev/null || echo \"No logs yet\"'" +} + +# Block an app +cmd_block_app() { + local package="${1:-}" + + if [[ -z "$package" ]]; then + echo "Usage: $0 block-app " + echo "Example: $0 block-app com.ubercab.eats" + exit 1 + fi + + ensure_device_ready + + log "Adding $package to block list..." + adb shell "su -c 'echo \"$package\" >> $GUARDIAN_DATA_DIR/blocked_apps.txt'" + + # Also add to local file + echo "$package" >>"$GUARDIAN_MODULE_DIR/blocked_apps.txt" + + # Try to uninstall if currently installed + if adb shell "pm list packages" 2>/dev/null | grep -q "package:$package"; then + log "Uninstalling $package..." + adb shell "pm uninstall $package" 2>/dev/null || true + fi + + echo "✓ $package added to block list" +} + +# Unblock an app +cmd_unblock_app() { + local package="${1:-}" + + if [[ -z "$package" ]]; then + echo "Usage: $0 unblock-app " + exit 1 + fi + + ensure_device_ready + + log "Removing $package from block list..." + adb shell "su -c 'grep -v \"^$package\$\" $GUARDIAN_DATA_DIR/blocked_apps.txt > $GUARDIAN_DATA_DIR/blocked_apps.tmp && mv $GUARDIAN_DATA_DIR/blocked_apps.tmp $GUARDIAN_DATA_DIR/blocked_apps.txt'" + + # Also remove from local file + grep -v "^$package$" "$GUARDIAN_MODULE_DIR/blocked_apps.txt" >"$GUARDIAN_MODULE_DIR/blocked_apps.tmp" && mv "$GUARDIAN_MODULE_DIR/blocked_apps.tmp" "$GUARDIAN_MODULE_DIR/blocked_apps.txt" + + echo "✓ $package removed from block list" +} + +# List blocked apps +cmd_list_blocked() { + ensure_device_ready + + echo "=== Blocked Apps ===" + adb shell "su -c 'cat $GUARDIAN_DATA_DIR/blocked_apps.txt 2>/dev/null'" | grep -v "^#" | grep -v "^$" || echo "No blocked apps" +} + +# Main +# Initialize Android script (handles sudo, sets WORK_DIR) +init_android_script "$@" + +COMMAND="${1:-install}" +shift || true + +case "$COMMAND" in +install) + cmd_install + ;; +status) + cmd_status + ;; +disable) + cmd_disable + ;; +enable) + cmd_enable + ;; +uninstall) + cmd_uninstall + ;; +logs) + cmd_logs + ;; +block-app) + cmd_block_app "$@" + ;; +unblock-app) + cmd_unblock_app "$@" + ;; +list-blocked) + cmd_list_blocked + ;; +pair) + cmd_pair + ;; +connect) + cmd_connect + ;; +disconnect) + cmd_disconnect + ;; +-h | --help | help) + show_usage + ;; +*) + echo "Unknown command: $COMMAND" + show_usage + exit 1 + ;; +esac