Хэндлим тему | Дерепко – Telegram
Хэндлим тему | Дерепко
275 subscribers
51 photos
3 videos
1 file
56 links
Discussion group @handle_topic_chat
Contact with me @xepozz
Download Telegram
Forwarded from Sharovatov (Vitaly Sharovatov)
> the essence of a model to be predictive

Ув. тов. Стафорд Бир считает, что любая модель создаётся исключительно для того, чтобы помогать в предсказании чего-то.

Я склонен согласиться с ним: ведь даже аналитические, учебные или там эвристические модели создаются так, чтоб с какой-то точностью представлять моделируемую систему, и представление это нужно исключительно для того, чтобы предсказывать изменение реальной системы.

Если модель не помогает в предсказании, то траты на её создание были оправданы лишь тогда, когда она выкидывается или изменяется так, чтобы таки начинать помогать в предсказании.

Если же модель не помогает предсказывать ничего и помочь не может, то она вредна. Вредна просто потому, что используя негодные модели, мы принимаем неоптимальные решения.

Получается, что "плохая" модель хуже отсутствия модели вообще, ведь в случае отсутствия модели вообще нам-таки придётся скорее всего подумать.

Я знаю такие примеры вредных моделей:
- DORA
- нумерология, френология
- юнгианские психотипы (DISC туда же)
- астрология и всякий human design
- theory x

а какие вредные модели знаете вы?
👍2
#оффтоп

🖼️ PHP Fart / gRPC / Protobuf

Посмотрел стрим ребят из PHP Fart про gRPC и Protobuf.

Как же я был счастлив, когда увидел нормальный генератор PHP классов по proto файлам: с нормальным конструктором, типизацией свойств, без лишних геттеров и сеттеров и без наследования огромного базового класса Message. Такие DTO теперь и не стыдно использовать, и прямых зависимостей от google/protobuf меньше, и вспомогательные инструменты будут считать класс “безпроблемным”.

Несколько лет назад было требование в одном из проектов работать с системой телефонии, которая предоставляла API только в protobuf формате. Тогда я и познакомился с этой штукой лицом к лицу.

Тоже бесили эти громоздкие файлы с кучей комментариев и отсутствием типизации, на которые вечно кричали различные линтеры и шторм. Если теперь и попадётся очередная интеграция с protobuf, то обязательно буду использовать их библиотеку, хоть она и не полностью независимая.
Советую и вам к использованию.

Кстати, надо бы в 🖼️ Yii3 сделать поддержку этого генератора в Gii.

-
--

Теперь осталось, чтобы кто-нибудь написал нормальный генератор PHP классов по Open API спеке, а то там вообще мрак. Может когда-нибудь и сам доберусь до него, чтобы интегрировать в Yii Dev Panel и генерировать контракты несколькими кликами в UI.

---

Ссылка на стрим: https://www.youtube.com/watch?v=E61resEfgUE
Ссылка на канал: https://news.1rj.ru/str/php_fart

Когда досмотрел стрим увидел, что он был 3 месяца назад 😬
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍6
#Пост №5. Про Open source

Open source – это идеология распространения программы таким образом, что любой желающий может увидеть её исходный код, внести изменения в исходный код и даже предложить это изменение авторам.

Open source – это место для тренировки коммуникативных и технических скиллов; место отдыха от рабочих проектов; место изучения новых технологий.

Open source – это желание улучшить мир.
Open source – это то, что ты можешь оставить после себя. Даже уйдя из IT.
Open source – это место обучения других.
Open source – это карма личности, популярность, уважение, открытые возможности.
Open source – это средство получить большую выгоду, жертвуя своей.

---

Как Open source может помочь Вам?

- Изучение новой технологии, с которой вы давно хотели поработать
- Изучение алгоритмов, которые используются в других проектах
- Изучение подходов и правил декомпозиции больших проектов, библиотек, фреймворков
- Подсмотреть лучшую версию компонента, который вы реализовали недавно

Архитектура? Шаблоны проектирования? Шаблоны программирования? Алгоритмы? Тесты? Документация? Системы сборки? Командные процессы? Внутренние договоренности? Всё это есть в открытом доступе, остается лишь дотянуться и начать становиться лучше.

Как вы можете помочь Open source?

- Ответ в Issue
- Проверка гипотезы
- Проверка бага
- Исправить баг
- Сделать Code review
- Написать фичу
- Поправить доку
- Добавить перевод
- Написать интеграцию
- Написать тест
- Предложить улучшения
- Добавить метрики
- Написать CI процесс
- Сделать замеры производительности
- Сделать инфографику
- Поддержите финансово

В Open source вы можете делать всё то, что вы умеете делать хорошо или всегда хотели начать делать.

Начните свою Open source жизнь прямо сейчас:

- Найдите репозиторий технологии / фреймворка / проекта, с которым чаще всего работаете
- Почитайте Issue, изучите проблемы или фича-запросы
- Углубитесь в кодовую базу, дайте ответ на проблему или подготовьте изменения в виде Pull Request

Сделав это несколько раз, могу предположить, вам однозначно понравится. Авторы будут вам благодарны за помощь, а комьюнити за развитие.

Open source – это не только про разработку непосредственно. Можно быть проджект менеджером, дизайнером, переводчиком, писателем документации, визионером или любой другой ролью

---

Если вы еще не знаете куда внести свой вклад, могу порекомендовать Yii3 😉

В Yii3 есть много репозиториев под различные цели. Если вы хотите сделать какую-то новую интеграцию и отдать её на поддержку в Yii, то напишите мне, я помогу вам это сделать.
1👍41🔥1
🤔 #мысли
💲Кэш ревью

Не вспомню уже где услышал такую фразу, но звучит очень мотивирующе:

Компания каждый раз проводит перформанс ревью (360, 180 и прочие его подобия) – это некое тестирования тебя, насколько круто ты перформишь. Так почему ты не проводишь “Кеш ревью” – тестирование компании на предмет того, насколько по рынку она тебе платит?


Рост в IT – это не только в отметка CRM “Ваня – джун”, “Саша – мидл”, “Дима – сеньор”.
Рост в IT – это и ответственности, которые ты на себя берешь, и масштабы личности, которые ты растишь, и так же заработная плата, за которую ты тратишь своё личное время на развитие компании.

Развивать себя нужно самому и никогда не забывать про денежную составляющую. Личный рост отдельного человека никому не интересен, если он не придёт и не заберет его сам.
Please open Telegram to view this post
VIEW IN TELEGRAM
1💯21
#мем

Увидел картинку в твиттере.
Ну что это, если не жиза? 😁
🤪3👍2
#оффтоп

Собеседование

Случайно в линке нашел пост, где человек на интервью "Senior React Developer" отказался решать задачки, комментируя тем, что "не знаю как решить".
Как оно там правда было не моё дело, но в комментах случайно зарубились с автором поста на тему следующего:

Я сказал, что считаю неуважением, когда тебе на позицию сеньора задают вопросы уровня джуна и дают соответствующие задачки на лайвкодинге.

Автор пытался меня убедить, что на интервью как раз такое и должно происходить, иначе "как понять, что ты сеньор разработчик, а не джун или сеньор gpt писатель промпта".

---

Бывает такое, что сеньоры валятся на сеньорских интервью, какие тут чат-гптшники уж.
Единственную мысль я бы хотел донести, что на процессе интервью нужно приходить с мыслью и целью партнёрства:

- Не вы должны компании, а вы нужны друг другу
- Не вы должны доказывать вашу компетентность, компания может подвергать её сомнению, а вы можете парировать.

Вы ведь не спрашиваете у компании о её годовых и квартальных доходах, количеству и качеству решенных задач за всё время. Спросить, конечно, вы можете, но ответ получите либо поверхностный, либо никакой.

Уйти с интервью, если вам не нравится общение или процесс интервью – это нормально. Так и нужно делать, если вас что-то не устраивает или вы считаете это неуважением к себе. Уважать нужно своё время, свои силы и навыки.

Если вы хотите пройти в компанию, о которой всегда мечтали, то можно и пожертвовать своим вкладом: и джуновские задачи порешать на интервью на сеньорскую позицию, и потратить ни один день на собесы, и на подготовку потратить месяц.

Не стоит возводить в максимализм это сообщение, но разделять тёплое и мягкое нужно научиться.
1👍4
Forwarded from Test chan
😁6
💾 Ретро 2023
#оффтоп

Этот год уже всё, давайте следующий.

Год подходит к концу и время подводить итоги: личная жизнь, здоровье, доходы, различные активности. Каюсь, в прошлом году было как-то лениво составлять планы, поэтому жил как жилось, но нажилось немало интересного. Расскажу урывками что случилось со мной за этот год:

✈️ Побывал в Турции, Грузии, России, Тайланде. Где-то несколько дней, где-то значительное время жил и живу
🦷 Вырвал зуб 6-ку, который года 3 был в ужасном состоянии
❤️ Завёл этот канал и нашел своих первых подписчиков
Начал больше времени уделять социальной части и медийки
🏍 Научился кататься на мотоцикле
📱 Купил экшен камеру и айфон
✂️ Научился делать резки и склейки в DaVinci
8️⃣ Поучаствовал в ~ 8-х разных проектах в качестве разработчика
📺 Посмотрел сотни фильмов
🎧 В Яндекс.Музыке прослушал почти 100 тысяч часов музыки
💲 Заработал десятки тысяч $$$

Ретроспектива состоит обычно из двух шагов, поэтому второй шаг будет с планами на новый 2024:

😬 Вставить зуб, а лучше 2
💯 Сделать тысячу подписчиков в телеграмме
📺 Запустить канал про IT мемы в Instagram / TikTok и набрать тысячу подписчиков там
👨‍🏫 Запустить серию обучающих уроков по приготовлению Yii3 на Youtube
🗺 Определиться с местом для постоянного места жительства
👫 Наладить личную жизнь
💪 Заменить пивное пузо спортивными кубиками пресса
🤑 Найти дополнительный источник заработка, помимо основной работы
🐈 Завести кота
🖼️ Зарелизить Yii3
🤑 Начать зарабатывать $10 000/month

Пока так, дальше буду делить подробнее, приоритезировать, фильтровать и ставить чекпоинты.

А вы ставите цели на год и следите за прогрессом время от времени? 😉
С наступающим новым 2024 годом!

——

Передаю эстафету ретро Александру Макарову и Олегу Мифле
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍6🔥1
Календарь, как смысл жизни
#пост №6.

Как-то случайно набрёл на статью одного из моих прошлых коллег про календарь. Статья занятная. Автор крутой.

Как обычно, телега не может засунуть больше 2 тысяч символов в мое сообщение, поэтому выкинул пост в телеграф: https://telegra.ph/Kalendar-kak-smysl-zhizni-01-23
1👍4
Тестирования функций из стандартной библиотеки PHP и не только

#пост №7

Цель

Подмена (mock) функций, которые уже “загружены” в PHP еще до подгрузки Composer Autoloader, каких-либо include или других объвлений function name(){}

Подмена не только из под не пустого namespace, например App\Service\name , но и из корневого namespace: проще всего это сделать через use function name;

Проблема

Если объявить функцию с именем, которая уже существует в стандартной библиотеке PHP, то получим ошибку, что такая функция уже существует и переопределить её нельзя.

Можно было бы “выгрузить” её из памяти, но увы, выгружать из памяти функции в PHP нельзя.

Можно лишь переопределить функцию до её непосредственного объявления. Но такой способ не подходит, потому что функция уже объявлена при любом вызове php .

Ресерч

В php.ini можно найти флаг disable_functions , которая принимает список имен функций, которые нужно “не объявлять” в недрах PHP.

Если использовать этот флаг, то php -ddisable_functions=time -r "echo time();" выкинет ошибку:


❯ php -ddisable_functions=time -r "echo time();"
PHP Fatal error: Uncaught Error: Call to undefined function time() in Command line code:1
Stack trace:
#0 {main}
thrown in Command line code on line 1

Fatal error: Uncaught Error: Call to undefined function time() in Command line code on line 1

Error: Call to undefined function time() in Command line code on line 1

Call Stack:
0.0000 389568 1. {main}() Command line code:0


Это и логично. Функции time больше нет. Но теперь ведь можно создать её самостоятельно?

Если объявить функцию самостоятельно, то ошибки больше не будет:

```shell
❯ php -ddisable_functions=time -r "function time() { return 123; } echo time();"
123%
```

Бинго!

Помещаем объявление функции в библиотеку, создаем State manager, через которого сможем управлять возвращаемым значение “123” и делаем пользователю интерфейс взаимодействия с этим менеджером.

Теперь, если пользователь захочет протестировать вызов time , то сможем самостоятельно указать требуемые значения. Время в будущем, в прошлом, 0, false, что угодно.

Но как быть, если нужно протестировать измененную функцию time лишь в одном тесте, а в других местах оставить всё как есть?

Можно так и сделать: State manager создает для всех тестов функцию, которая эмулирует стандартную time , а в нужном тесте наложить на общую эмуляцию частную.

Вроде всё логично и понятно. Можно накодить и наслаждаться тестированием.

Однако, а как эмулировать системное время? Если с различными полифилами от symfony всё понятно: можно создать какую-то функцию, которая будет базировать на другой функции, преобразовывать результат под новый формат и отдавать его.

Но на какой функции нужно базировать время?

DateTime`* классы? `
date() ? mktime ? hrtime ? А если их тоже отключить нужно?

Ba
sh! 🤪

PHP имеет возможность в любое время обратиться к своему старшему брату-башу простыми обратными кавычками: `command` . Результат будет строкой, но всегда можно "кастануть".

Для аналога time() команда `date +%s` .

Значит для State manager осталось написать только возможность использовать не статичное значение, а функцию, которая каждый раз будет выполняться.

Всё это и не только сделано в библиотеке xepozz/internal-mocker

Читаем доку по установке и первичной настройке, добавляем нужные файлы, вписываем следующую конфигурацию:


$mocker = new Mocker();
$mocker->load([
[
'namespace' => '',
'name' => 'time',
'function' => fn () => `date +%s`,
],
]);
MockerState::saveState();


——

Если кто-то писал свои костыли или специально убирал use function из файлов, чтобы подменять функции в нужном namespace, теперь можете избавиться от них и заменить это на подключение библиотеки и небольшой конфиг.

——

Описание disable-functions: https://www.php.net/manual/en/ini.core.php#ini.disable-functions

Internal mocker: https://github.com/xepozz/internal-mocker/
1👍13
Хэндлим тему | Дерепко
Тестирования функций из стандартной библиотеки PHP и не только #пост №7 Цель Подмена (mock) функций, которые уже “загружены” в PHP еще до подгрузки Composer Autoloader, каких-либо include или других объвлений function name(){} Подмена не только из под…
Решил превратить пост дополнительно в статью на хабре: https://habr.com/ru/articles/797343/

Планирую еще один пост написать про Advanced Usage этой штуки. Понимаю, что читать огромную доку мало кому будет интересно, а разобрать примеры и найти свой кейс будет самое лучшее для читателя.

Посты на индексируемом пространстве: хабр, медиум и прочие большие ресурсы хорошо подходят для продвижения твоих статей:
- матч по ключевым словам из поисковиков
- cross-reference от статьи к статье, по ссылкам внутри статьи
- знакомство с “чужой” аудиторией
- большая ротируемость просмотров

Выкладывать один и тот же текст на разные ресурсы – это очень грамотное продвижение. Но мне пока лень 🙂

——

Кстати, этот инструмент помог в Jetbrains php stubs исправить пару недочетов: раз и два.
А еще он хорошо подошел для тестирования функции flush() в Yii3.
🔥9👍2
Параллельные вычисления на PHP
#пост

Как сделать 1 000 HTTP запросов за 8 секунд?
А отправить миллион писем за 2 минуты?
А если без брокеров очередей и баз?

Сначала думал, что pcntl будет хорошим вариантом, но позже передумал.

Пощупал AMPHP и очень понравилось. Код выглядит максимально привычным, никаких расширений ставить не нужно, поддержка composer и всё типизировано.
Но я нашел проблему – документация практически отсутствует.

Как обычно, много текста в пост не влезло, поэтому закинул в телеграф:

https://telegra.ph/Parallelnye-vychisleniya-na-PHP-03-05

Да, здесь не про параллельные вычисления, но я захотел так назвать пост 😉
Если понадобится, могу поделиться полными результатами сравнения работы pcntl vs amphp: Генерировал 1 000 000 итераций, которые со случайной задержкой 1–10 сек. должны были выполнить операцию.

——

А пробовали ли вы асинхронные фреймворки?

@handle_topic
1🔥12👍3
Управление форматом ответов
#пост

Недавно в чате Yii Флудилочная @Kutuzov_ska столкнулся с проблемой разных ответов в dev и prod окружениях приложения на фреймворке Symfony. О проблеме можно почитать здесь.

Development

Как правило, когда мы разрабатываем приложение, мы хотим видеть как можно подробнее причину поломки нашего кода:

- Текст сообщения
- Файл, строку и код, где произошла поломка
- Stacktrace от точки входа в приложения до этой самой строчки
- Значения переменных, аргументов функций и прочее.

Обычно приложения с обработчиком исключений и ошибок это и делают: рисуют красивый UI, рисуют сниппет с ошибой и подсвечивают нужную строчку.

Даже в JSON API многие приложения конвертируют всё в JSON представление и клиенты этого API могут увидеть полный текст ошибки, stacktrace и т.п.

Production

Однако, в продакшене такое делать непозволительно опасно:

- Тексты ошибки дают злоумышленникам возможно эксплуатировать ваше приложение и найти уязвимости
- Stacktrace может раскрыть вашу внутреннюю структуру приложения
- Значения переменных могут раскрыть ваши данные для доступа к тем или иным сервисам

Чтобы такого не происходило, хорошей практикой считается сокрытие всех подробностей ошибки или исключения в конечном ответе, а залогировать ошибку можно “как есть”, считая безопасным попадания в систему сбора логов.

О надежности последнего можно говорить много, однако я бы хотел сделать упор на текст ошибки, выводимый в тело ответа.

Для клиентов API порой удобно завязаться на текст ошибки и сделать какое-то конкретное действие:

- Подождать какое-то время и отправить запрос заново
- Показать текст ошибки пользователю
- Выполнить какую-то логику, основываясь на тексте ошибки

Конечно, можно завязаться на HTTP код ответа и выполнять нужное действия, основываясь на значении этого кода, но текст ошибки иногда тоже приходится задействовать.

Чтобы ваш клиент не показал пользователю ошибку


Fatal error: Uncaught TypeError: find(): Argument #1 ($id) must be of type int, string given


Стоит как-то разделять текст, который можно показать пользователю и текст, который стоит скрыть за стандартным текстом HTTP кода: Internal server error, Bad request и другие.

Обработчик ошибок

Такое разделение, как правило, делают на стороне формирования этой ошибки – в нашем случае на бекенде.

В Yii2 есть концепция HttpException: есть несколько базовых классов, отражающие соответствующий HTTP код исключения и возможность задать свой текст ошибки, который увидит клиент. Подробнее можно почитать здесь: ссылка на документацияю.

В Symfony приложениях тоже есть аналогичный подход.

Exception Mapper

В своих проектах я предпочитаю написать свой mapper исключений в выводимый ответ:

- Создаю класс, который встраивается в логику обработки исключений
- Сформирует нужный мне формат ответа с дополнительными кодами и текстами
- Будет заниматься прочими удобствами для development окружения

Похожая схема есть и в Yii3: ссылка на документацию.

В Yii3 http stack построен на базе PSR middleware, поэтому нужно лишь добавить middleware в стек и настроить класс формирования ошибок.

В Symfony http stack построен на событийной модели, и для похожего действия нужно написать свой обработчик события onKernelException.

В Symfony приложениях я создаю несколько интерфейсов-маркеров, который могут задавать кастомный текст ошибки, который сможет увидеть клиент. Все остальные ошибки скрывают все свои детали.

Выглядит такой обработчик примерно так: ссылка на gist.

Имея собственный обработчик, этого позволяет мне внедрять множество коротких путей в разработке, уменьшая boilerplate кодовой базы. Выглядит очень просто и всегда можно изменить массово под требования.

——

Полезные ссылки:

List of http status codes
Yii Флудилочная

@handle_topic
1👍5🔥2
Remap – гидрация результатов sql запросов с преобразованием
#пост

Довольно часто мне приходилось делать raw sql запросы в БД для получения данных. Причин тому было несколько:

- Так быстрее
- Не нужно писать длинные билдеры
- Запрос часто менялся, проще всего переносить as-is из требований в код
- Подсветка синтаксиса в IDE
- Удобная отладка: скопировал в DB Viewer и запускаешь
- И многое другое

Зачастую в проекте уже была какая-нибудь ORM или Active Record, где всегда результат запроса был объектом с необходимыми свойствами и типами.

Однако работа с raw sql обычно заканчивалась перегоном массивом из одного метода в другой.

Это неудобно:

- Нет типизации параметров функции – array $data
- Нет типизации свойств – $data['user_id'] – int/string?
- Нет понятия наличия свойства в массиве вообще – $data['unknown_prop'] – ошибка, которую найдешь только при выполнении кода

Как-то давно общаясь в чате про Active Record в Yii3 ко мне пришло озарение, что AR – это всё еще сложно – нужно наследоваться от базового класса или подключать trait, где-то доставать фабрики и самое главное, всё равно raw sql не смапить в модельку.

К тому моменту hydrator из Yii3 был почти готов и я решил сделать Proof Of Concept обычного data-mapper, с использовать db и hydrator.

Вот что из этого вышло:

Remap

Библиотека содержит лишь 1 класс и делегирует работу по исполнению запроса в yiisoft/db. Создание объекта и его наполнение библиотека делегирует в yiisoft/hydrator.

Таким образом, логика выглядит линейной и понятной:

1. Выполняет raw sql запрос
2. Проходим построчно по результату запроса
3. Создаем DTO и наполняем его нужными полями

Всё это скрыто в методе Remap::map()

Пример работы с библиотекой:



final class Todo
{
public int $id;
public string $noscript;
public int $status;
public int $created_at;
}

$sql = 'SELECT id, noscript, status, created_at FROM todo WHERE id = :id LIMIT 1';
$params = ['id' => 1];

$remap->map(Todo::class, $sql, $params);


Remap::map()

Метод принимает первым аргументов класс, который нужно будет создать и наполнить.

Второй и третий аргументы – сам запрос и параметры для подстановки. Можно передать во второй параметр string $sql , а в третий array $params , а можно сразу во второй передать [$sql, $params]

Метод возвращает \Generator объектов. Это позволит обрабатывать большие объемы результатов запроса и не падать с нехваткой памяти.

Как вариант использования библиотеки я сразу подметил, что удобно было бы использовать класс, как AR и Query Builder, поэтому с легкостью вышеупомянутый пример можно превратить в следующее:


$remap->map(Todo::class, Todo::selectOne($id));
$remap->map(Todo::class, Todo::selectAll());


Использовать можно по-разному, поэтому для еще большего упрощения записи можно написать следующее:


$remap->map(...Todo::selectAll());


Статические методы в Todo в текущих примерах будут возвращать массив из нужных значений:

- [$sql, $params] в первом примере
- [self::class, $sql, $params] во втором примере

А использование yiisoft/hydrator позволило использовать Attributes для произведения дополнительных трансформаций. Например:


final class TodoModelHydrator
{
#[Data('id')] // В свойство $identifier запишется то, что лежит в id свойстве
public string $identifier; // дополнительно cast from int -> to string
#[Data('noscript')] // noscript -> text
public string $text;
public string $status; // int -> string
#[Data('created_at')] // created_at -> date_created
public string $date_created; // int -> string
}


Таким образом, результат запроса можно преобразовать под нужные конвенции объектов и не зависеть от устройства внешнего хранилища.

Причесал библиотеку, написал тесты, подкрутил Psalm на 1 уровень, тегнул 1.0.

Надеюсь эта библиотека поможет и вам. Буду рад любым предложениям по улучшению.

——

Полезные ссылки:

Remap
Использование атрибутов yiisoft/hydrator

@handle_topic
1👍11🔥7
#оффтоп

Хороший кейс, почему нужно писать свои программы быстро :)

Разбор, конечно, очень поверхностный, но сама история довольно интересная. Рекомендую к прочтению.
👍2
Forwarded from Авва
В мире компьютерной безопасности сегодня интересный день. Точнее, он начался вчера вечером, когда немецкий разработчик Андрес Фройнд опубликовал отчет о тайной лазейке (бэкдор), которую он обнаружил в новых версиях широко используемой библиотеки для сжатия liblzma (часть архиватора xz). Лазейка позволяет взломщикам заходить через SSH на системы, в которых установлены эти новые версии - к счастью, похоже, что это всего несколько дистрибутивов Линукса в их до-релизовых версиях.

Всех очень впечатлило, насколько эта лазейка была сделана хитро, и как взломщик или взломщики серьезно поработали над тем, чтобы замести следы:

- взломщик под именем/псевдонимом Jia Tan почти два года (!) участвовал в разработке опенсорсного пакета xz, завоевал доверие его мейнтейнеров и получил доступ к прямому коммиту в его репозиторию. Он сделал больше 700 коммитов, лишь малая часть которых медленно подготовила код для лазейки

- основной код лазейки спрятан в тестовых файлах проекта (примеры "плохих" и "хороших" архивов)

- исходный код, который включает лазейку в собственно библиотеку, вообще не является частью основной репозитории в Github. Он спрятан в тар-архивах двух последних релизов, которые обычно используются мейнтейнерами дистрибутивов. То есть есть таг релиза, есть архив, якобы собранный из репозитории в момент этого тага, но на самом деле в нем есть крохотная добавка; в самой репозитории ее нет

- эта добавка прячется в конфигурационной магии autoconf, которую все ненавидят лютой ненавистью и никто никогда не заглядывает внутрь

- она проверяет, когда исходники конфигурируют именно для постройки дебиан-пакета или RPM-пакета (т.е. то, что будут делать мейтейнеры дистрибутивов), и только в этом случае вынимает из тестовых файлов определенные куски и добавляет в код библиотеки

- внутри библиотеки код лазейки заменяет несколько функций, которые работают с символьными таблицами библиотек во время их подгружения. Затрачены специальные усилия, чтобы имена функций не появлялись в двоичном коде. Что именно дальше делает код лазейки, до конца еще не ясно, но он обрабатывает сам символьные таблицы библиотек, и видимо находит то, что имеет отношение к SSH серверу, и что-то там заменяет. Это еще проверяют сейчас.

- интересно, что openssh, стандартный SSH-сервер под линуксом, не использует библиотеку liblzma, в которую вставили эту лазейку, но несколько популярных дистрибутивов добавляют в него поддержку уведомлений системы, systemd, а библиотека libsystemd уже в свою очередь использует liblzma.

- после того, как вышли версии библиотеки с ошибкой, несколько разных людей с незамеченными до того именами (очевидно, альты взломщика или сообщники) стали открывать запросы в разных программах и пакетах сделать апгрейд на эти новые версии, и в некоторых случаях преуспели

Взломщик допустил только одну ошибку: код лазейки, когда он работает как часть openssh, довольно медленно обрабатывает эти символьные таблицы, или что он еще там делает, и даже неудачная попытка логина на такую систему занимает на полсекунды дольше, чем обычно. Андрес Фройнд заметил эти полсекунды задержки. Они его раздражали. Он решил найти, какой новый баг к этому приводит, и нашел эту лазейку.

Если бы все происходило быстро и не было задержки в полсекунды, очень может быть, что это не заметили бы месяцы и годы, и этот код попал бы в основные дистрибутивы, в версии Линукса, которые запускаются у основных облачных провайдеров итд. Они реально очень, ОЧЕНЬ хорошо замели следы.

Теперь все думают, что надо было/надо теперь делать по-другому, и как обнаружить следующую лазейку такого типа - или предыдущую, если она уже есть и никто не знает! - не опираясь на удачу и героическую занудливость Андреаса Фройнда.
1🔥6👍3😱3😁1
SSE или стримы на PHP
#пост

SSE – Server-sent events. Стрим – потоковая передача данных в рамках одной сессии.

SSE – протокол общения сервера и клиента, когда сервер отдает информацию частично, при этом не обрывая и не завершая соединение.

Для простой реализации такого протокола потребуется:

- Добавить в HTTP Headers Content-Type: text/event-stream
- В HTTP Body писать следующее:
- Передача сообщения начинается с data:
- Заканчивается сообщение с \n\n на конце строки
- Таких сообщений может быть неограниченное количество
- Задержка между сообщения может быть любая: секунда, минута, 30 минут, прочее

Рассмотрим несколько примеров с возможностями SSE:

- Так пишутся комментарии, с двоеточием вначале


: comment
: another comment
data: ...


- Кастомное имя события. Если не указать event, то событие будет типа message. В моем примере тип события = question с телом в виде JSON


event: question
data: {"tg_channel":"@handle_topic"}


- Событие с id. Не вижу в этом id какой-то полезности для себя.


data: text message
id: 55


- Длинные строки. Это всё еще одно событие.


data: looooooooooooooooong text
data: looooooooooooooooong text
data: looooooooooooooooong text


- А это уже два разных сообщения:


data: payload1

data: payload2



- Еще можно указать retry в milliseconds. Будет учтено при обрыве соединения и попытке восстановления. Например, 1 секунда (1000 миллисекунд).


data: ok
retry: 1000


Это довольно удобная штука, когда нужно что-то недолго* постримить пользователю:

- Прогресс бар для загрузки файлов
- Какое-то реалтайм действие
- Асинхронная операция и прочее

Реализация

Реализовать на чистом PHP довольно просто: посмотреть пример можно здесь.

Однако, мало кто пишет на чистом пхп свои бекенды. Скорее всего на бекенде используется какой-то фреймворк с ответами в виде класса Response. Либо сразу в контроллере, либо под капотом происходит трансформация возвращаемого значения в строковый ответ.

Если разбирать PSR ResponseInterface , то HTTP Body формируется через метод withBody, который принимает объект StreamInterface. Ага, вот и стримы обещанные.

Стримы

Так как задать несколько ответов с задержкой?

Раз уж наш ответ является стримом, то стрим не обязан возвращать все данные “за одно чтение”.

Поэтому можно сделать некий буфер, который будет вычитываться в методе read() . Если данных больше не будет, то достаточно поменять флаг eof и вернуть его в соответствующем методе объекта стрима.

Однако, набирать буффер и потом его сбрасывать может быть чревато разными проблемами:

- Бекенд будет думать, что клиент всё принял и обработал
- Клиент получит часть, что-то сломается, и получить остальную часть он уже не сможет
- Дополнительные затраты на память

Поэтому, можно сделать небольшой sleep() в методе чтения стрима и производить обработку следующего события только после того, как первое было успешно выдано клиенту.

Ограничения

Разберем еще несколько ограничений SSE:

- Можно стримить только body
- Хедеры нельзя менять после начала стрима
- Кодировка всегда UTF-8

Emitter фреймворка должен уметь в стримы, чтобы не выдать первый результат и закрыть стрим, либо объект стрима должен сам уметь блокироваться и чанковать данные.

Проблемы

- Сложная реализация
- Реализовывать стримминг событий на PHP при помощи SSE еще и в PSR обёртках?
- Проще подключить Mercure и настроить его.
- Протокол – пустышка
- Ни авторизации, ни разделения на каналы, ни бродкастинга
- Всё делать либо в HTTP, либо самому
- По сути в нем можно перегонять лишь текст и всё
- Это как HTTP внутри HTTP. Шутка про монитор в мониторе
- Свободные воркеры
- Свободные воркеры веб-сервера превращаются в зомби за мгновение
- Поэтому таймауты обязательны
- Либо Non-blocking I/O. Кстати, надо бы попробовать.

---

Полезные ссылки:

MDN Server-sent events
StreamInterface
HTML Standard

@handle_topic
1👍8🤨1
#мем

Концовка топ😂