Initial project setup - Phases 1-3 complete

This commit is contained in:
Trey t
2026-04-06 11:28:40 -05:00
commit c77e506db5
293 changed files with 14233 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
import Foundation
import GRDB
public enum BlockAction: String, Codable, Sendable, CaseIterable {
case blockAndHide = "block_and_hide"
case blockAndDisplay = "block_and_display"
case hideOnly = "hide_only"
public var displayName: String {
switch self {
case .blockAndHide: "Block & Hide Request"
case .blockAndDisplay: "Block & Display"
case .hideOnly: "Hide but not Block"
}
}
}
public struct BlockListEntry: Codable, FetchableRecord, MutablePersistableRecord, Identifiable, Sendable {
public var id: Int64?
public var name: String?
public var urlPattern: String
public var method: String
public var includeSubpaths: Bool
public var blockAction: String
public var isEnabled: Bool
public var createdAt: Double
public static let databaseTableName = "block_list_entries"
public mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
public init(
id: Int64? = nil,
name: String? = nil,
urlPattern: String,
method: String = "ANY",
includeSubpaths: Bool = true,
blockAction: BlockAction = .blockAndHide,
isEnabled: Bool = true,
createdAt: Double = Date().timeIntervalSince1970
) {
self.id = id
self.name = name
self.urlPattern = urlPattern
self.method = method
self.includeSubpaths = includeSubpaths
self.blockAction = blockAction.rawValue
self.isEnabled = isEnabled
self.createdAt = createdAt
}
public var action: BlockAction {
BlockAction(rawValue: blockAction) ?? .blockAndHide
}
}

View File

@@ -0,0 +1,39 @@
import Foundation
import GRDB
public struct BreakpointRule: Codable, FetchableRecord, MutablePersistableRecord, Identifiable, Sendable {
public var id: Int64?
public var name: String?
public var urlPattern: String
public var method: String
public var interceptRequest: Bool
public var interceptResponse: Bool
public var isEnabled: Bool
public var createdAt: Double
public static let databaseTableName = "breakpoint_rules"
public mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
public init(
id: Int64? = nil,
name: String? = nil,
urlPattern: String,
method: String = "ANY",
interceptRequest: Bool = true,
interceptResponse: Bool = true,
isEnabled: Bool = true,
createdAt: Double = Date().timeIntervalSince1970
) {
self.id = id
self.name = name
self.urlPattern = urlPattern
self.method = method
self.interceptRequest = interceptRequest
self.interceptResponse = interceptResponse
self.isEnabled = isEnabled
self.createdAt = createdAt
}
}

View File

@@ -0,0 +1,140 @@
import Foundation
import GRDB
public struct CapturedTraffic: Codable, FetchableRecord, MutablePersistableRecord, Identifiable, Sendable {
public var id: Int64?
public var requestId: String
public var domain: String
public var url: String
public var method: String
public var scheme: String
public var statusCode: Int?
public var statusText: String?
// Request
public var requestHeaders: String?
public var requestBody: Data?
public var requestBodySize: Int
public var requestContentType: String?
public var queryParameters: String?
// Response
public var responseHeaders: String?
public var responseBody: Data?
public var responseBodySize: Int
public var responseContentType: String?
// Timing
public var startedAt: Double
public var completedAt: Double?
public var durationMs: Int?
// Metadata
public var isSslDecrypted: Bool
public var isPinned: Bool
public var isWebsocket: Bool
public var isHidden: Bool
public var createdAt: Double
public static let databaseTableName = "captured_traffic"
public mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
public init(
id: Int64? = nil,
requestId: String = UUID().uuidString,
domain: String,
url: String,
method: String,
scheme: String,
statusCode: Int? = nil,
statusText: String? = nil,
requestHeaders: String? = nil,
requestBody: Data? = nil,
requestBodySize: Int = 0,
requestContentType: String? = nil,
queryParameters: String? = nil,
responseHeaders: String? = nil,
responseBody: Data? = nil,
responseBodySize: Int = 0,
responseContentType: String? = nil,
startedAt: Double = Date().timeIntervalSince1970,
completedAt: Double? = nil,
durationMs: Int? = nil,
isSslDecrypted: Bool = false,
isPinned: Bool = false,
isWebsocket: Bool = false,
isHidden: Bool = false,
createdAt: Double = Date().timeIntervalSince1970
) {
self.id = id
self.requestId = requestId
self.domain = domain
self.url = url
self.method = method
self.scheme = scheme
self.statusCode = statusCode
self.statusText = statusText
self.requestHeaders = requestHeaders
self.requestBody = requestBody
self.requestBodySize = requestBodySize
self.requestContentType = requestContentType
self.queryParameters = queryParameters
self.responseHeaders = responseHeaders
self.responseBody = responseBody
self.responseBodySize = responseBodySize
self.responseContentType = responseContentType
self.startedAt = startedAt
self.completedAt = completedAt
self.durationMs = durationMs
self.isSslDecrypted = isSslDecrypted
self.isPinned = isPinned
self.isWebsocket = isWebsocket
self.isHidden = isHidden
self.createdAt = createdAt
}
}
// MARK: - Computed Properties
extension CapturedTraffic {
public var decodedRequestHeaders: [String: String] {
guard let data = requestHeaders?.data(using: .utf8),
let dict = try? JSONDecoder().decode([String: String].self, from: data) else {
return [:]
}
return dict
}
public var decodedResponseHeaders: [String: String] {
guard let data = responseHeaders?.data(using: .utf8),
let dict = try? JSONDecoder().decode([String: String].self, from: data) else {
return [:]
}
return dict
}
public var decodedQueryParameters: [String: String] {
guard let data = queryParameters?.data(using: .utf8),
let dict = try? JSONDecoder().decode([String: String].self, from: data) else {
return [:]
}
return dict
}
public var startDate: Date {
Date(timeIntervalSince1970: startedAt)
}
public var formattedDuration: String {
guard let ms = durationMs else { return "-" }
if ms < 1000 {
return "\(ms) ms"
} else {
return String(format: "%.1f s", Double(ms) / 1000.0)
}
}
}

View File

@@ -0,0 +1,54 @@
import Foundation
import GRDB
public struct ComposeRequest: Codable, FetchableRecord, MutablePersistableRecord, Identifiable, Sendable {
public var id: Int64?
public var name: String
public var method: String
public var url: String?
public var headers: String?
public var queryParameters: String?
public var body: String?
public var bodyContentType: String?
public var responseStatus: Int?
public var responseHeaders: String?
public var responseBody: Data?
public var lastSentAt: Double?
public var createdAt: Double
public static let databaseTableName = "compose_requests"
public mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
public init(
id: Int64? = nil,
name: String = "New Request",
method: String = "GET",
url: String? = nil,
headers: String? = nil,
queryParameters: String? = nil,
body: String? = nil,
bodyContentType: String? = nil,
responseStatus: Int? = nil,
responseHeaders: String? = nil,
responseBody: Data? = nil,
lastSentAt: Double? = nil,
createdAt: Double = Date().timeIntervalSince1970
) {
self.id = id
self.name = name
self.method = method
self.url = url
self.headers = headers
self.queryParameters = queryParameters
self.body = body
self.bodyContentType = bodyContentType
self.responseStatus = responseStatus
self.responseHeaders = responseHeaders
self.responseBody = responseBody
self.lastSentAt = lastSentAt
self.createdAt = createdAt
}
}

View File

@@ -0,0 +1,30 @@
import Foundation
import GRDB
public struct DNSSpoofRule: Codable, FetchableRecord, MutablePersistableRecord, Identifiable, Sendable {
public var id: Int64?
public var sourceDomain: String
public var targetDomain: String
public var isEnabled: Bool
public var createdAt: Double
public static let databaseTableName = "dns_spoof_rules"
public mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
public init(
id: Int64? = nil,
sourceDomain: String,
targetDomain: String,
isEnabled: Bool = true,
createdAt: Double = Date().timeIntervalSince1970
) {
self.id = id
self.sourceDomain = sourceDomain
self.targetDomain = targetDomain
self.isEnabled = isEnabled
self.createdAt = createdAt
}
}

View File

@@ -0,0 +1,13 @@
import Foundation
import GRDB
public struct DomainGroup: Decodable, FetchableRecord, Identifiable, Hashable, Sendable {
public var id: String { domain }
public var domain: String
public var requestCount: Int
public init(domain: String, requestCount: Int) {
self.domain = domain
self.requestCount = requestCount
}
}

View File

@@ -0,0 +1,45 @@
import Foundation
import GRDB
public struct MapLocalRule: Codable, FetchableRecord, MutablePersistableRecord, Identifiable, Sendable {
public var id: Int64?
public var name: String?
public var urlPattern: String
public var method: String
public var responseStatus: Int
public var responseHeaders: String?
public var responseBody: Data?
public var responseContentType: String?
public var isEnabled: Bool
public var createdAt: Double
public static let databaseTableName = "map_local_rules"
public mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
public init(
id: Int64? = nil,
name: String? = nil,
urlPattern: String,
method: String = "ANY",
responseStatus: Int = 200,
responseHeaders: String? = nil,
responseBody: Data? = nil,
responseContentType: String? = nil,
isEnabled: Bool = true,
createdAt: Double = Date().timeIntervalSince1970
) {
self.id = id
self.name = name
self.urlPattern = urlPattern
self.method = method
self.responseStatus = responseStatus
self.responseHeaders = responseHeaders
self.responseBody = responseBody
self.responseContentType = responseContentType
self.isEnabled = isEnabled
self.createdAt = createdAt
}
}

View File

@@ -0,0 +1,22 @@
import Foundation
import GRDB
public struct SSLProxyingEntry: Codable, FetchableRecord, MutablePersistableRecord, Identifiable, Sendable {
public var id: Int64?
public var domainPattern: String
public var isInclude: Bool
public var createdAt: Double
public static let databaseTableName = "ssl_proxying_entries"
public mutating func didInsert(_ inserted: InsertionSuccess) {
id = inserted.rowID
}
public init(id: Int64? = nil, domainPattern: String, isInclude: Bool, createdAt: Double = Date().timeIntervalSince1970) {
self.id = id
self.domainPattern = domainPattern
self.isInclude = isInclude
self.createdAt = createdAt
}
}