Apply code-review fixes: identity/pagination, load races, TLS pin, leaks
Addresses a multi-agent code review (26 confirmed findings + a URLSession leak) across correctness, concurrency, security, and cleanup: - MongoDocument.id: deterministic fallback (was UUID() on every access) to stop SwiftUI List/ForEach identity churn; getAll pagination drives its cursor off the real _id via documentId, so a missing _id stops paging instead of looping on a fabricated cursor. - View models: per-load generation guard (+ captured-tab guard on ONU detail) so a cancelled or overlapping load can't commit stale results or land data on the wrong tab. - JSONValue.intValue: guard Int(d) against NaN/inf/out-of-range (crash). - ServerTrustEvaluator: hash the real SubjectPublicKeyInfo (prepend the algorithm-specific ASN.1 SPKI header) so a standard openssl-captured public-key pin actually matches; unknown key types fail closed. - AppEnvironment.configure: clear stale cookies + Keychain creds on host change. - FirmwareFile.isCompatible: empty metadata no longer passes as compatible-for-all. - APIClient: invalidate URLSession on deinit (per-configure/probe leak). - Dashboard best-effort sections keep last-good on transient failure; unified optical thresholds; LoginView prefill-once; populatedBuckets unique ForEach id; Format rounding rollover; dead-code/docstring/dedup cleanups. Verification pending on the Mac (no Swift toolchain on the Linux dev box). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8de962eeb8
commit
203465913c
21 changed files with 303 additions and 103 deletions
|
|
@ -15,6 +15,9 @@ enum ONUDetailTab: String, CaseIterable, Identifiable {
|
|||
final class ONUDetailViewModel {
|
||||
let onuId: String
|
||||
private let connection: MCMSConnection
|
||||
/// Bumped per (re)load so a late/cancelled request — or one for a tab the user
|
||||
/// has since left — can't commit its results over the current tab's data.
|
||||
private var loadGeneration = 0
|
||||
|
||||
var tab: ONUDetailTab = .stats
|
||||
var phase: LoadPhase = .idle
|
||||
|
|
@ -51,27 +54,52 @@ final class ONUDetailViewModel {
|
|||
}
|
||||
|
||||
private func reloadCurrentTab() async {
|
||||
loadGeneration += 1
|
||||
let gen = loadGeneration
|
||||
let requested = tab
|
||||
// Commit only if this is still the latest load AND the user is still on the
|
||||
// tab we fetched for — otherwise drop the result.
|
||||
func current() -> Bool { gen == loadGeneration && requested == tab && !Task.isCancelled }
|
||||
do {
|
||||
switch tab {
|
||||
switch requested {
|
||||
case .stats:
|
||||
// Live ONU-STATE carries the current optical/FEC levels (§3.12);
|
||||
// the /onus/stats/ time-series is a best-effort supplement.
|
||||
liveState = try await connection.onu.state(id: onuId)
|
||||
stats = (try? await connection.onu.stats(id: onuId, lastHours: 24)) ?? []
|
||||
case .config: config = try await connection.onu.config(id: onuId)
|
||||
case .cpe: cpes = try await connection.onu.cpes(id: onuId)
|
||||
case .alarms: alarms = try await connection.onu.alarmHistories(
|
||||
query: queryForONU()).sorted { $0.severity.rank < $1.severity.rank }
|
||||
case .logs: logs = try await connection.onu.logs(id: onuId, lastHours: 24)
|
||||
let state = try await connection.onu.state(id: onuId)
|
||||
let samples = (try? await connection.onu.stats(id: onuId, lastHours: 24)) ?? []
|
||||
guard current() else { return }
|
||||
liveState = state
|
||||
stats = samples
|
||||
case .config:
|
||||
let doc = try await connection.onu.config(id: onuId)
|
||||
guard current() else { return }
|
||||
config = doc
|
||||
case .cpe:
|
||||
let list = try await connection.onu.cpes(id: onuId)
|
||||
guard current() else { return }
|
||||
cpes = list
|
||||
case .alarms:
|
||||
let list = try await connection.onu.alarmHistories(query: queryForONU())
|
||||
.sorted { $0.severity.rank < $1.severity.rank }
|
||||
guard current() else { return }
|
||||
alarms = list
|
||||
case .logs:
|
||||
let list = try await connection.onu.logs(id: onuId, lastHours: 24)
|
||||
guard current() else { return }
|
||||
logs = list
|
||||
}
|
||||
phase = .loaded
|
||||
} catch {
|
||||
guard current() else { return }
|
||||
phase = .failed((error as? APIError)?.localizedDescription ?? error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter alarm-history list to this ONU. Reconcile the key with the real
|
||||
/// document shape; `_id` is a safe default for the per-ONU collection.
|
||||
/// Filter the fleet-wide alarm-history list to this ONU. ⚠️ The `_id` key is
|
||||
/// UNVERIFIED — if it's wrong the server ignores the filter and returns EVERY
|
||||
/// ONU's alarms into this detail screen (no error). Confirm the real key (or
|
||||
/// switch to the per-id `.onuAlarmHistory(id:)` endpoint) against openapi.json /
|
||||
/// a live response before trusting this tab.
|
||||
private func queryForONU() -> APIQuery {
|
||||
var q = APIQuery()
|
||||
q.query = ["_id": onuId]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue