diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml new file mode 100644 index 0000000..40a69fc --- /dev/null +++ b/.github/workflows/deno.yml @@ -0,0 +1,725 @@ +#!/data/data/com.termux/files/usr/bin/bash + +# إعداد الخيارات للتعامل مع الأخطاء +set -euo pipefail +IFS=$'\n\t' +clear + +echo "====== بدء إعداد وتشغيل نظام درع الأمة الذكي المتكامل بأداء متقدم ======" + +# تعريف المسارات +PROJECT_DIR="$HOME/smart_shield_project" +BACKEND_DIR="$PROJECT_DIR/backend" +FRONTEND_DIR="$PROJECT_DIR/frontend" +DB_DIR="$PROJECT_DIR/db" +LOG_DIR="$PROJECT_DIR/logs" +VENV_DIR="$PROJECT_DIR/venv" +CONFIG_FILE="$PROJECT_DIR/.env" +LOGFILE="$LOG_DIR/setup_$(date +'%Y%m%d-%H%M%S').log" + +# إنشاء المجلدات +mkdir -p "$PROJECT_DIR" "$BACKEND_DIR" "$FRONTEND_DIR" "$DB_DIR" "$LOG_DIR" "$PROJECT_DIR/scripts" + +echo "[1] تحديث النظام وتثبيت الحزم الأساسية..." | tee -a "$LOGFILE" +pkg update -y && pkg upgrade -y | tee -a "$LOGFILE" +pkg install -y python clang git openssl libffi libsqlite termux-api curl wget nano redis | tee -a "$LOGFILE" + +echo "[2] إنشاء وتفعيل البيئة الافتراضية..." | tee -a "$LOGFILE" +if [ ! -d "$VENV_DIR" ]; then + python3 -m venv "$VENV_DIR" | tee -a "$LOGFILE" +fi +source "$VENV_DIR/bin/activate" +pip install --upgrade pip setuptools wheel | tee -a "$LOGFILE" + +echo "[3] إعداد ملف متطلبات النظام..." | tee -a "$LOGFILE" +cat > "$PROJECT_DIR/requirements.txt" < "$CONFIG_FILE" < "$BACKEND_DIR/database.py" <<'PYTHON_DB' +from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from datetime import datetime +import os + +Base = declarative_base() + +class Transaction(Base): + __tablename__ = "transactions" + id = Column(Integer, primary_key=True, index=True) + source = Column(String(128)) + amount = Column(Float) + timestamp = Column(DateTime, default=datetime.utcnow) + +class ThreatAnalysis(Base): + __tablename__ = "threat_analyses" + id = Column(Integer, primary_key=True, index=True) + news_snippet = Column(String(2048)) + transaction_amount = Column(Float) + threat_level = Column(String(64)) + timestamp = Column(DateTime, default=datetime.utcnow) + +db_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "db", "smart_shield.db") +engine = create_engine(f"sqlite:///{db_path.replace(os.sep, '/')}") +Base.metadata.create_all(engine) +SessionLocal = sessionmaker(bind=engine) +PYTHON_DB + +# backend/main.py +cat > "$BACKEND_DIR/main.py" <<'PYTHON_API' +import logging +from fastapi import FastAPI, HTTPException, Depends, status +from fastapi.middleware.cors import CORSMiddleware +from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm +from pydantic import BaseModel +from sqlalchemy.orm import Session +import random, os, requests, redis, aiohttp, asyncio +from transformers import pipeline +from datetime import datetime +from passlib.context import CryptContext +from jose import JWTError, jwt +from backend.database import SessionLocal, Transaction, ThreatAnalysis +from dotenv import load_dotenv +from apscheduler.schedulers.asyncio import AsyncIOScheduler +import aiosmtplib +from email.message import EmailMessage + +logging.basicConfig(filename="logs/app.log", level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s") +logger = logging.getLogger(__name__) + +load_dotenv(dotenv_path="../.env") + +XAI_API_KEY = os.getenv("XAI_API_KEY") +HUGGINGFACE_API_KEY = os.getenv("HUGGINGFACE_API_KEY") +NOTIFICATION_EMAIL = os.getenv("NOTIFICATION_EMAIL") +SMTP_HOST = os.getenv("SMTP_HOST") +SMTP_PORT = int(os.getenv("SMTP_PORT", 587)) +SMTP_USER = os.getenv("SMTP_USER") +SMTP_PASSWORD = os.getenv("SMTP_PASSWORD") +JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY") +ALGORITHM = "HS256" + +app = FastAPI(title="درع الأمة الذكي - النظام المتكامل", version="6.0") + +app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:8080"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +try: + redis_client = redis.Redis(host=os.getenv("REDIS_HOST", "localhost"), + port=int(os.getenv("REDIS_PORT", 6379)), + decode_responses=True) + redis_client.ping() + logger.info("متصل بخادم Redis بنجاح") +except Exception as e: + logger.warning(f"فشل الاتصال بـ Redis: {e}. سيتم استخدام تخزين محلي مبسط") + redis_client = None + +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") +scheduler = AsyncIOScheduler() +scheduler.start() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +async def send_email(subject: str, content: str, to_email: str): + if not all([SMTP_HOST, SMTP_USER, SMTP_PASSWORD]): + logger.warning("بيانات SMTP ناقصة، لم يتم إرسال البريد الإلكتروني.") + return + msg = EmailMessage() + msg["Subject"] = subject + msg["From"] = SMTP_USER + msg["To"] = to_email + msg.set_content(content) + try: + await aiosmtplib.send(msg, hostname=SMTP_HOST, port=SMTP_PORT, + start_tls=True, username=SMTP_USER, password=SMTP_PASSWORD) + logger.info(f"تم إرسال رسالة تنبيه عبر البريد إلى {to_email}") + except Exception as ex: + logger.error(f"فشل إرسال البريد الإلكتروني: {ex}") + +class ThreatData(BaseModel): + news_snippet: str + transaction_amount: float + +finance_sources = [ + {"name": "أوقاف إسلامية", "ratio": 0.30, "range": (5000, 10000)}, + {"name": "تبرعات المقاومين", "ratio": 0.20, "range": (2000, 5000)}, + {"name": "استثمارات استراتيجية", "ratio": 0.25, "range": (3000, 8000)}, + {"name": "تمويل تجاري", "ratio": 0.25, "range": (10000, 20000)}, +] + +try: + local_model = pipeline("text-classification", model="distilbert-base-uncased", + device=-1) # CPU فقط لـ Termux + logger.info("تم تحميل نموذج DistilBERT بنجاح") +except Exception as e: + local_model = None + logger.warning(f"فشل تحميل النموذج المحلي: {e}. سيتم استخدام القواعد البرمجية.") + +def verify_password(plain_password, hashed_password): + return pwd_context.verify(plain_password, hashed_password) + +def get_password_hash(password): + return pwd_context.hash(password) + +async def verify_token(token: str = Depends(oauth2_scheme)): + try: + payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[ALGORITHM]) + username = payload.get("sub") + if not username: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="اعتماد غير صالح") + return username + except JWTError: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="اعتماد غير صالح") + +@app.post("/token", summary="تسجيل دخول المستخدم") +async def login(form_data: OAuth2PasswordRequestForm = Depends()): + if form_data.username == "admin" and form_data.password == "smartshield2025": + token = jwt.encode({"sub": form_data.username}, JWT_SECRET_KEY, algorithm=ALGORITHM) + return {"access_token": token, "token_type": "bearer"} + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="بيانات اعتماد غير صحيحة") + +@app.get("/add_transaction", summary="جمع تمويل جديد") +def add_transaction(db: Session = Depends(get_db), current_user: str = Depends(verify_token)): + source = random.choice(finance_sources) + amount = random.uniform(*source["range"]) * source["ratio"] + transaction = Transaction(source=source["name"], amount=amount) + db.add(transaction) + db.commit() + db.refresh(transaction) + logger.info(f"تم إنشاء معاملة جديدة من {source['name']} بمبلغ {amount:.2f}") + return {"source": transaction.source, "amount": transaction.amount, + "timestamp": int(transaction.timestamp.timestamp() * 1000)} + +@app.get("/launch_defense", summary="إطلاق دفاع يدوي") +def launch_defense(current_user: str = Depends(verify_token)): + success = random.random() > 0.2 + if success: + logger.info("تم تحييد التهديد بنجاح") + return {"success": True, "message": "تم تحييد التهديد بنجاح."} + else: + logger.error("فشل تحييد التهديد") + return {"success": False, "message": "فشل في تحييد التهديد، يرجى المحاولة لاحقا."} + +@app.post("/analyze_threat", summary="تحليل تهديد نصي") +async def analyze_threat(data: ThreatData, db: Session = Depends(get_db), + current_user: str = Depends(verify_token)): + cache_key = f"threat:{data.news_snippet}:{data.transaction_amount}" + if redis_client and redis_client.exists(cache_key): + threat_level = redis_client.get(cache_key) + logger.info("تم جلب مستوى التهديد من التخزين المؤقت") + else: + prompt = (f"قيم مستوى خطورة التهديد التالي: '{data.news_snippet}'. " + f"مبلغ التمويل: {data.transaction_amount} دولار. " + f"صنف المستوى: منخفض، متوسط، مرتفع، حرج.") + threat_level = "منخفض" + if XAI_API_KEY: + try: + async with aiohttp.ClientSession() as session: + async with session.post( + "https://api.x.ai/v1/chat/completions", + headers={"Authorization": f"Bearer {XAI_API_KEY}", "Content-Type": "application/json"}, + json={ + "model": "grok", + "messages": [{"role": "user", "content": prompt}], + "max_tokens": 50, + "temperature": 0.7 + }) as resp: + resp.raise_for_status() + result = await resp.json() + threat_level = result["choices"][0]["message"]["content"].strip() + logger.info("تحليل عبر Grok API ناجح") + except Exception as ex: + logger.error(f"فشل Grok API: {ex}") + elif HUGGINGFACE_API_KEY: + try: + resp = requests.post( + "https://api-inference.huggingface.co/models/distilbert-base-uncased", + headers={"Authorization": f"Bearer {HUGGINGFACE_API_KEY}"}, + json={"inputs": prompt}) + resp.raise_for_status() + threat_level = resp.json()[0]["label"] + logger.info("تحليل عبر HuggingFace API ناجح") + except Exception as ex: + logger.error(f"فشل HuggingFace API: {ex}") + elif local_model: + try: + result = local_model(data.news_snippet)[0]["label"] + threat_level = "مرتفع" if result == "POSITIVE" else "منخفض" + logger.info("تحليل عبر النموذج المحلي ناجح") + except Exception as ex: + logger.error(f"فشل نموذج التحليل المحلي: {ex}") + else: + keywords = { + "حرج": ["هجوم إرهابي", "تفجير", "سلاح نووي", "حرب شاملة"], + "مرتفع": ["هجوم", "عنف", "تدمير", "تمويل مشبوه"], + "متوسط": ["تهديد", "خطر", "تحذير", "مخاطر"], + "منخفض": [] + } + for level, words in keywords.items(): + if any(word in data.news_snippet for word in words): + threat_level = level + break + if data.transaction_amount > 10000 and threat_level != "حرج": + threat_level = "مرتفع" if threat_level == "منخفض" else threat_level + logger.info("تحليل عبر قواعد برمجية") + + if redis_client: + redis_client.setex(cache_key, 3600, threat_level) + db.add(ThreatAnalysis(news_snippet=data.news_snippet, + transaction_amount=data.transaction_amount, + threat_level=threat_level)) + db.commit() + + if NOTIFICATION_EMAIL and threat_level in ["مرتفع", "حرج"]: + await send_email(f"تنبيه تهديد {threat_level}", + f"تم اكتشاف تهديد: {data.news_snippet}", + NOTIFICATION_EMAIL) + return {"threat_level": threat_level} + +def scheduled_collect_funds(): + with SessionLocal() as db: + source = random.choice(finance_sources) + amount = random.uniform(*source["range"]) * source["ratio"] + transaction = Transaction(source=source["name"], amount=amount) + db.add(transaction) + db.commit() + logger.info(f"تم جمع التمويل تلقائيًا: {source['name']} - {amount:.2f} دولار") + +scheduler.add_job(scheduled_collect_funds, 'interval', minutes=5) + +@app.get("/generate_report", summary="توليد تقرير التمويل") +def generate_report(db: Session = Depends(get_db), current_user: str = Depends(verify_token)): + transactions = db.query(Transaction).order_by(Transaction.timestamp.desc()).limit(10).all() + total_funds = sum(t.amount for t in db.query(Transaction).all()) + source_totals = {} + for t in db.query(Transaction).all(): + source_totals[t.source] = source_totals.get(t.source, 0) + t.amount + + report_lines = [ + "تقرير التمويل - درع الأمة الذكي", + f"التاريخ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", + f"إجمالي الأموال المجمعة: {total_funds:.2f} دولار", + f"عدد المعاملات: {db.query(Transaction).count()}", + "تفاصيل المعاملات (آخر 10):", + ] + for t in transactions: + line = f"- {t.source}: {t.amount:.2f} دولار ({t.timestamp.strftime('%Y-%m-%d %H:%M:%S')})" + report_lines.append(line) + report_lines.append("إجمالي التمويل حسب المصدر:") + for source, total in source_totals.items(): + report_lines.append(f"- {source}: {total:.2f} دولار") + report_text = "\n".join(report_lines) + logger.info("تم إنشاء تقرير التمويل") + return {"report_text": report_text, "chart_data": source_totals} +PYTHON_API + +# frontend/index.html +cat > "$FRONTEND_DIR/index.html" <<'HTML_FRONTEND' + + + + + +درع الأمة الذكي - النسخة المتطورة + + + + + +
+
+

درع الأمة الذكي

تمويل ذكي - دفاع ذكي - تحليل آلي

+ +
+

تسجيل الدخول

+ + + +
+ +
+

التمويل التلقائي

+
إجمالي التمويل: 0 دولار
+ +
+
+ +
+

نظام الدفاع

+ + + + +

+
+
+
+
+ + + + + +HTML_FRONTEND + +echo "[7] التحقق من المنافذ..." | tee -a "$LOGFILE" +for port in 8000 8080 6379; do + if lsof -ti tcp:$port &>/dev/null; then + pid=$(lsof -ti tcp:$port) + echo "تحذير: المنفذ $port مستخدم (PID=$pid). يتم إغلاقه..." | tee -a "$LOGFILE" + kill -9 "$pid" + fi +done + +echo "[8] بدء تشغيل خادم Redis..." | tee -a "$LOGFILE" +redis-server --daemonize yes || { echo "فشل تشغيل Redis" | tee -a "$LOGFILE"; exit 1; } + +echo "[9] بدء تشغيل خادم FastAPI وHTTP Frontend..." | tee -a "$LOGFILE" +uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload & +UVICORN_PID=$! +sleep 2 +if ! ps -p $UVICORN_PID > /dev/null; then + echo "فشل تشغيل FastAPI" | tee -a "$LOGFILE" + exit 1 +fi + +python3 -m http.server --directory "$FRONTEND_DIR" 8080 & +HTTP_PID=$! +sleep 2 +if ! ps -p $HTTP_PID > /dev/null; then + echo "فشل تشغيل خادم HTTP" | tee -a "$LOGFILE" + exit 1 +fi + +# تنظيف الخوادم عند الإغلاق +trap "echo 'إيقاف الخوادم...' | tee -a $LOGFILE; kill -9 $UVICORN_PID $HTTP_PID 2>/dev/null; redis-cli shutdown 2>/dev/null; exit" EXIT INT TERM + +# فتح الواجهة في متصفح أندرويد +if command -v termux-open &>/dev/null; then + echo "فتح الواجهة في المتصفح..." | tee -a "$LOGFILE" + termux-open http://localhost:8080/index.html +else + echo "افتح المتصفح واذهب إلى http://localhost:8080/index.html" | tee -a "$LOGFILE" +fi + +echo -e "\n==== النظام قيد التشغيل ====" | tee -a "$LOGFILE" +echo "لتسجيل الدخول: اسم المستخدم: admin، كلمة المرور: smartshield2025" | tee -a "$LOGFILE" +echo "لإيقاف الخدمات: kill -9 $UVICORN_PID $HTTP_PID; redis-cli shutdown" | tee -a "$LOGFILE" +echo "السجلات: $LOGFILE" | tee -a "$LOGFILE" + +# الانتظار للحفاظ على السكريبت نشطًا +wait# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow will install Deno then run `deno lint` and `deno test`. +# For more information see: https://github.com/denoland/setup-deno + +name: Deno + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Setup repo + uses: actions/checkout@v4 + + - name: Setup Deno + # uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@61fe2df320078202e33d7d5ad347e7dcfa0e8f31 # v1.1.2 + with: + deno-version: v1.x + + # Uncomment this step to verify the use of 'deno fmt' on each commit. + # - name: Verify formatting + # run: deno fmt --check + + - name: Run linter + run: deno lint + + - name: Run tests + run: deno test -A diff --git a/.github/workflows/gatsby.yml b/.github/workflows/gatsby.yml new file mode 100644 index 0000000..9aaecfe --- /dev/null +++ b/.github/workflows/gatsby.yml @@ -0,0 +1,97 @@ +# Sample workflow for building and deploying a Gatsby site to GitHub Pages +# +# To get started with Gatsby see: https://www.gatsbyjs.com/docs/quick-start/ +# +name: Deploy Gatsby site to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +# Default to bash +defaults: + run: + shell: bash + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Detect package manager + id: detect-package-manager + run: | + if [ -f "${{ github.workspace }}/yarn.lock" ]; then + echo "manager=yarn" >> $GITHUB_OUTPUT + echo "command=install" >> $GITHUB_OUTPUT + exit 0 + elif [ -f "${{ github.workspace }}/package.json" ]; then + echo "manager=npm" >> $GITHUB_OUTPUT + echo "command=ci" >> $GITHUB_OUTPUT + exit 0 + else + echo "Unable to determine package manager" + exit 1 + fi + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: ${{ steps.detect-package-manager.outputs.manager }} + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + with: + # Automatically inject pathPrefix in your Gatsby configuration file. + # + # You may remove this line if you want to manage the configuration yourself. + static_site_generator: gatsby + - name: Restore cache + uses: actions/cache@v4 + with: + path: | + public + .cache + key: ${{ runner.os }}-gatsby-build-${{ hashFiles('public') }} + restore-keys: | + ${{ runner.os }}-gatsby-build- + - name: Install dependencies + run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} + - name: Build with Gatsby + env: + PREFIX_PATHS: 'true' + run: ${{ steps.detect-package-manager.outputs.manager }} run build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./public + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml new file mode 100644 index 0000000..f2c9e97 --- /dev/null +++ b/.github/workflows/static.yml @@ -0,0 +1,43 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: '.' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/au b/au new file mode 100644 index 0000000..7517130 --- /dev/null +++ b/au @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +TruthGuardian 2.0 - نظام مراقبة وحماية متقدم لـ Termux +""" + +import os +import sys +import time +import logging +import hashlib +import json +import yaml +import threading +from datetime import datetime +import telegram +from dotenv import load_dotenv + +# إعداد تسجيل الأحداث +logging.basicConfig( + level=logging.INFO, + format="[%(asctime)s][%(levelname)s] %(message)s", + handlers=[logging.StreamHandler(sys.stdout)] +) +log = logging.getLogger() + +# تحميل متغيرات البيئة +load_dotenv() +TELEGRAM_TOKEN = os.getenv("TELEGRAM_TOKEN") +TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID") +tg_bot = telegram.Bot(token=TELEGRAM_TOKEN) if TELEGRAM_TOKEN else None + +# تحميل ملف التكوين +CONFIG_PATH = os.path.join(os.environ["HOME"], "truthguardian_config.yaml") +DEFAULT_CONFIG = { + "monitored_files": [ + "/etc/passwd", + "/etc/hosts", + f"{os.environ['HOME']}/.bashrc" + ], + "scan_interval": 30, + "log_interval": 300, + "suspicious_patterns": ["password", "secret", "key", "token", "auth"] +} + +def load_config(): + try: + if os.path.exists(CONFIG_PATH): + with open(CONFIG_PATH, 'r') as f: + return yaml.safe_load(f) + else: + with open(CONFIG_PATH, 'w') as f: + yaml.safe_dump(DEFAULT_CONFIG, f) + return DEFAULT_CONFIG + except Exception as e: + log.error(f"خطأ في تحميل التكوين: {e}") + return DEFAULT_CONFIG + +# =============================== +# مراقبة النظام +# =============================== +class SystemMonitor: + def __init__(self): + self.metrics = {} + + def get_cpu_usage(self): + def get_cpu_stats(): + try: + with open('/proc/stat') as f: + line = f.readline() + if line.startswith('cpu '): + parts = line.split() + return sum(int(p) for p in parts[1:]), int(parts[4]) + except: + return 0, 0 + + total1, idle1 = get_cpu_stats() + time.sleep(1.0) # زيادة الفاصل الزمني لتحسين الدقة + total2, idle2 = get_cpu_stats() + total_diff = total2 - total1 + idle_diff = idle2 - idle1 + return 100 * (total_diff - idle_diff) / total_diff if total_diff > 0 else 0 + + def get_memory_usage(self): + try: + with open('/proc/meminfo') as f: + lines = f.readlines() + mem_info = {line.split()[0].rstrip(':'): int(line.split()[1]) for line in lines if len(line.split()) >= 2} + total = mem_info.get('MemTotal', 0) + available = mem_info.get('MemAvailable', 0) + return 100 * (total - available) / total if total > 0 else 0 + except: + return 0 + + def get_network_usage(self): + try: + with open('/proc/net/dev') as f: + lines = f.readlines() + for line in lines: + if 'wlan0' in line: # افتراض واجهة الشبكة + parts = line.split() + return int(parts[1]), int(parts[9]) # bytes received, sent + return 0, 0 + except: + return 0, 0 + + def collect_metrics(self): + rx1, tx1 = self.get_network_usage() + time.sleep(1.0) + rx2, tx2 = self.get_network_usage() + self.metrics = { + 'timestamp': datetime.now().isoformat(), + 'cpu_usage': round(self.get_cpu_usage(), 2), + 'memory_usage': round(self.get_memory_usage(), 2), + 'network_rx': round((rx2 - rx1) / 1024, 2), # KB/s + 'network_tx': round((tx2 - tx1) / 1024, 2) # KB/s + } + return self.metrics + +# =============================== +# سلامة الملفات +# =============================== +class FileIntegrityChecker: + def __init__(self): + self.checksums = {} + + def calculate_hash(self, filepath): + try: + hasher = hashlib.sha256() + with open(filepath, 'rb') as f: + for chunk in iter(lambda: f.read(8192), b""): # زيادة حجم القطعة + hasher.update(chunk) + return hasher.hexdigest() + except Exception as e: + log.error(f"خطأ في حساب التجزئة لـ {filepath}: {e}") + return None + + def monitor_file(self, filepath): + current_hash = self.calculate_hash(filepath) + if current_hash is None: + return False + if filepath in self.checksums: + if self.checksums[filepath] != current_hash: + log.warning(f"⚠️ تغيير في الملف: {filepath}") + if tg_bot and TELEGRAM_CHAT_ID: + tg_bot.send_message(chat_id=TELEGRAM_CHAT_ID, text=f"⚠️ تم تغيير الملف: {filepath}") + return False + else: + log.info(f"بدء مراقبة الملف: {filepath}") + self.checksums[filepath] = current_hash + return True + +# =============================== +# النظام الرئيسي +# =============================== +class TruthGuardian: + def __init__(self): + self.config = load_config() + self.monitor = SystemMonitor() + self.integrity_checker = FileIntegrityChecker() + self.running = False + self.monitored_files = [f for f in self.config['monitored_files'] if os.path.exists(f)] + + def start(self): + log.info("🚀 بدء تشغيل TruthGuardian 2.0") + self.running = True + log.info(f"جاري مراقبة {len(self.monitored_files)} ملف") + + # تشغيل المراقبة في خيط منفصل + monitor_thread = threading.Thread(target=self.run_monitoring) + monitor_thread.start() + monitor_thread.join() + + def run_monitoring(self): + iteration = 0 + while self.running: + try: + iteration += 1 + log.info(f"=== دورة المراقبة #{iteration} ===") + + # جمع بيانات النظام + metrics = self.monitor.collect_metrics() + log.info(f"📊 الأداء: CPU={metrics['cpu_usage']}%, RAM={metrics['memory_usage']}%, " + f"RX={metrics['network_rx']} KB/s, TX={metrics['network_tx']} KB/s") + + # مراقبة الملفات + for filepath in self.monitored_files: + self.integrity_checker.monitor_file(filepath) + + # حفظ السجلات + if iteration % (self.config['log_interval'] // self.config['scan_interval']) == 0: + self.save_logs(metrics) + + time.sleep(self.config['scan_interval']) + + except KeyboardInterrupt: + log.info("تم إيقاف التشغيل بواسطة المستخدم") + self.stop() + except Exception as e: + log.error(f"خطأ غير متوقع: {e}") + time.sleep(60) + + def save_logs(self, metrics): + try: + log_dir = os.path.join(os.environ['HOME'], 'truthguardian_logs') + os.makedirs(log_dir, exist_ok=True) + log_file = os.path.join(log_dir, f"log_{datetime.now().strftime('%Y%m%d_%H%M')}.json") + with open(log_file, 'w') as f: + json.dump({ + 'timestamp': datetime.now().isoformat(), + 'metrics': metrics, + 'monitored_files': self.monitored_files, + 'file_checksums': self.integrity_checker.checksums + }, f, indent=2) + log.info(f"تم حفظ السجلات في: {log_file}") + except Exception as e: + log.error(f"خطأ في حفظ السجلات: {e}") + + def stop(self): + log.info("🛑 إيقاف TruthGuardian 2.0") + self.running = False + +# =============================== +# نقطة الدخول +# =============================== +def main(): + print("=" * 50) + print("TruthGuardian 2.0 - نظام المراقبة والحماية المتقدم") + print("مصمم خصيصًا لـ Termux") + print("=" * 50) + + system = TruthGuardian() + try: + system.start() + except Exception as e: + log.error(f"فشل تشغيل النظام: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file