В предыдущей статье я рассказал как перенёс статьи в отдельный репозиторий. Многие заметили что в этом решении есть проблема. Чтоб понять что добавилась новая статья, я раз в минуту делаю запросы и сверяю время модификации репозитория. Для таких случаев правильнее использовать webhooks.
Настроить webhook в гитхабе достаточно просто. Нужно написать немного кода для обработки и верификации webhook`а.
import { config } from 'dotenv';
import Koa from 'koa';
import Router from '@koa/router';
import parser from 'koa-bodyparser';
import { createHmac } from 'crypto';
config();
const app = new Koa();
const router = new Router();
app.use(parser());
router.post('/hooks/github', (ctx) => {
// Подписываем body запроса нашим секретом.
const key = createHmac('sha256', process.env.WEBHOOK_SECRET as string)
.update(JSON.stringify(ctx.request.body))
.digest('hex');
// Сверяем получившуюся подпись, с подписью указанной в заголовке запроса.
if (ctx.request.headers['x-hub-signature-256'] !== 'sha256=' + key) {
return 404;
}
// Тут будет наш код который должен вызываться по webhook`у.
// Отвечаем что-нибудь гитхабу. Главное чтоб код ответа был 200.
ctx.body = { status: 'ok' };
});
app.use(router.routes());
app.listen(8000);
Секретный ключ не должен хранится в репозитории, а значит и в коде приложения. Правильным вариантом будет хранить его в .env файле. А для загрузки переменных окружения можно использовать dotenv
.
Чтобы убедится, что запрос приходит от гитхаба и по пути его никто не мог модифицировать, используется криптографическая подпись HMAC. Гитхаб при отправке сообщения подписывает body секретным ключом, который мы указываем при настройке webhook`а. А в коде приложения мы подписываем пришедший в запросе body и сверяем получившуюся подпись. Если подпись совпадает, то мы можем быть уверенны, что тот кто отправил этот запрос знает наш секрет, соответственно ему можно доверять.
В моём случае проверка подписи на самом деле не очень нужна, так как я использую webhook только для того, чтобы понять что в репозитории что-то изменилось и нужно пойти и обновить посты. Единственная угроза которая может быть, это то что злоумышленник заставит моё приложение очень часто обновлять посты, и у меня кончится лимит запросов к гитхабу.
В самом интерфейсе гитхаба в настройках репозитория со статьями нужно добавить webhook.
Payload URL
- урл по которому мы будем обрабатывать webhook, желательно чтоб это был https.
Content type
- в большинстве случаев лучше выбрать json
.
Secret
- тот самый секрет который мы записали в .env
. Это может быть любая строка, для генерации лучше воспользоваться генератором паролей, я использую Bitwarden. Строка из 40 символов, включая большие и маленькие буквы и цифры достаточно безопасна.
Единственная сложность которая может возникнуть при разработке приложения с webhook, это необходимость белого ip адреса для тестирования. Но если его нет, то можно воспользоваться сервисом ngrok. Он позволяет задать публичный url для локальной разработки и тестирования.