melikhov.dev – Telegram
melikhov.dev
4.63K subscribers
110 photos
2 videos
2 files
203 links
Фронтенд, фронт-бек и около. Всё, что в голову пришло. Иногда котики.
Download Telegram
Продолжаем.

Проникшись JavaScript Крокфорд чуствует, что будущее за Single Page Application (про которые пока ещё никто не знает). В своём стартапе State Software он с командой прорабатывает идею веб-приложений, написанных на JavaScript. Ну и быстро понимает, что XML очень жмёт. А надо сказать, что в тот момент XML был главным и важнейшим стандартом передачи данных. Умные именитые ребята ходили и убеждали всех, что будущее только за XML. Крупные компании вкладывались в XML. Где-то рядом уже запихивали XSLT в браузеры. All the hipsters were excited about XML 🤡.

Но вот сидит Крокфорд и грустит, что для того, чтобы запихнуть XML в JS ему нужен парсер. Но, тут вдруг его осеняет, что гораздо проще передать литерал объекта текстом, так, как мы уже привыкли создавать объекты в JS. И тогда парсер будет очень простым и объём кода, передаваемого по сети станет меньше. Даглас и Чип Морнингстар собирают концепт и идут искать инвесторов.

А на дворе самое начало нулевых, крах доткомов и инвесторы очень осторожны. Они не хотят вливать деньги в то, что не является стандартом. XML вот стандарт. Там есть инструменты. А ваша поделка завтра рассыпется и что делать? Тогда Даглас и Чип придумывают название нового стандарта — JSON (JavaScript Object Notation), Даглас покупает домен json.org и запиливает свой знаменитый сайт, который вы все возможно видели. У нас есть сайт и название, мы стандарт! :)

Дальше начинается битва с Дэйвом Винером который на тот момент был очень влиятельным разработчиком и создателем XML-RPC. Винеру очень не понравился JSON и он достаточно резко прошёлся по нему в своём блоге. «Я тут услышал о чем-то под названием JSON, что предлагает решить проблему, которая была аккуратно решена XML-RPC в 1998 году»

Кстати, Даглас назначает Винера ответственным и за популяризацию SOAP (тут Даглас язвит - Simple Object Annoying Protocol. I don’t remember what the A was, but it might have been atrocious or abominable, I don’t know) Но сам Винер признаёт, что SOAP so difficult to program если сравнивать его с оригинальным XML-RPC.

В общем, Винер смотрит на JSON и кричит «ВЫ ЧЕГО?!! ЭТО ЖЕ ДАЖЕ НЕ XML!», предлагает найти разработчиков этого чуда и привязать их к дереву. Кажется, Крокфорда это обидело на всю жизнь.

В любом случае, дело идёт так себе инвесторы не верят в идею и не дают денег, но тут появляется Gmail и совершает AJAX-революцию (X значит XML, хе-хе). Теперь все хотят SPA. Вера в будущее веба на XHTML и XSLT растворяется. Люди перестают думать про XML-инструменты. Новым людям, пришедшим сразу в веб был нужен стандарт, менее жирный, чем XML.

Тут Даглас говорит интересную штуку, что сложность формата XML породила логическую ловушку о том, что и все инструменты вокруг него должны быть сложными. И эта накопленная сложность воспринималась как должное и гуру XML говорили «ну да, мы делаем сложные штуки, а как вы хотели?». А тут появились ребята, которые топили за простоту, а не за сложность. И ментально было сложно принять, что все твои сложные знания уже больше не нужны, что инструменты стали простыми, что передача данных по сети — это очень просто. Что хорошо и красиво — это когда просто, а не когда сложно.

В итоге, JSON победил, а XML проиграл. JSON вошёл в стандарт и получил MIME type application/JSON. А Крокфорд хотел конечно text/JSON, потому что ну причём тут Application? Почему есть text/XML но нет text/JSON? Крокфорд не знает, шутит, что это месть ему от XML-фанатов.

Вот и всё. Даглас считает, что JSON это и была самая главная вещь, которую он сделал в своей жизни и второй великой вещи у него уже не выйдет.

А я однажды передал Дагласу соль, сидя с ним за столом. Возможно, это и был высшая цель моего существования :_)
🔥68😁288👍4
TIL

Можно оверрайдить красиво через переменную $<имя пакета> (но лучше не оверрайдить, конечно).


{
"dependencies": {
"foo": "^1.0.0"
},
"overrides": {
// BAD, will throw an EOVERRIDE error
// "foo": "^2.0.0"
// GOOD, specs match so override is allowed
// "foo": "^1.0.0"
// BEST, the override is defined as a reference to the dependency
"foo": "$foo",
// the referenced package does not need to match the overridden one
"bar": "$foo"
}
}
👍8
Тут спрашивают, а зачем вообще оверрайдить зависимости? Причин может быть несколько:
- Причесать зоопарк в транзитивных (например, жёстко задать одну версию lodash или axios)
- Точечно починить транзитивные зависимости в тех либах, на которые автор уже забил
- При переезде на npm 8 и выше починить кривые peerDependencies
- Придумайте сами

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

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

Вот только переключить так сходу свой большой проект на сборку в Тайпскрипте в ES modules я, кажется, не готов. Но что делать, кажется придётся потихоньку.
🤨7🤔6👍42
Просто любопытно — есть ли у меня в подписчиках такие преисполнившиеся оптимизациями ребята и девчата, что отключили алгоритм Нейгла в node.js?
🤔17👍2👏2👌1
30 апреля — время отключить Node.js 14. Тимур Шемсединов выпустил отличный чеклист по миграции https://github.com/HowProgrammingWorks/Drop-Nodejs14 .
Добавлю про lockfileVersion: 2. На него имеет смысл переходить, если у вас CI крутится на node 14 и вы хотите переехать плавно. Если везде подняли npm до 8 и выше, то можно сразу на lockfileVersion: 3.
🔥135👍3
Что не так с iframe

Довольно часто у бизнеса возникает желание запихнуть продукт в iframe и вставить так в чужой ресурс. Всё нормально до тех пор, пока не возникает вопрос аутентификации пользователя. Обычно мы сохраняем идентификатор сессии в куку, и вот тут проблема, что куки в данном случае становятся third-party, т.е. принадлежат не тому сайту, где установлен iframe, а третьей стороне.

Chrome и FF ещё можно обойти, если переставить аттрибут SameSite в none (напомнию, что по дефолту там Lax, который так же не даст отправить куку в iframe). Конечно, вам придётся повоевать с безопасниками и защитить ваше решение понизить безопасность у сессионной куки. А вот в Safari уже несколько лет как включен Intelligent Tracking Prevention (ITP) который режет куки в любом случае. Кстати, режим инкогнито в Chrome так же режет все third-party куки.

ITP блокирует все third-party cookies по умолчанию. Обойти его можно двумя способами:

- Заставить пользователя в настройках снять галочку Prevent cross-site tracking, что повлияет на все сайты
- Воспользоваться Storage Access API, с помощью которого мы явно запросим у пользователя разрешения прочитать куки с третьей стороны

Storage Access API имеет достаточно жёсткие ограничения и задействует различную неоднозначную эвристику, пытаясь догадаться, действительно ли пользователь хотел разрешить доступ. А пользователь может и не захотеть. Но, самое важное, это API закрыто в Chrome за флагом. Почему же? Скорее всего, потому, что ломает рекламный бизнес Гугл :_)

Что же делать? Вы не должны встраивать ваши сервисы в iframe as is. Вам придётся провернуть какой нибудь трюк. Например, открыть встраиваемый сервис во втором, «честном» окне, пройти аутентификацию, получить временный токен и перекинуть этот токен через postMessage в окно со страницей со встраиваемым iframe. И вот там уже перезагрузить iframe передав ему токен как get-параметр. И никаких кук.

Это не значит, что вы должны отказывать продактам в их странных желаниях. Желания продиктованы бизнесом. Но продакт не должен просить iframe. Он должен просить возможности встраивания, а вот как оно будет сделано — зависит от того, что мы сможем сделать, как разработчики.
👍4316
Не обновляйтесь на node.js 16

В этом нет большого смысла. Node.js 14 закончила свой срок жизни и лучшим выбором сейчас будет переехать сразу на v18. И v16 и v18 являются поддерживаемыми LTS-версиями, но жизнь v16 закончится гораздо раньше, чем могла бы быть в обычном релизном цикле — уже этой осенью, а именно 11 сентября. Связано это с тем, что 11 сентября прекратится поддержка OpenSSL 1.1.1, больше не будут выходить никакие патчи для него (да, там был вариант взять OpenSSL 1.1.1 из CentOS и протянуть ещё годик, но не сложилось).

Так получилось, что Node.js 16 не успела получить OpenSSL 3. Да да, тот самый из-за которого вам приходится писать --openssl-legacy-provider чтобы обойти ошибку ERR_OSSL_EVP_UNSUPPORTED на Node.js 17+. Возникает она от того, что в коде библиотек задействованы устаревшие криптографические алгоритмы и, как шутят авторы, ключ `legacy` открывает вам двери в дом престарелых алгоритмов.

К счастью, все важные библиотеки уже успели обновить свой код и если у вам нет престарелых зависимостей, то скорее всего ключ --openssl-legacy-provider вам будет не нужен. Так что смело обновляемся на v18, там уже v20 на подходе.
👍356
Ого, и я не знал, что в 18-й отключили по-умолчанию, пропустил.
Forwarded from Dilame Bowzee
Изучаю эту тему, и выяснил, что NodeJS с версии v16.15.0 помимо метода setNoDelay внедрила во многие сетевые конструкторы опцию noDelay (а также keepAlive and keepAliveInitialDelay). А так как почти все агенты прокидывают входящие опции ниже по течению, теперь есть возможность отключить delay из юзерленда даже в библиотеках, которые об этой опции не знают, и не нужен доступ к самому объекту сокета.

А начиная с NodeJS 18.0.0 метод http.createServer по умолчанию использует noDelay: true !!!
🪄💫 Пруф

Спасибо за наводку, очень интересно:)
👍102
С remote - SSH начинаю день с
ps -aux | grep "node --inspect" | grep -v grep | awk '{print $2}' | xargs kill -9

UPD

В комментах подсказали, что причина может быть в nodemon, и решается явным пробросом сигналов nodemon --signal SIGHUP
💯6🤨2🌚1🦄1
А я говорил (яжеговорил), что лямбды это дорого. Лямбды это способ гибко быстро масштабироваться при очень редких пиковых нагрузках, но держать на них большой проект — решение очень спорное.
А монолит.. Ну тут как с чиплетами, раз нужна скорость, значит придётся собирать всё вместе, поближе.

https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90
👍91
В свежем выпуске подкаста напомнил соведущим, что error.stack это не стандарт. Тут же Лёша отыскал пропозал по Error.prototype.stack. TS вот согласен, поля stack в объекте Error может и не быть:


interface Error {
name: string;
message: string;
stack?: string;
}


Как мы много узнали про ошибки и исключения в тот момент, когда TS 4.4 переключил catch(e) из any в unknown :) Пришлось разбираться и вспоминать, что в исключении может лететь не ошибка, а что угодно, например строка ( throw 'Oops' ). Набор полей там неизвестен, обработчики исключений необходимо писать, чтобы они сами не падали в исключения (а я встречал и такое).

На самом деле V8 даёт несколько довольно интересных механизмов по работе с трейсами. Например, можно увеличить глубину стектрейса через Error.stackTraceLimit или через флаг v8 --stack-trace-limit.

Ещё из интересного — так как остальные движки представляют стек просто как строку, то V8 решил не ломать это поведение, но даёт нам доступ к методу Error.prepareStackTrace(error, structuredStackTrace) который вызывается в момент обращения к свойству stack. И вот тут уже внутри метода можно работать с нормальным объектом structuredStackTrace и переписать весь вывод так, как нам нравится. Но опять же, напомню, что только в V8.

Подробнее в блоге V8
👍22
Многопоточность (мультитрединг) в JS

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

Да, у нас есть возможность порождать веб-воркеры и воркер-треды (одно в браузере, второе в node.js, соответственно). Можно соорудить воркер-пул и отбрасывать туда тяжёлые задачи, асинхронно забирая ответы. Многопоточность ли это? Скорее многопроцессность. Мы порождаем независимый процесс с полностью независимым контекстом (и независимым event loop) и общаемся с ним через сообщения с сериализованными данными или transferable objects (ArrayBuffer и ImageBitmap, например). Т.е. можно перебрасывать некоторый набор специальных объектов между контекстами (не шарить, а именно безопасно передавать из контекста в контекст).

Ещё круче, мы можем передать SharedArrayBuffer. Почти настоящая многопоточка! Да, несколько независимых контекстов обращаются к одной области памяти и могут устроить себе веселье. А чтобы веселья было поменьше нам даже завезли атомики. А так же завезли кучу ограничений безопасности, из-за чего пришлось откатывать SharedArrayBuffer и только буквально недавно он к нам вернулся. Но называть это мультитредингом язык не поворачивается всё равно.

Надо будет сделать отдельный пост про проблемы SharedArrayBuffer.

UPD

В комментах посоветовали эту книгу https://dmkpress.com/catalog/computer/programming/java/978-5-93700-129/ . Я сначала немного бомбанул на название, но авторы оказались честны «Надо признать, что, вопреки названию книги, сам язык не содержит никаких встроенных средств для создания потоков
👍35🔥12
Нет пароля — нет проблем?

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

Тл;др: выводы печальные — работает всё очень не очень. Лонг стори шот.

Как-то раз собрались разные ребята из разных больших компаний и решили порешать проблему паролей. И назвались они FIDO Alliance. После нескольких итераций родился стандарт FIDO2, который состоит собственно из протокола CTAP2 и браузерной апихи WebAuthn. Протокол этот позволяет браузеру общаться с хардварными аутентификаторами, встроенными в наши телефоны/ноутбуки, либо переносимыми (YubiKey). Идея простая как палка — когда мы хотим где-то зарегистрироваться, то создаётся пара ключей: публичный и приватный. Публичный ключ уезжает на сайт, приватный загружается в вашу железку (почти как SSH-ключи, только никаких файлов на диске не валяется). Каждая такая пара ключей уникальна для каждого сайта. Красть с сервера теперь нечего — ваш публичный ключ никуда не подложить.

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

Несмотря на то, что технология предполагалась для полной замены паролей, она, в основном, везде была внедрена как второй фактор (хотя сама по себе является двухфакторной, ваши ключики защищены биометрией или пин-кодом). Почему так? Да просто из-за излишней сложности для обычных нормальных людей. Ключи надо привязывать к аккаунтам во всём множестве, 1 устройство — 1 ключ. Т.е. на айфоне, и на макбуке и на айпаде надо создавать отдельные ключи (не копии). YubiKey немного спасает, но в него влазит мало ключей, потерять его легко, стоит дорого, а пользоваться неудобно.

Ну и год назад Apple на WWDC сказали, что вот, теперь у них готово решение, которое называется Passkeys. Что это такое? Это фактически те же самые WebAuthn ключи, но переносимые через облако. Вы создали 1 ключ на айфоне — теперь он доступен на всех Apple-устройствах. Google и Microsoft присоединились к этой идее переносимых через облако приватных ключей.

Стало ли лучше? И да и нет. Если вы живёте на экосистеме Apple, пользуетесь Safari и iCloud то всё у вас будет замечательно. С Chrome уже похуже (синхронизацию допиливают). С Firefox просто никак. В облаках Google и Microsoft тоже раздрай. В Linux нет и не планируется. Чужих облаков в этой системе пока нет (1Password обещает скоро запилить своё). Синхронизации между разными облаками тоже нет. Более того, переводя ключи в облако, Apple понизила безопасность WebAuthn убрав аттестацию аутентификатора. И, что ещё хуже, начиная с iOS 16 они отключили возможность хранить ключи локально в Secure Enclave телефона, обязательно требуется подключенный iCloud. Сволочи.

Отдельная печаль это вход через QR код. Придумано всё круто, связь между близкорасположенными устройствами только по Bluetooth, ничего не утекает, общение через relay-серверы владельцев экосистем. Ну вы понимаете, да. Некоторый такой лок.

Так что вот, решение какое-то есть, но вопросов к нему многовато.
👍525
Нет пароля — нет проблем?.pdf
8.4 MB
Слайды с доклада
🔥224👍3👏3
Взываю к помощи коллективного разума.

Смотрите, имеем node.js-процесс. Процесс спаунит чайл-процессы. Убийство родителя по ctrl+c приводит и к смерти чайлд-процессов. Но почему отправка SIGINT не приводит к такому результату и чайлды не умирают? Ни SIGINT, ни SIGTERM ни злобный SIGKILL не трогают чайлдов.
Так в чём здесь отличие ctrl+c?

UPD коллективный разум нашёл ответ https://stackoverflow.com/questions/8398845/what-is-the-difference-between-ctrl-c-and-sigint/8406413#8406413

Баш сам пробрасывает SIGINT по всей группе процессов.
👍16🔥3
Опять Гугл всё сломал

В мае Гугл запустил новый домен первого уровня .zip и неплохо так насолил безопасникам. Дело в том, что браузеру тоже можно скормить урл с userinfo частью (<протокол>//<userinfo>@<домен>), а значит, можно подсунуть пользователю адрес вида
https://github.com∕kubernetes∕kubernetes∕archive∕refs∕tags∕@v1.27.1.zip
.

Заметили подставу? А если бы вам не сказали, что в ссылке есть проблема?

Переход по такой ссылке направит нас на
v1.27.1.zip
. Более того, собачку в адресе можно скрыть в интерфейсе, уменьшив шрифт.

А чтобы жизнь была ещё веселей, Гугл добавил TLD .mov. А мессенджеры превратили это в ссылки. Так и живём.

Подробнее о проблеме и вариантах атак: https://medium.com/@bobbyrsec/the-dangers-of-googles-zip-tld-5e1e675e59a5

UPD

В фишинговой ссылке из примера используется два хака: символ @ и «другой» слеш ∕ (U+2215)
😁23🤯20😱42🤬2👍1😢1
Каждый год перед запуском ctf мучительно ищу подходящий RSA-ключ чтобы настроить каждый сервер. 1Password сделал свой ssh-agent но только в облачной версии, на которую я по понятным причинам переходить не хочу. Хранить на юбиках? Ну так ещё проще потерять юбик, чем облако.
Вот и продолжаю хранить в файликах и подбирать подходящий. Ещё один вариант — сделать мастер пароль и спрятать его в 1Password, а при утере ключа — ну и фиг с ним, залить новый.

Эй, подписчики, а вы как храните свои ключи?
Кто поленился настроить UFW и выставил ctf портами наружу — тот я :) Спасибо Саше Шоронову, что посканировал порты и пришёл с багой. Сколько не ставь Basic Auth в nginx, если рядом нода слушает сеть, то ой. А делал бы на юникс сокетах — горя бы не знал, но что-то подвела привычка (когда писал первую ctf уже жил в парадигме, что в контейнере nginx не нужен, и нода сама слушает сеть, как бы это не странно звучало).

В общем, не будьте мной, не ленитесь в виртуалках прикрывать порты. А unix-сокеты так-то всё ещё хороши.


sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'

UPD

Тут просят пояснить, что за набор букв я
написал. Смотрите, запущенный сервер на node.js слушает либо unix-сокет (который описывается как файл на файловой системе) либо сетевой порт. Какой-нибудь 3000, например. Перед нодой стоит какой-нибудь nginx, слушает порты 80 и 443 и закидывает трафик на 3000 порт локлхоста который и слушает node.js. Это называется «реверс-прокси». Если не закрыть порты фаерволом, оставив только 80, 443 и какой-нибудь 22 для ssh, то можно будет просканировать все порты снаружи, найти наш 3000 и постучаться на ноду в обход nginx, забив на все его правила.
Если же nginx гонит трафик на node через unix-сокет, то даже при открытых портах снаружи через сеть туда уже будет не достучаться.
😱1511👍4