wip(k1): checkpoint connection recovery rewrite

Capture the current unreleased K1 connection, recovery, lifecycle, viewer, and test work as a single known-bad baseline for subsequent fixes.
This commit is contained in:
DCCONSTRUCTIONS
2026-08-14 14:57:50 +03:00
parent aff331082f
commit 0ca7316a24
157 changed files with 152962 additions and 4036 deletions
+406 -172
View File
@@ -1,6 +1,7 @@
import AppKit
import CoreWLAN
import CryptoKit
import Foundation
import LocalAuthentication
import Security
private let keychainService = "NODEDC Mission Core Host Wi-Fi Profiles"
@@ -14,6 +15,8 @@ private struct HostWifiRequest: Decodable {
let password: String?
let scanTimeoutSeconds: Double?
let credentialSourceID: String?
let interfaceName: String?
let continuityKeyHex: String?
enum CodingKeys: String, CodingKey {
case action
@@ -22,6 +25,8 @@ private struct HostWifiRequest: Decodable {
case password
case scanTimeoutSeconds = "scan_timeout_seconds"
case credentialSourceID = "credential_source_id"
case interfaceName = "interface_name"
case continuityKeyHex = "continuity_key_hex"
}
}
@@ -60,6 +65,9 @@ private struct HostWifiResponse: Encodable {
let scanAttemptCount: Int?
let scanElapsedMilliseconds: Int?
let credentialSource: String?
let wifiInterface: Bool?
let associationIdentity: String?
let associationEvidence: String?
let reasonCode: String?
enum CodingKeys: String, CodingKey {
@@ -73,6 +81,9 @@ private struct HostWifiResponse: Encodable {
case scanAttemptCount = "scan_attempt_count"
case scanElapsedMilliseconds = "scan_elapsed_ms"
case credentialSource = "credential_source"
case wifiInterface = "wifi_interface"
case associationIdentity = "association_identity"
case associationEvidence = "association_evidence"
case reasonCode = "reason_code"
}
}
@@ -88,6 +99,9 @@ private func emit(
scanAttemptCount: Int? = nil,
scanElapsedMilliseconds: Int? = nil,
credentialSource: String? = nil,
wifiInterface: Bool? = nil,
associationIdentity: String? = nil,
associationEvidence: String? = nil,
reasonCode: String? = nil,
exitCode: Int32
) -> Never {
@@ -102,6 +116,9 @@ private func emit(
scanAttemptCount: scanAttemptCount,
scanElapsedMilliseconds: scanElapsedMilliseconds,
credentialSource: credentialSource,
wifiInterface: wifiInterface,
associationIdentity: associationIdentity,
associationEvidence: associationEvidence,
reasonCode: reasonCode
)
if let data = try? JSONEncoder().encode(response) {
@@ -148,10 +165,75 @@ private func materialKeychainQuery(sourceID: String) -> [String: Any] {
return keychainQuery(service: credentialMaterialKeychainService, account: sourceID)
}
private func loadProfile(profileID: String) throws -> StoredProfile {
private func nonInteractiveAuthenticationContext() -> LAContext {
let context = LAContext()
context.interactionNotAllowed = true
return context
}
private func keychainItemExists(service: String, account: String) throws -> Bool {
var query = keychainQuery(service: service, account: account)
query[kSecReturnAttributes as String] = true
query[kSecMatchLimit as String] = kSecMatchLimitOne
// Preflight is deliberately non-interactive. Authorization prompts belong
// only to an explicit enrollment/migration step, never to a K1 network
// mutation that has already been admitted by the browser.
query[kSecUseAuthenticationContext as String] = nonInteractiveAuthenticationContext()
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
if status == errSecSuccess {
return true
}
if status == errSecItemNotFound {
return false
}
throw NSError(domain: "HostWifiKeychainMetadata", code: Int(status))
}
private func keychainReasonCode(_ error: Error, missing: String) -> String {
let status = OSStatus((error as NSError).code)
switch status {
case errSecItemNotFound:
return missing
case errSecInteractionNotAllowed:
return "keychain-authorization-required"
case errSecAuthFailed:
return "keychain-authorization-denied"
case errSecUserCanceled:
return "keychain-authorization-cancelled"
default:
return "keychain-access-failed"
}
}
private func coreWLANReasonCode(_ error: Error) -> String {
let nsError = error as NSError
guard nsError.domain == CWErrorDomain else {
return "corewlan-error"
}
// Stable CWErr values from Apple's CoreWLANTypes contract. Export only a
// reviewed failure class; NSError descriptions may contain host details.
switch nsError.code {
case -3930: // kCWOperationNotPermittedErr
return "corewlan-authorization-denied"
case -3905, -3925: // kCWTimeoutErr, kCWSupplicantTimeoutErr
return "host-wifi-operation-timeout"
default:
return "corewlan-error"
}
}
private func loadProfile(
profileID: String,
interactionAllowed: Bool = true
) throws -> StoredProfile {
var query = profileKeychainQuery(profileID: profileID)
query[kSecReturnData as String] = true
query[kSecMatchLimit as String] = kSecMatchLimitOne
if !interactionAllowed {
query[kSecUseAuthenticationContext as String] = nonInteractiveAuthenticationContext()
}
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
@@ -191,10 +273,16 @@ private func storeProfile(profileID: String, profile: StoredProfile) throws {
}
}
private func loadCredentialMaterial(sourceID: String) throws -> StoredCredentialMaterial {
private func loadCredentialMaterial(
sourceID: String,
interactionAllowed: Bool = true
) throws -> StoredCredentialMaterial {
var query = materialKeychainQuery(sourceID: sourceID)
query[kSecReturnData as String] = true
query[kSecMatchLimit as String] = kSecMatchLimitOne
if !interactionAllowed {
query[kSecUseAuthenticationContext as String] = nonInteractiveAuthenticationContext()
}
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
@@ -237,25 +325,6 @@ private func storeCredentialMaterial(
}
}
private func loadSystemWiFiProfile(ssid: String, ssidData: Data) -> StoredProfile? {
var password: NSString?
let status = CWKeychainFindWiFiPassword(
CWKeychainDomain.user,
ssidData,
&password
)
guard status == errSecSuccess, let password else {
return nil
}
let profile = StoredProfile(
schemaVersion: 1,
ssid: ssid,
password: password as String,
credentialSource: "system-wifi-keychain"
)
return profileIsValid(profile) ? profile : nil
}
private struct TargetedScanResult {
let network: CWNetwork?
let attemptCount: Int
@@ -298,26 +367,57 @@ private func scanForExpectedNetwork(
}
}
private func promptForDevicePassword(ssid: String) -> String? {
let application = NSApplication.shared
application.setActivationPolicy(.accessory)
let passwordField = NSSecureTextField(frame: NSRect(x: 0, y: 0, width: 360, height: 24))
passwordField.placeholderString = "Пароль точки доступа K1"
let alert = NSAlert()
alert.alertStyle = .informational
alert.messageText = "Первое подключение к \(ssid)"
alert.informativeText = "macOS не нашла локальный профиль этой точки доступа. Если credential вам неизвестен, нажмите «Отмена» и выполните авторизованный импорт device-профиля LixelGO. Введённое значение будет сохранено только в Keychain этого Mac и не попадёт в браузер, API, журнал или evidence Mission Core."
alert.accessoryView = passwordField
alert.addButton(withTitle: "Подключиться")
alert.addButton(withTitle: "Отмена")
application.activate(ignoringOtherApps: true)
guard alert.runModal() == .alertFirstButtonReturn else {
private func decodeContinuityKey(_ value: String) -> Data? {
let bytes = Array(value.utf8)
guard bytes.count == 64 else {
return nil
}
return passwordField.stringValue
func nibble(_ byte: UInt8) -> UInt8? {
switch byte {
case 48 ... 57:
return byte - 48
case 97 ... 102:
return byte - 87
default:
return nil
}
}
var decoded = Data(capacity: 32)
for offset in stride(from: 0, to: bytes.count, by: 2) {
guard let high = nibble(bytes[offset]), let low = nibble(bytes[offset + 1]) else {
return nil
}
decoded.append((high << 4) | low)
}
return decoded
}
private func appendLengthPrefixed(_ value: String, to material: inout Data) {
let data = Data(value.utf8)
var length = UInt32(data.count).bigEndian
withUnsafeBytes(of: &length) { bytes in
material.append(contentsOf: bytes)
}
material.append(data)
}
private func associationIdentity(
continuityKey: Data,
interfaceName: String,
bssid: String
) -> String {
// BSSID is the association identity. SSID visibility is permission- and
// timing-dependent on macOS, so folding it into this token would rotate a
// healthy binding when the same AP alternates between `ssid+bssid` and
// `bssid-only` evidence.
var material = Data("mission-core/host-wifi-association/v2".utf8)
appendLengthPrefixed(interfaceName, to: &material)
appendLengthPrefixed(bssid.lowercased(), to: &material)
let digest = HMAC<SHA256>.authenticationCode(
for: material,
using: SymmetricKey(data: continuityKey)
)
return digest.map { String(format: "%02x", $0) }.joined()
}
private let input = FileHandle.standardInput.readDataToEndOfFile()
@@ -335,6 +435,75 @@ do {
emit(ok: false, reasonCode: "profile-id-invalid", exitCode: 1)
}
if request.action == "inspect-association" {
guard let interfaceName = request.interfaceName,
(1 ... 32).contains(interfaceName.count),
interfaceName.allSatisfy({
$0.isASCII && ($0.isLetter || $0.isNumber || ".-_".contains($0))
}),
let continuityKeyHex = request.continuityKeyHex,
let continuityKey = decodeContinuityKey(continuityKeyHex)
else {
emit(ok: false, reasonCode: "association-inspection-invalid", exitCode: 1)
}
guard let interface = CWWiFiClient.shared().interface(withName: interfaceName) else {
emit(
ok: true,
adapter: "CoreWLAN",
wifiInterface: false,
associationIdentity: associationIdentity(
continuityKey: continuityKey,
interfaceName: interfaceName,
bssid: "not-wifi-interface"
),
associationEvidence: "not-wifi",
exitCode: 0
)
}
guard interface.powerOn(), interface.serviceActive() else {
emit(
ok: true,
adapter: "CoreWLAN",
wifiInterface: true,
associationEvidence: "unavailable",
reasonCode: "wifi-interface-inactive",
exitCode: 0
)
}
let currentSSID = interface.ssid()?.trimmingCharacters(in: .whitespacesAndNewlines)
let currentBSSID = interface.bssid()?.trimmingCharacters(in: .whitespacesAndNewlines)
guard let currentBSSID, !currentBSSID.isEmpty else {
// SSID alone is not an exact association identity: two APs may use
// the same network name. Returning no digest forces the Python
// caller to rotate its fail-closed continuity token.
emit(
ok: true,
adapter: "CoreWLAN",
wifiInterface: true,
associationEvidence: "unavailable",
reasonCode: "association-identity-unavailable",
exitCode: 0
)
}
emit(
ok: true,
adapter: "CoreWLAN",
wifiInterface: true,
associationIdentity: associationIdentity(
continuityKey: continuityKey,
interfaceName: interfaceName,
bssid: currentBSSID
),
associationEvidence: (
currentSSID == nil || currentSSID?.isEmpty == true
? "bssid-only"
: "ssid+bssid"
),
exitCode: 0
)
}
if request.action == "store-profile" {
guard let ssid = request.ssid, let password = request.password else {
emit(ok: false, reasonCode: "credential-missing", exitCode: 1)
@@ -364,20 +533,27 @@ do {
if request.action == "check-credential-material" {
do {
_ = try loadCredentialMaterial(sourceID: request.profileID)
let available = try keychainItemExists(
service: credentialMaterialKeychainService,
account: request.profileID
)
emit(
ok: true,
adapter: "macOS Keychain",
profileAvailable: true,
credentialSource: "exact-firmware-profile",
profileAvailable: available,
credentialSource: available ? "exact-firmware-profile" : nil,
exitCode: 0
)
} catch {
emit(
ok: true,
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
exitCode: 0
reasonCode: keychainReasonCode(
error,
missing: "credential-source-unavailable"
),
exitCode: 1
)
}
}
@@ -395,55 +571,77 @@ do {
emit(ok: false, reasonCode: "credential-source-invalid", exitCode: 1)
}
let material: StoredCredentialMaterial
do {
material = try loadCredentialMaterial(sourceID: sourceID)
let profileAvailable = try keychainItemExists(
service: keychainService,
account: request.profileID
)
if profileAvailable {
let profile = try loadProfile(
profileID: request.profileID,
interactionAllowed: false
)
guard profile.ssid == ssid else {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
profileEnrolled: false,
reasonCode: "profile-ssid-mismatch",
exitCode: 1
)
}
guard profile.credentialSource == "exact-firmware-profile" else {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
profileEnrolled: false,
reasonCode: "profile-credential-source-mismatch",
exitCode: 1
)
}
emit(
ok: true,
adapter: "macOS Keychain",
profileAvailable: true,
profileEnrolled: false,
credentialSource: "exact-firmware-profile",
exitCode: 0
)
}
} catch {
emit(
ok: true,
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
profileEnrolled: false,
reasonCode: "credential-source-unavailable",
exitCode: 0
reasonCode: keychainReasonCode(error, missing: "profile-unavailable"),
exitCode: 1
)
}
let material: StoredCredentialMaterial
do {
material = try loadCredentialMaterial(
sourceID: sourceID,
interactionAllowed: false
)
} catch {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
profileEnrolled: false,
reasonCode: keychainReasonCode(
error,
missing: "credential-source-unavailable"
),
exitCode: 1
)
}
do {
let existing = try loadProfile(profileID: request.profileID)
guard existing.ssid == ssid else {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
profileEnrolled: false,
reasonCode: "profile-ssid-mismatch",
exitCode: 1
)
}
if existing.password == material.password,
existing.credentialSource != "exact-firmware-profile" {
try storeProfile(
profileID: request.profileID,
profile: StoredProfile(
schemaVersion: 1,
ssid: ssid,
password: existing.password,
credentialSource: "exact-firmware-profile"
)
)
}
emit(
ok: true,
adapter: "macOS Keychain",
profileAvailable: true,
profileEnrolled: false,
credentialSource: existing.password == material.password
? "exact-firmware-profile"
: (existing.credentialSource ?? "mission-core-keychain"),
exitCode: 0
)
} catch {
try storeProfile(
profileID: request.profileID,
profile: StoredProfile(
@@ -461,39 +659,82 @@ do {
credentialSource: "exact-firmware-profile",
exitCode: 0
)
}
}
if request.action == "check-profile" {
let profile: StoredProfile
do {
profile = try loadProfile(profileID: request.profileID)
} catch {
emit(
ok: true,
adapter: "macOS Keychain",
profileAvailable: false,
exitCode: 0
)
}
if let expectedSSID = request.ssid, profile.ssid != expectedSSID {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
reasonCode: "profile-ssid-mismatch",
profileEnrolled: false,
reasonCode: keychainReasonCode(error, missing: "profile-unavailable"),
exitCode: 1
)
}
emit(
ok: true,
adapter: "macOS Keychain",
profileAvailable: true,
exitCode: 0
)
}
guard request.action == "associate" || request.action == "scan-profile" else {
if request.action == "check-profile" {
guard let expectedSSID = request.ssid,
let expectedSSIDData = expectedSSID.data(using: .utf8),
(1 ... 32).contains(expectedSSIDData.count)
else {
emit(ok: false, reasonCode: "ssid-invalid", exitCode: 1)
}
do {
let available = try keychainItemExists(
service: keychainService,
account: request.profileID
)
if !available {
emit(
ok: true,
adapter: "macOS Keychain",
profileAvailable: false,
exitCode: 0
)
}
let profile = try loadProfile(
profileID: request.profileID,
interactionAllowed: false
)
guard profile.ssid == expectedSSID else {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
reasonCode: "profile-ssid-mismatch",
exitCode: 1
)
}
guard profile.credentialSource == "exact-firmware-profile" else {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
reasonCode: "profile-credential-source-mismatch",
exitCode: 1
)
}
emit(
ok: true,
adapter: "macOS Keychain",
profileAvailable: true,
credentialSource: "exact-firmware-profile",
exitCode: 0
)
} catch {
emit(
ok: false,
adapter: "macOS Keychain",
profileAvailable: false,
reasonCode: keychainReasonCode(error, missing: "profile-unavailable"),
exitCode: 1
)
}
}
guard request.action == "associate"
|| request.action == "associate-ephemeral"
|| request.action == "scan-profile"
else {
emit(ok: false, reasonCode: "action-unsupported", exitCode: 1)
}
guard let interface = CWWiFiClient.shared().interface() else {
@@ -528,7 +769,7 @@ do {
)
}
guard request.action == "associate" else {
guard request.action == "associate" || request.action == "associate-ephemeral" else {
emit(ok: false, reasonCode: "action-unsupported", exitCode: 1)
}
guard let expectedSSID = request.ssid,
@@ -554,83 +795,76 @@ do {
)
}
var profileEnrolled = false
var profileNeedsStore = false
let credentialSource: String
let profile: StoredProfile
do {
profile = try loadProfile(profileID: request.profileID)
credentialSource = profile.credentialSource ?? "mission-core-keychain"
} catch {
if let systemProfile = loadSystemWiFiProfile(
ssid: expectedSSID,
ssidData: expectedSSIDData
) {
profile = systemProfile
credentialSource = "system-wifi-keychain"
profileNeedsStore = true
} else {
guard let password = promptForDevicePassword(ssid: expectedSSID) else {
emit(
ok: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
reasonCode: "credential-entry-cancelled",
exitCode: 1
)
}
guard let passwordData = password.data(using: .utf8),
(1 ... 64).contains(passwordData.count)
else {
emit(
ok: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
reasonCode: "credential-invalid",
exitCode: 1
)
}
profile = StoredProfile(
schemaVersion: 1,
ssid: expectedSSID,
password: password,
credentialSource: "native-secure-prompt"
let associationPassword: String
if request.action == "associate-ephemeral" {
guard let password = request.password,
let passwordData = password.data(using: .utf8),
(1 ... 64).contains(passwordData.count)
else {
emit(
ok: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
reasonCode: "credential-missing",
exitCode: 1
)
credentialSource = "native-secure-prompt"
profileNeedsStore = true
}
}
guard profile.ssid == expectedSSID else {
emit(
ok: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
reasonCode: "profile-ssid-mismatch",
exitCode: 1
)
credentialSource = "operation-memory"
associationPassword = password
} else {
let profile: StoredProfile
do {
// The AP write has already happened. A prepared-host Quick action must
// never trigger a Keychain authorization sheet at this stage.
profile = try loadProfile(
profileID: request.profileID,
interactionAllowed: false
)
guard profile.credentialSource == "exact-firmware-profile" else {
emit(
ok: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
reasonCode: "profile-credential-source-mismatch",
exitCode: 1
)
}
credentialSource = "exact-firmware-profile"
} catch {
emit(
ok: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
reasonCode: keychainReasonCode(error, missing: "profile-unavailable"),
exitCode: 1
)
}
guard profile.ssid == expectedSSID else {
emit(
ok: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
reasonCode: "profile-ssid-mismatch",
exitCode: 1
)
}
associationPassword = profile.password
}
if interface.ssid() == profile.ssid {
if profileNeedsStore {
try storeProfile(profileID: request.profileID, profile: profile)
profileEnrolled = true
}
if interface.ssid() == expectedSSID {
emit(
ok: true,
adapter: "CoreWLAN",
alreadyAssociated: true,
profileEnrolled: profileEnrolled,
profileEnrolled: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
credentialSource: credentialSource,
exitCode: 0
)
}
try interface.associate(to: network, password: profile.password)
if profileNeedsStore {
try storeProfile(profileID: request.profileID, profile: profile)
profileEnrolled = true
}
try interface.associate(to: network, password: associationPassword)
// CoreWLAN's synchronous association call throws on failure. Reading the
// current SSID again would require Location authorization on recent macOS
// versions and could turn a successful association into a false negative.
@@ -638,12 +872,12 @@ do {
ok: true,
adapter: "CoreWLAN",
alreadyAssociated: false,
profileEnrolled: profileEnrolled,
profileEnrolled: false,
scanAttemptCount: scan.attemptCount,
scanElapsedMilliseconds: scan.elapsedMilliseconds,
credentialSource: credentialSource,
exitCode: 0
)
} catch {
emit(ok: false, reasonCode: "corewlan-error", exitCode: 1)
emit(ok: false, reasonCode: coreWLANReasonCode(error), exitCode: 1)
}