feat(ios): device enrollment flow + silent cert rotation (B3)
Wire the SecureEnclave enroll library into a real flow (login->bearer->CSR->
/device/enroll->keychain identity), presented on the existing mTLS path; add a
rotation scheduler. Atomic keychain replace (add-before-delete); renew body is
{csr}-only; renewal-failing surfaced in the UI. ClientTLS 48 tests pass.
This commit is contained in:
@@ -54,6 +54,12 @@ struct AdaptiveRootView: View {
|
||||
.sheet(isPresented: $coordinator.isDeviceCertPresented) {
|
||||
deviceCertSheet
|
||||
}
|
||||
.sheet(
|
||||
isPresented: $coordinator.isEnrollmentPresented,
|
||||
onDismiss: { coordinator.enrollmentDismissed() }
|
||||
) {
|
||||
enrollmentSheet
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Layout branch (the SOLE size-class consumer)
|
||||
@@ -126,4 +132,21 @@ struct AdaptiveRootView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Device enrollment sheet (B3, zero-.p12 auto-cert)
|
||||
|
||||
/// 自带 NavigationStack + 右上「完成」。VM 由 coordinator 每次进入构建
|
||||
/// (`presentEnrollment`);关闭后 `enrollmentDismissed` 丢弃 VM 并跑一次轮换。
|
||||
@ViewBuilder private var enrollmentSheet: some View {
|
||||
if let viewModel = coordinator.enrollmentViewModel {
|
||||
NavigationStack {
|
||||
EnrollmentScreen(model: viewModel)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Button(RootCopy.done) { coordinator.isEnrollmentPresented = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user