# Retro Firmware H3V — Bug Fix Plan

Firmware: `retro_2026` | Последна версия: `H3V_1.0.7`  
Дата на анализ: 2026-06-26  
Статус: 🔴 В прогрес

---

## Легенда

| Икона | Статус |
|-------|--------|
| ⬜ | Не е започнато |
| 🔄 | В прогрес |
| ✅ | Завършено |

---

## Сесия A — Сигурност и функционалност

### 🔴 Критични бъгове

#### A1 ✅ Buffer overflow в `loadConfiguration()` — грешни размери в `strlcpy`
**Файл:** `src/main.cpp` — функция `loadConfiguration()`  
**Проблем:** Навсякъде е `sizeof(field) + 1` вместо `sizeof(field)`. `strlcpy(dst, src, n)` вече включва null-terminator — добавянето на +1 позволява запис извън буфера.  
Второ: `config.appass` (16 байта) се копира с `sizeof(config.pass)` (30) → buffer overflow.
```cpp
// ГРЕШНО:
strlcpy(config.ip_address, doc["ip_address"] | "192.168.1.100", sizeof(config.ip_address) + 1);
strlcpy(config.appass, doc["appass"] | "biodit2021", sizeof(config.pass) + 1);

// ПРАВИЛНО:
strlcpy(config.ip_address, doc["ip_address"] | "192.168.1.100", sizeof(config.ip_address));
strlcpy(config.appass, doc["appass"] | "biodit2021", sizeof(config.appass));
```

#### A2 ✅ Buffer overflow в `factory_reset()` — грешен размер
**Файл:** `src/main.cpp` — функция `factory_reset()`  
**Проблем:** `config.gateway` (16 байта) се копира с `sizeof(config.mqtt)` (30).
```cpp
// ГРЕШНО:
strlcpy(config.gateway, "192.168.1.1", sizeof(config.mqtt));

// ПРАВИЛНО:
strlcpy(config.gateway, "192.168.1.1", sizeof(config.gateway));
```

#### A3 ✅ Събитието не се записва ако SPIFFS не се монтира в `wakeup_by_proxy()`
**Файл:** `src/main.cpp` — функция `wakeup_by_proxy()`  
**Проблем:** `SPIFFS.begin()` е преди `checkAccess()`. При SPIFFS грешка функцията излиза преди да е проверила картата — събитието се губи.  
**Уточнение:** Вратата ще се отвори, защото `config` е в `RTC_DATA_ATTR` и е наличен. Проблемът е само, че логът не се записва.  
**Fix:** Опитай SPIFFS.begin() но не прекъсвай при грешка — провери картата винаги, запиши лог само ако SPIFFS е OK.
```cpp
// СЕГА:
if (!SPIFFS.begin(false)) { return; }  // ← излиза, губи събитието
if (card_found) { checkAccess(); }

// ТРЯБВА:
bool spiffs_ok = SPIFFS.begin(false);
if (card_found) { checkAccess(); }     // ← винаги проверява
if (spiffs_ok) { loadConfiguration(); }
// saveEvent() вътрешно трябва да провери дали SPIFFS е монтиран
```

---

### 🟠 Бъгове

#### A4 ✅ `publishErrorCard()` игнорира параметъра си
**Файл:** `src/main.cpp` — функция `publishErrorCard()`  
**Проблем:** Параметърът `card` веднага се override-ва с `access_late_card`. Параметърът е безсмислен.
```cpp
void publishErrorCard(uint64_t card) {
  card = access_late_card; // ← ГРЕШНО: игнорира параметъра
}
// Fix: премахни override реда, ползвай параметъра
```

#### A5 ✅ `clear` MQTT команда — `deleteFile()` без монтиран SPIFFS
**Файл:** `src/main.cpp` — `mac_subscriber()`, case `"clear"`  
**Проблем:** `deleteFile(SPIFFS, "/users.txt")` се извиква без `SPIFFS.begin()`. При timer wakeup SPIFFS не е монтиран.
```cpp
// Fix: добави SPIFFS.begin() преди deleteFile
else if (payload.equals("clear"))
{
  SPIFFS.begin(false);
  deleteFile(SPIFFS, "/users.txt");
  confirmOkReceiving();
  return;
}
```

#### A6 ✅ Log файлът се "изчиства" с интервал `" "` вместо с `""`
**Файл:** `src/main.cpp` — функция `sendLog()`  
**Проблем:** `filesys.writeFile(SPIFFS, "/log.csv", " ")` — следващото `readFile` ще прочете `" "` и ще го изпрати по MQTT. Django парсерът трябва да го обработва, но е по-чисто да се изчиства напълно.
```cpp
// ГРЕШНО:
filesys.writeFile(SPIFFS, "/log.csv", " ");

// ПРАВИЛНО:
filesys.writeFile(SPIFFS, "/log.csv", "");
```

#### A7 ✅ Грешен MIME type за `/log.csv`
**Файл:** `src/main.cpp` — функция `startServer()`  
**Проблем:** `"text/css"` вместо `"text/plain"`.
```cpp
// ГРЕШНО:
request->send(SPIFFS, "/log.csv", "text/css");

// ПРАВИЛНО:
request->send(SPIFFS, "/log.csv", "text/plain");
```

#### A8 ✅ MQTT credentials са hardcoded — не се ползват config полетата
**Файл:** `src/main.cpp` — функция `connectBroker()`  
**Проблем:** `config.mqtt_user` и `config.mqtt_user_pass` се зареждат от конфига, но не се ползват.
```cpp
// ГРЕШНО:
mqttClient.setCredentials("device", "biodit");

// ПРАВИЛНО:
mqttClient.setCredentials(config.mqtt_user, config.mqtt_user_pass);
```

#### A9 ✅ `saveEvent()` guard е с обърната логика
**Файл:** `src/main.cpp` — функция `saveEvent()`  
**Проблем:** `#ifndef RFID_ONLY return;` — работи правилно, но е объркващо. Трябва `#ifdef RFID_ONLY` за яснота.
```cpp
// ГРЕШНО (объркващо):
#ifndef RFID_ONLY
  return;
#endif
// ... код, който трябва да се изпълнява само при RFID_ONLY

// ПРАВИЛНО (ясно):
#ifndef RFID_ONLY
  return;  // или по-добре: изтрий guard-а изцяло (RFID_ONLY е винаги дефиниран)
#endif
// Алтернатива: просто махни guard-а щом RFID_ONLY е permanent define
```

---

## Сесия B — Мъртъв код (cleanup)

#### B1 ⬜ Премахни `ready_to_sleep` — никога не се сетва `true`
**Файл:** `src/main.cpp`  
Декларация на ред ~150, проверка в `closedoor()` — branch никога не се изпълнява.

#### B2 ⬜ Премахни `corectTime()` — никъде не се извиква
**Файл:** `src/main.cpp`, `src/main.h`  
Функцията е дефинирана и декларирана, но никога не се извиква.

#### B3 ⬜ Премахни `sendLateMessage()` и `to_send_late` — dead code
**Файл:** `src/main.cpp`, `src/main.h`  
`to_send_late` никога не се сетва `true`. `sendLateMessage()` е коментирана в `wakeup_by_time()`.

#### B4 ⬜ Премахни неизползвани глобални променливи
**Файл:** `src/main.cpp`  
Следните се декларират но никога не се ползват:
- `const char *ttime` 
- `ThreadController threadControl`
- `Thread thread`
- `String ledState`
- `const String s = ""`
- `RTC_DATA_ATTR int bootCount` (декларира се, никога не се инкрементира или чете)

#### B5 ⬜ Опрости `publishUserAcces()` — премахни `if (card > 200)` branch
**Файл:** `src/main.cpp`  
Беше за разграничаване fingerprint slot (малко число) от RFID card number (голямо число). След махане на fingerprint, `card` е винаги RFID (голямо число ≥ 10 цифри). `else` branch е мъртъв.
```cpp
// Опрости до:
sprintf(out_message_buffer, "%s/%s/%010llu/%llu/%s/%u", 
        MAC_char, EVENT_TYPE, card, userId, stime, 
        tools.calc_battery_percentage(analogRead(BATTERY_IN)));
```

#### B6 ⬜ Премахни `USERS_FILE` define и `WiFiClient espClient`
**Файл:** `src/main.cpp`  
- `USERS_FILE` (`/users.txt`) вече не се ползва след махане на fingerprint  
- `WiFiClient espClient` — ползва се само за `espClient.stop()` в `goSleep()`, което не прави нищо полезно без активна connection

#### B7 ⬜ Поправи `AWAKE_TIME` коментар
**Файл:** `src/main.cpp` ред ~76  
```cpp
#define AWAKE_TIME 5000  // 2 sec  ← ГРЕШНО, трябва "5 sec"
```

#### B8 ⬜ Поправи дублираната декларация на `sendLog()` в `main.h`
**Файл:** `src/main.h`  
`sendLog()` е декларирана два пъти.

---

## След всяка сесия

- [ ] Rebuild с PlatformIO: `pio run`
- [ ] Upload новия .bin в Django admin
- [ ] Тест с реална платка

---

## Версии

| Версия | Промени |
|--------|---------|
| H3V_1.0.7 | Махнат fingerprint код (SensorSM30, SensorController) |
| H3V_1.0.8 | *планирана — Сесия A fixes* |
| H3V_1.0.9 | *планирана — Сесия B cleanup* |
