Волгатех.Коллектив: своя почта для университетского Exchange
В версии 0.5.0 «Почта» стала встроенным клиентом вместо веб-версии в окне приложения. Университетская почта — локальный Exchange без OAuth, поэтому клиенту нужен пароль, а приложение до сих пор обходилось без него. Как это решено, как устроен вход по NTLM и что клиент умеет.
До версии 0.5.0 «Почта» в Волгатех.Коллективе открывала веб-версию почты внутри приложения. Это работало, но оставалось сайтом в окне: без значка непрочитанных, без жестов и с вёрсткой, рассчитанной на компьютер. 30 сентября вышла версия со встроенным почтовым клиентом. На скриншотах здесь и ниже — вымышленные письма и адреса.



Пароль, который всё-таки понадобился
В первом разборе одно из правил приложения называлось так: «Пароль, которого нет». Приложение хранит только токены, а в почту и портал вход выполняется на самих сайтах. Встроенный клиент это правило нарушает, и обойти это нельзя.
Почта университета — локальный Exchange, а не Microsoft 365. У него нет ни OAuth, ни Graph API: клиент может войти только с паролем от почты. Поэтому решение устроено так, чтобы пароль появлялся лишь у тех, кто сам этого захотел:
- встроенный клиент — в отдельной сборке. Каждый выпуск содержит два набора APK одного приложения:
app-mail-*со встроенной почтой и обычныеapp-*, где почта по-прежнему открывается веб-версией; - у обеих сборок одна подпись, поэтому любая ставится поверх другой, и вернуться к веб-версии можно в любой момент;
- пароль хранится в защищённом хранилище ОС и удаляется пунктом «Выйти из почты».
Сценарий выпуска собирает оба набора и перед публикацией проверяет сертификат подписи у каждого APK — так же, как это делалось для обычной сборки начиная с версии 0.4.2.
Вход по NTLM
Клиент говорит с сервером через Exchange Web Services, а вход по HTTP там выполняется по NTLMv2. Рукопожатие реализовано в самом приложении, по спецификации MS-NLMP. Нужна только его часть, отвечающая за проверку подлинности: протоколу HTTP не требуются подпись и шифрование сообщений, поэтому сеансовый ключ не согласуется.
Самодельная криптография — то место, где ошибку не видно, пока сервер не откажет во входе. Поэтому тесты сверяют вычисления с примером из самой спецификации: хеш NTOWFv2, NTProofStr и ответ LMv2 должны совпасть с опубликованными значениями байт в байт. Отдельно проверено, что логин вида ДОМЕН\имя разбивается на домен и имя, а адрес вида имя@домен передаётся целиком.
Список, похожий на Outlook
Список писем повторяет привычное по Outlook: заголовки «Сегодня», «Вчера», «На этой неделе», точки у непрочитанных, а письма, закреплённые в Outlook, собраны сверху в сворачиваемую группу. Есть поиск, выбор папки с числом непрочитанных, обновление жестом вниз; первая страница сохраняется и открывается без сети. Число непрочитанных показывается значком у пункта «Почта» и на кнопке меню.
Ящик университетской почты ограничен по размеру, поэтому у каждого письма показан размер, а строка окрашивается по нему: бледно-жёлтым от 100 КБ, оранжевым к 1 МБ, красным от 10 МБ. Шкала — последовательная палитра от жёлтого к красному, так что большое письмо видно, не читая цифр. Цвет и группу закреплённых можно отключить в меню.
Чтение без слежки
Письма в HTML показываются в изолированной странице с политикой безопасности содержимого: скрипты запрещены, внешние загрузки тоже. Это отключает пиксели отслеживания и удалённые картинки — письмо не сообщает отправителю, что его открыли. Разрешены только встроенные стили и вложенные изображения: картинки, на которые письмо ссылается через cid:, встраиваются прямо в страницу. Обычный текст экранируется и показывается как есть.
Вложения можно открыть, сохранить на телефон или отправить в другое приложение; по строке отправителя видны все участники переписки; письмо можно перенести в другую папку.
Письмо, автоответ и размер ящика


Ответ и пересылка, подсказки из адресной книги университета в полях «Кому» и «Копия», вложения до 18 МБ. Подпись один раз импортируется из веб-версии. После нажатия «Отправить» есть пять секунд, чтобы передумать, а неотправленный текст сохраняется черновиком.
«Автоответ» устанавливается на сервере, как в Outlook, поэтому работает и при выключенном телефоне.
«Размер ящика» показывает занятое место по папкам, а полоска заполнения видна рядом с «Входящими». Здесь пришлось учесть две особенности сервера. Удалённые насовсем письма сервер ещё какое-то время хранит для восстановления, но в лимит они не входят — и приложение показывает их отдельной строкой, а не прибавляет к занятому. А сам лимит сервер приложению не сообщает, поэтому его можно один раз ввести вручную, переписав из веб-версии.
Дальше
Следующие шаги — уведомления о новых письмах и закрепление писем прямо из приложения. Обычные сборки с веб-версией почты остаются в каждом выпуске.
Выводы
- Принцип «приложение не хранит пароль» стоит нарушать только явно: отдельной сборкой, которую человек выбирает сам, с паролем в хранилище ОС и понятным способом его удалить.
- Одна подпись у двух сборок превращает выбор в обратимый: любая ставится поверх другой.
- Собственную реализацию протокола проверяют по примерам из спецификации: ошибка в хеше иначе выглядит как «неверный пароль».
- Почтовый клиент, который не загружает внешние ресурсы, не сообщает отправителю о прочтении. Такую защиту стоит закладывать с первой версии.
- Данные сервера нужно показывать так, как он их считает: удалённые письма, которые не входят в лимит, нельзя прибавлять к занятому месту.
Доступность
Приложение распространяется в виде APK для Android. Для большинства современных телефонов подходят:
app-mail-arm64-v8a-release.apk— со встроенным почтовым клиентом;app-arm64-v8a-release.apk— с веб-версией почты, как раньше.
Ссылки:
- Последняя версия: github.com/nikita-konkin/volgatech.corp/releases
- Исходный код: github.com/nikita-konkin/volgatech.corp
Теги
Другие обновления по проекту
Волгатех.Коллектив: Liquid Glass — стекло, иней и узоры времён года
Как в приложении появилась тема «Liquid Glass»: полупрозрачные панели над цветным фоном, матовое стекло, иней из фрактальных кристаллов и узор по времени года — листья, иней, цв...
Волгатех.Коллектив: обновление из приложения, версия для iPhone и компьютеров, напоминания и виджет
Версии 0.5.1 и 0.5.2: приложение само предлагает обновление и проверяет файл перед установкой, работает в браузере — на iPhone без App Store и на компьютере в своей раскладке, н...