232 lines
5.7 KiB
C++
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;
|
|
}
|