Add bond conversion API between v1 and v2 bond data preserving old bonds#1121
Conversation
📝 WalkthroughWalkthroughArr, this PR adds a bidirectional NimBLE bond-store migration utility (V1 ⇄ current) and a new Arduino example that can run a one‑time migration before NimBLE initialization, then configures BLE security, creates a service/characteristics, and starts advertising. Changes
Sequence Diagram(s)sequenceDiagram
participant Arduino as Arduino Setup
participant Migration as NimBLEBondMigration
participant NVS as NVS Storage
participant NimBLE as NimBLE Core
Arduino->>Migration: call migrateBondStoreToCurrent()/migrateBondStoreToV1()
Migration->>NVS: nvs_open(namespace)
loop for each index 0..maxEntries
NVS->>Migration: nvs_get_blob(key_our_sec / key_peer_sec)
alt entry found & convertible
Migration->>Migration: parse & convert blob (V1 ⇄ current)
Migration->>NVS: nvs_set_blob(new_key, converted_blob)
else skip or invalid
Migration->>Migration: record skip/unknown
end
end
Migration->>NVS: nvs_commit() (if changes)
Migration->>NVS: nvs_close()
Migration->>Arduino: return success/failure
alt migration not performed or failed
Arduino->>NimBLE: NimBLEDevice::init() and normal startup
else migration succeeded
Arduino-->>Arduino: log + halt for user action
end
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/NimBLEBondMigration.h (1)
202-261: The resource cleanup be correct but could use some streamlinin', matey!Arr, ye be callin'
nvs_close(nvsHandle)on every error path like a responsible sailor. However, the repeated pattern be makin' the code a bit barnacle-encrusted. Consider a simple RAII wrapper or scope guard to reduce duplication.🏴☠️ Optional: RAII cleanup fer cleaner waters
// Simple scope guard approach: struct NvsHandleGuard { nvs_handle_t handle; ~NvsHandleGuard() { nvs_close(handle); } }; inline esp_err_t migrateBondStore(bool toCurrent, uint16_t maxEntries) { nvs_handle_t nvsHandle; esp_err_t err = nvs_open(kBondNamespace, NVS_READWRITE, &nvsHandle); if (err != ESP_OK) { ESP_LOGE(kLogTag, "Failed to open NVS namespace '%s', err=%d", kBondNamespace, static_cast<int>(err)); return err; } NvsHandleGuard guard{nvsHandle}; // ... rest of the function with simple `return err;` statements ... }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NimBLEBondMigration.h` around lines 202 - 261, The function migrateBondStore repeatedly calls nvs_close(nvsHandle) on every error path; introduce a simple RAII/scope-guard (e.g., struct NvsHandleGuard { nvs_handle_t handle; ~NvsHandleGuard() { nvs_close(handle); } }) right after successful nvs_open and initialize it with nvsHandle, then remove all explicit nvs_close calls throughout migrateBondStore so that the guard always closes the handle on return; keep the existing nvs_commit usage and return behavior unchanged, and place the NvsHandleGuard definition in the same translation unit (or a shared header) so migrateBondStore can use it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/NimBLE_Bond_Migration/NimBLE_Bond_Migration.ino`:
- Around line 32-43: When NIMBLE_BOND_MIGRATION_MODE == 2 the code currently
only halts on success; if migrateBondStoreToV1() returns rc != ESP_OK you must
prevent continuing with NimBLE initialization. Modify the block around
NimBLE_Bond_Migration::migrateBondStoreToV1() to detect rc != ESP_OK, log a
clear error (using Serial.printf/println with the rc value and a descriptive
message), and stop further execution (e.g., enter an infinite delay loop) so the
system does not proceed to initialize NimBLE with a failed/partial bond store;
ensure you reference migrateBondStoreToV1(), the rc variable, and ESP_OK in your
change.
In `@src/NimBLEBondMigration.h`:
- Around line 31-69: The BleStoreValueSecV1 and BleStoreValueSecCurrent structs
are vulnerable to compiler padding changes; make their on-disk layout explicit
by applying packing (e.g., wrap definitions with `#pragma` pack(push,1)/#pragma
pack(pop) or add __attribute__((packed)) to each struct) and update any
sizeof()-based version detection to use the packed sizes; alternatively (or
additionally) implement a versioned blob header (magic, version, payload_size)
prepended to stored bond blobs and validate the header before casting bytes to
BleStoreValueSecV1/BleStoreValueSecCurrent to avoid silent corruption across
builds.
---
Nitpick comments:
In `@src/NimBLEBondMigration.h`:
- Around line 202-261: The function migrateBondStore repeatedly calls
nvs_close(nvsHandle) on every error path; introduce a simple RAII/scope-guard
(e.g., struct NvsHandleGuard { nvs_handle_t handle; ~NvsHandleGuard() {
nvs_close(handle); } }) right after successful nvs_open and initialize it with
nvsHandle, then remove all explicit nvs_close calls throughout migrateBondStore
so that the guard always closes the handle on return; keep the existing
nvs_commit usage and return behavior unchanged, and place the NvsHandleGuard
definition in the same translation unit (or a shared header) so migrateBondStore
can use it.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 00d8e269-3224-4f18-b19e-f3e0a11d836b
📒 Files selected for processing (2)
examples/NimBLE_Bond_Migration/NimBLE_Bond_Migration.inosrc/NimBLEBondMigration.h
a7e6a09 to
086a8d9
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/NimBLEBondMigration.h (1)
81-90: Arr, a minor treasure to polish here, cap'n!In
appendLine, ye be callin'strlen(buf)whenwrittenalready tells ye the length (if not truncated). A small optimization to avoid the extra voyage through the string:🏴☠️ Optional polish for efficiency
inline void appendLine(std::string& out, const char* fmt, ...) { char buf[256]; va_list args; va_start(args, fmt); const int written = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (written > 0) { - out.append(buf, strlen(buf)); + out.append(buf, static_cast<size_t>(written) < sizeof(buf) ? written : sizeof(buf) - 1); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NimBLEBondMigration.h` around lines 81 - 90, The appendLine function currently appends using strlen(buf) which redundantly scans the buffer; change it to use the vsnprintf return value `written` to determine how many bytes to append: append `written` when written is non-negative and less than the buffer size, otherwise append the truncated length (buffer size minus one). Update the append in appendLine to calculate the length via written vs. sizeof(buf) to avoid the extra strlen call and to correctly handle truncation cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/NimBLEBondMigration.h`:
- Around line 81-90: The appendLine function currently appends using strlen(buf)
which redundantly scans the buffer; change it to use the vsnprintf return value
`written` to determine how many bytes to append: append `written` when written
is non-negative and less than the buffer size, otherwise append the truncated
length (buffer size minus one). Update the append in appendLine to calculate the
length via written vs. sizeof(buf) to avoid the extra strlen call and to
correctly handle truncation cases.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9355dbf7-0379-4cf3-be55-f435f0ce95c0
📒 Files selected for processing (2)
examples/NimBLE_Bond_Migration/NimBLE_Bond_Migration.inosrc/NimBLEBondMigration.h
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/NimBLE_Bond_Migration/NimBLE_Bond_Migration.ino
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/NimBLEBondMigration.h (2)
404-486: Arr, the resource cleanup be scattered across the seven seas!The
nvs_close(nvsHandle)call appears at every early-return point (lines 420, 426, 431, 437, 444, 449, 455, 460, 470). While functionally correct, this pattern be prone to forgettin' a cleanup on future modifications. A simple RAII wrapper or scope guard would consolidate the cleanup, ye savvy?🧹 Optional RAII cleanup pattern
// At the top of the function, after nvs_open succeeds: struct NvsGuard { nvs_handle_t h; ~NvsGuard() { nvs_close(h); } } guard{nvsHandle}; // Then all returns can simply `return false;` or `return true;` // without explicit nvs_close calls.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NimBLEBondMigration.h` around lines 404 - 486, The function migrateBondStore currently calls nvs_close(nvsHandle) at every early return; introduce a RAII scope guard immediately after successful nvs_open to ensure nvs_close always runs (e.g., a small local struct NvsGuard with nvs_handle_t h and a destructor that calls nvs_close(h)), remove all explicit nvs_close calls in migrateBondStore so early returns simply return true/false, and keep the final commit/return logic unchanged; reference migrateBondStore, nvs_open, nvs_close and the optional NvsGuard wrapper when making the change.
96-105: Consider usin'writtendirectly, ye scallywag!On line 103,
strlen(buf)be redundant whenwrittenalready tells ye the length. However, I spy the subtlety: when truncation occurs (written >= sizeof(buf)),strlengives the correct truncated length. If ye want both efficiency and truncation safety, cap the length explicitly:🔧 Optional efficiency tweak
inline void appendLine(std::string& out, const char* fmt, ...) { char buf[256]; va_list args; va_start(args, fmt); const int written = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (written > 0) { - out.append(buf, strlen(buf)); + const size_t len = (static_cast<size_t>(written) < sizeof(buf)) + ? static_cast<size_t>(written) + : sizeof(buf) - 1; + out.append(buf, len); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NimBLEBondMigration.h` around lines 96 - 105, The appendLine function currently uses strlen(buf) to determine how many bytes to append, which is redundant and unsafe; instead use the vsnprintf return value `written` to compute the append length but cap it to the buffer size to handle truncation and ignore negative errors: compute a length = (written < 0 ? 0 : (written >= (int)sizeof(buf) ? (int)sizeof(buf) - 1 : written)) and call out.append(buf, length) in appendLine (referencing appendLine, buf, and written).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/NimBLEBondMigration.h`:
- Around line 404-486: The function migrateBondStore currently calls
nvs_close(nvsHandle) at every early return; introduce a RAII scope guard
immediately after successful nvs_open to ensure nvs_close always runs (e.g., a
small local struct NvsGuard with nvs_handle_t h and a destructor that calls
nvs_close(h)), remove all explicit nvs_close calls in migrateBondStore so early
returns simply return true/false, and keep the final commit/return logic
unchanged; reference migrateBondStore, nvs_open, nvs_close and the optional
NvsGuard wrapper when making the change.
- Around line 96-105: The appendLine function currently uses strlen(buf) to
determine how many bytes to append, which is redundant and unsafe; instead use
the vsnprintf return value `written` to compute the append length but cap it to
the buffer size to handle truncation and ignore negative errors: compute a
length = (written < 0 ? 0 : (written >= (int)sizeof(buf) ? (int)sizeof(buf) - 1
: written)) and call out.append(buf, length) in appendLine (referencing
appendLine, buf, and written).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b9d9ee94-012d-499a-b711-93b8792a3e92
📒 Files selected for processing (2)
examples/NimBLE_Bond_Migration/NimBLE_Bond_Migration.inosrc/NimBLEBondMigration.h
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/NimBLE_Bond_Migration/NimBLE_Bond_Migration.ino
|
@thebentern It looks like this may be of interest to you. |
Fixes #740
Summary by CodeRabbit