Add handling for updateDatabase() in call context
This commit is contained in:
parent
3cd8f8469a
commit
1569019fab
|
|
@ -26,23 +26,18 @@
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "SendEncryptedContext.h"
|
#include "CallContext.h"
|
||||||
#include "HomeSpan.h"
|
#include "HomeSpan.h"
|
||||||
#include "HAP.h"
|
#include "HAP.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
|
||||||
SendEncryptedContext::SendEncryptedContext(HAPClient& hapClient)
|
CallContext::CallContext()
|
||||||
: hapClient(hapClient),
|
: stringBuffer(1024, "CallContext stringBuffer")
|
||||||
stringBuffer(FRAME_SIZE + 1, "SendEncryptedContext dataBuffer"),
|
|
||||||
sendBuffer(FRAME_SIZE + 2 + 16, "SendEncryptedContext sendBuffer") // FRAME_SIZE + AAD + Auth
|
|
||||||
{
|
{
|
||||||
LOG2("\n>>>>>>>>>> ");
|
|
||||||
LOG2(hapClient.client.remoteIP());
|
|
||||||
LOG2(" >>>>>>>>>>\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendEncryptedContext::printf(const char* format, ...)
|
void CallContext::printf(const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
|
|
@ -53,28 +48,19 @@ void SendEncryptedContext::printf(const char* format, ...)
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendEncryptedContext::print(const char* text)
|
|
||||||
{
|
|
||||||
auto len = strlen(text);
|
|
||||||
auto buffer = reserveStringBuffer(len);
|
|
||||||
memcpy(buffer, text, len);
|
|
||||||
LOG2(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* SendEncryptedContext::reserveStringBuffer(int stringLength)
|
char* CallContext::reserveStringBuffer(int stringLength)
|
||||||
{
|
{
|
||||||
int requiredNewBufferLength = stringLength + 1; // reserve buffer for characters and string terminator '\0'
|
int requiredNewBufferLength = stringLength + 1; // reserve buffer for characters and string terminator '\0'
|
||||||
if (stringBuffer.len() - usedStringLength < requiredNewBufferLength)
|
if (stringBuffer.len() - usedStringLength < requiredNewBufferLength)
|
||||||
{
|
{
|
||||||
// to less memory, send first exitsting buffer
|
// to less memory, send first exitsting buffer
|
||||||
if (usedStringLength > 0)
|
if (usedStringLength > 0)
|
||||||
{
|
flush();
|
||||||
sendEncrypted(stringBuffer.get(), usedStringLength);
|
|
||||||
usedStringLength = 0;
|
|
||||||
}
|
|
||||||
// Check if still more memory is needed
|
// Check if still more memory is needed
|
||||||
if (stringBuffer.len() < requiredNewBufferLength)
|
if (stringBuffer.len() < requiredNewBufferLength)
|
||||||
stringBuffer = TempBuffer<char>(requiredNewBufferLength, "SendEncryptedContext::reserveMemory");
|
stringBuffer = TempBuffer<char>(requiredNewBufferLength, "SendEncryptedCallContext::reserveMemory");
|
||||||
}
|
}
|
||||||
int alreadyInUse = usedStringLength;
|
int alreadyInUse = usedStringLength;
|
||||||
usedStringLength += stringLength;
|
usedStringLength += stringLength;
|
||||||
|
|
@ -83,11 +69,35 @@ char* SendEncryptedContext::reserveStringBuffer(int stringLength)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendEncryptedContext::sendEncrypted(const char* buffer, int length)
|
void CallContext::flush()
|
||||||
|
{
|
||||||
|
handlePage(stringBuffer.get(), usedStringLength);
|
||||||
|
usedStringLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallContext::print(const char* text)
|
||||||
|
{
|
||||||
|
auto len = strlen(text);
|
||||||
|
auto buffer = reserveStringBuffer(len);
|
||||||
|
memcpy(buffer, text, len);
|
||||||
|
LOG2(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
SendEncryptedCallContext::SendEncryptedCallContext(HAPClient& hapClient)
|
||||||
|
: hapClient(hapClient),
|
||||||
|
sendBuffer(FRAME_SIZE + 2 + 16, "SendEncryptedCallContext sendBuffer") // FRAME_SIZE + AAD + Auth
|
||||||
|
{
|
||||||
|
LOG2("\n>>>>>>>>>> ");
|
||||||
|
LOG2(hapClient.client.remoteIP());
|
||||||
|
LOG2(" >>>>>>>>>>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SendEncryptedCallContext::handlePage(const char* buffer, int length)
|
||||||
{
|
{
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return;
|
return;
|
||||||
sentLength += length;
|
|
||||||
LOG2(buffer);
|
LOG2(buffer);
|
||||||
|
|
||||||
for(int i=0;i<length;i+=FRAME_SIZE){ // encrypt FRAME_SIZE number of bytes in dataBuf in sequential frames
|
for(int i=0;i<length;i+=FRAME_SIZE){ // encrypt FRAME_SIZE number of bytes in dataBuf in sequential frames
|
||||||
|
|
@ -108,9 +118,30 @@ void SendEncryptedContext::sendEncrypted(const char* buffer, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendEncryptedContext::~SendEncryptedContext()
|
SendEncryptedCallContext::~SendEncryptedCallContext()
|
||||||
{
|
{
|
||||||
if (usedStringLength > 0)
|
flush();
|
||||||
sendEncrypted(stringBuffer.get(), usedStringLength);
|
|
||||||
LOG2("-------- SENT ENCRYPTED! --------\n");
|
LOG2("-------- SENT ENCRYPTED! --------\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CalcHashCallContext::CalcHashCallContext()
|
||||||
|
: CallContext()
|
||||||
|
{
|
||||||
|
memset(&tHash, 0, HASH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalcHashCallContext::handlePage(const char* buffer, int length)
|
||||||
|
{
|
||||||
|
uint8_t newHash[HASH_SIZE];
|
||||||
|
// create SHA-384 hash of JSON and xor with previous part (can be any hash - just looking for a unique key)
|
||||||
|
mbedtls_sha512_ret((uint8_t *)buffer,length, newHash,1);
|
||||||
|
for (int i=0; i<48; i++)
|
||||||
|
tHash[i] = tHash[i] ^ newHash[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* CalcHashCallContext::getHashCode()
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
return tHash;
|
||||||
|
}
|
||||||
|
|
@ -30,27 +30,57 @@
|
||||||
|
|
||||||
struct HAPClient;
|
struct HAPClient;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CallContext class
|
||||||
|
// Store strings off a call and call handlePage after the page limit was reached
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
class CallContext
|
||||||
// SendEncryptedContext class
|
|
||||||
// Write encrypted data as response to a web call
|
|
||||||
|
|
||||||
class SendEncryptedContext
|
|
||||||
{
|
{
|
||||||
const int FRAME_SIZE=1024; // number of bytes to use in each ChaCha20-Poly1305 encrypted frame when sending encrypted JSON content to Client
|
private:
|
||||||
|
|
||||||
TempBuffer<char> stringBuffer;
|
TempBuffer<char> stringBuffer;
|
||||||
int usedStringLength = 0;
|
int usedStringLength = 0;
|
||||||
int sentLength = 0;
|
|
||||||
HAPClient& hapClient;
|
|
||||||
TempBuffer<uint8_t> sendBuffer;
|
|
||||||
public:
|
public:
|
||||||
SendEncryptedContext(HAPClient& hapClient);
|
CallContext();
|
||||||
~SendEncryptedContext();
|
|
||||||
|
|
||||||
void printf(const char* format, ...);
|
void printf(const char* format, ...);
|
||||||
void print(const char* text);
|
void print(const char* text);
|
||||||
char* reserveStringBuffer(int stringLength);
|
char* reserveStringBuffer(int stringLength);
|
||||||
private:
|
void flush();
|
||||||
void sendEncrypted(const char* buffer, int length);
|
protected:
|
||||||
|
virtual void handlePage(const char* buffer, int length) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SendEncryptedCallContext class
|
||||||
|
// Sends the pages encrypted to the network
|
||||||
|
|
||||||
|
class SendEncryptedCallContext : public CallContext
|
||||||
|
{
|
||||||
|
static const int FRAME_SIZE=1024; // number of bytes to use in each ChaCha20-Poly1305 encrypted frame when sending encrypted JSON content to Client
|
||||||
|
|
||||||
|
HAPClient& hapClient;
|
||||||
|
TempBuffer<uint8_t> sendBuffer;
|
||||||
|
public:
|
||||||
|
SendEncryptedCallContext(HAPClient& hapClient);
|
||||||
|
~SendEncryptedCallContext();
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void handlePage(const char* buffer, int length) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CalcHashCallContext class
|
||||||
|
// Calc an hash code out of the provided strings
|
||||||
|
|
||||||
|
class CalcHashCallContext : public CallContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int HASH_SIZE=48;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t tHash[CalcHashCallContext::HASH_SIZE];
|
||||||
|
public:
|
||||||
|
CalcHashCallContext();
|
||||||
|
const uint8_t* getHashCode();
|
||||||
|
protected:
|
||||||
|
void handlePage(const char* buffer, int length) override;
|
||||||
};
|
};
|
||||||
|
|
@ -876,9 +876,9 @@ int HAPClient::getAccessoriesURL(){
|
||||||
// free(body);
|
// free(body);
|
||||||
|
|
||||||
|
|
||||||
SendEncryptedContext context(*this);
|
SendEncryptedCallContext callContext(*this);
|
||||||
context.printf("HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes);
|
callContext.printf("HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes);
|
||||||
homeSpan.sprintfAttributes(NULL, GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, &context);
|
homeSpan.sprintfAttributes(NULL, GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, &callContext);
|
||||||
return(1);
|
return(1);
|
||||||
|
|
||||||
} // getAccessories
|
} // getAccessories
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
#include "HomeSpan.h"
|
#include "HomeSpan.h"
|
||||||
#include "HAP.h"
|
#include "HAP.h"
|
||||||
#include "SendEncryptedContext.h"
|
#include "CallContext.h"
|
||||||
|
|
||||||
const __attribute__((section(".rodata_custom_desc"))) SpanPartition spanPartition = {HOMESPAN_MAGIC_COOKIE,0};
|
const __attribute__((section(".rodata_custom_desc"))) SpanPartition spanPartition = {HOMESPAN_MAGIC_COOKIE,0};
|
||||||
|
|
||||||
|
|
@ -1228,33 +1228,33 @@ Span& Span::setWifiCredentials(const char *ssid, const char *pwd){
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
int Span::sprintfAttributes(char *cBuf, int flags, SendEncryptedContext* sendEncryptedContext){
|
int Span::sprintfAttributes(char *cBuf, int flags, CallContext* callContext){
|
||||||
|
|
||||||
int nBytes=0;
|
int nBytes=0;
|
||||||
|
|
||||||
nBytes+=snprintf(cBuf,cBuf?64:0,"{\"accessories\":[");
|
nBytes+=snprintf(cBuf,cBuf?64:0,"{\"accessories\":[");
|
||||||
if (sendEncryptedContext != NULL)
|
if (callContext != NULL)
|
||||||
sendEncryptedContext->print("{\"accessories\":[");
|
callContext->print("{\"accessories\":[");
|
||||||
|
|
||||||
for(int i=0;i<Accessories.size();i++){
|
for(int i=0;i<Accessories.size();i++){
|
||||||
SpanAccessory* accessory=Accessories[i];
|
SpanAccessory* accessory=Accessories[i];
|
||||||
int accessoryBytes=accessory->sprintfAttributes(cBuf?(cBuf+nBytes):NULL,flags);
|
int accessoryBytes=accessory->sprintfAttributes(cBuf?(cBuf+nBytes):NULL,flags);
|
||||||
nBytes+= accessoryBytes;
|
nBytes+= accessoryBytes;
|
||||||
if (sendEncryptedContext != NULL)
|
if (callContext != NULL)
|
||||||
{
|
{
|
||||||
char* buffer = sendEncryptedContext->reserveStringBuffer(accessoryBytes);
|
char* buffer = callContext->reserveStringBuffer(accessoryBytes);
|
||||||
accessory->sprintfAttributes(buffer, flags);
|
accessory->sprintfAttributes(buffer, flags);
|
||||||
}
|
}
|
||||||
if(i+1<Accessories.size())
|
if(i+1<Accessories.size())
|
||||||
{
|
{
|
||||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",");
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",");
|
||||||
if (sendEncryptedContext != NULL)
|
if (callContext != NULL)
|
||||||
sendEncryptedContext->print(",");
|
callContext->print(",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,"]}");
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,"]}");
|
||||||
if (sendEncryptedContext != NULL)
|
if (callContext != NULL)
|
||||||
sendEncryptedContext->print("]}");
|
callContext->print("]}");
|
||||||
return(nBytes);
|
return(nBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1606,15 +1606,20 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){
|
||||||
|
|
||||||
boolean Span::updateDatabase(boolean updateMDNS){
|
boolean Span::updateDatabase(boolean updateMDNS){
|
||||||
|
|
||||||
uint8_t tHash[48];
|
// uint8_t tHash[48];
|
||||||
TempBuffer <char> tBuf(sprintfAttributes(NULL,GET_META|GET_PERMS|GET_TYPE|GET_DESC)+1, "Span::updateDatabase");
|
// TempBuffer <char> tBuf(sprintfAttributes(NULL,GET_META|GET_PERMS|GET_TYPE|GET_DESC)+1, "Span::updateDatabase");
|
||||||
sprintfAttributes(tBuf.get(),GET_META|GET_PERMS|GET_TYPE|GET_DESC);
|
// sprintfAttributes(tBuf.get(),GET_META|GET_PERMS|GET_TYPE|GET_DESC);
|
||||||
mbedtls_sha512_ret((uint8_t *)tBuf.get(),tBuf.len(),tHash,1); // create SHA-384 hash of JSON (can be any hash - just looking for a unique key)
|
// mbedtls_sha512_ret((uint8_t *)tBuf.get(),tBuf.len(),tHash,1); // create SHA-384 hash of JSON (can be any hash - just looking for a unique key)
|
||||||
|
|
||||||
|
|
||||||
|
CalcHashCallContext callContext = CalcHashCallContext();
|
||||||
|
sprintfAttributes(NULL ,GET_META|GET_PERMS|GET_TYPE|GET_DESC, &callContext);
|
||||||
|
const uint8_t* hash = callContext.getHashCode();
|
||||||
|
|
||||||
boolean changed=false;
|
boolean changed=false;
|
||||||
|
|
||||||
if(memcmp(tHash,hapConfig.hashCode,48)){ // if hash code of current HAP database does not match stored hash code
|
if(memcmp(hash,hapConfig.hashCode,CalcHashCallContext::HASH_SIZE)){ // if hash code of current HAP database does not match stored hash code
|
||||||
memcpy(hapConfig.hashCode,tHash,48); // update stored hash code
|
memcpy(hapConfig.hashCode,hash,CalcHashCallContext::HASH_SIZE); // update stored hash code
|
||||||
hapConfig.configNumber++; // increment configuration number
|
hapConfig.configNumber++; // increment configuration number
|
||||||
if(hapConfig.configNumber==65536) // reached max value
|
if(hapConfig.configNumber==65536) // reached max value
|
||||||
hapConfig.configNumber=1; // reset to 1
|
hapConfig.configNumber=1; // reset to 1
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
#include "extras/Pixel.h"
|
#include "extras/Pixel.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "SendEncryptedContext.h"
|
#include "CallContext.h"
|
||||||
#include "Network.h"
|
#include "Network.h"
|
||||||
#include "HAPConstants.h"
|
#include "HAPConstants.h"
|
||||||
#include "HapQR.h"
|
#include "HapQR.h"
|
||||||
|
|
@ -269,7 +269,7 @@ class Span{
|
||||||
void resetStatus(); // resets statusLED and calls statusCallback based on current HomeSpan status
|
void resetStatus(); // resets statusLED and calls statusCallback based on current HomeSpan status
|
||||||
void reboot(); // reboots device
|
void reboot(); // reboots device
|
||||||
|
|
||||||
int sprintfAttributes(char *cBuf, int flags=GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, SendEncryptedContext* sendEncryptedContext = nullptr); // prints Attributes JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator
|
int sprintfAttributes(char *cBuf, int flags=GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, CallContext* callContext = nullptr); // prints Attributes JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator
|
||||||
|
|
||||||
void prettyPrint(char *buf, int nsp=2, int minLogLevel=0); // print arbitrary JSON from buf to serial monitor, formatted with indentions of 'nsp' spaces, subject to specified minimum log level
|
void prettyPrint(char *buf, int nsp=2, int minLogLevel=0); // print arbitrary JSON from buf to serial monitor, formatted with indentions of 'nsp' spaces, subject to specified minimum log level
|
||||||
SpanCharacteristic *find(uint32_t aid, int iid); // return Characteristic with matching aid and iid (else NULL if not found)
|
SpanCharacteristic *find(uint32_t aid, int iid); // return Characteristic with matching aid and iid (else NULL if not found)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue