feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل

قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة
ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ.

الخريطة:
  backend · payment_server · loction_server · ride_server ·
  passenger_server · docker · dashboard · stress_test  → الجذر
  siro_rider  → apps/rider          siro_driver  → apps/driver
  siro_admin  → dashboards/admin    siro_service → dashboards/service
  android_bot → apps/android_bot    socialBot    → apps/socialBot

نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب)
لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً:
كل ما يلي يصير فرقاً مقروءاً مقابل المصدر.

لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز،
سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh
(ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في
مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و
dashboards/transit-web).

⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة:
1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر):
   كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner.
2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist)
   يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً.
3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع →
   يجب ضمّ الحزم داخله أسوة بـ apps/rider.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-07-27 05:14:13 +03:00
co-authored by Claude Opus 5
parent 9909d9b4c1
commit 4d8414c96b
3198 changed files with 766859 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
import UIKit
import Flutter
import FirebaseCore
import CoreLocation
@main
@objc class AppDelegate: FlutterAppDelegate {
let locationManager = CLLocationManager()
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Now continue with the rest of the app initialization.
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
// التأكد من أن الجهاز غير مخترق قبل تشغيل التطبيق
if SecurityChecks.isDeviceCompromised() {
showSecurityAlert()
return false
}
// تهيئة قنوات الاتصال مع Flutter
setupMethodChannel()
// ضبط مدير الموقع لمتابعة تغييرات الأذونات
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// MARK: - تهيئة القناة بين Swift و Flutter
func setupMethodChannel() {
guard let controller = window?.rootViewController as? FlutterViewController else {
return
}
let channel = FlutterMethodChannel(name: "com.siro.siro_driver/security",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler { call, result in
switch call.method {
case "isNativeRooted":
result(SecurityChecks.isDeviceCompromised())
default:
result(FlutterMethodNotImplemented)
}
}
}
// MARK: - عرض تنبيه عند اكتشاف جهاز مخترق
func showSecurityAlert() {
guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else {
exit(0)
}
let alert = UIAlertController(
title: "Security Warning".localized,
message: "Compromised device detected. Exiting.".localized,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK".localized, style: .destructive) { _ in
self.obfuscatedExit()
})
if #available(iOS 15.0, *) {
alert.popoverPresentationController?.sourceView = rootVC.view
alert.popoverPresentationController?.sourceRect = CGRect(x: rootVC.view.bounds.midX, y: rootVC.view.bounds.midY, width: 0, height: 0)
alert.popoverPresentationController?.permittedArrowDirections = []
alert.presentationController?.delegate = self
if let presentationController = alert.presentationController as? UISheetPresentationController {
presentationController.detents = [.medium()]
presentationController.preferredCornerRadius = 20
presentationController.prefersEdgeAttachedInCompactHeight = true
presentationController.prefersGrabberVisible = false
}
}
rootVC.present(alert, animated: true, completion: nil)
}
// MARK: - إخفاء عملية الخروج بطريقة مشفرة
func obfuscatedExit() {
let selector = NSSelectorFromString(String(format: "%@%@", "ex", "it:"))
if responds(to: selector) {
perform(selector, with: 0)
}
}
}
// MARK: - التعامل مع أذونات الموقع بطريقة آمنة
extension AppDelegate: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
if #available(iOS 14.0, *) {
let status = manager.authorizationStatus
switch status {
case .authorizedWhenInUse, .authorizedAlways:
print("Authorization granted")
case .denied, .restricted:
print("Authorization denied")
case .notDetermined:
manager.requestWhenInUseAuthorization()
@unknown default:
break
}
} else {
// لنظام iOS 13 وما قبله، نستخدم الطريقة القديمة
let status = CLLocationManager.authorizationStatus()
switch status {
case .authorizedWhenInUse, .authorizedAlways:
print("Authorization granted")
case .denied, .restricted:
print("Authorization denied")
case .notDetermined:
manager.requestWhenInUseAuthorization()
@unknown default:
break
}
}
}
}
// MARK: - منع إغلاق التنبيهات الأمنية
extension AppDelegate: UIAdaptivePresentationControllerDelegate {
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
return false
}
}
// MARK: - دعم الترجمة للنصوص
extension String {
var localized: String {
return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "")
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

@@ -0,0 +1,158 @@
{
"images": [
{
"size": "20x20",
"idiom": "iphone",
"filename": "40.png",
"scale": "2x"
},
{
"size": "20x20",
"idiom": "iphone",
"filename": "60.png",
"scale": "3x"
},
{
"size": "29x29",
"idiom": "iphone",
"filename": "29.png",
"scale": "1x"
},
{
"size": "29x29",
"idiom": "iphone",
"filename": "58.png",
"scale": "2x"
},
{
"size": "29x29",
"idiom": "iphone",
"filename": "87.png",
"scale": "3x"
},
{
"size": "40x40",
"idiom": "iphone",
"filename": "80.png",
"scale": "2x"
},
{
"size": "40x40",
"idiom": "iphone",
"filename": "120.png",
"scale": "3x"
},
{
"size": "57x57",
"idiom": "iphone",
"filename": "57.png",
"scale": "1x"
},
{
"size": "57x57",
"idiom": "iphone",
"filename": "114.png",
"scale": "2x"
},
{
"size": "60x60",
"idiom": "iphone",
"filename": "120.png",
"scale": "2x"
},
{
"size": "60x60",
"idiom": "iphone",
"filename": "180.png",
"scale": "3x"
},
{
"size": "20x20",
"idiom": "ipad",
"filename": "20.png",
"scale": "1x"
},
{
"size": "20x20",
"idiom": "ipad",
"filename": "40.png",
"scale": "2x"
},
{
"size": "29x29",
"idiom": "ipad",
"filename": "29.png",
"scale": "1x"
},
{
"size": "29x29",
"idiom": "ipad",
"filename": "58.png",
"scale": "2x"
},
{
"size": "40x40",
"idiom": "ipad",
"filename": "40.png",
"scale": "1x"
},
{
"size": "40x40",
"idiom": "ipad",
"filename": "80.png",
"scale": "2x"
},
{
"size": "50x50",
"idiom": "ipad",
"filename": "50.png",
"scale": "1x"
},
{
"size": "50x50",
"idiom": "ipad",
"filename": "100.png",
"scale": "2x"
},
{
"size": "72x72",
"idiom": "ipad",
"filename": "72.png",
"scale": "1x"
},
{
"size": "72x72",
"idiom": "ipad",
"filename": "144.png",
"scale": "2x"
},
{
"size": "76x76",
"idiom": "ipad",
"filename": "76.png",
"scale": "1x"
},
{
"size": "76x76",
"idiom": "ipad",
"filename": "152.png",
"scale": "2x"
},
{
"size": "83.5x83.5",
"idiom": "ipad",
"filename": "167.png",
"scale": "2x"
},
{
"size": "1024x1024",
"idiom": "ios-marketing",
"filename": "1024.png",
"scale": "1x"
}
],
"info": {
"version": 1,
"author": "xcode"
}
}
@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

@@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
@@ -0,0 +1,97 @@
import CarPlay
import MapKit
class CarPlaySceneDelegate: NSObject {
var interfaceController: CPInterfaceController?
var mapTemplate: CPMapTemplate?
var navigationSession: CPNavigationSession?
// MARK: - Navigation Actions
func startNavigation(
instruction: String,
distance: Double,
eta: Double,
maneuverType: Int
) {
guard let mapTemplate = mapTemplate else { return }
let origin = MKMapItem(
placemark: MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: 0, longitude: 0))
)
let destination = MKMapItem(
placemark: MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: 0, longitude: 0))
)
let trip = CPTrip(origin: origin, destination: destination)
let session = mapTemplate.startNavigationSession(for: trip)
self.navigationSession = session
updateManeuver(instruction: instruction, distance: distance, maneuverType: maneuverType)
updateArrivalEstimates(eta: eta)
}
func updateManeuver(instruction: String, distance: Double, maneuverType: Int) {
guard let session = navigationSession else { return }
let maneuver = CPManeuver()
maneuver.instructionVariants = [instruction]
if let color = maneuverColor(for: maneuverType) {
maneuver.symbolColor = color
}
let distanceEstimate = CPTravelEstimates(
distance: Measurement(value: distance, unit: UnitLength.meters),
timeRemaining: 0
)
session.updateManeuvers([maneuver], travelEstimates: distanceEstimate)
}
func updateArrivalEstimates(eta: Double) {
guard let session = navigationSession else { return }
let arrivalEstimate = CPTravelEstimates(
distance: Measurement(value: 0, unit: UnitLength.meters),
timeRemaining: eta
)
// `updatingArrival` is deprecated; for iOS 15+ use `updating(_:)` on the maneuver's arrivalEstimates.
// We keep this for broad compatibility.
session.updatingArrival(to: arrivalEstimate)
}
func updateLocation(lat: Double, lng: Double, bearing: Double) {
let center = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let region = MKCoordinateRegion(
center: center,
span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
)
mapTemplate?.showPanningInterface(animated: true)
}
func stopNavigation() {
guard let session = navigationSession else { return }
session.cancel()
self.navigationSession = nil
mapTemplate?.hideTripPreviews()
}
// MARK: - Helpers
private func maneuverColor(for type: Int) -> UIColor? {
switch type {
case 4: return .systemGreen
case 2, -2: return .systemBlue
default: return nil
}
}
}
// MARK: - Shared State
class CarPlayState {
static let shared = CarPlayState()
weak var sceneDelegate: CarPlaySceneDelegate?
private init() {}
}
+13
View File
@@ -0,0 +1,13 @@
//
// Constants.swift
// Runner
//
// Created by Hamza Aleghwairyeen on 26/07/2025.
//
import Foundation
struct Constants {
static let googleMapsAPIKey = "AIzaSyDzGO9a-1IDMLD2FxhmOO9ONL1gMssFa9g"
}
+140
View File
@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Siro Driver</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleGetInfoString</key>
<string></string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>siro_driver</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>siromove.com</string>
<key>CFBundleURLSchemes</key>
<array>
<string>siromove</string>
</array>
</dict>
</array>
<key>FlutterDeepLinkingEnabled</key>
<true/>
<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>
<key>GMSApiKey</key>
<string>YOUR_API_KEY</string>
<key>LSApplicationCategoryType</key>
<string></string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlechromes</string>
<string>comgooglemaps</string>
<string>whatsapp</string>
</array>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSBonjourServices</key>
<array>
<string>_dartVmService._tcp</string>
<string>_dartobservatory._tcp</string>
</array>
<key>NSCameraUsageDescription</key>
<string>This app requires access to your camera in order to scan QR codes and capture images
for uploading and access to connect to a call.</string>
<key>NSContactsUsageDescription</key>
<string>This app requires contacts access to function properly.</string>
<key>NSFaceIDUsageDescription</key>
<string>Use Face ID to securely authenticate payment accounts.</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>NSLocalNetworkUsageDescription</key>
<string>Allow debugging over the local network.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to your location to provide you with the best ride experience.
Your location data will be used to find the nearest available cars and connect you with
the closest captain for efficient and convenient rides.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to your location to provide you with the best ride experience.
Your location data will be used to find the nearest available cars and connect you with
the closest captain for efficient and convenient rides.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires access to your microphone to record audio, allowing you to add
voice recordings to your photos and videos and access to connect to a call.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to your photo library to allow you to upload and manage
images.</string>
<key>CPApplication</key>
<array>
<dict>
<key>CPApplicationDriverManeuver</key>
<dict>
<key>supportsAudio</key>
<false/>
<key>supportsCommunication</key>
<false/>
<key>supportsNavigation</key>
<true/>
</dict>
</dict>
</array>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>location</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
@@ -0,0 +1,27 @@
//
// JailbreakDetection.swift
// Runner
//
// Created by Hamza Aleghwairyeen on 26/07/2025.
//
import Foundation
class JailbreakDetection {
static func isJailbroken() -> Bool {
let paths = [
"/Applications/Cydia.app",
"/Library/MobileSubstrate/MobileSubstrate.dylib",
"/usr/sbin/sshd",
"/etc/apt"
]
for path in paths {
if FileManager.default.fileExists(atPath: path) {
return true
}
}
return false
}
}
@@ -0,0 +1,2 @@
#import "GeneratedPluginRegistrant.h"
#import "SecurityChecks.h"
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>
+20
View File
@@ -0,0 +1,20 @@
//
// SecurityChecks.h
// Runner
//
// Created by Hamza Aleghwairyeen on 26/07/2025.
//
#ifndef SecurityChecks_h
#define SecurityChecks_h
#endif /* SecurityChecks_h */
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> // Import UIKit
@interface SecurityChecks : NSObject
+ (BOOL)isDeviceCompromised; // Combined check
@end
+198
View File
@@ -0,0 +1,198 @@
//
// SecurityChecks.m
// Runner
//
// Created by Hamza Aleghwairyeen on 26/07/2025.
//
#import <Foundation/Foundation.h>
#import "SecurityChecks.h"
#import <sys/stat.h>
#include <dlfcn.h>
#import <sys/sysctl.h>
#include <mach-o/dyld.h> // For _dyld_image_count and _dyld_get_image_name
#include <unistd.h> // for fork()
#include <sys/socket.h> //for socket, connect
#include <netinet/in.h> // for sockaddr_in
#include <arpa/inet.h> // for inet_pton
@implementation SecurityChecks
+ (BOOL)isDeviceJailbroken {
// (Same jailbreak checks as before - from previous responses)
// 1. Check for common jailbreak files
NSArray *jailbreakPaths = @[
@"/Applications/Cydia.app",
// #if !TARGET_IPHONE_SIMULATOR
// @"/bin/bash",
// #endif
@"/Library/MobileSubstrate/MobileSubstrate.dylib",
@"/bin/bash",
@"/usr/sbin/sshd",
@"/etc/apt",
@"/private/var/lib/apt/",
@"/private/var/tmp/cydia.log",
];
for (NSString *path in jailbreakPaths) {
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSLog(@"Jailbreak file detected: %@", path);
return YES;
}
}
// 2. Check if we can write outside the sandbox (a strong indicator)
NSError *error = nil;
NSString *testPath = @"/private/jailbreaktest.txt";
[@"test" writeToFile:testPath atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!error) {
// If we can write, it's jailbroken. Remove the file immediately.
[[NSFileManager defaultManager] removeItemAtPath:testPath error:nil];
NSLog(@"Sandbox write test indicates jailbreak.");
return YES;
}
//3: Check for existence of the symbolic link /Applications.
struct stat s;
if (lstat("/Applications", &s) == 0) {
if (S_ISLNK(s.st_mode)) {
NSLog(@"Symbolic link /Applications exists, jailbroken");
return YES;
}
}
//4:Check for dyld Libraries
uint32_t count = _dyld_image_count();
for (uint32_t i = 0 ; i < count ; ++i) {
const char *dyld = _dyld_get_image_name(i);
if (strstr(dyld, "MobileSubstrate") != NULL || strstr(dyld, "libcycript") != NULL) {
NSLog(@"Suspicious dyld library found: %s", dyld);
return YES;
}
}
//5 Check if fork() is available. Sandboxed apps should not be able to call fork().
#if !TARGET_IPHONE_SIMULATOR // Don't run this on the simulator
int pid = fork();
if (pid == 0)
{
//in child, exit immediately to avoid crashing.
exit(0);
} else if (pid > 0)
{
NSLog(@"Fork available. Likely jailbroken.");
return YES; // Fork succeeded; likely jailbroken
}
#endif
return NO; // No jailbreak indicators found
}
+ (BOOL)isDebuggerAttached {
int mib[4];
struct kinfo_proc info;
size_t size = sizeof(info);
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
sysctl(mib, 4, &info, &size, NULL, 0);
return (info.kp_proc.p_flag & P_TRACED) != 0;
}
// Check for Frida's default port
+ (BOOL)isFridaListeningOnDefaultPort {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
return NO; // Couldn't create socket
}
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(27042); // Default Frida port
inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr);
if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) != -1) {
NSLog(@"Frida default port (27042) is open.");
close(sock);
return YES;
}
close(sock);
return NO;
}
+ (BOOL)isFridaDetected {
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
size_t length;
struct kinfo_proc *procs, *proc;
sysctl(name, 3, NULL, &length, NULL, 0);
procs = malloc(length);
sysctl(name, 3, procs, &length, NULL, 0);
for (proc = procs; (char *)proc < (char *)procs + length; proc++) {
if (strstr(proc->kp_proc.p_comm, "frida") != NULL) {
free(procs);
return YES;
}
}
free(procs);
return NO;
}
// Check for loaded dylibs that indicate Frida
+(BOOL) checkForFridaDylib{
uint32_t count = _dyld_image_count();
for (uint32_t i = 0 ; i < count ; ++i) {
const char *dyld = _dyld_get_image_name(i);
if (strstr(dyld, "FridaGadget") != NULL) { // Look for FridaGadget
NSLog(@"FridaGadget dylib found: %s", dyld);
return YES;
}
}
return NO;
}
// Check process name
+ (BOOL)checkProcessName {
NSString* processName = [[NSProcessInfo processInfo] processName];
if ([processName containsString:@"Frida"]) {
return YES;
}
return NO;
}
// A combined check for jailbreak and Frida
+ (BOOL)isDeviceCompromised {
if ([SecurityChecks isDeviceJailbroken]) {
return YES;
}
if ([SecurityChecks isFridaListeningOnDefaultPort]) {
return YES;
}
if ([SecurityChecks checkForFridaDylib]) {
return YES;
}
if([SecurityChecks checkProcessName]){
return YES;
}
// if ([SecurityChecks isDebuggerAttached]) {
// return YES;
// }
// if ([SecurityChecks isFridaDetected]) {
// return YES;
// }
return NO;
}
@end
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>APIKey</key>
<string>AIzaSyDdqkLMCrqjVrn7XmadIqynyoBa7P27OeM</string>
</dict>
</plist>