Защита Bridge и камеры K1 при переподключении

This commit is contained in:
DCCONSTRUCTIONS
2026-08-23 01:25:25 +03:00
parent 0752e5c6bf
commit 71c8b043c9
8 changed files with 737 additions and 87 deletions
@@ -819,11 +819,16 @@ export function localProvisioningDraftFenceKey({
function observationRequest(
target: ReadOnlyConnectionObservationTarget,
desiredModeRevision: number | null | undefined,
reconfigurationRevision: number,
reconfigurationIntentId: string | null,
): ConnectionVerifyRequest | null {
if (!Number.isInteger(desiredModeRevision) || (desiredModeRevision ?? -1) < 0) {
return null;
}
const commonRequest = {
device_id: target.deviceId,
expected_mode_revision: desiredModeRevision as number,
compatibility_attestation: profileSelectionForConnectionMode(
target.connectionMode,
),
@@ -1688,7 +1693,8 @@ export function K1ProvisioningPipeline({
currentReadOnlyReconnectPresentation?.kind === "connection"
&& currentReadOnlyReconnectPresentation.connectionMode === connectionMode;
const physicalRecoveryVerificationPending =
currentReadOnlyReconnectPresentation?.kind === "physical";
currentReadOnlyReconnectPresentation?.kind === "physical"
&& currentReadOnlyReconnectPresentation.connectionMode === connectionMode;
const provisioningMutationBusy = Boolean(
livePreparationPending
|| presentedPendingAction
@@ -1886,8 +1892,15 @@ export function K1ProvisioningPipeline({
const physicalRecoveryAuthorityKey = physicalRecoveryPresentationAuthorityKey(
state,
);
const physicalRecoveryMatchesSelectedMode = Boolean(
physicalRecoveryTarget?.connectionMode === connectionMode
&& state?.desired_connection_mode === connectionMode,
);
const physicalReadOnlyVerificationAvailable = Boolean(
physicalRecoveryTarget?.serverBound || physicalRecoveryVerificationPending,
(
physicalRecoveryMatchesSelectedMode
&& physicalRecoveryTarget?.serverBound
) || physicalRecoveryVerificationPending,
);
const presentedPhysicalRecoveryMode = physicalRecoveryBinding?.connectionMode
?? (physicalRecoveryVerificationPending
@@ -2588,6 +2601,7 @@ export function K1ProvisioningPipeline({
const request = appliedNetworkRecoveryTarget
? observationRequest(
appliedNetworkRecoveryTarget,
desiredModeRevision,
reconfigurationRevision,
reconfigurationIntentId,
)
@@ -2644,6 +2658,7 @@ export function K1ProvisioningPipeline({
async (target) => {
const request = observationRequest(
target,
desiredModeRevision,
reconfigurationRevision,
reconfigurationIntentId,
);
@@ -2709,12 +2724,23 @@ export function K1ProvisioningPipeline({
if (
!physicalRecoveryRequired
|| !physicalRecoveryTarget?.serverBound
|| physicalRecoveryTarget.connectionMode !== connectionMode
|| state?.desired_connection_mode !== connectionMode
|| !snapshotRuntimeId
|| !verificationKey
|| isBusy
|| typeof getConnectionActionAuthority !== "function"
) return;
const modeAuthority = getConnectionActionAuthority(connectionMode);
if (!modeAuthority) {
setCandidateUnavailableMessage(
"Не удалось переподключиться: состояние K1 изменилось. Повторите проверку или подключите новый K1 вручную.",
);
return;
}
const request = observationRequest(
physicalRecoveryTarget,
modeAuthority.desiredModeRevision,
reconfigurationRevision,
reconfigurationIntentId,
);
@@ -2734,19 +2760,10 @@ export function K1ProvisioningPipeline({
});
setCandidateUnavailableMessage(null);
try {
const modeAuthority = await commitDesiredModeForExplicitAction(
physicalRecoveryTarget.connectionMode,
);
if (!localScenarioActionEpochIsCurrent(
actionEpoch,
localScenarioActionEpoch.current,
)) return;
if (!modeAuthority) {
setCandidateUnavailableMessage(
"Не удалось переподключиться: состояние K1 изменилось. Повторите проверку или подключите новый K1 вручную.",
);
return;
}
const actionFence = activateRuntimeActionFence(modeAuthority);
if (!actionFence || !runtimeActionIsCurrent(actionFence)) return;
try {