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
This commit is contained in:
Trey t
2026-04-11 12:52:18 -05:00
parent c77e506db5
commit 148bc3887c
77 changed files with 6710 additions and 847 deletions

View File

@@ -0,0 +1,538 @@
import AppKit
import CoreGraphics
import Foundation
enum SplitLockVariant: CaseIterable {
case balancedGate
case glassCore
case bracketTrace
case shieldLock
case signalKeyhole
var title: String {
switch self {
case .balancedGate: return "Balanced Gate"
case .glassCore: return "Glass Core"
case .bracketTrace: return "Bracket Trace"
case .shieldLock: return "Shield Lock"
case .signalKeyhole: return "Signal Keyhole"
}
}
var summary: String {
switch self {
case .balancedGate:
return "Closest to the original idea. Balanced lock and readable traces."
case .glassCore:
return "More premium and layered. Feels the most iOS 26-native."
case .bracketTrace:
return "Leans developer-tool. The right half reads closer to code."
case .shieldLock:
return "Feels safer and more consumer-trust oriented than technical."
case .signalKeyhole:
return "Adds a pulse/keyhole center so inspection feels active, not static."
}
}
var accent: NSColor {
switch self {
case .balancedGate: return NSColor(hex: 0x4F86FF)
case .glassCore: return NSColor(hex: 0x67B8FF)
case .bracketTrace: return NSColor(hex: 0x5A9DFF)
case .shieldLock: return NSColor(hex: 0x41A6FF)
case .signalKeyhole: return NSColor(hex: 0x4DE3FF)
}
}
}
enum LockStyle {
case flat
case glossy
}
struct Page {
static let size = CGSize(width: 960, height: 1400)
}
let outputDirectory = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
.appendingPathComponent("Design/icon_concepts", isDirectory: true)
let pdfURL = outputDirectory.appendingPathComponent("split_lock_variants.pdf")
let pngURL = outputDirectory.appendingPathComponent("split_lock_variants_preview.png")
try FileManager.default.createDirectory(at: outputDirectory, withIntermediateDirectories: true)
renderPDF(to: pdfURL)
renderPreview(to: pngURL)
print("Generated:")
print(pdfURL.path)
print(pngURL.path)
func renderPDF(to url: URL) {
var mediaBox = CGRect(origin: .zero, size: Page.size)
guard let context = CGContext(url as CFURL, mediaBox: &mediaBox, nil) else {
fatalError("Unable to create PDF context")
}
beginPDFPage(context, mediaBox) {
drawOverviewPage(in: mediaBox)
}
beginPDFPage(context, mediaBox) {
drawLargeIconsPage(in: mediaBox)
}
context.closePDF()
}
func renderPreview(to url: URL) {
let previewSize = CGSize(width: 1500, height: 2188)
let image = NSImage(size: previewSize)
image.lockFocus()
NSGraphicsContext.current?.imageInterpolation = .high
let scale = previewSize.width / Page.size.width
let context = NSGraphicsContext.current?.cgContext
context?.saveGState()
context?.scaleBy(x: scale, y: scale)
drawOverviewPage(in: CGRect(origin: .zero, size: Page.size))
context?.restoreGState()
image.unlockFocus()
guard let tiff = image.tiffRepresentation,
let rep = NSBitmapImageRep(data: tiff),
let png = rep.representation(using: .png, properties: [:]) else {
fatalError("Unable to create PNG preview")
}
try? png.write(to: url)
}
func beginPDFPage(_ context: CGContext, _ mediaBox: CGRect, draw: () -> Void) {
context.beginPDFPage(nil)
let graphicsContext = NSGraphicsContext(cgContext: context, flipped: false)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = graphicsContext
draw()
NSGraphicsContext.restoreGraphicsState()
context.endPDFPage()
}
func drawOverviewPage(in rect: CGRect) {
fill(rect, color: NSColor(hex: 0xF5F7FC))
drawText(
"Split Lock Explorations",
in: CGRect(x: 68, y: rect.height - 116, width: rect.width - 136, height: 40),
font: .systemFont(ofSize: 34, weight: .bold),
color: NSColor(hex: 0x0F172A)
)
drawText(
"Five directions built from the Split Lock concept. Each card shows the glossy primary icon with a small flat simplification inset.",
in: CGRect(x: 68, y: rect.height - 160, width: rect.width - 136, height: 34),
font: .systemFont(ofSize: 16, weight: .medium),
color: NSColor(hex: 0x475467)
)
let cardWidth = (rect.width - 68 * 2 - 26) / 2
let cardHeight: CGFloat = 300
let layouts: [(SplitLockVariant, CGRect)] = [
(.balancedGate, CGRect(x: 68, y: 900, width: cardWidth, height: cardHeight)),
(.glassCore, CGRect(x: 68 + cardWidth + 26, y: 900, width: cardWidth, height: cardHeight)),
(.bracketTrace, CGRect(x: 68, y: 574, width: cardWidth, height: cardHeight)),
(.shieldLock, CGRect(x: 68 + cardWidth + 26, y: 574, width: cardWidth, height: cardHeight)),
(.signalKeyhole, CGRect(x: 68, y: 248, width: cardWidth, height: cardHeight))
]
for (variant, frame) in layouts {
drawVariantCard(variant: variant, in: frame)
}
drawDecisionCard(
in: CGRect(x: 68 + cardWidth + 26, y: 248, width: cardWidth, height: cardHeight)
)
}
func drawLargeIconsPage(in rect: CGRect) {
fill(rect, color: NSColor(hex: 0xF8FAFD))
drawText(
"Large Icon Comparison",
in: CGRect(x: 68, y: rect.height - 114, width: rect.width - 136, height: 38),
font: .systemFont(ofSize: 32, weight: .bold),
color: NSColor(hex: 0x0F172A)
)
drawText(
"This page removes most of the annotation so you can judge silhouette, weight, and app-store readability.",
in: CGRect(x: 68, y: rect.height - 156, width: rect.width - 136, height: 28),
font: .systemFont(ofSize: 15, weight: .medium),
color: NSColor(hex: 0x475467)
)
let rowHeight: CGFloat = 220
for (index, variant) in SplitLockVariant.allCases.enumerated() {
let y = rect.height - 250 - CGFloat(index) * (rowHeight + 16)
let frame = CGRect(x: 68, y: y, width: rect.width - 136, height: rowHeight)
drawSurface(frame, fill: NSColor.white, stroke: NSColor(hex: 0xD9E0EC))
drawIconBackground(in: CGRect(x: frame.minX + 30, y: frame.minY + 26, width: 168, height: 168))
drawSplitLock(variant: variant, style: .glossy, in: CGRect(x: frame.minX + 42, y: frame.minY + 38, width: 144, height: 144))
drawText(
variant.title,
in: CGRect(x: frame.minX + 228, y: frame.maxY - 62, width: frame.width - 252, height: 30),
font: .systemFont(ofSize: 26, weight: .bold),
color: NSColor(hex: 0x111827)
)
drawText(
variant.summary,
in: CGRect(x: frame.minX + 228, y: frame.maxY - 118, width: frame.width - 252, height: 60),
font: .systemFont(ofSize: 16, weight: .medium),
color: NSColor(hex: 0x475467)
)
drawPill(
"glossy primary",
in: CGRect(x: frame.minX + 228, y: frame.minY + 28, width: 112, height: 28),
fill: variant.accent.withAlphaComponent(0.14),
textColor: NSColor(hex: 0x275FD7)
)
}
}
func drawVariantCard(variant: SplitLockVariant, in frame: CGRect) {
drawSurface(frame, fill: NSColor.white, stroke: NSColor(hex: 0xD9E0EC))
let iconFrame = CGRect(x: frame.minX + 24, y: frame.minY + 62, width: 158, height: 158)
drawIconBackground(in: iconFrame)
drawSplitLock(variant: variant, style: .glossy, in: iconFrame.insetBy(dx: 14, dy: 14))
let flatFrame = CGRect(x: frame.minX + 30, y: frame.minY + 196, width: 58, height: 58)
drawMiniBadge(flatFrame, variant: variant)
drawText(
variant.title,
in: CGRect(x: frame.minX + 204, y: frame.maxY - 70, width: frame.width - 226, height: 28),
font: .systemFont(ofSize: 22, weight: .bold),
color: NSColor(hex: 0x111827)
)
drawText(
variant.summary,
in: CGRect(x: frame.minX + 204, y: frame.maxY - 138, width: frame.width - 226, height: 78),
font: .systemFont(ofSize: 14, weight: .medium),
color: NSColor(hex: 0x475467)
)
drawPill(
"flat inset",
in: CGRect(x: frame.minX + 100, y: frame.minY + 208, width: 72, height: 22),
fill: NSColor(hex: 0xEDF2FF),
textColor: NSColor(hex: 0x3A63D1)
)
}
func drawDecisionCard(in frame: CGRect) {
drawSurface(frame, fill: NSColor(hex: 0x17223A), stroke: NSColor(hex: 0x17223A))
drawText(
"What To Pick For",
in: CGRect(x: frame.minX + 26, y: frame.maxY - 68, width: frame.width - 52, height: 28),
font: .systemFont(ofSize: 24, weight: .bold),
color: .white
)
let bullets = [
"Most balanced: Balanced Gate",
"Most premium: Glass Core",
"Most dev-tool: Bracket Trace",
"Most trustworthy: Shield Lock",
"Most active / dynamic: Signal Keyhole"
]
for (index, bullet) in bullets.enumerated() {
let rowY = frame.maxY - 118 - CGFloat(index) * 34
fillEllipse(CGRect(x: frame.minX + 28, y: rowY + 6, width: 10, height: 10), color: NSColor(hex: 0x6DA1FF))
drawText(
bullet,
in: CGRect(x: frame.minX + 48, y: rowY, width: frame.width - 72, height: 22),
font: .systemFont(ofSize: 15, weight: .semibold),
color: NSColor.white.withAlphaComponent(0.94)
)
}
drawText(
"Pick one and Ill iterate on thickness, color, background, or make it more minimal.",
in: CGRect(x: frame.minX + 26, y: frame.minY + 28, width: frame.width - 52, height: 42),
font: .systemFont(ofSize: 15, weight: .medium),
color: NSColor.white.withAlphaComponent(0.82)
)
}
func drawIconBackground(in rect: CGRect) {
let path = NSBezierPath(roundedRect: rect, xRadius: rect.width * 0.23, yRadius: rect.height * 0.23)
let gradient = NSGradient(colors: [
NSColor(hex: 0xF6F9FF),
NSColor(hex: 0xDFE9FF),
NSColor(hex: 0xD1DEFF)
])
gradient?.draw(in: path, angle: 90)
let highlight = NSBezierPath(roundedRect: rect.insetBy(dx: 16, dy: 16).offsetBy(dx: 0, dy: 20), xRadius: 34, yRadius: 34)
NSColor.white.withAlphaComponent(0.24).setFill()
highlight.fill()
NSColor.white.withAlphaComponent(0.74).setStroke()
path.lineWidth = 1.6
path.stroke()
}
func drawMiniBadge(_ rect: CGRect, variant: SplitLockVariant) {
let path = NSBezierPath(roundedRect: rect, xRadius: rect.width * 0.28, yRadius: rect.height * 0.28)
let gradient = NSGradient(colors: [NSColor(hex: 0xFCFDFF), NSColor(hex: 0xEEF3FF)])
gradient?.draw(in: path, angle: 90)
NSColor.white.withAlphaComponent(0.8).setStroke()
path.lineWidth = 1.2
path.stroke()
drawSplitLock(variant: variant, style: .flat, in: rect.insetBy(dx: 8, dy: 8))
}
func drawSplitLock(variant: SplitLockVariant, style: LockStyle, in rect: CGRect) {
switch variant {
case .balancedGate:
drawBalancedGate(style: style, in: rect)
case .glassCore:
drawGlassCore(style: style, in: rect)
case .bracketTrace:
drawBracketTrace(style: style, in: rect)
case .shieldLock:
drawShieldLock(style: style, in: rect)
case .signalKeyhole:
drawSignalKeyhole(style: style, in: rect)
}
}
func drawBalancedGate(style: LockStyle, in rect: CGRect) {
drawBaseLock(style: style, in: rect, bodyInset: 0, shackleLift: 0)
drawTraceLines(
in: rect,
color: NSColor(hex: style == .flat ? 0x5EA4FF : 0x7EB8FF),
spread: 26,
weight: style == .flat ? 6 : 7
)
}
func drawGlassCore(style: LockStyle, in rect: CGRect) {
drawBaseLock(style: style, in: rect, bodyInset: 4, shackleLift: 6)
let glowRect = CGRect(x: rect.midX - 18, y: rect.midY - 14, width: 36, height: 36)
if style == .glossy {
fillEllipse(glowRect.insetBy(dx: -10, dy: -10), color: NSColor(hex: 0x84DAFF).withAlphaComponent(0.16))
}
fillEllipse(glowRect, color: NSColor(hex: style == .flat ? 0x6CCFFF : 0x86E5FF))
drawTraceLines(
in: rect,
color: NSColor(hex: style == .flat ? 0x74B0FF : 0xA5CCFF),
spread: 20,
weight: style == .flat ? 5 : 6
)
}
func drawBracketTrace(style: LockStyle, in rect: CGRect) {
drawBaseLock(style: style, in: rect, bodyInset: 0, shackleLift: 0)
let bracket = NSBezierPath()
bracket.move(to: CGPoint(x: rect.midX + 10, y: rect.midY + 34))
bracket.line(to: CGPoint(x: rect.maxX - 30, y: rect.midY + 34))
bracket.line(to: CGPoint(x: rect.maxX - 30, y: rect.midY + 10))
bracket.move(to: CGPoint(x: rect.midX + 10, y: rect.midY - 34))
bracket.line(to: CGPoint(x: rect.maxX - 30, y: rect.midY - 34))
bracket.line(to: CGPoint(x: rect.maxX - 30, y: rect.midY - 10))
bracket.lineWidth = style == .flat ? 6 : 7
bracket.lineCapStyle = .round
bracket.lineJoinStyle = .round
NSColor(hex: style == .flat ? 0x67A8FF : 0x8FC1FF).setStroke()
bracket.stroke()
drawTraceLines(
in: rect,
color: NSColor(hex: style == .flat ? 0x4F86FF : 0x69A8FF),
spread: 24,
weight: style == .flat ? 5 : 6
)
}
func drawShieldLock(style: LockStyle, in rect: CGRect) {
let shield = NSBezierPath()
shield.move(to: CGPoint(x: rect.midX, y: rect.maxY - 6))
shield.curve(
to: CGPoint(x: rect.minX + 32, y: rect.midY + 18),
controlPoint1: CGPoint(x: rect.midX - 40, y: rect.maxY - 8),
controlPoint2: CGPoint(x: rect.minX + 26, y: rect.maxY - 26)
)
shield.line(to: CGPoint(x: rect.midX, y: rect.minY + 6))
shield.line(to: CGPoint(x: rect.maxX - 32, y: rect.midY + 18))
shield.curve(
to: CGPoint(x: rect.midX, y: rect.maxY - 6),
controlPoint1: CGPoint(x: rect.maxX - 26, y: rect.maxY - 26),
controlPoint2: CGPoint(x: rect.midX + 40, y: rect.maxY - 8)
)
shield.close()
if style == .glossy {
NSColor.white.withAlphaComponent(0.18).setFill()
shield.fill()
} else {
NSColor(hex: 0xEDF4FF).setFill()
shield.fill()
}
drawBaseLock(style: style, in: rect.insetBy(dx: 10, dy: 10), bodyInset: 2, shackleLift: 2)
drawTraceLines(
in: rect.insetBy(dx: 10, dy: 10),
color: NSColor(hex: style == .flat ? 0x5F9FFF : 0x8CC1FF),
spread: 22,
weight: style == .flat ? 5 : 6
)
}
func drawSignalKeyhole(style: LockStyle, in rect: CGRect) {
drawBaseLock(style: style, in: rect, bodyInset: 1, shackleLift: 0)
let keyholeCircle = CGRect(x: rect.midX - 14, y: rect.midY + 2, width: 28, height: 28)
let keyholeStem = NSBezierPath(roundedRect: CGRect(x: rect.midX - 7, y: rect.midY - 24, width: 14, height: 30), xRadius: 7, yRadius: 7)
if style == .glossy {
fillEllipse(keyholeCircle.insetBy(dx: -8, dy: -8), color: NSColor(hex: 0x7FE4FF).withAlphaComponent(0.16))
}
fillEllipse(keyholeCircle, color: NSColor(hex: style == .flat ? 0x143A6F : 0xF8FBFF))
let stemColor = style == .flat ? NSColor(hex: 0x143A6F) : NSColor(hex: 0xF8FBFF)
stemColor.setFill()
keyholeStem.fill()
drawTraceLines(
in: rect,
color: NSColor(hex: style == .flat ? 0x49CFFF : 0x5CE7FF),
spread: 28,
weight: style == .flat ? 5 : 6
)
}
func drawBaseLock(style: LockStyle, in rect: CGRect, bodyInset: CGFloat, shackleLift: CGFloat) {
let bodyRect = CGRect(
x: rect.midX - 42 + bodyInset,
y: rect.midY - 34,
width: 96 - bodyInset * 2,
height: 76
)
let body = NSBezierPath(roundedRect: bodyRect, xRadius: 22, yRadius: 22)
switch style {
case .flat:
NSColor(hex: 0xF7FAFF).setFill()
body.fill()
NSColor(hex: 0x1E3A72).setStroke()
body.lineWidth = 5.5
body.stroke()
case .glossy:
let gradient = NSGradient(colors: [
NSColor.white.withAlphaComponent(0.92),
NSColor(hex: 0xE0EBFF).withAlphaComponent(0.88)
])
gradient?.draw(in: body, angle: 90)
NSColor.white.withAlphaComponent(0.82).setStroke()
body.lineWidth = 5
body.stroke()
}
let shackle = NSBezierPath()
shackle.move(to: CGPoint(x: rect.midX - 32, y: bodyRect.maxY - 1))
shackle.curve(
to: CGPoint(x: rect.midX + 12, y: bodyRect.maxY + 40 + shackleLift),
controlPoint1: CGPoint(x: rect.midX - 34, y: bodyRect.maxY + 42 + shackleLift),
controlPoint2: CGPoint(x: rect.midX + 12, y: bodyRect.maxY + 42 + shackleLift)
)
shackle.lineWidth = style == .flat ? 11 : 12
shackle.lineCapStyle = .round
NSColor(hex: style == .flat ? 0x1E3A72 : 0xF8FBFF).setStroke()
shackle.stroke()
let leftFillRect = CGRect(x: bodyRect.minX, y: bodyRect.minY, width: bodyRect.width * 0.52, height: bodyRect.height)
let leftFill = NSBezierPath(roundedRect: leftFillRect, xRadius: 18, yRadius: 18)
NSColor(hex: style == .flat ? 0x76A8FF : 0xBCD4FF).setFill()
leftFill.fill()
}
func drawTraceLines(in rect: CGRect, color: NSColor, spread: CGFloat, weight: CGFloat) {
let traces: [(CGFloat, CGFloat)] = [(spread, 0.94), (0, 1.0), (-spread, 0.92)]
for (offset, scale) in traces {
let start = CGPoint(x: rect.midX + 6, y: rect.midY + offset * 0.32)
let end = CGPoint(x: rect.maxX - 20, y: rect.midY + offset)
let path = NSBezierPath()
path.move(to: start)
path.curve(
to: end,
controlPoint1: CGPoint(x: start.x + 22, y: start.y),
controlPoint2: CGPoint(x: end.x - 18, y: end.y)
)
path.lineWidth = weight * scale
path.lineCapStyle = .round
color.setStroke()
path.stroke()
fillEllipse(CGRect(x: end.x - 5, y: end.y - 5, width: 10, height: 10), color: color)
}
}
func drawSurface(_ rect: CGRect, fill: NSColor, stroke: NSColor) {
let shadow = NSShadow()
shadow.shadowColor = NSColor.black.withAlphaComponent(0.08)
shadow.shadowOffset = CGSize(width: 0, height: -7)
shadow.shadowBlurRadius = 18
NSGraphicsContext.saveGraphicsState()
shadow.set()
let path = NSBezierPath(roundedRect: rect, xRadius: 26, yRadius: 26)
fill.setFill()
path.fill()
NSGraphicsContext.restoreGraphicsState()
let strokePath = NSBezierPath(roundedRect: rect, xRadius: 26, yRadius: 26)
stroke.setStroke()
strokePath.lineWidth = 1.1
strokePath.stroke()
}
func drawPill(_ title: String, in rect: CGRect, fill: NSColor, textColor: NSColor) {
let path = NSBezierPath(roundedRect: rect, xRadius: rect.height / 2, yRadius: rect.height / 2)
fill.setFill()
path.fill()
drawText(title, in: rect.offsetBy(dx: 0, dy: 2), font: .systemFont(ofSize: 11, weight: .bold), color: textColor, alignment: .center)
}
func drawText(_ text: String, in rect: CGRect, font: NSFont, color: NSColor, alignment: NSTextAlignment = .left) {
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = alignment
paragraph.lineBreakMode = .byWordWrapping
let attributes: [NSAttributedString.Key: Any] = [
.font: font,
.foregroundColor: color,
.paragraphStyle: paragraph
]
NSString(string: text).draw(with: rect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: attributes)
}
func fill(_ rect: CGRect, color: NSColor) {
color.setFill()
NSBezierPath(rect: rect).fill()
}
func fillEllipse(_ rect: CGRect, color: NSColor) {
color.setFill()
NSBezierPath(ovalIn: rect).fill()
}
extension NSColor {
convenience init(hex: Int, alpha: CGFloat = 1.0) {
let red = CGFloat((hex >> 16) & 0xFF) / 255.0
let green = CGFloat((hex >> 8) & 0xFF) / 255.0
let blue = CGFloat(hex & 0xFF) / 255.0
self.init(calibratedRed: red, green: green, blue: blue, alpha: alpha)
}
}