<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>OpenDevCast</title><author><name>OpenDevCast</name></author><id>https://teletype.in/atom/opendevcast</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/opendevcast?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@opendevcast?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=opendevcast"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/opendevcast?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-05-13T22:19:21.905Z</updated><entry><id>opendevcast:rJdVVRny8</id><link rel="alternate" type="text/html" href="https://teletype.in/@opendevcast/rJdVVRny8?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=opendevcast"></link><title>Что там нового в вебе?</title><published>2020-01-03T15:10:24.049Z</published><updated>2020-01-03T15:13:25.414Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://teletype.in/files/27/21/2721b64f-1a05-42d6-881a-5eb5f95a2b79.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://teletype.in/files/27/21/2721b64f-1a05-42d6-881a-5eb5f95a2b79.png&quot;&gt;Приближение нового года натолкнуло меня на мысль составить список наиболее интересных рюшечек в вебе. После ленивого серфинга интернета, наткнулся на блог Google Chrome. Эти то ребята шарят, как изнасиловать пожесче и так замученный веб. У них есть удобный список публикаций по месяцам, а самое интересное — посты из серии &quot;Что нового в версии XX&quot;. Все это безобразие вот тут.</summary><content type="html">
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/27/21/2721b64f-1a05-42d6-881a-5eb5f95a2b79.png&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Приближение нового года натолкнуло меня на мысль составить список наиболее интересных рюшечек в вебе. После ленивого серфинга интернета, наткнулся на блог Google Chrome. Эти то ребята шарят, как изнасиловать пожесче и так замученный веб. У них есть удобный список публикаций по месяцам, а самое интересное — посты из серии &amp;quot;Что нового в версии XX&amp;quot;. Все это безобразие &lt;a href=&quot;https://developers.google.com/web/updates/capabilities&quot; target=&quot;_blank&quot;&gt;вот тут&lt;/a&gt;.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;Chrome 80 еще нет в stable релизе, но описание DevTools выходит раньше. Вот что добавили: поддержка переопределений let и class в консоли, улучшения для отладки WebAssembly, цепочки инициаторов запроса в network, ну и прочие плюхи, про которые &lt;a href=&quot;https://developers.google.com/web/updates/2019/12/devtools&quot; target=&quot;_blank&quot;&gt;можно почитать тут&lt;/a&gt;.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2&gt;Chrome 79 / 2019.12&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/12/nic79&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;https://developers.google.com/web/updates/2019/12/nic79&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;&lt;strong&gt;Maskable Icons&lt;/strong&gt;&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/de/53/de53e6fc-271a-4c3c-9dc6-d13c2d328175.png&quot; width=&quot;1600&quot; /&gt;
    &lt;figcaption&gt;Для PWA под Android&lt;br /&gt;  &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;Все дело в том, что начиная с Oreo после добавления PWA приложения вокруг иконки появлялся раздражающий белый кружок. Ну вот ребята и добавили поддержку Maskable Icons. &lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Web XR&lt;/strong&gt;&lt;/p&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/a5/bf/a5bff619-86f4-4179-8925-b5c8d593afcd.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Дополненная реальность уже и до веба доползла. Вот во что стоит поиграть на новогодних каникулах. Еще спеки, примеры и статейки:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://immersive-web.github.io/&quot; target=&quot;_blank&quot;&gt;https://immersive-web.github.io/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://web.dev/vr-comes-to-the-web/&quot; target=&quot;_blank&quot;&gt;https://web.dev/vr-comes-to-the-web/&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://codelabs.developers.google.com/codelabs/ar-with-webxr/#0&quot; target=&quot;_blank&quot;&gt;https://codelabs.developers.google.com/codelabs/ar-with-webxr/#0&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3&gt;&lt;strong&gt;Wake Lock&lt;/strong&gt;&lt;/h3&gt;
  &lt;p&gt;Запрещает блокировку экрана и переход в спящий режим. Говорят, будет удобно, если вы любите залипать на слайды фоточек или готовить еду по рецепту из браузера. Но я думаю, что по факту новый диван с амазона будет смотреть на вас всю ночь. Можете найти имена авторов, которых будете проклинать, на &lt;strong&gt;&lt;a href=&quot;https://w3c.github.io/wake-lock/&quot; target=&quot;_blank&quot;&gt;w3c&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;Также добавили атрибут &lt;code&gt;rendersubtree&lt;/code&gt;. Новая игрушка для любителей оптимизации. Атрибут сообщает браузеру, что он может пропустить рендеринг поддерева. Сами почитаете, короче...&lt;/p&gt;
  &lt;p&gt;В DevTools фичи для печенек, имитации prefers-color-scheme/prefers-reduced-motion, улучшения в code coverage и стек вызовов JS в network. Подробнее почитать можно тут: &lt;a href=&quot;https://developers.google.com/web/updates/2019/10/devtools&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/10/devtools&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2&gt;Chrome 78 / 2019.10&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/10/nic78&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;https://developers.google.com/web/updates/2019/10/nic78&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;Fresher service workers&lt;/h3&gt;
  &lt;p&gt;О МОЙ БОГ, неужели больше не придется менять URL для обновления скриптов service workers?! Говорят, теперь побайтовая проверка как у Лисы и Сафари.&lt;/p&gt;
  &lt;h3&gt;Native File System&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/34/c8/34c82210-1849-45eb-b563-8bbcb8e17620.png&quot; width=&quot;480&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Нативная поддержка ФС, долгожданное и ужасающее обновление. Можете теперь работать с файловой системой без загрузки на сервер, что очень расширяет возможности PWA. Вроде как запрашивает разрешение у пользователей, но я всё равно жду криптолокер под веб.&lt;/p&gt;
  &lt;h3&gt;SMS Receiver&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/3f/3d/3f3d86ed-8d5f-487d-8c08-416c9121e83b.png&quot; width=&quot;230&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;С SMS Receiver API можно будет получать код из смс сразу в после ввода. Все как у взрослых ребят из нативных приложений.&lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;Ещё есть про кастомные свойства CSS с API&amp;#x27;шкой, может кому это будет интересно. По мне еще большее усложнение исходников и CSS.&lt;/p&gt;
  &lt;p&gt;В DevTools добавили ещё улучшений в панели аудита, отладчик для Payment Handler, LCP в производительности и еще по мелочи. Ссылка: &lt;a href=&quot;https://developers.google.com/web/updates/2019/09/devtools&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/09/devtools&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;Chrome 77 / 2019.09&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/09/nic77&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;https://developers.google.com/web/updates/2019/09/nic77&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;Largest Contentful Paint&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/d0/de/d0de62d1-b352-4c8c-8ad3-7bf6c0427ad6.png&quot; width=&quot;1400&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Игрушки для любителей оптимизации в виде API для поиска самого жирного (по времени отрисовки) элемента в видимой области. Там ещё есть подробная статейка с примерами кода, но я не читал.&lt;/p&gt;
  &lt;h3&gt;New forms capabilities&lt;/h3&gt;
  &lt;pre&gt;const form = document.querySelector(&amp;#x27;form&amp;#x27;);
form.addEventListener(&amp;#x27;formdata&amp;#x27;, ({formData}) =&amp;gt; {  
  formData.append(&amp;#x27;teamled&amp;#x27;, &amp;#x27;Лошара&amp;#x27;);
});&lt;/pre&gt;
  &lt;p&gt;Событие formdata, которое позволит влиять на процесс отправки данных из формы. Вы же хотели больше неявных логик? Получайте! Зато теперь не нужен скрытый input для CSRF токена.&lt;/p&gt;
  &lt;p&gt;Form-associated для кастомных элементов. Теперь ваш говнокод может быть частью формы, только не забудьте объявить нужные свойства.&lt;/p&gt;
  &lt;h3&gt;Native lazy loading&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/8e/d0/8ed0ab59-cac6-4370-8339-07690f287aa5.png&quot; width=&quot;826&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Нативно и всего одним атрибутом &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;, жалко что пока все равно придется писать js для всех старых версий...&lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;Добавили в триалы &lt;a href=&quot;https://web.dev/contact-picker/&quot; target=&quot;_blank&quot;&gt;Contact Picker API&lt;/a&gt;, новые единицы измерения в &lt;a href=&quot;https://v8.dev/features/intl-numberformat&quot; target=&quot;_blank&quot;&gt;intl&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt;В DevTools добавили автопереключение темки из вашей ОС, в панели Network показывается prefetch cache, показ приватных свойств объекта при инспектировании в консоле, нотификации и пуши и что-то еще. Ссылка: &lt;a href=&quot;https://developers.google.com/web/updates/2019/07/devtools&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/07/devtools&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;Chrome 76 / 2019.07&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/07/nic76&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;https://developers.google.com/web/updates/2019/07/nic76&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;PWA Omnibox Install Button&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/db/12/db12537a-4b30-4562-9870-2d953fbf4080.png&quot; width=&quot;627&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;В омнибокс добавили кнопульку для PWA. Мелочь, а приятно. Все потому что ранее эту технологию сделали доступной для десктопа. Даже на Linux робит (см. Chrome 70). Правда, мне всё равно, я на &lt;a href=&quot;https://dwm.suckless.org/&quot; target=&quot;_blank&quot;&gt;dwm&lt;/a&gt; сижу.&lt;/p&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/7a/34/7a34e600-e901-4833-bb93-d23a2bb536e4.png&quot; width=&quot;1440&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Теперь можно подменять mini-infobar с предложением установки на свой кастомный. Обязательно сделайте крестик очень маленьким.&lt;/p&gt;
  &lt;h3&gt;Faster updates to WebAPKs&lt;/h3&gt;
  &lt;p&gt;Теперь манифест будет проверяться на предмет изменений каждый день. Раньше было каждые 3 дня. &lt;/p&gt;
  &lt;h3&gt;Dark mode&lt;/h3&gt;
  &lt;pre&gt;@media (prefers-color-scheme: dark) {
  body {
    background-color: black;
    color: white;
  }
}&lt;/pre&gt;
  &lt;p&gt;Новый медиа запрос который запрашивает тему вашей ОС (светлая\темная) что бы вы могли автоматически под нее переключить тему на сайте. Неплохо, кстати. Возможно, всё меньше сайтов будут слепить нас по ночам.&lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;Также &lt;code&gt;Promise.allSettled&lt;/code&gt;, новые методы &lt;code&gt;text(), arrayBuffer(), stream()&lt;/code&gt; для работы с BLOB, поддержка изображений в async clipboard API.&lt;/p&gt;
  &lt;p&gt;В DevTools добавили новый UI для панели Network, HAR теперь содержит сообщения WS, наконец-то использование памяти в реалтайме и еще много интерестного. Посмотрите сами: &lt;a href=&quot;https://developers.google.com/web/updates/2019/05/devtools#HAR&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/05/devtools#HAR&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2&gt;Chrome 75 / 2019.06&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/06/nic75&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;https://developers.google.com/web/updates/2019/06/nic75&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;Web Share API&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/cb/f2/cbf206f6-ab16-40c3-b417-b19b5e54331f.png&quot; width=&quot;354&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Позволяет использовать нативные сервисы шаринга контента из OS, что очень полезно для мобильных устройств. Уже поддерживает шаринг аудиофайлов, изображений, видео и текстовых документов. Свойство &lt;code&gt;navigator.canShare&lt;/code&gt; в помощь.&lt;/p&gt;
  &lt;h3&gt;Numeric separators&lt;/h3&gt;
  &lt;p&gt;В числовые литералы добавили нижнее подчеркивание (_, U+005F) как разделитель для читабельности, теперь он будет игнорируется при математических операциях. Ну фиг знает кому это удобно.&lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;Добавили desynchronized hint для canvas.&lt;/p&gt;
  &lt;p&gt;В DevTools, в основном, добавили мелкие, но полезные улучшения интерфейса. Подробнее тут: &lt;a href=&quot;https://developers.google.com/web/updates/2019/04/devtools&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/04/devtools&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;Chrome 74 / 2019.04&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/04/nic74&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;https://developers.google.com/web/updates/2019/04/nic74&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;Private class fields&lt;/h3&gt;
  &lt;p&gt;Приватные и публичные свойства класса, одна из основных болей при разработке на JavaScript. Ребята до этого добавили префикс для объявления публичного свойства, а теперь еще и для приватного. Смотрятся, если честно, так себе...&lt;/p&gt;
  &lt;h3&gt;Пользователь не хочет анимаций&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/a8/66/a8667877-fe53-4fdf-8082-1a5ebbbdedc5.png&quot; width=&quot;472&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Медиа запрос &lt;code&gt;prefers-reduced-motion, &lt;/code&gt;который сообщает нам о том, что пользователь не хочет всех этих ваших анимаций. Говорят, некоторых действительно подташнивает от параллаксов.&lt;/p&gt;
  &lt;h3&gt;CSS transition events&lt;/h3&gt;
  &lt;p&gt;Добавили события для отслеживания и изменения поведения при выполнении transition.&lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;Обновления в Feature policies, которые позволяют выборочно включать, отключать и изменять поведение определенных функций и API в браузере.&lt;/p&gt;
  &lt;p&gt;В DevTools добавили Lighthouse v4 в аудите, выделение DOM объектов, к которым применяется выбранное CSS правило, улучшенный просмотр бинарных сообщений в WS, скриншоты выделенных областей, фильтры для service workers, улучшения для анализа профилирования, и еще по мелочи. Смотреть тут: &lt;a href=&quot;https://developers.google.com/web/updates/2019/03/devtools&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/03/devtools&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;h2&gt;Chrome 73 / 2019.3&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/03/nic73&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;https://developers.google.com/web/updates/2019/03/nic73&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;h3&gt;Progressive Web Apps work everywhere&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/59/52/595230e8-af07-4f22-8993-7380a47e08b3.png&quot; width=&quot;1600&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Добавили поддержку PWA для MacOS, теперь работает на всех популярных настольных платформах. И это очень даже классно.&lt;/p&gt;
  &lt;h3&gt;Signed HTTP Exchanges (SXG)&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/2a/7f/2a7f98d3-2f0f-416f-8fb5-f93a10469edf.png&quot; width=&quot;951&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Механизм для размещения верифицированных копий web-страниц на других сайтах, выглядящих для пользователя как исходные страницы. При помощи SXG владелец одного сайта, при помощи цифровой подписи, может авторизовать размещения определённых страниц на другом сайте. В случае обращения к этим страницам на втором сайте, браузер будет показывать пользователю URL исходного сайта, несмотря на то, что страница загружена с другого хоста. &lt;/p&gt;
  &lt;p&gt;Я думаю, это важная часть развития AMP, так как решает проблему с отображением в адресной строке другого домена. Также технология может помочь распространению Web Packaging в режиме p2p.&lt;/p&gt;
  &lt;p&gt;Это технология явно заслуживает отдельной статьи в новом году. &lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;Constructable style sheets, метод matchAll() и еще несколько мелочей.&lt;/p&gt;
  &lt;p&gt;В DevTools добавили Logpoints для отладки кода в панели без console.log, экспорт информации о code coverage и еще много интерестного. Больше тут: &lt;a href=&quot;https://developers.google.com/web/updates/2019/01/devtools&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/01/devtools&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;Chrome 72 / 2019.01&lt;/h2&gt;
  &lt;h3&gt;Public class fields&lt;/h3&gt;
  &lt;p&gt;Еще один шаг к ООП в JS, возможность объявлять публичные методы класса без кода в конструкторе. Продолжение этих идей вы уже видели в 74й версии.&lt;/p&gt;
  &lt;h3&gt;User Activation API&lt;/h3&gt;
  &lt;figure class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/7f/92/7f924f0b-3b5b-4683-b33e-de5948639cc4.png&quot; width=&quot;800&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;User Activation v2, которая призвана стать стандартом во всех браузерах.&lt;/p&gt;
  &lt;h3&gt;Localizing lists of things with &lt;code&gt;Intl.format&lt;/code&gt;&lt;/h3&gt;
  &lt;pre&gt;const opts = {type: &amp;#x27;disjunction&amp;#x27;};
const lf = new Intl.ListFormat(&amp;#x27;fr&amp;#x27;, opts);
lf.format([&amp;#x27;chien&amp;#x27;, &amp;#x27;chat&amp;#x27;, &amp;#x27;oiseau&amp;#x27;]);
// → &amp;#x27;chien, chat ou oiseau&amp;#x27;
lf.format([&amp;#x27;chien&amp;#x27;, &amp;#x27;chat&amp;#x27;, &amp;#x27;oiseau&amp;#x27;, &amp;#x27;lapin&amp;#x27;]);
// → &amp;#x27;chien, chat, oiseau ou lapin&amp;#x27;&lt;/pre&gt;
  &lt;p&gt;Добавлен новый метод &lt;code&gt;.format()&lt;/code&gt;, который упрощает работу со списками.&lt;/p&gt;
  &lt;h3&gt;Остальное&lt;/h3&gt;
  &lt;p&gt;В DevTools добавили визуализацию метрик производительности и по мелочам: &lt;a href=&quot;https://developers.google.com/web/updates/2018/11/devtools&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2018/11/devtools&lt;/a&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;h2&gt;Показалось мне интересным:&lt;/h2&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/08/get-started-with-gpu-compute-on-the-web&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/08/get-started-with-gpu-compute-on-the-web&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/07/chrome-75-media-updates&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/07/chrome-75-media-updates&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/06/layoutNG&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/06/layoutNG&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/05/desynchronized&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/05/desynchronized&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/02/lit-element-and-lit-html&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/02/lit-element-and-lit-html&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/01/rtcquictransport-api&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/01/rtcquictransport-api&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2019/01/emscripten-npm&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2019/01/emscripten-npm&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2018/11/signed-exchanges&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2018/11/signed-exchanges&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2018/10/wasm-threads&quot; target=&quot;_blank&quot;&gt;https://developers.google.com/web/updates/2018/10/wasm-threads&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>opendevcast:rJJLWwXYB</id><link rel="alternate" type="text/html" href="https://teletype.in/@opendevcast/rJJLWwXYB?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=opendevcast"></link><title>k8s at home for fun and leisure</title><published>2019-10-15T15:10:02.006Z</published><updated>2019-10-15T15:10:02.006Z</updated><summary type="html">У домашнего кластера на Kubernetes может быть несколько применений - от файлохранилки до хостинга личного блога. Но главным из них, безусловно, является оттачивание навыков. Теперь не только ваша команды \ клиенты зависят от надежности и производительности, но и лично вы. Других стимулов, кроме “я смог это сделать” не стоит ждать (см. IKEA effect).</summary><content type="html">
  &lt;h1&gt;Потому что могу&lt;/h1&gt;
  &lt;p&gt;У домашнего кластера на Kubernetes может быть несколько применений - от файлохранилки до хостинга личного блога. Но главным из них, безусловно, является оттачивание навыков. Теперь не только ваша команды \ клиенты зависят от надежности и производительности, но и лично вы. Других стимулов, кроме “я смог это сделать” не стоит ждать (см. &lt;a href=&quot;https://en.wikipedia.org/wiki/IKEA_effect&quot; target=&quot;_blank&quot;&gt;IKEA effect&lt;/a&gt;).&lt;/p&gt;
  &lt;p&gt;Но почему именно Kubernetes? Ответ довольно прост - он довольно снисходительно относится к неожиданным перекройкам инфраструктуры. Не нужно переносить systemd сервисы на другую машины - достаточно ввести новую ноду в кластер. Одно из приложений внезапно стало нагружать процессор - ему установить разумный лимит, проверив потребление через мониторинг.&lt;/p&gt;
  &lt;p&gt;Кроме того, несмотря на применение в крупных компаниях, Kubernetes кластер не заставляет тащить стойки с оборудованием домой - вполне достаточно нескольких старых десктопов или ноутбуков.&lt;/p&gt;
  &lt;p&gt;Вопросы разворачивания на одной машине (будет не так интересно) или использования Raspberry Pi для кластера (для них потребуются имаджи для другой архитектуры) оставим вне рамок этой статьи.&lt;/p&gt;
  &lt;h1&gt;Поделки из желудей и пластилина&lt;/h1&gt;
  &lt;p&gt;Итак, есть некоторое количество оборудования, которое требуется объединить в кластер. В моем случае:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;ноутбук Lenovo x240 с 8 ГБ памяти, 250 Гб SSD для корневого диска и 500 Гб HDD для данных&lt;/li&gt;
    &lt;li&gt;старый десктоп в формате mini-ITX, 8 Гб RAM и Athlon времен взятия Очакова, 250 Гб SSD для корня и 500 Гб HDD&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;На обе машины была установлена Fedora Atomic 29. Выбор ОС - дело каждого, в моем случае привычнее скачивать апдейты в оффлайне и иметь возможность откатится на прошлую версию (эти и другие преимущества описаны &lt;a href=&quot;https://www.projectatomic.io/docs/os-updates/&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;)&lt;/p&gt;
  &lt;p&gt;Дистрибутивом Kubernetes был выбран OpenShift по принципу “выбирай тот который использует ближайший к тебе отзывчивый эксперт”. В наличии только 2 машины, потому приходится пользоваться релизом OKD 3.11 вместо OCP 4.&lt;/p&gt;
  &lt;h1&gt;Наш человек в Гаване&lt;/h1&gt;
  &lt;p&gt;Мой провайдер запрещает внешние коннекты к портам 80 и 22, потому для внешнего доступа нам потребуется виртуальная машина в публичном хостинге с хорошей репутацией. В моем случае это Fedora CoreOS на Digital Ocean.&lt;/p&gt;
  &lt;p&gt;Она служит как промежуточный хост для reverse ssh tunnel - из машины в кластере (bmo.vrutkovs.eu) устанавливается ssh соединение в сокет &lt;code&gt;/run/bmo.sock&lt;/code&gt; на машине в DO (&lt;code&gt;do.vrutkovs.eu&lt;/code&gt;). Таким образом, если послать данные в сокет bmo.sock они попадут на нужный порт в машине bmo.&lt;/p&gt;
  &lt;p&gt;Для этого достаточно запустить &lt;code&gt;autossh&lt;/code&gt;:&lt;/p&gt;
  &lt;pre&gt;/usr/bin/docker run --name %n -it  \
  -v /root/.ssh/vrutkovs.pem:/id_rsa:z \
  -e SSH_HOSTNAME=vrutkovs.eu \
  -e SSH_TUNNEL_REMOTE=/run/bmo.sock \
  -e SSH_TUNNEL_HOST=172.17.0.1 \
  -e SSH_TUNNEL_LOCAL=443 \
  jnovack/autossh&lt;/pre&gt;
  &lt;p&gt;Теперь на &lt;code&gt;do.vrutkovs.eu&lt;/code&gt; мы может перенаправлять запросы на внутренний сервер с помощью haproxy. Часть конфига:&lt;/p&gt;
  &lt;pre&gt;frontend https
    bind *:443
    mode tcp
    default_backend bmo

backend bmo
    mode tcp
    server bmo /run/bmo.sock&lt;/pre&gt;
  &lt;p&gt;Кроме того &lt;code&gt;do.vrutkovs.eu&lt;/code&gt; может служить как машина для почтового сервера и получения Let’s Encrypt сертификатов. Для простоты обслуживания проще получить wildcard сертификат, который затем будет применять роутер опеншифта.&lt;/p&gt;
  &lt;h1&gt;Сердце тьмы&lt;/h1&gt;
  &lt;p&gt;Основой всего будет OpenShift, потому нам потребуется развернуть его на внутренних серверах с помощью openshift-ansible.&lt;/p&gt;
  &lt;p&gt;Процесс установки довольно специфичен и сложен, да и объяснить его лучше &lt;a href=&quot;https://docs.openshift.com/container-platform/3.11/install/index.html&quot; target=&quot;_blank&quot;&gt;документация&lt;/a&gt; сложно. Вот несколько рекомендаций&lt;/p&gt;
  &lt;p&gt;Научит роутер применять наши LetsEncrypt сертификаты:&lt;/p&gt;
  &lt;pre&gt;openshift_master_overwrite_named_certificates: true
openshift_master_named_certificates:
- certfile: &amp;quot;{{ inventory_dir }}/vrutkovs.eu.crt&amp;quot;
  keyfile: &amp;quot;{{ inventory_dir }}/vrutkovs.eu.key&amp;quot;
  names:
    - &amp;quot;vrutkovs.eu&amp;quot;
  cafile: &amp;quot;{{ inventory_dir }}/letsencrypt.ca.crt&amp;quot;&lt;/pre&gt;
  &lt;p&gt;Все роуты будут получать поддомен автоматически:&lt;/p&gt;
  &lt;pre&gt;openshift_master_default_subdomain: vrutkovs.eu&lt;/pre&gt;
  &lt;p&gt;OpenShift рекомендуется запускать на машинах с 16 Гб памяти, поэтому:&lt;/p&gt;
  &lt;pre&gt;openshift_disable_check: memory_availability&lt;/pre&gt;
  &lt;p&gt;После установки консоль будет доступна по адресу &lt;a href=&quot;https://console.vrutkovs.eu/&quot; target=&quot;_blank&quot;&gt;https://console.vrutkovs.eu&lt;/a&gt;&lt;/p&gt;
  &lt;h1&gt;Always Own Your Platform&lt;/h1&gt;
  &lt;p&gt;Что с этим кластером теперь делать? Я следую принципу &lt;a href=&quot;http://www.alwaysownyourplatform.com/&quot; target=&quot;_blank&quot;&gt;Always Own Your Platform&lt;/a&gt;. Потому необходимыми для меня приложениями являются:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://gitea.io/&quot; target=&quot;_blank&quot;&gt;gitea&lt;/a&gt; - git сервер&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://nextcloud.com/&quot; target=&quot;_blank&quot;&gt;nextcloud&lt;/a&gt; - сервер синхронизации файлов, RSS-читалка и многое другое&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://transmissionbt.com/&quot; target=&quot;_blank&quot;&gt;transmission&lt;/a&gt; - битторрент клиент (только чтобы скачивать linux дистрибутивы)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/Jackett/Jackett&quot; target=&quot;_blank&quot;&gt;jackett&lt;/a&gt; - API для битторрент серверов&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/Sonarr/Sonarr&quot; target=&quot;_blank&quot;&gt;sonarr&lt;/a&gt; - информация о сериалах&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/lidarr/Lidarr/&quot; target=&quot;_blank&quot;&gt;lidarr&lt;/a&gt; - информация о музыке&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/vrutkovs/blog&quot; target=&quot;_blank&quot;&gt;этот блог&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Некоторые другие вещи (например Matrix сервер или Mastodon) пока приходится отложить из-за низкой скорости интернета.&lt;/p&gt;
  &lt;p&gt;Другие полезные идеи для приложений можно почерпнуть &lt;a href=&quot;https://github.com/Kickball/awesome-selfhosted&quot; target=&quot;_blank&quot;&gt;awesome-selfhosted&lt;/a&gt;&lt;/p&gt;
  &lt;h1&gt;Домашние заготовки&lt;/h1&gt;
  &lt;p&gt;Некоторые полезные вещи для домашнего кластера:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/vrutkovs/homelab-openshift-ci/blob/master/git-cluster-state.sh&quot; target=&quot;_blank&quot;&gt;скрипт&lt;/a&gt; для сохранения состояния кластера (&lt;code&gt;oc get --export&lt;/code&gt; объектов и создание коммита во внутреннем репозитории)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/tektoncd/pipeline&quot; target=&quot;_blank&quot;&gt;tekton&lt;/a&gt; для CI - например, автоматического импорта свежих изменений в ImageStream&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner&quot; target=&quot;_blank&quot;&gt;local provisioner&lt;/a&gt; - для выделения локальных каталогов подам&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes-incubator/external-storage/tree/master/nfs&quot; target=&quot;_blank&quot;&gt;nfs provisioner&lt;/a&gt; - для выделения NFS каталогов подам&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/metalmatze/alertmanager-bot&quot; target=&quot;_blank&quot;&gt;alertmanager-bot&lt;/a&gt; - Telegram бот для событий из Alertmanager&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/joyrex2001/nightshift&quot; target=&quot;_blank&quot;&gt;nightshift&lt;/a&gt; - бот для управления деплойментами по календарю&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/vrutkovs/conumser/&quot; target=&quot;_blank&quot;&gt;conumser&lt;/a&gt; - Telegram бот для обработки вебхуков&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://github.com/prometheus/blackbox_exporter&quot; target=&quot;_blank&quot;&gt;blackbox exporter&lt;/a&gt; - для мониторинга инфры и доступности сайтов&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h1&gt;Выводы&lt;/h1&gt;
  &lt;p&gt;Одомашенный Kubernetes - это совсем не страшно, главное найти полезное применения старому оборудованию и внимательно следить за алертами из мониторинга.&lt;/p&gt;

</content></entry><entry><id>opendevcast:rJpTJh78B</id><link rel="alternate" type="text/html" href="https://teletype.in/@opendevcast/rJpTJh78B?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=opendevcast"></link><title>Топ тупых лазеек для исследования конкурентов: .git для всех</title><published>2019-09-12T12:15:11.008Z</published><updated>2019-09-12T12:21:50.252Z</updated><summary type="html">&lt;img src=&quot;https://teletype.in/files/96/96f39ba3-7ced-4c8b-9869-8b2ee28eb35e.png&quot;&gt;Лазейки такого рода — чистая халатность разработчиков. Сколько уже говорили об этом, сколько писали. Все равно, даже большие компании совершают одни и те же ошибки. Давайте вспомним хотя бы Аэрофлот и Яндекс. </summary><content type="html">
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/96/96f39ba3-7ced-4c8b-9869-8b2ee28eb35e.png&quot; width=&quot;1253&quot; /&gt;
    &lt;figcaption&gt;Мое лицо когда получил 200 ОК на запрос /.git/config&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2&gt;Введение&lt;/h2&gt;
  &lt;p&gt;Лазейки такого рода — чистая халатность разработчиков. Сколько уже говорили об этом, сколько &lt;a href=&quot;https://lynt.cz/blog/global-scan-exposed-git&quot; target=&quot;_blank&quot;&gt;писали&lt;/a&gt;. Все равно, даже большие компании совершают одни и те же ошибки. Давайте вспомним хотя бы &lt;a href=&quot;https://github.com/aeroflotsrc/webapp&quot; target=&quot;_blank&quot;&gt;Аэрофлот&lt;/a&gt; и &lt;a href=&quot;https://habr.com/ru/post/70330/&quot; target=&quot;_blank&quot;&gt;Яндекс. &lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;А всего-то можно с самого начала закрыть доступ ко всем файлам с точки и забыть об этом.&lt;/p&gt;
  &lt;h2&gt;Репозиторий git в вебе&lt;/h2&gt;
  &lt;p&gt;Пожалуй, одно из самого страшного и тупого что может произойти с проектом. Любой, кто знаком с GIT, сразу догадается, что с этим можно сделать. Проверить очень просто: введите в браузер &lt;code&gt;http(s)://example.com/.git/config&lt;/code&gt;, и если вы получили содержимое, то... ну вот, в принципе, и все, делаете &lt;code&gt;wget --mirror&lt;/code&gt; или берете любую поделку типа &lt;a href=&quot;https://github.com/internetwache/GitTools&quot; target=&quot;_blank&quot;&gt;GitTools&lt;/a&gt;. &lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/da/da898ad5-1344-43c1-a249-3fb5813478fb.png&quot; width=&quot;878&quot; /&gt;
    &lt;figcaption&gt;Слишком просто&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;Получаете репозиторий с исходниками и историей коммитов. При такой квалификации команды разработки наверняка ещё и конфиги с паролями. Если же нет, то поиск уязвимостей будет намного проще. Только нужно ли оно вам? Только если задефейсить ради смеха.&lt;/p&gt;
  &lt;p&gt;Например, недавно меня попросили взглянуть на сайт заказа еды из сети суши ресторанов в Москве, и на 2й минуте просмотра я уже выкачивал их репозиторий. &lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/a2/a2c183c4-01b7-423d-8dff-88f30a72b370.png&quot; width=&quot;873&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/f7/f7a62a2b-e988-4c30-ab80-3c38dc8cce57.png&quot; width=&quot;857&quot; /&gt;
    &lt;figcaption&gt;Это занимает достаточно времени...&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;После того, как выкачаем репозиторий, можно восстановить файлы. Вполне возможно, что вам хватит простого &lt;code&gt;git reset --hard&lt;/code&gt;. Давай посмотрим, что у нас там внутри. Но для начала сделаем копию &lt;code&gt;tar -zcvf repo.tgz repo&lt;/code&gt; , не хочу опять тратить 20 минут на выкачивание если что-то сломаю.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/85/853b1daf-1a51-4d6a-af9b-ac8db6322ef4.png&quot; width=&quot;1150&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Хм, похоже, это Битрикс с кучей самописного кода сомнительного качества.&lt;/p&gt;
  &lt;p&gt;Ребята молодцы, защитили сервер на подключения только из под VPN, только вот сам ключ уже лежит для меня в репозитории, спасибо.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/d8/d8af2038-88eb-4f76-bf67-5b6cd0fb1f26.png&quot; width=&quot;858&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;А вот и доступы к iiko, почему то мне стыдно за это.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/5a/5a520f8e-eff4-47c5-b1fa-d66f0613c395.png&quot; width=&quot;949&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Отлично, вот пароль от БД, директория с phpMyAdmin сразу же нашлась в &lt;code&gt;.gitignore&lt;/code&gt;, даже искать не придется... &lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/31/3150fd6f-da57-487e-9ac3-c9b9d6206efd.png&quot; width=&quot;1401&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Давайте попробуем поработать с iiko. У нас есть хост, логин, пароль и логика из полученных файлов. Выясняем, как получить авторизационный ключ.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/47/47b7a0ea-f471-40f4-8e93-f2b6e0e0f0e1.png&quot; width=&quot;1397&quot; /&gt;
    &lt;figcaption&gt;Я человек простой, использую tor&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;Отлично, теперь можно поиграться с API iiko. &lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/7c/7c6cbf7d-066d-48a0-a92e-e03b03ad8cf3.png&quot; width=&quot;1402&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Спустя 40 минут (вы уж простите, репозиторий выкачивался 20) мы уже знаем всех клиентов, кол-во заказов, средний чек, зарплаты и многое другое. Намного эффективнее и точнее классического бизнес анализа, правда?&lt;/p&gt;
  &lt;h2&gt;Итог&lt;/h2&gt;
  &lt;p&gt;Из-за желания сэкономить на разработчиках — найм неквалифицированных кадров. Банальное раздолбайство на все самые простые правила разработки и безопасности. В итоге весь бизнес поставлен под угрозу. Статья получилась довольно скучной. Наверное, это самое глупое, что можно допустить в плане безопасности вашего продукта. Несмотря на это, я всегда начинаю с проверки доступности GIT, Mercurial, Docker Registry.&lt;/p&gt;

</content></entry><entry><id>opendevcast:SJPve3Q8S</id><link rel="alternate" type="text/html" href="https://teletype.in/@opendevcast/SJPve3Q8S?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=opendevcast"></link><title>Топ тупых лазеек для исследования конкурентов: mobile API</title><published>2019-09-11T11:59:08.472Z</published><updated>2019-10-06T17:39:25.489Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://teletype.in/files/24/249a954c-fd03-4d2b-8fc5-56698855ac8d.jpeg"></media:thumbnail><summary type="html">&lt;img src=&quot;https://teletype.in/files/02/029f588e-2ebb-47d7-94eb-a1672bb0da3a.jpeg&quot;&gt;Почему-то последнее время я все чаще встречаюсь с тем что бэкенд разработчики не особо парятся об своих мобильных API. Может быть они считают что никто туда не полезет? Если вы считаете так же, то зря. </summary><content type="html">
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/02/029f588e-2ebb-47d7-94eb-a1672bb0da3a.jpeg&quot; width=&quot;1200&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2&gt;&lt;strong&gt;Введение&lt;/strong&gt;&lt;/h2&gt;
  &lt;p&gt;Почему-то последнее время я все чаще встречаюсь с тем что бэкенд разработчики не особо парятся об своих мобильных &lt;a href=&quot;https://ru.wikipedia.org/wiki/API&quot; target=&quot;_blank&quot;&gt;API&lt;/a&gt;. Может быть они считают что никто туда не полезет? Если вы считаете так же, то зря. &lt;/p&gt;
  &lt;p&gt;В основном я встречаюсь с банальным отсутсвием ограничений на кол-во запросов. Вкупе с инкрементальными ID открываются приятные возможности пособирать данные. А данные для нас как это золото. Их часто не легко добыть, они копятся годами, и чем их больше, тем больше возможностей. &lt;/p&gt;
  &lt;p&gt;Изначально я не планировал писать о Кинопоиске, а хотел поигратся с мобильным апи сервисов такси. Банально выводить на карту в режиме онлайн машинки, но то что я нашел превзошло все ожидания. А история была бы совсем скучной и настолько тупой что и не заслужила бы попасть даже в эту подборку. Сказ о ней возможно будет в другой статье, после исправления уязвимости.&lt;/p&gt;
  &lt;p&gt;Пока я сидел и тихо офигевал от увиденного, один мой друг написал, что очень бы хотел базу фильмов (ну как у Кинопоиска, ага). Почему бы и нет? Так как у меня было всего 2 банки сидра, пачка сигарет, тупенький ноут, телефон не лучше и приблежающаяся ночь за окном... Я решил что рассказ об этом будет куда интереснее и взялся за дело! Под катом я расскажу как можно получить эти данные и не возится с парсингом HTML.&lt;/p&gt;
  &lt;h2&gt;Классика MITM атаки&lt;/h2&gt;
  &lt;p&gt;Само название подхода (man-in-the-middle) говорит само за себя. Грубо говоря, мы просто вклиниваемся в общение между приложением и API на сервере. Так как сейчас не 2007, и все уже научились устанавливать &lt;a href=&quot;https://ru.wikipedia.org/wiki/Let%25E2%2580%2599s_Encrypt&quot; target=&quot;_blank&quot;&gt;Let’s Encrypt&lt;/a&gt;, то нам понадобится добавить наш сертификат на устройство как доверенный, чтобы проксировать &lt;a href=&quot;https://ru.wikipedia.org/wiki/HTTPS&quot; target=&quot;_blank&quot;&gt;HTTP(S)&lt;/a&gt; трафик.&lt;/p&gt;
  &lt;p&gt;Вы можете выбрать любое устройство, но я возьму свой старенький телефон (топ за свои деньги) на Andoird. Иногда можно даже эмулятор использовать, но некоторые хитрые разработчики это &lt;a href=&quot;https://github.com/framgia/android-emulator-detector&quot; target=&quot;_blank&quot;&gt;проверяют&lt;/a&gt; и их приложения бузят. Ладно, ладно... У меня просто не хватило памяти на ноутбуке.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/99/99846e01-5fb8-4ade-8d11-25eba7867aa1.png&quot; width=&quot;1053&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Для таких &amp;quot;интимных дел&amp;quot; мой люибый инструмент это &lt;a href=&quot;https://mitmproxy.org/&quot; target=&quot;_blank&quot;&gt;mitmproxy&lt;/a&gt;. Качаем, ставим и поднимаем свой прокси. Да еще и сертификаты генерит! Что еще нужно? А когда-то я со &lt;a href=&quot;https://en.wikipedia.org/wiki/Squid_(software)&quot; target=&quot;_blank&quot;&gt;squid&lt;/a&gt;&amp;#x27;ом мучался... Кстати, после запуска сертификаты будут в &lt;code&gt;~/.mitmproxy&lt;/code&gt;, их нужно поставить на ваше устройство. Для андроида мне понадобится mitmproxy-ca-cert.cer. Перекидываем любым известным вам способом и добавляем в доверенные.&lt;br /&gt;&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/79/79f0d300-6508-4b26-8e1c-3f7183a17887.png&quot; width=&quot;1440&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Подключаемся к одной сети с обоих устройств, вписываем IP адрес (порт не забудьте) нашего компютера. Теперь HTTP(S) запросы будут проходит через наш прокси, и мы легко сможем их мониторить\копировать и все такое. Вот мы и готовы к поискам золота и приключений.&lt;/p&gt;
  &lt;h2&gt;Мониторим запросы&lt;/h2&gt;
  &lt;p&gt;Открываем интересующие нас приложения, в моем случае это кинопоиск. Года 2 назад я уже игрался с ним, за это время они поменяли версию API и ключ. &lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Кстати раньше у них было что-то душевное, для версии 3.4.1 ключем было samuraivbolote.Тогда за ночь я выкачал всю базу с помощию домашних серверов и пула из 200 прокси. Использовал ее для игр с нейронными сетями.&lt;/em&gt;&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/c9/c99d77c6-6b65-42fd-a830-932394b1b3f2.png&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/b0/b053dc3a-6632-42ae-8533-729532ea741e.jpeg&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Смотрим запрос на информацию о фильме. Что это тут у нас? Инкрементальные id. Божечки, как я люблю инкрементальные id. Пытаемся повторить запрос.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/6e/6e0802aa-41f1-4630-83e8-ed02d72c4409.png&quot; width=&quot;1022&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Получаем 403, вы же не думали что будет просто? Анализируя заголовки понимаем что каждый запрос подписывается некой сигнатурой. При помощи простых наблюдей приходим к выводу что в подписи участвует timestamp, т.е. подпись меняется от времени запроса. &lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/f0/f095e73c-e296-42dc-b460-cad81deefe29.png&quot; width=&quot;1463&quot; /&gt;
    &lt;figcaption&gt;Отметил красными точками&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;Чудесно этой информации нам хватит для начала исследования. Мы уже знаем что можем перебирать id фильмов, что запросы подписываются, в подписи участвует время и судя по всему кусок самого запроса. А это значит что на сервере есть метод проверки этого ключа, и теперь мы его хотим. Пора разобратся со всем этим и заглянуть, что же там происходит внутри приложения.&lt;/p&gt;
  &lt;h2&gt;Разбираем APK&lt;/h2&gt;
  &lt;p&gt;Качаем apk файл этого приложения с любого более менее нормального сайта, найденного в гугле по запросу &amp;quot;download apk&amp;quot;.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/06/0635da01-a39d-48dc-ac83-3dfcd4e657f1.jpeg&quot; width=&quot;735&quot; /&gt;
    &lt;figcaption&gt;Вот этот вроде ничего, сойдет&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;Сверяем вресии. Вроде то, что нужно. Приступем к распаковке. Для этого я использую несколько инструментов, давайте начнем с самого простого и удобного - &lt;a href=&quot;https://github.com/skylot/jadx&quot; target=&quot;_blank&quot;&gt;Jadx&lt;/a&gt;. Переходим по ссылке и ставим. Так как я счастливый пользовать Arch, то поставлю его из пакетов. &lt;/p&gt;
  &lt;p&gt;Распаковываем apk, и получаем древо директорий с декомпилированным и поэтому обфусцированным кодом. Вроде как декомпиляторы для Java не очень стабильные (может кто расскажет больше?), и некоторые части могут быть с ошибками или не восстановлены или восстановленны не верно. Что порождает кучи мусора.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/4e/4e2b955c-a411-44a8-8ae7-983979c07242.jpeg&quot; width=&quot;623&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/46/46f4be3e-9557-4d0f-b2ca-38a2695ec634.jpeg&quot; width=&quot;564&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Это та еще помойка, но мы уже знаем, что будем искать. Разбираем наш запрос по уникальным кусочкам. Думаю вы согласитесь что самое актуальное и уникальное это имя метода. Грепаем... &lt;/p&gt;
  &lt;p&gt;&lt;code&gt;grep -r &amp;quot;getKPFilmDetailView&amp;quot; ./unpack/sources/&lt;/code&gt;&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/d9/d977967a-7ee3-4a13-9cd2-83be6641f93d.jpeg&quot; width=&quot;1053&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Отлично! Что-то нашли. Открываем и смотрим, что там...&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/5a/5aaeac73-4d67-4e67-bff4-8bbc4ed6fe57.jpeg&quot; width=&quot;1050&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Ага, список методов. Беглый осмотр соседних файлов не дал никаких результатов. А раз не дал, значит, мы не нашли место формирования запроса. Что же, мы зашли немного не туда, но эта ситуация подсказыват нам следующий шаг. Грепаем по request в уже интиресующей нас директории.&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;grep -r &amp;quot;request&amp;quot; ./unpack/sources/ru/&lt;/code&gt;&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/d4/d4268c21-d8af-45c6-a0fc-7de0da0e5437.jpeg&quot; width=&quot;1048&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Среди всего мусора находим что-то интересное. Я, конечно, не эксперт, но это похоже на функцию подписи URL запроса.&lt;/p&gt;
  &lt;p&gt;&lt;code&gt;grep -r &amp;quot;UrlSigner&amp;quot; ./unpack/sources/ru/&lt;/code&gt;&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/18/18a7be80-b51a-450c-bb1c-d9d6048ec31e.jpeg&quot; width=&quot;1008&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Вынесли в отдельный пакет. Похоже мы нашли, что искали. Переходим в директорию и изучаем содержимое.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/04/041b4414-ee28-4c09-ad61-edc6b7e66aec.jpeg&quot; width=&quot;682&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Ну явно что-то полезное...&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/a7/a7bc831c-8251-4729-81b8-518fd7b909d6.jpeg&quot; width=&quot;1050&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Ага, вот и наш сигнер, еще и стратегии есть, неплохо. Смотрим дальше.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/d1/d1bc7ce1-8b48-432c-9f43-83c867a24cc0.jpeg&quot; width=&quot;1049&quot; /&gt;
    &lt;figcaption&gt;Код надо понять. Компилятором. Я его дам. Запрос нужно подписать Ключом. Ключ я не дам.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;Ага это явно то что мы искали. Сначала я испугался множеств кривых операций, и хотел подключить этот метод из jar файла. Но потом поработав с &lt;a href=&quot;https://bitbucket.org/mstrobel/procyon/wiki/browse/&quot; target=&quot;_blank&quot;&gt;Procyon&lt;/a&gt; и &lt;a href=&quot;https://www.benf.org/other/cfr/&quot; target=&quot;_blank&quot;&gt;CFR&lt;/a&gt;, все встало на свои места. Не буду расскрывать какой секретный ключ, намекну лишь что если вы знаете некоторые известные алгоритмы и немного увлекались необратимым хэшированием, то быстро поймете что делать. &lt;/p&gt;
  &lt;p&gt;&lt;em&gt;Кстати,&lt;/em&gt; &lt;a href=&quot;http://javadecompilers.com&quot; target=&quot;_blank&quot;&gt;javadecompilers.com&lt;/a&gt;&lt;em&gt; вам в помщь, там есть все основные инструменты и даже ничего не нужно ставить.&lt;/em&gt;&lt;/p&gt;
  &lt;p&gt;После часа работы над этим кусочком, переписыванием, удалением всего лишнего, поиском остальных элементов мозайки, заменой методов мне удалось запустить рабочий код и получить подпись для запроса. Я не Java программист, и мне хватило &lt;a href=&quot;https://www.jdoodle.com/online-java-compiler/&quot; target=&quot;_blank&quot;&gt;онлайн компилятора&lt;/a&gt; и &lt;s&gt;упоротости&lt;/s&gt; упорности, чтобы найти ответ. Еще через полчаса переписать это на другой ЯП, получить короткий ключик, и понять, как все это работает.Вообще, на это можно писать отдельную статью, но мне лень. &lt;/p&gt;
  &lt;p&gt;Мы были правы в функции генерации подписи участвуют URL запроса с GET параметрами, timestamp и ключ. Проверяем:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/c7/c76a621b-6b88-4916-a832-41a655abc9d9.png&quot; width=&quot;858&quot; /&gt;
    &lt;figcaption&gt;Кто  сказал что php ни на что не годен?&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/05/055fe57b-79a5-4740-8f99-8df7d7c1add9.png&quot; width=&quot;596&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Подпись совпадает с подписью из запроса! Это хороший знак. Давайте проверим это в действии. Так как время уже позднее, то мне лень писать код. Воспользуемся возможностями Postman и напишем небольшой &amp;quot;Pre-request script&amp;quot;. Поместим необходимые параметры в переменные и используем их в заголовках. Кусок с URL просто захардкодим, и так сойдет.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/f2/f2d697a2-b9d8-488e-87d5-b5eb37d58ada.png&quot; width=&quot;1533&quot; /&gt;
    &lt;figcaption&gt;В комментарии метод генерации md5 скопированный с stackoverflow&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/3c/3c58a72c-1100-48e1-8c01-e011ff8e49e9.png&quot; width=&quot;1541&quot; /&gt;
    &lt;figcaption&gt;Расскажите потом как вам фильм (:&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p&gt;Чтож это победа. Ключ подходит, методом тыка можно исключить кучу не влияющих на ответ заголовков. Что касается параметра &lt;code&gt;uuid&lt;/code&gt;, я сгенерировал пару случайных, и ничего не изменилось. Перебрал парочку ID фильмов, все хорошо работает. Теперь можно писать скрипт для обхода и собирать свою базу фильмов. А я пожалуй пойду спать.&lt;/p&gt;

</content></entry><entry><id>opendevcast:SyYaunCHB</id><link rel="alternate" type="text/html" href="https://teletype.in/@opendevcast/SyYaunCHB?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=opendevcast"></link><title>Топ тупых лазеек для исследования конкурентов: source map</title><published>2019-09-10T10:31:32.062Z</published><updated>2022-01-27T15:11:46.008Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://teletype.in/files/70/70c9b5cc-a1d0-4dbe-987b-aec69295a232.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://teletype.in/files/2e/2e77bb3f-618b-40ad-ad4d-101a2001cc59.png&quot;&gt;Инструменты и подходы из этой серии маленьких статьей вроде уже достаточно давно известны и расписаны, но я все равно встречаю такие лазейки один-два раза в неделю. На 1 из 10 проектов до сих пор находятся чемпионы, у которых открыт и .git с конфигами к БД и phpMyAdmin, бери не хочу.</summary><content type="html">
  &lt;figure id=&quot;iwcu&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/2e/2e77bb3f-618b-40ad-ad4d-101a2001cc59.png&quot; width=&quot;1020&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;igJ9&quot;&gt;&lt;strong&gt;Введение&lt;/strong&gt;&lt;/h2&gt;
  &lt;p id=&quot;qOR2&quot;&gt;Инструменты и подходы из этой серии маленьких статьей вроде уже достаточно давно известны и расписаны, но я все равно встречаю такие лазейки один-два раза в неделю. На 1 из 10 проектов до сих пор находятся чемпионы, у которых открыт и .git с конфигами к БД и &lt;a href=&quot;https://ru.wikipedia.org/wiki/PhpMyAdmin&quot; target=&quot;_blank&quot;&gt;phpMyAdmin&lt;/a&gt;, бери не хочу.&lt;/p&gt;
  &lt;p id=&quot;FFuC&quot;&gt;Я часто присматриваюсь к конкурентам, продуктам и компаниям, в которых есть интерес к покупке (или реализации своими силами). Чтобы оценивать техническую составляющую, или подготовится к переговорам о слиянии, я всегда сам исследую интересующий продукт. Моя задача — понять насколько крутой в технологическом плане конкурент или проект, который мы могли бы купить. Но не стоит даже и переговоров начинать без минимального представления о состоянии &amp;quot;чужого храма&amp;quot;. Иногда мне просто интересно кого-то &amp;quot;поковырять&amp;quot;. &lt;/p&gt;
  &lt;p id=&quot;7Wp0&quot;&gt;Я уж точно не являюсь профессионалом в пентестинге и уже тем более куллхакерцом, но с древних времен предпочитаю исследовать все ручками. Мне немного чужды инструменты комплексного сканирования (например, &lt;a href=&quot;https://github.com/rapid7/metasploit-framework&quot; target=&quot;_blank&quot;&gt;Metasploit&lt;/a&gt;), для меня пропадает вся интрига и атмосфера.&lt;/p&gt;
  &lt;h2 id=&quot;s6r0&quot;&gt;&lt;strong&gt;Source map для всех&lt;/strong&gt;&lt;/h2&gt;
  &lt;p id=&quot;iAct&quot;&gt;Какое-то время назад верстальщикам стало скучно, ребята на JQuery тоже приуныли, и вот в один неизвестный день они собрались вместе и сказали – «Хватит! Мы тоже хотим писать много кода», и придумали современный фронтенд стек. Рынок сказал — «Супер, еще большее разделение труда!», и нехило так подогрел зарплаты фронтендеров и жопы некоторых бэкендеров. &lt;/p&gt;
  &lt;p id=&quot;BHNN&quot;&gt;И вроде все нормально, такое уже было и с мобильной разработкой, и с вебом, когда я был еще молод, но в этот раз целая куча вайтишников побежало писать на этих ваших ангулярах и реактах. Как результат - вырвиглазный код и бандлы по 20 мегабайт. Не поймите меня неправильно, я не хочу обидеть всех фронтенд разработчиков, но ваши менее опытные коллеги на зарплате в 300к сильно вас подставляют.&lt;/p&gt;
  &lt;p id=&quot;SuvW&quot;&gt;Вам же, наверняка, будет не очень удобно дебажить сжатый и обфусцированный код в браузере, тут на помощь нам приходят Source Map файлы. Если же вы можете получить к ним доступ, то, скорее всего, сможете восстановить изначальный код фронта и его конфигов (если они не .env, респект этим ребятам) и иногда даже с комментариями. Грешат этим многие, например мой любимый Яндекс.&lt;/p&gt;
  &lt;p id=&quot;IDwO&quot;&gt;Давйте приступим!&lt;/p&gt;
  &lt;figure id=&quot;ZZ8v&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/bb/bb404c70-0ed3-47c2-b50a-05292ba8d0dd.png&quot; width=&quot;746&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;qgsa&quot;&gt;Открываем исходную страничку, ищем подключенные js файлы, а в них упоминание файла с расширением js.map, и проверяем их доступность. Обычно в React.js это &lt;code&gt;app.js&lt;/code&gt; с кодом приложения и &lt;code&gt;vendor.js&lt;/code&gt; с подключенными пакетами. Если source map доступны, начинаем нашу экспедицию.&lt;/p&gt;
  &lt;figure id=&quot;m8wS&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/a9/a92193da-f2fe-45e0-adae-9a0fbaa38e2e.png&quot; width=&quot;1052&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;1rOn&quot;&gt;Скачиваем нужные нам файлы, кладем в директорию и распаковываем. Так как эти файлы обычный JSON, можно накалякать на коленке простенький скрипт для распаковки. Вот, например, мой максимально понятный и прозрачный:&lt;/p&gt;
  &lt;pre id=&quot;vbSU&quot;&gt;const path = require(&amp;#x27;path&amp;#x27;), fs = require(&amp;#x27;fs&amp;#x27;), mf = process.argv[2], dir = &amp;#x27;unpack&amp;#x27;, 
{sources:s = [], sourcesContent:sc = []} = JSON.parse(fs.readFileSync(mf, {encoding: &amp;#x27;utf8&amp;#x27;}));
s.forEach((uri, i) =&amp;gt; (fpath = &amp;#x60;./${dir}/${uri}&amp;#x60;
.replace(&amp;#x27;webpack:///&amp;#x27;, &amp;#x27;&amp;#x27;), fdir = path.dirname(fpath)) 
&amp;amp;&amp;amp; (fs.existsSync(fdir) || fs.mkdirSync(fdir, { recursive: true })) 
&amp;amp;&amp;amp; fs.writeFileSync(fpath, sc[i]) || console.log(&amp;#x60;-&amp;gt; ${fpath}&amp;#x60;));
&lt;/pre&gt;
  &lt;figure id=&quot;l6sI&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/07/07f9121d-484b-4f05-8a78-0dff5a8ffebe.png&quot; width=&quot;1049&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;xdPO&quot;&gt;После распаковки получаем древо со всеми файлами фронт проекта, теперь можно искать интересные роуты, перенимать опыт и т.д. &lt;br /&gt;&lt;/p&gt;
  &lt;figure id=&quot;WS2c&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/ed/ed50f0c4-d4bf-4b45-b9a9-f05c2c8cbde6.png&quot; width=&quot;1052&quot; /&gt;
    &lt;figcaption&gt;Полезная штука, надо бы сохронить&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;pJNe&quot;&gt;Но я люблю &amp;quot;поставить на мониторинг&amp;quot;: создаем гит репозиторий и пишем баш скриптик, который будет выкачивать, распаковывать и коммитить раз в неделю, например.&lt;/p&gt;
  &lt;figure id=&quot;MTpo&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/36/367ac42f-eddc-4765-bdcb-778fc19d0ff3.png&quot; width=&quot;972&quot; /&gt;
    &lt;figcaption&gt;Еженедельная история изменений Яндекс Еды&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;2phx&quot;&gt;&lt;strong&gt;Итог&lt;/strong&gt;&lt;/h2&gt;
  &lt;p id=&quot;aY4H&quot;&gt;Подход мониторинга изменений помогает анализировать в какую сторону движется разработка и предсказать многие события, например: выход в новые страны, смену технологий и бизнес процессов. На долгосрочную перспективу - это очень интересный подход. Он уже выручал меня не раз в предсказании новых фич конкурентов, и мы всегда были на шаг впереди.&lt;/p&gt;
  &lt;p id=&quot;mPlL&quot;&gt;Если у вас есть фронт, разработанный на React/Angular или других фреймворках, и вам не пофиг, то советую проверить ваши js.map, возможно ваши матюги в комментариях уже кто-то читает. &lt;/p&gt;
  &lt;p id=&quot;1LlV&quot;&gt;Самый быстрый способ скрыть их от лишних глаз, добавить конфиг в nginx на закрытие файлов по маске *.map.&lt;/p&gt;
  &lt;pre id=&quot;QdEV&quot;&gt;location ~ \.map$ { # Hide js.map, css.map and others *.map files
    error_page 404; # Send 404
    # deny all;     # Send 403
}&lt;/pre&gt;

</content></entry><entry><id>opendevcast:rJdWg6ABB</id><link rel="alternate" type="text/html" href="https://teletype.in/@opendevcast/rJdWg6ABB?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=opendevcast"></link><title>Зависимые типы</title><published>2019-09-05T17:53:06.020Z</published><updated>2019-09-05T17:53:06.020Z</updated><summary type="html">&lt;img src=&quot;https://teletype.in/files/aa/aafd450f-249e-4eac-bb80-47c998cd581a.png&quot;&gt;Вот есть какая-то функция. Давайте, для примера, возьмём деление. Что мы знаем о входных значениях?</summary><content type="html">
  &lt;p&gt;Вот есть какая-то функция. Давайте, для примера, возьмём деление. Что мы знаем о входных значениях?&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Оба аргумента -- числа.&lt;/li&gt;
    &lt;li&gt;Второй аргумент -- не ноль. На ноль делить нельзя.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p&gt;То есть, у нашей функции есть условия для входных параметров. Как эти условия задать в программе?&lt;/p&gt;
  &lt;h3&gt;Типизация&lt;/h3&gt;
  &lt;p&gt;Типизация позволяет отнести объект к определенному заранее заданному классу. Любой современный язык имеет класс для чисел с плавающей запятой. То есть, то, что это число, мы нормальных языках (ну вы поняли про исключения, да) можем проверить, причём во многих из них это происходит на этапе компиляции. Когда пользователь вводит какие-то данные, компилятор скажет нам, что если мы хотим работать с этими данными как с числом, то надо сначала проверить, действительно ли это число. Если нет -- выводим сообщение пользователю и ничего дальше не делаем. В ином же случае, во всей остальной программе мы можем не проводить такую проверку, потому что уже получили гарантии, что это число.&lt;/p&gt;
  &lt;p&gt;С условием &amp;quot;число не равно нулю&amp;quot; сложнее. Причём такие ограничения на допустимые значения внутри одного типа встречаются довольно часто. Ещё один пример -- взятие индекса от списка. А вдруг список короче? На каждый размер списка отдельными типами не запастись, да и работать с таким будет сложно. К тому же, необходимая длина списка зависит от конкретного значения индекса, которое мы не знаем.&lt;/p&gt;
  &lt;h3&gt;Исключения&lt;/h3&gt;
  &lt;p&gt;Исключения довольно логичны. Исключительная ситуация? Поднимаем исключение. В общем случае, оно летит вверх до самого интерфейса и показывается пользователю как сообщение об ошибке. Концепция простая в реализации, но сложная в работе:&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Исключения часто &lt;strong&gt;неявные&lt;/strong&gt;. В итоге, в языке с исключениями сломаться может всё.&lt;/li&gt;
    &lt;li&gt;Обычно проверить их можно только &lt;strong&gt;в рантайме&lt;/strong&gt;. Пока не сломается, не узнаем.&lt;/li&gt;
    &lt;li&gt;Исключения всегда &lt;strong&gt;нужно аккуратно обрабатывать&lt;/strong&gt;. Например, переводим вот мы зарплату сотрудникам в цикле, и тут в один момент возникает исключение. Кому-то перевели зарплату, кому-то нет. По-хорошему, надо бы всё откатить, но для откатывания транзакций надо написать специальный код, споровождать его, тестировать. А ещё этот код тоже может сломаться.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h3&gt;Специальное значение&lt;/h3&gt;
  &lt;p&gt;Можно вообще не рассматривать такие ситуации как что-то особенное. Делим на ноль? Возвращаем &lt;code&gt;Infinity&lt;/code&gt;. Взяли несуществующи индекс? Вернули &lt;strong&gt;&lt;code&gt;Null&lt;/code&gt;&lt;/strong&gt;. Проблемы:&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Такие случаи всё равно &lt;strong&gt;надо явно обрабатывать&lt;/strong&gt;, точно так же, как и исключения. То-то ваши пользователи, не опубликовавшие ни одного поста, обрадуются, когда их средний рейтинг будет &lt;strong&gt;&lt;code&gt;Infinity&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
    &lt;li&gt;А вдруг первый аргумент деления был &lt;strong&gt;&lt;code&gt;Infinity&lt;/code&gt;&lt;/strong&gt;? А вдруг по нужному индексу в списке лежал &lt;strong&gt;&lt;code&gt;Null&lt;/code&gt;&lt;/strong&gt;? В итоге, такие особые ситуации становится &lt;strong&gt;невозможно отличить&lt;/strong&gt; от случаев, когда всё идёт как и задумано.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h3&gt;Оборачиваем значения&lt;/h3&gt;
  &lt;p&gt;Можно обернуть возвращаемое значение в специальный тип. Это гибрид исключений и специальных значений. А поведение для случаев с ошибкой мы пропишем явно: нужно ли нам сразу пробросить ошибку выше, или же сначала закончить переводить зарплаты остальным. К тому же, это хорошо ложится на типизацию. В функциональных языках это монада &lt;a href=&quot;https://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe&quot; target=&quot;_blank&quot;&gt;Maybe&lt;/a&gt;. В Python её потрогать можно с помощью библиотеки &lt;a href=&quot;https://github.com/dry-python/returns&quot; target=&quot;_blank&quot;&gt;returns&lt;/a&gt;.&lt;/p&gt;
  &lt;h3&gt;Контрактное программирование&lt;/h3&gt;
  &lt;p&gt;Предыдущий подход удобен, когда мы заранее не можем быть уверены в корректности приходящих извне данных, и нам приходится проверять это уде внутри функции. Но давайте вспомним первый пример с типизацией: мы объявляли, что наша функция принимает только числа, и потребовали соблюдение этого условия от внешнего кода, и внутри функции мы можем избежать всяческих проверок. Точно так же мы можем сделать контракт, который будет говорить внешнему коду о том, что на 0 делить нельзя. Это называется &lt;a href=&quot;https://en.wikipedia.org/wiki/Design_by_contract&quot; target=&quot;_blank&quot;&gt;Контрактное Программирование&lt;/a&gt;. Контракт может накладывать ограничение на входные параметры, результат функции и внутреннее состояние атрибутов класса. Можно проверять это всё в рантайме, как это делается в &lt;a href=&quot;https://github.com/orsinium/deal&quot; target=&quot;_blank&quot;&gt;deal&lt;/a&gt;, но хочется узнать о проблемах ещё на этапе компиляции. Итак, что мы можем проверить статически:&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Некоторые ограничения, которые известны из типа. Например, контракт &lt;strong&gt;&lt;code&gt;orderable&lt;/code&gt;&lt;/strong&gt;, который требует, чтобы передаваемые объекты могли быть сравниваемы друг с другом (это нужно для функций сортировки, например). Обычно такое реализуется с помощью интерфейсов.&lt;/li&gt;
    &lt;li&gt;Передаваемые константы. Если мы видим, что вот тут в функцию передается число 42, то, очевидно, контракт &lt;strong&gt;&lt;code&gt;!= 0&lt;/code&gt;&lt;/strong&gt; соблюдён.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p&gt;И всё?&lt;/p&gt;
  &lt;h3&gt;Зависимые типы&lt;/h3&gt;
  &lt;p&gt;Нет, не всё. Тут на сцене появляются &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependent_type&quot; target=&quot;_blank&quot;&gt;зависимые типы&lt;/a&gt;. Зависимые типы -- это когда тип данных зависит от конкретных значений. Примеры всё те же: при делении второе число не может равняться 0, а при взятии индекса индекс не может быть больше длины вектора. И язык с зависимыми типами не даст скомпилировать программу, пока все неявные моменты не будут явно покрыты:&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Если мы явно передаем заранее &lt;strong&gt;известное значение&lt;/strong&gt; (константу), то всё отлично, компилятор сам проверит соблюдение условий типа.&lt;/li&gt;
    &lt;li&gt;Если мы ничего не знаем о значениях (они приходят из внешнего мира), то тут не остается выбора, кроме как забыть о контрактах и явно сделать &lt;strong&gt;проверку в рантайме&lt;/strong&gt;.&lt;/li&gt;
    &lt;li&gt;А вот если всё из внешнего мира было уже провалидировано, и это всё внутренние коммуникации, то несоблюдение зависимых типов может означать только ошибку разработчика. А значит, их соблюдение &lt;strong&gt;надо доказать&lt;/strong&gt;.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p&gt;Доказательство -- сложно, но это даёт офигенную надёжность кода. Тесты проверяют только частные случаи и предназначены показать наличие ошибок, тогда как строгое доказательство показывает их отсутствие. Тесты тоже нужны, конечно, но достаточно протестировать только доказательную базу.&lt;/p&gt;
  &lt;p&gt;Первое практическое применение в программировании -- язык &lt;a href=&quot;https://ru.wikipedia.org/wiki/Coq&quot; target=&quot;_blank&quot;&gt;Coq&lt;/a&gt;, созданный для доказательства теорем. В нём вообще всё строится вокруг строгих доказательств, пожтому зависимые типы для его задач -- как раз то, что нужно. Но можно ли это использовать в языках общего назначения?&lt;/p&gt;
  &lt;h3&gt;Idris&lt;/h3&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/aa/aafd450f-249e-4eac-bb80-47c998cd581a.png&quot; width=&quot;487&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.idris-lang.org/&quot; target=&quot;_blank&quot;&gt;Idris&lt;/a&gt; -- чистый функциональный язык общего назначения со строгой статической типизацией с зависимыми типами.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Плюсы&lt;/strong&gt;: БЕЗОПАСНОСТЬ.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Минусы&lt;/strong&gt;: охрененный порог вхождения, адски математичный синтаксис, скорость функциональных языков.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Особенности:&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;Синтаксис вдохновлён &lt;strong&gt;Haskell&lt;/strong&gt;, конечно же.&lt;/li&gt;
    &lt;li&gt;Ещё один источник вдохновения -- &lt;a href=&quot;https://ru.wikipedia.org/wiki/Agda&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;Agda&lt;/strong&gt;&lt;/a&gt;. Оттуда пришли зависимые типы, механизм доказательства теорем, вот это всё.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Termination analysis&lt;/strong&gt; -- компилятор проверит, что каждая функция покрывает и корректно обрабатывает ВСЕ возможные варианты входных значений.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Proof assistant&lt;/strong&gt; -- можно прям из IDE интерактивно взаимодействовать с магической тукой, которая может разворачивать доказательства, искать частные случаи, выносить леммы и прочее. Математическая индукция, всё такое.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;В общем, даже не знаю, что добавить. Это точно не тот язык, на котором через 10 лет будут написаны все web-сайты. Так же это не тот язык, на котором хочется написать свой бложик. Но пока что это тот язык, коорый в наиболее дружелюбной форме реализует зависимые типы и доказательства. Пока что не очень дружелюбно полуается, но всё же. Возможно, эти идеи пройдут путь упрощения и адаптации, и в какой-нибудь там версии Kotlin или Scala (ха-ха, шучу, &lt;a href=&quot;https://github.com/milessabin/shapeless&quot; target=&quot;_blank&quot;&gt;Scala уже&lt;/a&gt;) мы увидим упрощенный theorem prover. Ну а пока что если хочется почувствовать себя профессором кафедры математики (или добить свою самооценку), Idris отличный вариант.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Ссылки по теме:&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;https://habr.com/ru/post/228957/&quot; target=&quot;_blank&quot;&gt;Обзор языка Idris&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://habr.com/ru/post/463957/&quot; target=&quot;_blank&quot;&gt;Как развернуть односвязный список на собеседовании&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://habr.com/ru/company/piter/blog/432416/&quot; target=&quot;_blank&quot;&gt;Зависимые типы — будущее языков программирования&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://docs.idris-lang.org/en/latest/tutorial/index.html&quot; target=&quot;_blank&quot;&gt;Официальный туториал по Idris&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;&lt;br /&gt;&lt;/p&gt;

</content></entry></feed>