Fixed bug in setPairingCode() and added second "internal" argument

homeSpan.setPairingCode() operates silently if called from within a sketch, but will report error to Serial Monitor and HALT sketch if code is invalid.

Otherwise, if called from 'S', or from AP, or as default during start-up, diagnostics are printed as usual and sketch will NOT halt if invalid code is provided
This commit is contained in:
Gregg 2024-03-02 11:57:40 -06:00
parent c17fabe326
commit 0d404ccf1b
5 changed files with 68 additions and 49 deletions

View File

@ -38,9 +38,6 @@ void HAPClient::init(){
size_t len; // not used but required to read blobs from NVS
nvs_open("SRP",NVS_READWRITE,&srpNVS); // open SRP data namespace in NVS
nvs_open("HAP",NVS_READWRITE,&hapNVS); // open HAP data namespace in NVS
if(strlen(homeSpan.spanOTA.otaPwd)==0){ // OTA password has not been specified in sketch
if(!nvs_get_str(homeSpan.otaNVS,"OTADATA",NULL,&len)){ // if found OTA data in NVS...
nvs_get_str(homeSpan.otaNVS,"OTADATA",homeSpan.spanOTA.otaPwd,&len); // ...retrieve data.
@ -49,9 +46,6 @@ void HAPClient::init(){
}
}
if(nvs_get_blob(srpNVS,"VERIFYDATA",NULL,&len)) // if Pair-Setup verification code data not found in NVS
homeSpan.setPairingCode(DEFAULT_SETUP_CODE); // create and save verification from using Pairing Setup Code
if(!strlen(homeSpan.qrID)){ // if Setup ID has not been specified in sketch
if(!nvs_get_str(hapNVS,"SETUPID",NULL,&len)){ // check for saved value
nvs_get_str(hapNVS,"SETUPID",homeSpan.qrID,&len); // retrieve data
@ -60,6 +54,9 @@ void HAPClient::init(){
}
}
if(nvs_get_blob(homeSpan.srpNVS,"VERIFYDATA",NULL,&len)) // if Pair-Setup verification code data not found in NVS
homeSpan.setPairingCode(DEFAULT_SETUP_CODE,false); // create and save verification from default Pairing Setup Code
if(!nvs_get_blob(hapNVS,"ACCESSORY",NULL,&len)){ // if found long-term Accessory data in NVS
nvs_get_blob(hapNVS,"ACCESSORY",&accessory,&len); // retrieve data
} else {
@ -316,6 +313,8 @@ int HAPClient::unauthorizedError(){
int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
static SRP6A *srp=NULL; // must persist across multiple calls to postPairSetupURL
HAPTLV iosTLV;
HAPTLV responseTLV;
HAPTLV subTLV;
@ -378,7 +377,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
TempBuffer<Verification> verifyData; // retrieve verification data (should already be stored in NVS)
size_t len=verifyData.len();
nvs_get_blob(srpNVS,"VERIFYDATA",verifyData,&len);
nvs_get_blob(homeSpan.srpNVS,"VERIFYDATA",verifyData,&len);
responseTLV.add(kTLVType_Salt,16,verifyData.get()->salt); // write Salt from verification data into TLV
@ -542,6 +541,7 @@ int HAPClient::postPairSetupURL(uint8_t *content, size_t len){
tlvRespond(responseTLV); // send response to client
delete srp; // delete SRP - no longer needed once pairing is completed
srp=NULL; // reset to NULL
mdns_service_txt_item_set("_hap","_tcp","sf","0"); // broadcast new status
@ -1691,11 +1691,10 @@ void HapOut::HapStreamBuffer::printFormatted(char *buf, size_t nChars, size_t ns
// instantiate all static HAP Client structures and data
nvs_handle HAPClient::hapNVS;
nvs_handle HAPClient::srpNVS;
HKDF HAPClient::hkdf;
pairState HAPClient::pairStatus;
Accessory HAPClient::accessory;
list<Controller, Mallocator<Controller>> HAPClient::controllerList;
SRP6A *HAPClient::srp=NULL;
//SRP6A *HAPClient::srp=NULL;
int HAPClient::conNum;

View File

@ -106,10 +106,9 @@ struct HAPClient {
static const int MAX_ACCESSORIES=150; // maximum number of allowed Accessories (HAP limit=150)
static nvs_handle hapNVS; // handle for non-volatile-storage of HAP data
static nvs_handle srpNVS; // handle for non-volatile-storage of SRP data
static HKDF hkdf; // generates (and stores) HKDF-SHA-512 32-byte keys derived from an inputKey of arbitrary length, a salt string, and an info string
static pairState pairStatus; // tracks pair-setup status
static SRP6A *srp; // stores all SRP-6A keys used for Pair-Setup (must persist through multiple calls to Pair-Setup)
// static SRP6A *srp; // stores all SRP-6A keys used for Pair-Setup (must persist through multiple calls to Pair-Setup)
static Accessory accessory; // Accessory ID and Ed25519 public and secret keys- permanently stored
static list<Controller, Mallocator<Controller>> controllerList; // linked-list of Paired Controller IDs and ED25519 long-term public keys - permanently stored
static int conNum; // connection number - used to keep track of per-connection EV notifications

View File

@ -45,15 +45,35 @@ const __attribute__((section(".rodata_custom_desc"))) SpanPartition spanPartitio
using namespace Utils;
HapOut hapOut; // Specialized output stream that can both print to serial monitor and encrypt/transmit to HAP Clients with minimal memory usage (global-scope)
HapOut hapOut; // Specialized output stream that can both print to serial monitor and encrypt/transmit to HAP Clients with minimal memory usage (global-scoped variable)
HAPClient **hap; // HAP Client structure containing HTTP client connections, parsing routines, and state variables (global-scoped variable)
Span homeSpan; // HAP Attributes database and all related control functions for this Accessory (global-scoped variable)
HapCharacteristics hapChars; // Instantiation of all HAP Characteristics (used to create SpanCharacteristics)
HapCharacteristics hapChars; // Instantiation of all HAP Characteristics used to create SpanCharacteristics (global-scoped variable)
///////////////////////////////
// Span //
///////////////////////////////
Span::Span(){
nvs_flash_init(); // initialize non-volatile-storage partition in flash
nvs_open("CHAR",NVS_READWRITE,&charNVS); // open Characteristic data namespace in NVS
nvs_open("WIFI",NVS_READWRITE,&wifiNVS); // open WIFI data namespace in NVS
nvs_open("OTA",NVS_READWRITE,&otaNVS); // open OTA data namespace in NVS
nvs_open("SRP",NVS_READWRITE,&srpNVS); // open SRP data namespace in NVS
nvs_open("HAP",NVS_READWRITE,&HAPClient::hapNVS); // open HAP data namespace in NVS
nvs_get_u8(wifiNVS,"REBOOTS",&rebootCount);
rebootCount++;
nvs_set_u8(wifiNVS,"REBOOTS",rebootCount);
nvs_commit(wifiNVS);
}
///////////////////////////////
void Span::begin(Category catID, const char *displayName, const char *hostNameBase, const char *modelName){
loopTaskHandle=xTaskGetCurrentTaskHandle(); // a roundabout way of getting the current task handle
@ -78,16 +98,6 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa
hapServer=new WiFiServer(tcpPortNum);
nvs_flash_init(); // initialize non-volatile-storage partition in flash
nvs_open("CHAR",NVS_READWRITE,&charNVS); // open Characteristic data namespace in NVS
nvs_open("WIFI",NVS_READWRITE,&wifiNVS); // open WIFI data namespace in NVS
nvs_open("OTA",NVS_READWRITE,&otaNVS); // open OTA data namespace in NVS
nvs_get_u8(wifiNVS,"REBOOTS",&rebootCount);
rebootCount++;
nvs_set_u8(wifiNVS,"REBOOTS",rebootCount);
nvs_commit(wifiNVS);
size_t len;
if(strlen(network.wifiData.ssid)){ // if setWifiCredentials was already called
@ -677,7 +687,7 @@ void Span::processSerialCommand(const char *c){
case 'S': {
setPairingCode(c+1);
setPairingCode(c+1,false);
}
break;
@ -736,13 +746,10 @@ void Span::processSerialCommand(const char *c){
nvs_set_blob(wifiNVS,"WIFIDATA",&network.wifiData,sizeof(network.wifiData)); // update data
nvs_commit(wifiNVS); // commit to NVS
LOG0("\n*** Credentials saved!\n");
if(strlen(network.setupCode)){
char s[10];
sprintf(s,"S%s",network.setupCode);
processSerialCommand(s);
} else {
if(strlen(network.setupCode))
setPairingCode(network.setupCode,false);
else
LOG0("*** Setup Code Unchanged\n");
}
LOG0("\n*** Restarting...\n\n");
STATUS_UPDATE(start(LED_ALERT),HS_AP_TERMINATED)
@ -1204,33 +1211,42 @@ const char* Span::statusString(HS_STATUS s){
///////////////////////////////
Span& Span::setPairingCode(const char *s){
Span& Span::setPairingCode(const char *s, boolean progCall){
char setupCode[10];
sscanf(s," %9[0-9]",setupCode);
if(strlen(setupCode)!=8){
LOG0("\n*** Invalid request to change Setup Code. Code must be exactly 8 digits.\n\n");
LOG0("\n*** Invalid request to change Setup Code to '%s'. Code must be exactly 8 digits.\n\n",s);
if(progCall){
LOG0("=== PROGRAM HALTED ===");
while(1);
}
return(*this);
}
if(!network.allowedCode(setupCode)){
LOG0("\n*** Invalid request to change Setup Code. Code too simple.\n\n");
LOG0("\n*** Invalid request to change Setup Code to '%s'. Code too simple.\n\n",s);
if(progCall){
LOG0("=== PROGRAM HALTED ===");
while(1);
}
return(*this);
}
TempBuffer<Verification> verifyData; // temporary storage for verification data
SRP6A *srp=new SRP6A; // create temporary instance of SRP
LOG0("\nGenerating SRP verification data for new Setup Code: %.3s-%.2s-%.3s ... ",setupCode,setupCode+3,setupCode+5);
if(!progCall)
LOG0("\nGenerating new SRP verification data for Setup Code: %.3s-%.2s-%.3s ... ",setupCode,setupCode+3,setupCode+5);
srp->createVerifyCode(setupCode,verifyData); // create random salt and compute verification code from specified Setup Code
nvs_set_blob(HAPClient::srpNVS,"VERIFYDATA",verifyData,verifyData.len()); // update data
nvs_commit(HAPClient::srpNVS); // commit to NVS
srp->createVerifyCode(setupCode,verifyData); // create random salt and compute verification code from specified Setup Code
nvs_set_blob(srpNVS,"VERIFYDATA",verifyData,verifyData.len()); // update data
nvs_commit(srpNVS); // commit to NVS
LOG0("New Code Saved!\n");
LOG0("Setup Payload for Optional QR Code: %s\n\n",qrCode.get(atoi(setupCode),qrID,atoi(category)));
if(!progCall)
LOG0("New Code Saved!\nSetup Payload for Optional QR Code: %s\n\n",qrCode.get(atoi(setupCode),qrID,atoi(category)));
delete srp;
return(*this);

View File

@ -215,9 +215,6 @@ class Span{
boolean isBridge=true; // flag indicating whether device is configured as a bridge (i.e. first Accessory contains nothing but AccessoryInformation and HAPProtocolInformation)
HapQR qrCode; // optional QR Code to use for pairing
const char *sketchVersion="n/a"; // version of the sketch
nvs_handle charNVS; // handle for non-volatile-storage of Characteristics data
nvs_handle wifiNVS=0; // handle for non-volatile-storage of WiFi data
nvs_handle otaNVS; // handle for non-volatile storage of OTA data
char pairingCodeCommand[12]=""; // user-specified Pairing Code - only needed if Pairing Setup Code is specified in sketch using setPairingCode()
String lastClientIP="0.0.0.0"; // IP address of last client accessing device through encrypted channel
boolean newCode; // flag indicating new application code has been loaded (based on keeping track of app SHA256)
@ -225,6 +222,11 @@ class Span{
uint8_t rebootCount=0; // counts number of times device was rebooted (used in optional Reboot callback)
uint32_t rebootCallbackTime; // length of time to wait (in milliseconds) before calling optional Reboot callback
nvs_handle charNVS; // handle for non-volatile-storage of Characteristics data
nvs_handle wifiNVS=0; // handle for non-volatile-storage of WiFi data
nvs_handle otaNVS; // handle for non-volatile storage of OTA data
nvs_handle srpNVS; // handle for non-volatile storage of SRP data
int connected=0; // WiFi connection status (increments upon each connect and disconnect)
unsigned long waitTime=60000; // time to wait (in milliseconds) between WiFi connection attempts
unsigned long alarmConnect=0; // time after which WiFi connection attempt should be tried again
@ -291,6 +293,8 @@ class Span{
public:
Span(); // constructor
void begin(Category catID=DEFAULT_CATEGORY,
const char *displayName=DEFAULT_DISPLAY_NAME,
const char *hostNameBase=DEFAULT_HOST_NAME,
@ -342,7 +346,7 @@ class Span{
Span& setWifiCredentials(const char *ssid, const char *pwd); // sets WiFi Credentials
Span& setStatusCallback(void (*f)(HS_STATUS status)){statusCallback=f;return(*this);} // sets an optional user-defined function to call when HomeSpan status changes
const char* statusString(HS_STATUS s); // returns char string for HomeSpan status change messages
Span& setPairingCode(const char *s); // sets the Pairing Code - use is NOT recommended. Use 'S' from CLI instead
Span& setPairingCode(const char *s, boolean progCall=true); // sets the Pairing Code - use is NOT recommended. Use 'S' from CLI instead
void deleteStoredValues(){processSerialCommand("V");} // deletes stored Characteristic values from NVS
int enableOTA(boolean auth=true, boolean safeLoad=true){return(spanOTA.init(auth, safeLoad, NULL));} // enables Over-the-Air updates, with (auth=true) or without (auth=false) authorization password

View File

@ -27,7 +27,7 @@
#include "HomeSpan.h"
#define MAX_LIGHTS 2
#define MAX_LIGHTS 1
void setup() {
@ -35,6 +35,7 @@ void setup() {
homeSpan.setLogLevel(2);
homeSpan.enableWebLog(50,"pool.ntp.org","UTC",NULL);
homeSpan.setPairingCode("12345670");
// homeSpan.enableWebLog(50,"pool.ntp.org","UTC","myStatus");
// homeSpan.enableWebLog(50,NULL,NULL,NULL);