fix(companion): pack and history files from the card checked, contact loops skip the reserved slots, small UI fixes

- L2 vector packs: a damaged count can't wrap the index size, and an
  entry pointing past the file is refused.
- L2 map share-target list: sized for 40 long channel names and 16
  favourites (it could overflow), off the stack.
- L2 SD history: a file with an unreadable header is set aside as .bad
  instead of written over; Delete message history takes those too.
- Contact lookups by key or hash start after the reserved anon slots (an
  empty one matched a 00 hop hash with a blank name); MessagesScreen uses
  contactctl::hopName().
- Nearby keeps its selection by public key: deleting a contact shifts
  the table.
- ui-new Live Share target cycle holds every channel and favourite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-12 18:31:35 +02:00
co-authored by Claude Opus 5.5
parent 4eee794a17
commit 57db27512d
10 changed files with 51 additions and 41 deletions
@@ -59,6 +59,7 @@ public:
Pack& p = _p[i];
uint32_t off, len;
if (!lookup(p, key, off, len)) continue;
if ((uint64_t)p.data_off + off + len > p.size) return false; // an entry pointing past the file
FILE* f = handle(i);
if (!f || fseek(f, p.data_off + off, SEEK_SET) != 0) return false;
s.f = f; s.len = len; s.owned = false;
@@ -128,8 +129,10 @@ private:
fseek(f, 0, SEEK_END);
p.size = (uint32_t)ftell(f);
p.index = nullptr;
uint32_t isz = p.count * 16;
ok = p.index_off + isz <= p.size && p.data_off <= p.size;
// In 64 bits / by division: a damaged count would otherwise wrap count * 16
// to a small size, pass, and send the index search far past its buffer.
ok = p.count <= p.size / 16 && (uint64_t)p.index_off + (uint64_t)p.count * 16 <= p.size && p.data_off <= p.size;
uint32_t isz = ok ? p.count * 16 : 0;
if (ok && isz <= INDEX_IN_RAM_MAX) {
p.index = psramBuf<uint8_t>(isz ? isz : 1);
if (p.index && (fseek(f, p.index_off, SEEK_SET) != 0 || !readFast(f, p.index, isz))) { free(p.index); p.index = nullptr; }