ESP8266_swiss_army_board/src/app/OTAUpdater.cpp

232 lines
5.7 KiB
C++

#include "OTAUpdater.h"
#include "HttpClient.h"
//#define DEBUG_OTA_UPDATER
OTAUpdater::OTAUpdater(const char *serverAddress, const char *path, const char *ota_auth_key, uint16_t port) : _port(port)
{
if(serverAddress)
_serverAddress = strdup(serverAddress);
if(path)
_path = strdup(path);
if(ota_auth_key)
_ota_auth_key = strdup(ota_auth_key);
}
OTAUpdater::OTAUpdater(int httpClientTimeout,const char *serverAddress, const char *path, const char *ota_auth_key, uint16_t port) : ESP8266HTTPUpdate(httpClientTimeout), _port(port)
{
if(serverAddress)
_serverAddress = strdup(serverAddress);
if(path)
_path = strdup(path);
if(ota_auth_key)
_ota_auth_key = strdup(ota_auth_key);
}
OTAUpdater::~OTAUpdater()
{
if(_publicKey != nullptr)
delete _publicKey;
if(_hash != nullptr)
delete _hash;
if(_signingVerifier != nullptr)
delete _signingVerifier;
free(_serverAddress);
free(_path);
free(_ota_auth_key);
}
//Enables the binary signing verification
void OTAUpdater::enableSHA256UpdateVerification(const char *publicKey)
{
if(_publicKey != nullptr)
delete _publicKey;
if(_hash != nullptr)
delete _hash;
if(_signingVerifier != nullptr)
delete _signingVerifier;
_publicKey = new BearSSL::PublicKey(publicKey);
_hash = new BearSSL::HashSHA256();
_signingVerifier = new BearSSL::SigningVerifier(_publicKey);
Update.installSignature(_hash, _signingVerifier);
}
void OTAUpdater::setServerAddress(const char *serverAddress)
{
if(!serverAddress)
return;
free(_serverAddress);
_serverAddress = strdup(serverAddress);
}
void OTAUpdater::setPath(const char *path)
{
//The path can be empty
if(!path)
{
free(_path);
_path = nullptr;
}
else
{
free(_path);
_path = strdup(path);
}
}
void OTAUpdater::setOtaAuthKey(const char *ota_auth_key)
{
//The authKey can be empty
if(!ota_auth_key)
{
free(_ota_auth_key);
_ota_auth_key = nullptr;
}
else
{
free(_ota_auth_key);
_ota_auth_key = strdup(ota_auth_key);
}
}
void OTAUpdater::setPort(uint16_t port)
{
_port = port;
}
OTAUpdater::UpdateInfo OTAUpdater::fetchUpdateInfo(const char *softwareVersion, uint32_t timeout)
{
HttpClient httpClient(_serverAddress, _path, _port, timeout);
UpdateInfo ui;
if(!softwareVersion)
{
ui.info = OTAUpdater::UpdateInfo::HTTP_NO_UPDATE;
return ui;
}
Dictionary<DictionaryHelper::StringEntity> getData;
getData.add("authKey", DictionaryHelper::StringEntity(_ota_auth_key));
getData.add("checkonly", NULL);
Dictionary<DictionaryHelper::StringEntity> headerData;
headerData.add("x-ESP8266-version",DictionaryHelper::StringEntity(softwareVersion));
headerData.add("x-ESP8266-STA-MAC",DictionaryHelper::StringEntity(WiFi.macAddress().c_str()));
headerData.add("User-Agent",DictionaryHelper::StringEntity("ESP8266-http-Update"));
if(httpClient.sendHttpQuery(HttpClient::HttpRequestMethod::GET, &getData, NULL, &headerData) == 0)
{
HttpConstants::HTTP_CODE result = httpClient.isReplyAvailable(1000);
switch(result)
{
case HttpConstants::HTTP_CODE::HTTP_CODE_OK:
{
char buffer[100];
httpClient.readHttpBody((uint8_t *)buffer, 100);
#ifdef DEBUG_OTA_UPDATER
Serial.printf("Response from update service : %s\n", buffer);
#endif
char *p = strstr_P(buffer, PSTR("bin_version"));
if(p)
{
p+=14;
char *end = strchr(p, '"');
if(end)
{
*end = '\0';
ui.version = (char *)malloc(strlen(p) * sizeof(char) + 1);
if(ui.version)
strcpy(ui.version, p);
}
}
ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_AVAILABLE;
}
break;
case HttpConstants::HTTP_CODE::HTTP_CODE_NOT_MODIFIED:
ui.info = OTAUpdater::UpdateInfo::HTTP_NO_UPDATE;
break;
case HttpConstants::HTTP_CODE::HTTP_CODE_FORBIDDEN:
ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_AUTH_ERROR;
break;
case HttpConstants::HTTP_CODE::HTTP_CODE_NOT_FOUND:
ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_REACH_ERROR;
break;
default:
#ifdef DEBUG_OTA_UPDATER
Serial.printf("HTTP ERROR CODE IS : %u\n", result);
#endif
ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_UNDEFINED_ERROR;
}
httpClient.stop();
}
else
ui.info = OTAUpdater::UpdateInfo::HTTP_UPDATE_REACH_ERROR;
return ui;
}
#define DEBUG_OTA_UPDATER
HTTPUpdateResult OTAUpdater::update(const char *softwareVersion)
{
if(!softwareVersion)
{
#ifdef DEBUG_OTA_UPDATER
Serial.printf("Missing softwareVersion !\n");
#endif
return HTTPUpdateResult::HTTP_UPDATE_NO_UPDATES;
}
if(!_serverAddress)
{
#ifdef DEBUG_OTA_UPDATER
Serial.printf("Missing server address !\n");
#endif
return HTTPUpdateResult::HTTP_UPDATE_FAILED;
}
//Depending on the presence or not of the path and the authKey, we compute the size we must allocate for the full path
uint16_t length = 1 /*for the \0*/;
length += _path ? strlen(_path) : 0;
length += _ota_auth_key ? strlen(_ota_auth_key) + 9/*for : ?authKey=*/ : 0;
char *fullpath = (char *)malloc(length * sizeof(char));
if(!fullpath)return HTTP_UPDATE_FAILED;
fullpath[0] = '\0';
WiFiClient client;
if(_path)strcpy(fullpath, _path);
if(_ota_auth_key)
{
strcat(fullpath, "?authKey=");
strcat(fullpath, _ota_auth_key);
}
#ifdef DEBUG_OTA_UPDATER
Serial.printf("The fullpath is : %s\n", fullpath);
#endif
HTTPUpdateResult result = ESP8266HTTPUpdate::update(client, _serverAddress, _port, fullpath, softwareVersion);
free(fullpath);
return result;
}