ESP8266:Прошивки/Arduino/Библиотеки/Библиотека ESP8266WiFi/Класс защищенного клиента/Проверка статуса билда: различия между версиями

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску
м (Myagkij переименовал страницу ESP8266:Прошивки/Arduino/Библиотеки/Библиотека ESP8266WiFi/Класс защищенного клиента/ в [[ESP8266:Прошивки/Arduino/Библиотеки/Б…)
 
Нет описания правки
Строка 35: Строка 35:
В верхней части кода давайте объявим константы для названия [[хост]]а ([[host]]) и соответствующего отпечатка ('''fingerprint''').
В верхней части кода давайте объявим константы для названия [[хост]]а ([[host]]) и соответствующего отпечатка ('''fingerprint''').


<syntaxhighlight lang="c" enclose="div">
<syntaxhighlight lang="c">
const char* host = "api.github.com";
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";
const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C";
Строка 50: Строка 50:
Создаем экземпляр класса WiFiClientSecure и устанавливаем соединение (обратите внимание, что для безопасного соединения используется не порт '''«80»''', а '''httpsPort''').
Создаем экземпляр класса WiFiClientSecure и устанавливаем соединение (обратите внимание, что для безопасного соединения используется не порт '''«80»''', а '''httpsPort''').


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
WiFiClientSecure client;
WiFiClientSecure client;
Serial.print("connecting to ");
Serial.print("connecting to ");
Строка 66: Строка 66:
Теперь проверяем, соответствует ли наш отпечаток тому, что предоставлен сервером:
Теперь проверяем, соответствует ли наш отпечаток тому, что предоставлен сервером:


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
if (client.verify(fingerprint, host)) {
if (client.verify(fingerprint, host)) {
   Serial.println("certificate matches");
   Serial.println("certificate matches");
Строка 82: Строка 82:
Далее нам нужно выполнить команду [[GET]]. Это делается аналогично тому, как в [[ESP8266:Прошивки/Arduino/Библиотеки/Библиотека_ESP8266WiFi/Класс_клиента/Загрузка_содержимого_веб-страницы_в_монитор_порта|скетче-примере, использующем класс «обычного» клиента]].
Далее нам нужно выполнить команду [[GET]]. Это делается аналогично тому, как в [[ESP8266:Прошивки/Arduino/Библиотеки/Библиотека_ESP8266WiFi/Класс_клиента/Загрузка_содержимого_веб-страницы_в_монитор_порта|скетче-примере, использующем класс «обычного» клиента]].


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
             "Host: " + host + "\r\n" +
             "Host: " + host + "\r\n" +
Строка 93: Строка 93:
Заголовок ответа можно пропустить. Это можно сделать, читая ответ до символа пустой строки ('''«\r»'''), который как раз отмечает конец заголовка.
Заголовок ответа можно пропустить. Это можно сделать, читая ответ до символа пустой строки ('''«\r»'''), который как раз отмечает конец заголовка.


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
while (client.connected()) {
while (client.connected()) {
   String line = client.readStringUntil('\n');
   String line = client.readStringUntil('\n');
Строка 108: Строка 108:
Наконец, считываем [[JSON]]-сообщение от сервера и проверяем, содержит ли оно '''{"state": "success"''':
Наконец, считываем [[JSON]]-сообщение от сервера и проверяем, содержит ли оно '''{"state": "success"''':


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
String line = client.readStringUntil('\n');
String line = client.readStringUntil('\n');
if (line.startsWith("{\"state\":\"success\"")) {
if (line.startsWith("{\"state\":\"success\"")) {
Строка 127: Строка 127:
Если все в порядке (включая статус [[билд]]а [[ESP8266]]/[[Arduino]]), вы должны увидеть примерно следующее:
Если все в порядке (включая статус [[билд]]а [[ESP8266]]/[[Arduino]]), вы должны увидеть примерно следующее:


<syntaxhighlight lang="bash" enclose="div">
<syntaxhighlight lang="bash">
connecting to sensor-net
connecting to sensor-net
........
........

Версия от 19:55, 23 мая 2023

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Черновик


Проверка статуса билда 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-буфера.

О функциях класса защищенного клиента смотрите по этой ссылке.

См.также

Внешние ссылки