ESP8266:Прошивки/Arduino/Библиотеки/Библиотека ESP8266WiFi/Класс защищенного клиента/Проверка статуса билда
Черновик |
Проверка статуса билда Arduino-аддона для ESP8266[1]
Класс безопасного клиента – это все тот же класс клиента, но оснащенный защитой. Скетч ниже будет проще понять, если вы уже пробовали разобраться с похожим и более простым скетчем-примером для «обычного» клиента. Но в этой статье мы сосредоточимся на обсуждении кода, связанного с классом безопасного клиента.
Введение
В этом скетче мы будем извлекать информацию из защищенного сервера «https://api.github.com/». Это сервер, предназначенный для предоставления структурированной информации о GitHub-репозиториях. К примеру, через него можно запросить статус билда или последнюю версию Arduino-аддона для ESP8266.
Статус билда можно узнать на домашней странице репозитория или на сайте Travic CI.
Вся информация на этом сервере представлена в формате JSON.
Теперь давайте воспользуемся классом безопасного клиента для того, чтобы обратиться к серверу и запросить статус билда. Для этого откройте в браузере специальный ресурс, имеющийся в API и содержащий необходимую нам информацию:
Итак, что нам нужно? При помощи класса защищенного клиента подключиться к https://api.github.com, открыть ресурс /repos/esp8266/Arduino/commits/master/status, найти строчку "state": "success", а затем напечатать в мониторе порта, что билд либо прошел CI-проверку (от «continuous integration», что значит «непрерывная интеграция»), либо нет.
Скетч
Скетч, выполняющий эту задачу, можно найти в скетчах-примерах библиотеки ESP8266WiFi. Здесь мы шаг за шагом разберем, как он устроен.
Как проверить идентичность сервера?
Чтобы установить безопасное соединение с сервером, нам нужно проверить его идентичность. Клиент, установленный на «обычном» компьютере, выполняет это через сравнение сертификата сервера со списком корневых сертификатов, хранящимся на самом компьютере. Такие сертификаты занимают всего несколько сотен килобайт, поэтому вполне умещаются в памяти ESP8266. Но в качестве альтернативы можно воспользоваться SHA1 – это отпечаток сертификата, и его преимущество в том, что он весит гораздо меньше.
В верхней части кода давайте объявим константы для названия хоста (host) и соответствующего отпечатка (fingerprint).
const char* host = "api.github.com";
const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C";
Извлечение отпечатка
Узнать отпечаток хоста можно при помощи браузера. К примеру, в Chrome нажмите Ctrl + ⇧ Shift + I , а затем кликните по Security > View Sertificate > Состав > Отпечаток. Откроется окно, где можно скопировать отпечаток, а потом вставить его в свой скетч.
Подключение к серверу
Создаем экземпляр класса WiFiClientSecure и устанавливаем соединение (обратите внимание, что для безопасного соединения используется не порт «80», а httpsPort).
WiFiClientSecure client;
Serial.print("connecting to ");
// "подключение к "
Serial.println(host);
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
// "подключиться не удалось"
return;
}
Это ТОТ САМЫЙ сервер?
Теперь проверяем, соответствует ли наш отпечаток тому, что предоставлен сервером:
if (client.verify(fingerprint, host)) {
Serial.println("certificate matches");
// "сертификат соответствует"
} else {
Serial.println("certificate doesn't match");
// "сертификат не соответствует"
}
Если проверка не удастся, нам нужно решить, закрыть ли соединение или продолжить дальше. Также обратите внимание, что у этого сертификата есть срок действия. То есть, если сегодня проверка отпечатка прошла успешно, то позднее этот отпечаток, возможно, проверку уже не пройдет.
Ответ от сервера на запрос GET
Далее нам нужно выполнить команду GET. Это делается аналогично тому, как в скетче-примере, использующем класс «обычного» клиента.
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
После отправки запроса ждем ответ и обрабатываем присланную информацию.
Заголовок ответа можно пропустить. Это можно сделать, читая ответ до символа пустой строки («\r»), который как раз отмечает конец заголовка.
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
// "получены заголовки"
break;
}
}
Чтение и проверка ответа
Наконец, считываем JSON-сообщение от сервера и проверяем, содержит ли оно {"state": "success":
String line = client.readStringUntil('\n');
if (line.startsWith("{\"state\":\"success\"")) {
Serial.println("esp8266/Arduino CI successfull!");
// "билд esp8266/Arduino прошел CI-проверку"
} else {
Serial.println("esp8266/Arduino CI has failed");
// "билд esp8266/Arduino не прошел CI-проверку"
}
Это работает?
Теперь, когда вы знаете, как все это работает, скопируйте скетч.
Вставьте в него данные своей WiFi-сети. Узнайте действующий отпечаток «api.github.com» и, если потребуется, обновите его. Затем загрузите скетч на ESP8266 и откройте монитор порта.
Если все в порядке (включая статус билда ESP8266/Arduino), вы должны увидеть примерно следующее:
connecting to sensor-net
........
WiFi connected
IP address:
192.168.1.104
connecting to api.github.com
certificate matches
requesting URL: /repos/esp8266/Arduino/commits/master/status
request sent
headers received
esp8266/Arduino CI successfull!
reply was:
==========
{"state":"success","statuses":[{"url":"https://api.github.com/repos/esp8266/Arduino/statuses/8cd331a8bae04a6f1443ff0c93539af4720d8ddf","id":677326372,"state":"success","description":"The Travis CI build passed","target_url":"https://travis-ci.org/esp8266/Arduino/builds/148827821","context":"continuous-integration/travis-ci/push","created_at":"2016-08-01T09:54:38Z","updated_at":"2016-08-01T09:54:38Z"},{"url":"https://api.github.com/repos/esp8266/Arduino/statuses/8cd331a8bae04a6f1443ff0c93539af4720d8ddf","id":677333081,"state":"success","description":"27.62% (+0.00%) compared to 0718188","target_url":"https://codecov.io/gh/esp8266/Arduino/commit/8cd331a8bae04a6f1443ff0c93539af4720d8ddf","context":"codecov/project","created_at":"2016-08-01T09:59:05Z","updated_at":"2016-08-01T09:59:05Z"},
(...)
==========
closing connection
Итого
Программирование безопасного клиента почти идентично программированию «обычного» клиента. Разница лишь в дополнительном шаге с проверкой идентичности сервера. Не забывайте об ограничениях, связанных с сильной нагрузкой на память из-за стойкости ключа, используемого сервером и того, хочет ли сервер «договариваться» о размере TLS-буфера.
О функциях класса защищенного клиента смотрите по этой ссылке.