Add handling for updateDatabase() in call context
This commit is contained in:
parent
3cd8f8469a
commit
1569019fab
|
|
@ -26,23 +26,18 @@
|
|||
********************************************************************************/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "SendEncryptedContext.h"
|
||||
#include "CallContext.h"
|
||||
#include "HomeSpan.h"
|
||||
#include "HAP.h"
|
||||
#include "Settings.h"
|
||||
#include <sodium.h>
|
||||
|
||||
SendEncryptedContext::SendEncryptedContext(HAPClient& hapClient)
|
||||
: hapClient(hapClient),
|
||||
stringBuffer(FRAME_SIZE + 1, "SendEncryptedContext dataBuffer"),
|
||||
sendBuffer(FRAME_SIZE + 2 + 16, "SendEncryptedContext sendBuffer") // FRAME_SIZE + AAD + Auth
|
||||
CallContext::CallContext()
|
||||
: stringBuffer(1024, "CallContext stringBuffer")
|
||||
{
|
||||
LOG2("\n>>>>>>>>>> ");
|
||||
LOG2(hapClient.client.remoteIP());
|
||||
LOG2(" >>>>>>>>>>\n");
|
||||
}
|
||||
|
||||
void SendEncryptedContext::printf(const char* format, ...)
|
||||
void CallContext::printf(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
|
@ -53,28 +48,19 @@ void SendEncryptedContext::printf(const char* format, ...)
|
|||
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'
|
||||
if (stringBuffer.len() - usedStringLength < requiredNewBufferLength)
|
||||
{
|
||||
// to less memory, send first exitsting buffer
|
||||
if (usedStringLength > 0)
|
||||
{
|
||||
sendEncrypted(stringBuffer.get(), usedStringLength);
|
||||
usedStringLength = 0;
|
||||
}
|
||||
flush();
|
||||
|
||||
// Check if still more memory is needed
|
||||
if (stringBuffer.len() < requiredNewBufferLength)
|
||||
stringBuffer = TempBuffer<char>(requiredNewBufferLength, "SendEncryptedContext::reserveMemory");
|
||||
stringBuffer = TempBuffer<char>(requiredNewBufferLength, "SendEncryptedCallContext::reserveMemory");
|
||||
}
|
||||
int alreadyInUse = usedStringLength;
|
||||
usedStringLength += stringLength;
|
||||
|
|
@ -83,11 +69,35 @@ char* SendEncryptedContext::reserveStringBuffer(int stringLength)
|
|||
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)
|
||||
return;
|
||||
sentLength += length;
|
||||
LOG2(buffer);
|
||||
|
||||
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)
|
||||
sendEncrypted(stringBuffer.get(), usedStringLength);
|
||||
flush();
|
||||
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;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// CallContext class
|
||||
// Store strings off a call and call handlePage after the page limit was reached
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// SendEncryptedContext class
|
||||
// Write encrypted data as response to a web call
|
||||
|
||||
class SendEncryptedContext
|
||||
class CallContext
|
||||
{
|
||||
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;
|
||||
int usedStringLength = 0;
|
||||
int sentLength = 0;
|
||||
HAPClient& hapClient;
|
||||
TempBuffer<uint8_t> sendBuffer;
|
||||
public:
|
||||
SendEncryptedContext(HAPClient& hapClient);
|
||||
~SendEncryptedContext();
|
||||
|
||||
CallContext();
|
||||
void printf(const char* format, ...);
|
||||
void print(const char* text);
|
||||
char* reserveStringBuffer(int stringLength);
|
||||
private:
|
||||
void sendEncrypted(const char* buffer, int length);
|
||||
void flush();
|
||||
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);
|
||||
|
||||
|
||||
SendEncryptedContext context(*this);
|
||||
context.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);
|
||||
SendEncryptedCallContext callContext(*this);
|
||||
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, &callContext);
|
||||
return(1);
|
||||
|
||||
} // getAccessories
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
#include "HomeSpan.h"
|
||||
#include "HAP.h"
|
||||
#include "SendEncryptedContext.h"
|
||||
#include "CallContext.h"
|
||||
|
||||
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;
|
||||
|
||||
nBytes+=snprintf(cBuf,cBuf?64:0,"{\"accessories\":[");
|
||||
if (sendEncryptedContext != NULL)
|
||||
sendEncryptedContext->print("{\"accessories\":[");
|
||||
if (callContext != NULL)
|
||||
callContext->print("{\"accessories\":[");
|
||||
|
||||
for(int i=0;i<Accessories.size();i++){
|
||||
SpanAccessory* accessory=Accessories[i];
|
||||
int accessoryBytes=accessory->sprintfAttributes(cBuf?(cBuf+nBytes):NULL,flags);
|
||||
nBytes+= accessoryBytes;
|
||||
if (sendEncryptedContext != NULL)
|
||||
if (callContext != NULL)
|
||||
{
|
||||
char* buffer = sendEncryptedContext->reserveStringBuffer(accessoryBytes);
|
||||
char* buffer = callContext->reserveStringBuffer(accessoryBytes);
|
||||
accessory->sprintfAttributes(buffer, flags);
|
||||
}
|
||||
if(i+1<Accessories.size())
|
||||
{
|
||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",");
|
||||
if (sendEncryptedContext != NULL)
|
||||
sendEncryptedContext->print(",");
|
||||
if (callContext != NULL)
|
||||
callContext->print(",");
|
||||
}
|
||||
}
|
||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,"]}");
|
||||
if (sendEncryptedContext != NULL)
|
||||
sendEncryptedContext->print("]}");
|
||||
if (callContext != NULL)
|
||||
callContext->print("]}");
|
||||
return(nBytes);
|
||||
}
|
||||
|
||||
|
|
@ -1606,15 +1606,20 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){
|
|||
|
||||
boolean Span::updateDatabase(boolean updateMDNS){
|
||||
|
||||
uint8_t tHash[48];
|
||||
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);
|
||||
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)
|
||||
// uint8_t tHash[48];
|
||||
// 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);
|
||||
// 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;
|
||||
|
||||
if(memcmp(tHash,hapConfig.hashCode,48)){ // if hash code of current HAP database does not match stored hash code
|
||||
memcpy(hapConfig.hashCode,tHash,48); // update 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,hash,CalcHashCallContext::HASH_SIZE); // update stored hash code
|
||||
hapConfig.configNumber++; // increment configuration number
|
||||
if(hapConfig.configNumber==65536) // reached max value
|
||||
hapConfig.configNumber=1; // reset to 1
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
#include "extras/Pixel.h"
|
||||
#include "Settings.h"
|
||||
#include "Utils.h"
|
||||
#include "SendEncryptedContext.h"
|
||||
#include "CallContext.h"
|
||||
#include "Network.h"
|
||||
#include "HAPConstants.h"
|
||||
#include "HapQR.h"
|
||||
|
|
@ -269,7 +269,7 @@ class Span{
|
|||
void resetStatus(); // resets statusLED and calls statusCallback based on current HomeSpan status
|
||||
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
|
||||
SpanCharacteristic *find(uint32_t aid, int iid); // return Characteristic with matching aid and iid (else NULL if not found)
|
||||
|
|
|
|||
Loading…
Reference in New Issue