C# Short Posts 🔞 – Telegram
C# Short Posts 🔞
251 subscribers
110 photos
4 videos
151 links
Здесь я, Дима Афонченко @Undermove1, публикую короткие заметки о разработке (и около). Я не претендую на правильность высказываний и открыт к дискуссиям, исправлениям и конструктивной критике. С любыми деструктивными вещами можно приходить в комменты)
Download Telegram
👨 Для чего нам Distroless?

Distroless образы довольно давно уже вошли в обиход. И у нас в Додо вообще есть требование, что все наши сервисы должны работать на них. Но я всё ещё в разговорах замечаю, что большинство вообще не сечёт, о чём это и для чего.

Оно в целом не удивительно: это довольно неочевидно с одной стороны и довольно очевидно с другой. Поэтому с одной стороны не задают вопросов, а с другой — не видят смысла в ответах.

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

Контейнер — это просто процесс, запущенный с определёнными ограничениями. То есть это не виртуалка.

Любому процессу нужно давать как можно меньше прав, и все это прекрасно знают. Но почему?

Ведь я сам написал весь код, если даже не я написал этот код, то я проведу ревью, и, если в коде есть какие-то подозрительные места, то я их уничтожу!

Так думает обыватель, и он по-своему прав в этой невинной наивности.

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

И весь код, который там написан, как вы понимаете, поревьюить, мягко говоря, не получится.

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

😡 Ок, но какую опасность может представлять вредоносный нугет-пакет?

Да — очень простую. К примеру, в одной из транзитивных NuGet-зависимостей появилась строка, которая при инициализации вызывает запуск внешней программы через Process.Start. Если в контейнере есть утилиты (bash, sh, curl, wget), то вредоносный код может просто запустить их и отправить конфиденциальные данные (переменные окружения, файлы конфигурации, нюдсы, дикпики) на внешний сервер или вызвать внутренний админ-эндпоинт под именем сервиса.

🅰️ как нам поможет distroless?

А так, что в distroless-образе этих внешних утилит просто нет — нет bash, нет curl, нет sh и даже нюдсов и дикпиков нет. Поэтому сценарий «внезапно запустить системную утилиту из контейнера» потерпит поражение: бинарник не найден, команда не выполнится. Это закрывает быстрый и «грубый» вектор дополнительной загрузки кода, который часто используется в мелких эксплойтах и supply-chain-атаках.

Очевидно, что это не стопроцентная защита. Если вредоносный код использует возможности самого рантайма (в .NET — HttpClient, файловые операции и т.д.), он по-прежнему сможет делать сетевые запросы или читать файлы. Distroless снижает эти конкретные риски. Вот, собственно, и всё.

Поделитесь по-сестрински этим знанием с теми, кто ещё не в курсе. Рили почему-то мало людей понимают про это.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥433
🎃 Воскрешаем мертвые репозитории! ☠️

Я тут подумал, ведь бывает так, что призраками становятся не только люди, но и репозитории! К примеру вы хреначили репозиторий, который набрал пару тысяч звезд, а потом… Ну просто забили. И репозиторий как бы жив и популярен, но никому уже не нужен. Получается застрял между двух состояний. Выходит – призракопозиторий 👻

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

Идея простая:
1. Заходите на сайт
2. Крутите слот-машину 🎰 (тянем рычаг справа вниз)
3. Вам выпадает три рандомных репозитория с большим количеством звезд, но с последним коммитом, сделанным Бог знает когда
4. Ставите репозиторию звезду
5. Автор охреневает и радуется!

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

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

Ну и моей репке тоже звездочку там аккуратно звезданите ⭐️. Может через лет пять круг замкнется и она высветит в слотах сама себя) Лайк и репост тоже приветствуются, разумеется 🎃
Please open Telegram to view this post
VIEW IN TELEGRAM
8🎃5💘4
Вчерашний хэллоуин обернулся настоящим кошмаром — сегодня рабочая суббота!
💯8😡33😱2
Пиздос как это круто! Вообще у нас супер-крутая команда работает над авторизацией. Регулярно что-то поставляют такое, чего нам людям даже и не снилось – атакующие корабли, пылающие над Орионом, лучи Си разрывающие мрак у ворот Тангейзера. Все эти моменты теперь дополнены и такой вот автозизованной библиотекой
83😎2
Forwarded from Dodo Engineering
🐳 Нашу реализацию Passkey для .NET признал FiDO Alliance

Они разрабатывают и продвигают открытые стандарты для безопасной аутентификации без паролей по всему миру. Более того, FIDO Alliance включил наш способ в список библиотек, рекомендованных к использованию.

Почему это круто?

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

Чем занимается FIDO?

Fast IDentity Online Alliance устраняет зависимость от уязвимых к фишингу, перехвату и утечкам паролей. Они стремятся:
🟠повысить безопасность онлайн-аутентификации;
🟠сделать вход в аккаунты удобнее — с помощью отпечатков пальцев, Face ID, USB-ключей и не только;
🟠найти и предложить открытые стандарты авторизации для всех — компаний, разработчиков, производителей устройств.

👑 Кто входит в альянс?

В FIDO Alliance входят: Apple, Google, Microsoft, Amazon, Intel, Samsung, Mastercard, VISA, Bank of America и другие крупные компании.

🌐 Где используются FIDO-стандарты?

🟠В системах двухфакторной аутентификации. Например, при логине в Google с использованием ключей безопасности.
🟠В корпоративных сервисах и VPN.
🟠В банковских и других финтех-приложениях.
🟠В операционных системах: Windows Hello, Apple Face ID/Touch ID через Safari, Android Biometrics и т. д.

💻 И где теперь это будет использоваться?

Во-первых, мы сами использовали нашу библиотеку, чтобы подключить к Dodo IS Passkey.

Во-вторых, наша библиотека — OpenSource. Ее могут использовать все, кому нужно, и везде, где есть вход по логину/паролю, а бэкенд написан на .Net. Сейчас есть 9 форков — это немного, но уже значит, что кто-то сделал себе копию и доработал ее под себя.
Please open Telegram to view this post
VIEW IN TELEGRAM
👏76
Сегодня – .NET Conf и, конечно, день релиза .NET 10

На самом деле, в этом году я впервые ждал новую версию .NET по двум причинам:

🥇 Запускаемые файлы C# — для меня эта фича самая ожидаемая. Шарпику уже давно было пора сделать что-то со своей инфраструктурой. Я с огромной завистью смотрел на то, как быстро запускается всё питоновское и нодовское на компе. Как удобно вообще можно запускать любую утилиту просто из консоли — и прям дико завидовал. Большая часть изменений в .NET до этого, на мой взгляд, — ну не хуйня, но близко к этому. Каждый раз, когда говорили про то, что упростят написание очередного свитч-кейса тем, что дадут писать палочку вместо слова, рука сама небрежно касалась лица, производя шлепок.

🥈 И вторая причина, по которой жду .NET 10, — это просто LTS-версия. До недавнего времени не видел смысла переходить на STS-версии, ибо при таком манёвре ты фактически обрекал себя на переезд строго через год. А это обычно в ноябре, под Новый год, когда сроки горят. То есть окно манёвра было мизерное. А я, к примеру, предпочитаю перестраховаться и взять сразу то, что будет долго поддерживаться, чтобы переехать потом спокойно — под сезон отпусков, когда страсти поутихают.

Такие дела. Плюс, говорят, там ускорили что-то, что-то там на стек перенесли. Но это уже перестало удивлять — его, кажется, каждый год ускоряют в сто раз. Так что скоро новая версия дотнета уйдёт в нирвану и начнёт обрабатывать ещё не отправленные запросы.
🔥75😁41👍1👌1
❤️ Очень странные дела: баги в .NET 10

В пятницу классно поразгоняли с ребятами на наших внутренних техпосиделках про переезд на .NET 10.

Хедлайнером у нас был ослепительный @granstel, который перевёл свой сервис на .NET 10 первым (как минимум в Додо а может и в мире, кто знает). Сервис некритичный, но полезный — он является бэком для этой охуенной интерактивной карты. Идеальная площадка для тестов.

Так вот что удалось выяснить в процессе переезда/обсуждений:

1) В целом всё работает
2) Но есть один довольно критичный ишуй

В версии 10.0.100 внезапно сломан хендлинг вложенных try/catch/finally.
Как показано на пояснительном дикпике выше 🍆
Если внутренний finally бросает исключение, то:

внутренний catch не вызывается,

внутренний finally не доходит до конца,

внешний finally не вызывается вообще,

исключение вылетает наружу без обработки.

Довольно жёсткая штука — потому что using и await using разворачиваются компилятором именно во вложенные try/finally. А значит, при dispose может соскочить вся цепочка освобождения ресурсов.

То есть вложенный try/catch в принципе не перехватывает исключение из вложенного finally. А это уже влияет и на using, и на await using.

То есть вот такой код может быть потенциально опасным, если disposableTwo в своем диспоузе кинет исключение


using System;
using System.Threading.Tasks;

await using var disOne = new FirstDisposable("ONE");

await using var disTwo = new SecondDisposable("TWO");

Console.WriteLine("Before throw");
throw new Exception("FUCK");


sealed class FirstDisposable : IAsyncDisposable
{
private readonly string _name;
public FirstDisposable(string name) => _name = name;

public async ValueTask DisposeAsync()
{
Console.WriteLine($"DisposeAsync({_name}) START");
await Task.Delay(10);
Console.WriteLine($"DisposeAsync({_name}) END");

// На .NET 10.0.100 этот DisposeAsync вообще НЕ вызовется,
// потому что исключение из DisposeAsync(TWO) оборвёт цепочку.
Console.WriteLine($"NOTE: DisposeAsync({_name}) WAS CALLED — но это произойдёт только на .NET 8");
}
}

sealed class SecondDisposable : IAsyncDisposable
{
private readonly string _name;
public SecondDisposable(string name) => _name = name;

public ValueTask DisposeAsync()
{
Console.WriteLine($"DisposeAsync({_name}) THROWS — сейчас всё сломается");
throw new Exception($"DisposeAsync boom: {_name}");
}
}


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

Все уже пофикшено судя по всему, наверняка заедет в следующую версию.

🚧 Вообще не всем дано переехать сразу.

Например, я попытался перевезти свою Базу знаний на новые рельсы, но столкнулся с тем, что нужный пакет Pomelo.EntityFrameworkCore.MySql пока отсутствует для .NET 10.

Так что переехать сходу смогут не все.
Может, даже и хорошо — с таким багом можно и потерпеть 🎃
Please open Telegram to view this post
VIEW IN TELEGRAM
5👾5🤝2
С этим красавчиком мы вместе делаем новую Базу Знаний для Додошки) Вообще классно работать с заряженными людьми!
4🤝1
Знакомьтесь, Blok!

Blok — это блочный, визуальный open-source редактор типа Notion.

В основу Blok лёг Editor.js — прекрасный визуальный редактор, который в своём развитии остановился где-то в 2018-м году, где было приемлемо иметь средненький UX, плохую документацию и решение не поддерживающее современные фреймворки.

Blok призван решить все эти проблемы и стать тем самым визуальным редактором, который вы искали.

Уже сейчас в Blok, в отличие от Editor.js, исправлены многие баги и проблемы безопасности, повышена стабильность и тестируемость редактора, а также появилась возможность перетаскивать блоки с помощью drag&drop!

В ближайших обновлениях Blok станет React-first для максимально удобной интеграции с вашими приложениями.

Blok доступен бесплатно прямо сейчас!
🔥4311
А вот результат, ради чего все это делается! Человек пару недель ночами не спал – делал возможным Notion-like экпириенс для наших редакторов! 🧨

На гифке короткое представление, как было и как стало:
This media is not supported in your browser
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥104🔥2
Год назад делали с Серегой Орловым LiveActivities на андроиде.

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

Но я тогда открыл для себя, что в Андроиде все вещи, которые выглядят простыми скорее всего делать будет тупо сложно!

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

К примеру на верхней картинке верхний и нижний островок – это тупо разные компоненты, а не один и тот же просто переверстанный 👁👁

Вообще мне всегда было забавно, как у нас ребята на андроиде радуются таким вот штучкам. Мне всегда это было как-то до лампочки, у меня вообще все уведомления выключены. А у них там целая история в этих отключенных оповещениях!

Короче, статья вышла прикольная! Заслуживает плюсика в карму 💯
Please open Telegram to view this post
VIEW IN TELEGRAM
53👍1
🐸🐸 BackgroundTaskQueue

В первый раз за долгое время в практике понадобилось использовать бэкграундную таску.

Нужно было добавить в процесс логина автоприсваивание пользователям определенных доступов. Операция не обязательная и из-за нее не должен падать логин. Тем более процесс логина из-за нее тоже не хочется растягивать.

Можно было сделать fire and forget опустив слово await:


groupAccessService.AssignPredefinedSpacesAsync(existingUser, CancellationToken.None);


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

Вспомнил, что когда-то с IHostedService слышал про BackgroundTaskQueue

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


using System.Threading.Channels;

namespace Dodo.KnowledgeBase.Web.Services.BackgroundTasks;

public class BackgroundTaskQueue(IServiceScopeFactory serviceScopeFactory) : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, ValueTask>> _queue =
Channel.CreateUnbounded<Func<CancellationToken, ValueTask>>();

public async ValueTask QueueAsync(Func<CancellationToken, ValueTask> workItem)
{
ArgumentNullException.ThrowIfNull(workItem);
await _queue.Writer.WriteAsync(workItem);
}

public async ValueTask QueueAsync(Func<IServiceProvider, CancellationToken, ValueTask> workItem)
{
ArgumentNullException.ThrowIfNull(workItem);

await _queue.Writer.WriteAsync(ScopedWorkItem);
return;

async ValueTask ScopedWorkItem(CancellationToken ct)
{
using var scope = serviceScopeFactory.CreateScope();
await workItem(scope.ServiceProvider, ct);
}
}

internal async IAsyncEnumerable<Func<CancellationToken, ValueTask>> DequeueAsync(
[System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct)
{
await foreach (var item in _queue.Reader.ReadAllAsync(ct))
{
yield return item;
}
}
}


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


namespace Dodo.KnowledgeBase.Web.Services.BackgroundTasks;

public class QueuedHostedService(
IBackgroundTaskQueue taskQueue,
ILogger<QueuedHostedService> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken ct)
{
logger.LogInformation("Queued Hosted Service is running");

await foreach (var workItem in ((BackgroundTaskQueue)taskQueue).DequeueAsync(ct))
{
try
{
await workItem(ct);
}
catch (Exception ex)
{
logger.LogError(ex, "Error occurred executing task work item");
}
}
}
}


И вот так это можно использовать:

await backgroundTaskQueue.QueueAsync(async (sp, ct) =>
{
var groupAccessService = sp.GetRequiredService<IGroupAccessService>();
await groupAccessService.AssignPredefinedSpacesAsync(existingUser, ct);
});


Вроде несложно, но если что упадет, то всегда можно увидеть в логах в отличие от fire and forget запуска.

В отличие от варианта в доке сделал через IAsyncEnumerable. Так что вышло ну чуть покрасивше и с моей любимой фичей, которую редко когда получается заюзать.
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍21🤝1