#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 getData; getData.add("authKey", DictionaryHelper::StringEntity(_ota_auth_key)); getData.add("checkonly", NULL); Dictionary 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; }