Skip to content

Commit

Permalink
Bugfixing and security features
Browse files Browse the repository at this point in the history
- detect sensor replacement by pairing
- added missing dependencies
  • Loading branch information
frickelzeugs committed Feb 5, 2022
1 parent f62e69e commit a27e890
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 33 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Hard resetting via RTS pin...

Your device should now boot up and the LED ring should start flashing slowly red ("breathing") to signal that it's currently in WiFi Config mode. Proceed with the configuration of the device.

## Build and flash with Visual Studio Code and PlattformIO
## Method 2: build and flash with Visual Studio Code and PlattformIO
todo

# Configuration
Expand All @@ -122,9 +122,11 @@ todo
todo

## Firmware Update
If you've managed to walk the bumpy path of flashing the firmware on the ESP32 for the first time, be calmed: every further firmware update will be a piece of cake. FingerprintDoorbell is using the Library Elegant OTA to make this as handy as possible. You don't even have to pull out the micro controller of the wall and connect it to your computer by USB, because the "OTA" in "Elegant OTA" is for Over-the-air updates. All you need to do is to go on the settings page of the WebUI and hit "Firmware update". In the following Dialog you have to upload two files
If you've managed to walk the bumpy path of flashing the firmware on the ESP32 for the first time, be calmed: every further firmware update will be a piece of cake. FingerprintDoorbell is using the really cool Library [AsyncElegantOTA](https://github.com/ayushsharma82/AsyncElegantOTA) to make this as handy as possible. You don't even have to pull the microcontroller out of the wall and connect it to your computer, because the "OTA" in "AsyncElegantOTA" is for "Over-the-air" updates. All you need to do is to browse to the settings page of the WebUI and hit "Firmware update". In the following Dialog you have to upload 2 files

- firmware.bin for the "Firmware" radio button
- spiffs.bin for the "Filesystem" radio button

Done. Reboot your system to get the new firmware live.

# FAQ
Expand Down
1 change: 1 addition & 0 deletions data/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
<label class="col-md-4 control-label" for="btnFirmwareUpdate"></label>
<div class="col-md-4">
<button id="btnFirmwareUpdate" name="btnFirmwareUpdate" class="btn btn-info" type="submit" formaction="update">Firmware-Update </button>
<button id="btnDoPairing" name="btnDoPairing" class="btn btn-warning" type="submit" formaction="pairing">Pairing a new sensor </button>
<button id="btnFactoryReset" name="btnFactoryReset" class="btn btn-danger" type="submit" formaction="factoryReset" onclick="return confirm('This will delete all fingerprints, your settings and your WiFi configuration. Are you sure you wanna do that?')">Factory-Reset</button>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ lib_deps =
me-no-dev/ESP Async WebServer@^1.2.3
ayushsharma82/AsyncElegantOTA@^2.2.6
knolleary/PubSubClient@^2.8
adafruit/Adafruit Fingerprint Sensor Library@^2.0.7
intrbiz/Crypto@^1.0.0
lib_ldf_mode = deep
62 changes: 57 additions & 5 deletions src/FingerprintManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ NewFinger FingerprintManager::enrollFinger(int id, String name) {
NewFinger newFinger;
newFinger.enrollResult = EnrollResult::error;

lastTouchState = true; // HACK: after enrollment, scan mode kicks in again. Force update of the ring light back to normal on first iteration of scan mode.
lastTouchState = true; // after enrollment, scan mode kicks in again. Force update of the ring light back to normal on first iteration of scan mode.


notifyClients(String("Enrollment for id #") + id + " started. We need to scan your finger 5 times until enrollment is completed.");
Expand Down Expand Up @@ -470,17 +470,69 @@ bool FingerprintManager::deleteAll() {



void FingerprintManager::writeNotepad(String text) {
uint8_t FingerprintManager::writeNotepad(uint8_t pageNumber, const char *text, uint8_t length) {
uint8_t data[34];

if (length>32)
length = 32;

data[0] = FINGERPRINT_WRITENOTEPAD;
data[1] = pageNumber;
for (int i=0; i<length; i++)
data[i+2] = text[i];

Adafruit_Fingerprint_Packet packet(FINGERPRINT_COMMANDPACKET, sizeof(data), data);
finger.writeStructuredPacket(packet);
if (finger.getStructuredPacket(&packet) != FINGERPRINT_OK)
return FINGERPRINT_PACKETRECIEVEERR;
if (packet.type != FINGERPRINT_ACKPACKET)
return FINGERPRINT_PACKETRECIEVEERR;
return packet.data[0];
}


String FingerprintManager::readNotepad() {
String text;
return text;
uint8_t FingerprintManager::readNotepad(uint8_t pageNumber, char *text, uint8_t length) {
uint8_t data[2];

data[0] = FINGERPRINT_READNOTEPAD;
data[1] = pageNumber;

Adafruit_Fingerprint_Packet packet(FINGERPRINT_COMMANDPACKET, sizeof(data), data);
finger.writeStructuredPacket(packet);
if (finger.getStructuredPacket(&packet) != FINGERPRINT_OK)
return FINGERPRINT_PACKETRECIEVEERR;
if (packet.type != FINGERPRINT_ACKPACKET)
return FINGERPRINT_PACKETRECIEVEERR;

if (packet.data[0] == FINGERPRINT_OK) {
// read data payload
for (uint8_t i=0; i<length; i++) {
text[i] = packet.data[i+1];
}
}

return packet.data[0];

}


String FingerprintManager::getPairingCode() {
char buffer[33];
buffer[32] = 0; // null termination needed for convertion to string at the end
if (readNotepad(0, (char*)buffer, 32) == FINGERPRINT_OK)
return String((char*)buffer);
else
return "";
}


bool FingerprintManager::setPairingCode(String pairingCode) {
if (writeNotepad(0, pairingCode.c_str(), 32) == FINGERPRINT_OK)
return true;
else
return false;
}


// ToDo: support sensor replacement by enable transferring of sensor DB to another sensor
void FingerprintManager::exportSensorDB() {
Expand Down
7 changes: 5 additions & 2 deletions src/FingerprintManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ class FingerprintManager {
bool isRingTouched();
void loadFingerListFromPrefs();
void disconnect();
void writeNotepad(String text);
String readNotepad();
uint8_t writeNotepad(uint8_t pageNumber, const char *text, uint8_t length);
uint8_t readNotepad(uint8_t pageNumber, char *text, uint8_t length);



public:
Expand All @@ -63,6 +64,8 @@ class FingerprintManager {
void setLedRingError();
void setLedRingWifiConfig();
void setLedRingReady();
String getPairingCode();
bool setPairingCode(String pairingCode);

bool deleteAll();

Expand Down
42 changes: 40 additions & 2 deletions src/SettingsManager.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "SettingsManager.h"
#include <Crypto.h>

void SettingsManager::loadWifiSettings() {
Preferences preferences;
Expand All @@ -17,6 +18,9 @@ void SettingsManager::loadAppSettings() {
appSettings.mqttPassword = preferences.getString("mqttPassword", String(""));
appSettings.mqttRootTopic = preferences.getString("mqttRootTopic", String("fingerprintDoorbell"));
appSettings.ntpServer = preferences.getString("ntpServer", String("pool.ntp.org"));
appSettings.sensorPin = preferences.getString("sensorPin", "00000000");
appSettings.sensorPairingCode = preferences.getString("pairingCode", "");
appSettings.sensorPairingValid = preferences.getBool("pairingValid", false);
preferences.end();
}

Expand All @@ -37,14 +41,17 @@ void SettingsManager::saveAppSettings() {
preferences.putString("mqttPassword", appSettings.mqttPassword);
preferences.putString("mqttRootTopic", appSettings.mqttRootTopic);
preferences.putString("ntpServer", appSettings.ntpServer);
preferences.putString("sensorPin", appSettings.sensorPin);
preferences.putString("pairingCode", appSettings.sensorPairingCode);
preferences.putBool("pairingValid", appSettings.sensorPairingValid);
preferences.end();
}

WifiSettings SettingsManager::getWifiSettings() {
return wifiSettings;
}

void SettingsManager::setWifiSettings(WifiSettings newSettings) {
void SettingsManager::saveWifiSettings(WifiSettings newSettings) {
wifiSettings = newSettings;
saveWifiSettings();
}
Expand All @@ -53,7 +60,7 @@ AppSettings SettingsManager::getAppSettings() {
return appSettings;
}

void SettingsManager::setAppSettings(AppSettings newSettings) {
void SettingsManager::saveAppSettings(AppSettings newSettings) {
appSettings = newSettings;
saveAppSettings();
}
Expand Down Expand Up @@ -85,3 +92,34 @@ bool SettingsManager::deleteWifiSettings() {
return rc;
}

String SettingsManager::generateNewPairingCode() {

/* Create a SHA256 hash */
SHA256 hasher;

/* Put some unique values as input in our new hash */
hasher.doUpdate( String(esp_random()).c_str() ); // random number
hasher.doUpdate( String(millis()).c_str() ); // time since boot
hasher.doUpdate(getTimestampString().c_str()); // current time (if NTP is available)
hasher.doUpdate(appSettings.mqttUsername.c_str());
hasher.doUpdate(appSettings.mqttPassword.c_str());
hasher.doUpdate(wifiSettings.ssid.c_str());
hasher.doUpdate(wifiSettings.password.c_str());

/* Compute the final hash */
byte hash[SHA256_SIZE];
hasher.doFinal(hash);

// Convert our 32 byte hash to 32 chars long hex string. When converting the entire hash to hex we would need a length of 64 chars.
// But because we only want a length of 32 we only use the first 16 bytes of the hash. I know this will increase possible collisions,
// but for detecting a sensor replacement (which is the use-case here) it will still be enough.
char hexString[33];
hexString[32] = 0; // null terminatation byte for converting to string later
for (byte i=0; i < 16; i++) // use only the first 16 bytes of hash
{
sprintf(&hexString[i*2], "%02x", hash[i]);
}

return String((char*)hexString);
}

11 changes: 8 additions & 3 deletions src/SettingsManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ struct AppSettings {
String mqttUsername = "";
String mqttPassword = "";
String mqttRootTopic = "fingerprintDoorbell";
String ntpServer = "pool.ntp.org";
String ntpServer = "pool.ntp.org";
String sensorPin = "00000000";
String sensorPairingCode = "";
bool sensorPairingValid = false;
};

class SettingsManager {
Expand All @@ -31,16 +34,18 @@ class SettingsManager {
void loadAppSettings();

WifiSettings getWifiSettings();
void setWifiSettings(WifiSettings newSettings);
void saveWifiSettings(WifiSettings newSettings);

AppSettings getAppSettings();
void setAppSettings(AppSettings newSettings);
void saveAppSettings(AppSettings newSettings);

bool isWifiConfigured();

bool deleteAppSettings();
bool deleteWifiSettings();

String generateNewPairingCode();

};

#endif
1 change: 1 addition & 0 deletions src/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
#include <WString.h>

extern void notifyClients(String message);
extern String getTimestampString();

#endif
Loading

0 comments on commit a27e890

Please sign in to comment.