# How the Panic Wipe Feature Works in BitChat: A Complete Source Code Walkthrough

> Explore the BitChat Panic Wipe source code. Understand how this atomic reset synchronously deletes all user data across services, ensuring complete privacy with one tap. Learn more now.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: deep-dive
- Published: 2026-08-22

---

**TLDR:** BitChat's Panic Wipe is a coordinated, atomic reset that synchronously deletes all user-generated data across every service layer — location caches, BLE media files, message outboxes, and in-memory state — then restarts the app cleanly so a user's privacy is fully protected with a single tap.

BitChat, the open-source peer-to-peer messaging app from `permissionlesstech`, implements a privacy-critical **Panic Wipe** feature that erases all locally stored content and resets internal state. Designed to be transactional, the operation either completes fully or leaves the previous state untouched. This walkthrough examines the exact implementation across BitChat's Swift source files.

## What Is the Panic Wipe Feature in BitChat?

The **Panic Wipe** is an emergency data-erasure mechanism that instantly clears every piece of user-generated content stored on the device. Unlike a normal logout or cache clear, it's designed as an atomic operation: the app first stops all network and media services, then synchronously deletes on-disk payloads and in-memory caches, and only then restarts services — guaranteeing no partially-cleared state.

According to the `permissionlesstech/bitchat` repository, the feature is spread across five key layers:

| Layer | Responsibility | Key Implementation |
|-------|----------------|---------------------|
| **UI / ViewModel** | Triggers the wipe (e.g., a user tap on "Panic Wipe") and forwards the request to the core. | `VoiceRecordingViewModel.panicWipe()` — [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/VoiceRecordingViewModel.swift#L228) |
| **ChatViewModel** | Orchestrates the high-level steps: stops network activity, invokes service-level wipes, and finally restarts services after the wipe commits. | `ChatViewModel.panicClearAllData()` calls `LocationStateManager.shared.panicWipe()` — [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/ChatViewModel.swift#L1613) |
| **LocationStateManager** | Performs a global clean-up of location-related caches and timers. | `LocationStateManager.panicWipe()` — [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/LocationStateManager.swift#L630) |
| **BLEIncomingFileStore** | Deletes every managed media file, recreates empty directories, and clears receipt caches. | `BLEIncomingFileStore.panicWipe()` — [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEIncomingFileStore.swift#L196) |
| **AppChromeModel** | Tracks whether a panic wipe is currently blocked (e.g., during a modal presentation) and notifies the UI. | `@Published private(set) var panicWipeBlocked` — [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/App/AppChromeModel.swift#L29) |

## How the Panic Wipe Sequence Unfolds

The wipe operation follows a strict, six-step sequence designed to eliminate race conditions and guarantee complete erasure.

### 1. User Initiates the Panic Wipe

The UI calls `voiceRecordingVM?.panicWipe()` or the higher-level `ChatViewModel.panicClearAllData()`, which forwards the request down the application stack. A simple button in the UI triggers the entire flow:

```swift
// Example: user taps a "Panic Wipe" button in the UI
Button("Panic Wipe") {
    // The view model handles the full reset
    voiceRecordingVM?.panicWipe()
}

```

### 2. Active Services Are Stopped

Before any data is deleted, `ChatViewModel` disables network connections via the **panic network lifecycle** and halts any ongoing media recordings. This prevents new data from being written while the wipe is in progress.

### 3. Service-Level Wipe Methods Execute

Each service — the location manager, BLE file store, message outbox, and bridge courier — implements its own `panicWipe()` method. These methods **synchronously**:

- Delete on-disk payloads
- Clear in-memory caches
- Invalidate any pending callbacks

This is verified in the code by the test suite mentioned in the analysis. For example, [`BLEFileTransferHandlerTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEFileTransferHandlerTests.swift) confirms that pending file transfer operations are cancelled cleanly.

### 4. Persist a Recovery Marker

Some stores write a durable **panic-recovery marker** before deletion. This marker ensures the app can resume from a crash without re-creating deleted data. The marker is kept until an explicit commit succeeds, making the wipe resumable and crash-safe.

### 5. Restart Services

Once every store reports successful deletion, `ChatViewModel` restarts the network layer and UI components. This guarantees the app returns to a clean, usable state.

### 6. UI Feedback

`AppChromeModel.panicWipeBlocked` is toggled to prevent UI interactions during the wipe. The UI can display a progress indicator and, after completion, an "All data cleared" confirmation.

## Code Example: The Full Orchestration

The following Swift code demonstrates how `ChatViewModel` coordinates the entire panic clear operation at the top level:

```swift
// Lower-level: ChatViewModel performing a full data purge
func panicClearAllData(restartServices: Bool = true) async -> Bool {
    // 1. Stop network and media pipelines
    panicNetworkLifecycle.shutdown()
    // 2. Invoke every service's panic wipe
    await LocationStateManager.shared.panicWipe()
    await BLEIncomingFileStore.shared.panicWipe()
    await MessageOutboxStore.shared.panicWipe()
    // 3. Optionally restart services after the wipe commits
    if restartServices { panicNetworkLifecycle.startup() }
    return true
}

```

This method demonstrates the transactional nature: synchronous tasks run sequentially, waiting for each service to complete before the next begins. The `restartServices` parameter provides flexibility for scenarios where the caller wants to keep the app paused.

## Key Source Files for the Panic Wipe Feature

| File | Role | Link |
|------|------|------|
| [`VoiceRecordingViewModel.swift`](https://github.com/permissionlesstech/bitchat/blob/main/VoiceRecordingViewModel.swift) | Defines `panicWipe()` for the voice recording UI layer. | [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/VoiceRecordingViewModel.swift) |
| [`ChatViewModel.swift`](https://github.com/permissionlesstech/bitchat/blob/main/ChatViewModel.swift) | Top-level orchestrator for panic wipes. | [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/ChatViewModel.swift) |
| [`LocationStateManager.swift`](https://github.com/permissionlesstech/bitchat/blob/main/LocationStateManager.swift) | Clears location-related caches and timers. | [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/LocationStateManager.swift) |
| [`BLEIncomingFileStore.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEIncomingFileStore.swift) | Clears all incoming BLE media files and receipt stores. | [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEIncomingFileStore.swift) |
| [`AppChromeModel.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppChromeModel.swift) | UI state flag that blocks actions during a panic wipe. | [source](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/App/AppChromeModel.swift) |

## Why the Panic Wipe Is Synchronous by Design

The codebase deliberately implements critical paths as **synchronous** operations. For instance, `panicCancelSynchronously()` appears in [`VoiceCaptureSessionTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/VoiceCaptureSessionTests.swift), verifying that no asynchronous file-writes or network calls can race with the wipe.

This design choice makes the **Panic Wipe transactional**: either everything is cleared and the app restarts, or the operation aborts and the previous state remains untouched. There is no middle ground where partial data survives, which is essential for a privacy-guaranteeing feature.

## Summary

- BitChat's Panic Wipe is a layered, atomic reset that deletes all user data, stops services, and restarts the app.
- The flow begins with `VoiceRecordingViewModel.panicWipe()`, is orchestrated by `ChatViewModel.panicClearAllData()`, and delegates to service-specific `panicWipe()` methods.
- Each wipe is **synchronous**, preventing race conditions between deletion and background writes.
- A persistent recovery marker makes the wipe crash-safe, ensuring the app can resume from a restart without recreating deleted files.
- `AppChromeModel.panicWipeBlocked` guards the UI during the process, providing clean user feedback.

## Frequently Asked Questions

### How does Panic Wipe differ from logging out in BitChat?

Panic Wipe deletes **all** locally stored data — media files, caches, message history — and resets internal app state. Logging out typically preserves some data like message archives, while Panic Wipe is designed to be a complete privacy erasure.

### Is the Panic Wipe reversible?

No. Once the wipe commits, data deletion is immediate and beyond recovery. That's why the operation runs synchronously after the user confirms, and the app stops network services first to prevent accidental re-sync of deleted content.

### What happens if the app crashes mid-wipe?

The panic-recovery marker is written before deletion begins. If a crash occurs, the app reads the marker on next launch and continues deleting the remaining data — never partial state.

### Can a developer call Panic Wipe programmatically?

Yes. Any Swift code can invoke `ChatViewModel.panicClearAllData(restartServices:)` directly, or tap into a specific service's `panicWipe()` method — if they need to clear just location data or BLE media files without a full reset.