Files
ProxyIOS/ProxyCore/Sources/ProxyEngine/RulesEngine.swift
Trey t 148bc3887c Add iPad support, auto-pinning, and comprehensive logging
- Adaptive iPhone/iPad layout with NavigationSplitView sidebar
- Auto-detect SSL-pinned domains, fall back to passthrough
- Certificate install via local HTTP server (Safari profile flow)
- App Group-backed CA, per-domain leaf cert LRU cache
- DB-backed config repository, Darwin notification throttling
- Rules engine, breakpoint rules, pinned domain tracking
- os.Logger instrumentation across tunnel/proxy/mitm/capture/cert/rules/db/ipc/ui
- Fix dyld framework embed, race conditions, thread safety
2026-04-11 12:52:18 -05:00

83 lines
3.0 KiB
Swift

import Foundation
/// Centralized rules engine that checks proxy rules (block list, map local, DNS spoofing, no-cache)
/// against live traffic. All methods are static and synchronous for use in NIO pipeline handlers.
public enum RulesEngine {
private static let rulesRepo = RulesRepository()
// MARK: - Block List
/// Returns the `BlockAction` if the given URL + method matches an enabled block rule, or nil.
public static func checkBlockList(url: String, method: String) -> BlockAction? {
guard IPCManager.shared.isBlockListEnabled else { return nil }
do {
let entries = try rulesRepo.fetchEnabledBlockEntries()
for entry in entries {
guard entry.method == "ANY" || entry.method == method else { continue }
if blockEntry(entry, matches: url) {
return entry.action
}
}
} catch {
print("[RulesEngine] Failed to check block list: \(error)")
}
return nil
}
// MARK: - Map Local
/// Returns the first matching `MapLocalRule` for the URL + method, or nil.
public static func checkMapLocal(url: String, method: String) -> MapLocalRule? {
do {
let rules = try rulesRepo.fetchEnabledMapLocalRules()
for rule in rules {
guard rule.method == "ANY" || rule.method == method else { continue }
if WildcardMatcher.matches(url, pattern: rule.urlPattern) {
return rule
}
}
} catch {
print("[RulesEngine] Failed to check map local rules: \(error)")
}
return nil
}
// MARK: - DNS Spoofing
/// Returns the target domain if the given domain matches an enabled DNS spoof rule, or nil.
public static func checkDNSSpoof(domain: String) -> String? {
guard IPCManager.shared.isDNSSpoofingEnabled else { return nil }
do {
let rules = try rulesRepo.fetchEnabledDNSSpoofRules()
for rule in rules {
if WildcardMatcher.matches(domain, pattern: rule.sourceDomain) {
return rule.targetDomain
}
}
} catch {
print("[RulesEngine] Failed to check DNS spoof rules: \(error)")
}
return nil
}
// MARK: - No-Cache
/// Returns true if the no-caching toggle is enabled.
public static func shouldStripCache() -> Bool {
IPCManager.shared.isNoCachingEnabled
}
private static func blockEntry(_ entry: BlockListEntry, matches url: String) -> Bool {
if WildcardMatcher.matches(url, pattern: entry.urlPattern) {
return true
}
guard entry.includeSubpaths else { return false }
guard !entry.urlPattern.contains("*"), !entry.urlPattern.contains("?") else { return false }
let normalizedPattern = entry.urlPattern.hasSuffix("/") ? entry.urlPattern : "\(entry.urlPattern)/"
return url == entry.urlPattern || url.hasPrefix(normalizedPattern)
}
}