Проверка целостности материалов
Как убедиться, что статья на портале не менялась после публикации: манифест sha256, дерево Меркла и проверка одной командой
Каждый материал портала публикуется двумя файлами: страницей index.html, которую вы читаете, и её исходником index.md рядом. Вместе с сайтом выкладывается манифест /integrity.json — по записи на каждый материал и общий корень дерева Меркла.
Манифест нужен для одной вещи: вы можете проверить сами, что статья не менялась после публикации, не веря нам на слово.
Проверить одну статью
Возьмите адрес статьи, добавьте index.md и посчитайте хэш:
curl -s https://courses.digitable.life/post/logic/01-concepts-definitions-classification/index.md | sha256sum
Теперь найдите ту же статью в манифесте и сравните значения:
curl -s https://courses.digitable.life/integrity.json \
| jq -r '.articles[] | select(.path == "/post/logic/01-concepts-definitions-classification/index.md") | .sha256'
Строки совпали — файл ровно тот, который был заверен. Не совпали — статью правили после генерации манифеста, и это видно без нашего участия.
Проверить весь портал разом
curl -s https://courses.digitable.life/integrity.json > integrity.json
jq -r '.articles[] | "\(.sha256) .\(.path)"' integrity.json > SHA256SUMS
# выкачайте нужные index.md в ту же структуру каталогов и:
sha256sum -c SHA256SUMS
Что означает корень
Поле root — вершина дерева Меркла, построенного по всем материалам. Дерево, а не общий хэш от склейки, выбрано ради практического свойства: неизменность одной статьи доказывается путём длиной около десяти хэшей, без выкачивания остальных.
Правила счёта опубликованы прямо в манифесте, в поле merkle, чтобы корень мог пересчитать кто угодно:
- записи отсортированы по полю
path; - лист:
sha256("digitable-leaf\n" + path + "\n" + sha256(файл)); - узел:
sha256("digitable-node\n" + левый + правый); - нечётный элемент уровня поднимается выше без изменений.
Разные префиксы у листа и узла — не украшение: без них дерево уязвимо к подмене листа на пару узлов.
Поля revision и generated в корень не входят. Иначе он менялся бы при каждой пересборке сайта, даже когда ни один материал не тронут.
Чего эта проверка не даёт
Манифест отвечает на вопрос «файл не менялся после того, как манифест сгенерировали». Он пока не отвечает на вопрос «манифест сгенерировали именно мы»: тот, кто подменил бы сайт целиком, перегенерировал бы и манифест. Закрывает это подпись корня ключом владельца — она в работе, вместе с публикацией отпечатка ключа вне портала.
Доказательства даты публикации манифест тоже не даёт. Если оно понадобится, добавится якорение корня во времени — 32 байта на весь портал. Сами материалы в блокчейн не попадут никогда: неизменяемая запись противоречит обязанности удалять персональные данные по требованию, а корень эту обязанность не нарушает, потому что восстановить из него текст нельзя.
Если хэши не сошлись
Напишите на support@digitable.ru и приложите адрес статьи и обе строки. Расхождение — это либо наша ошибка в выкладке, либо подмена; в обоих случаях мы хотим о нём знать.