ARMANOS

Синхронизация сессий

Ваша сессия на двух компьютерах

Куки и входы лежат в папке на той машине, где работал браузер. ARMANOS перевозит их на второй компьютер шифрованным файлом через папку, которую и так синхронизирует ваше облако, поэтому ваших сессий у нас нет.
scrypt и AES-256-GCM
Шифрование
ваша папка, не наша
Хранение
1 / 2 / 5 / 20 по тарифу
Мест под машины
3 минуты, продлевается пока открыт
Замок профиля

Второй компьютер это то место, где теряют аккаунты

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

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

ARMANOS отвечает на это двумя половинами. Сессия едет одним шифрованным файлом через папку, которая у вас уже есть. Профиль открывается на одной машине за раз, а открытый профиль программа не трогает вовсе. Дальше эти две половины в том порядке, в каком их делает код.

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

Папка ваша, и облако под ней тоже ваше

Вы показываете программе папку. Годится всё, что ваше облако и так синхронизирует: Dropbox, iCloud Drive, Google Drive, рабочий сетевой диск, каталог на домашнем хранилище. Программа не знает, чем это синхронизируется, и не спрашивает.

Это решение, а не пробел. Хранилища для ваших сессий у нас нет, значит нечего терять, нечего выдавать и не о чем беспокоиться. Заодно функция заработала сразу, а не после того, как у продукта появилось бы объектное хранилище.

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

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

  1. 1

    Выберите папку

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

  2. 2

    Задайте пароль

    Не короче 8 знаков и одинаковый на обеих машинах. Без него второй компьютер файл не откроет.

  3. 3

    Назовите этот компьютер

    Офис, ноутбук, дом. Именно это имя увидит вторая машина, когда оттуда приедет сессия.

  4. 4

    Включите обмен

    Без папки и пароля переключатель не включится, вместо того чтобы сказать «включено» и не делать ничего.

Что кладётся в файл, а что выброшено нарочно

В папке появляются два файла на профиль. Архив это <id>.armanos, он зашифрован. Рядом лежит <id>.json, маленькая открытая метка, которую вторая машина читает первой.

В архиве лежат каталоги сессии обоих движков, каждый под своим именем: встроенный Chromium и ARMANOS Browser 153.0.7978.0 едут в одном файле без вложенных архивов. Рядом с ними profile.json: опознаватель профиля, имя, сценарий, группа, метки, заметка, стартовая страница, шаблон и поколение отпечатка, правки отпечатка, прокси, ключ двухфакторной авторизации, сохранённый вход и список включённых расширений. Опознаватель едет потому, что из него выводится отпечаток. На второй машине профиль остаётся ТОЙ ЖЕ машиной, а не знакомыми куками с чужого компьютера.

Кэш выброшен намеренно. Кэши, кэши видеокарты и шейдеров, хранилище Service Worker, blob-хранилище и отчёты о падениях это сотни мегабайт, которые сайты перезальют сами. Замковые файлы вроде SingletonLock тоже пропускаются. Архив больше 400 МБ получает честный отказ, а не запись наполовину.

В метке рядом с архивом нет имени профиля. Там только время, размер в байтах и имя, которое вы дали этому компьютеру. Облачная папка это ровно то место, куда чужой доступ приходит первым, и метка со словами «Instagram рабочий» рассказала бы, какие аккаунты вы ведёте.

Что именноЕдет ли
Куки, входы, локальное хранилище и IndexedDBДа, внутри шифрованного архива
Опознаватель, имя, сценарий, группа, метки, заметка, стартовая страницаДа, файлом profile.json внутри архива
Шаблон отпечатка, поколение и ручные правкиДа, вместе с опознавателем, поэтому отпечаток остаётся прежним
Прокси, страна, ключ двухфакторной авторизации, сохранённый входДа, и только внутри шифрованного файла
Какие расширения включеныДа, сам выбор; файлы расширений не кладутся
Кэши, Service Worker, blob-хранилище, отчёты о паденияхНет, сайты перезальют их сами, а файл стал бы неподъёмным
Замковые файлы, DevToolsActivePort, сокетыНет
Имя профиля снаружи шифрованного файлаНет, в метке только время, размер и имя вашего компьютера

Один пароль, и он остаётся на этой машине

Формат тот же, каким пользуется ручной перенос профиля, поэтому файл, положенный одной дорогой, открывается другой. Заголовок, случайная соль в 16 байт, одноразовое число в 12 байт, scrypt с N 32768 до ключа в 256 бит и AES-256-GCM. Метка проверяется при открытии, поэтому неверный пароль даёт честный отказ, а не мусор.

Пароль хранится на этой машине, и программа говорит об этом на экране. Спрашивать его при каждом закрытии профиля значит не сделать автоматическую выгрузку вовсе, то есть не сделать функцию. Где система даёт связку ключей, пароль закрывается ею; где не даёт, он пишется в файл, доступный только вам. В папку синхронизации он не попадает никогда и наружу в окно не отдаётся.

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

Права «только для хозяина» это про macOS и Linux

На Windows тот же вызов меняет лишь признак «только для чтения»: правами там распоряжаются списки доступа, до которых программа не дотягивается. Защищает там другое: данные программы лежат внутри вашего пользовательского профиля. Честнее написать это здесь, чем намекать на большее.

Когда обмен случается на самом деле

Перед открытием профиля программа забирает из папки более свежую сессию. Именно до появления окна: подменять файлы под работающим Chromium значит испортить профиль, да и браузер уже прочитал бы старые базы.

Через четыре секунды после закрытия профиля сессия уезжает. Chromium дописывает свои базы ещё пару секунд после того, как окно исчезло, и программа заново убеждается, что профиль не открыли снова. Если в эти секунды закрыть саму программу, отправка догоняется при следующем запуске: по одному профилю с паузой, потому что сборка тридцати сессий разом подвесила бы машину сразу после старта.

Пока программа открыта, она смотрит на папку раз в минуту. Сначала читается одна отметка времени самой папки, и только при её изменении читаются метки профилей: двести профилей не превращаются в двести обращений к облаку каждую минуту. Молча ничего не забирается. Принести чужую сессию в профиль, с которым вы работаете, значит подменить вам землю под ногами, поэтому программа только говорит, что появилось новое.

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

  • Отправить свою в папку

    Для одного профиля, с подтверждением, которое прямо говорит, что оно заменяет лежащее там.

  • Забрать ту, что в папке

    Для одного профиля, взамен сессии, которая есть у него на этом компьютере.

  • Отправить все и забрать все

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

  • Найти профили в папке

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

Когда менялись обе стороны, не затирается ничего

Решение принимает одна небольшая функция, и она сравнивает отметки, а не часы. «Менялось здесь» это самое свежее время файлов сессии на этой машине против того же числа, запомненного в прошлую синхронизацию. «Менялось там» это метка в папке против той метки, которую программа оттуда в прошлый раз взяла или туда положила. Часы двух машин в сравнение не входят вовсе.

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

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

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

Что изменилось с прошлой синхронизацииЧто делает программа
В папке для этого профиля пока ничего нетОтправляет, как только есть что отправлять
Менялось только на этой машинеОтправляет
Менялось только в папкеЗабирает, до открытия профиля
Не менялось ни там, ни здесьНе пишет ничего
Менялось и там, и здесьНе трогает ничего, говорит вам, и выбираете вы
Метка свежее, чем файл рядом с нейВ этот раз ничего; вернётся, когда файл догонит метку

Облака делают своё за вашей спиной, и программа этого ждёт

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

Отсутствие архива тоже не значит «пусто». iCloud с оптимизацией хранилища, OneDrive Files On-Demand, включённый на Windows по умолчанию, и Dropbox Smart Sync убирают содержимое с диска, оставляя заглушку. Тяжёлый архив сессии первый кандидат на выгрузку, а маленькая метка остаётся лежать. Правило простое: есть метка, значит сессия была. Забрать её сейчас нельзя, а затирать мы не вправе.

Запись идёт через соседний файл и переименование, потому что половина архива поверх работавшей сессии не расшифровывается. Оборванная запись оставляет соседа лежать, а сосед это полная копия сессии в папке, место в которой оплачиваете вы. Раз в час программа подметает обрезки старше часа, у которых имя в точности её собственное. Чужой недописанный файл не трогается никогда.

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

Что сделало облакоЧто получаете вы
Привезло метку раньше архиваВ этот раз ничего, потом обычную загрузку, когда файл доедет
Выгрузило архив ради экономии местаНичего не берётся и ничего не затирается
Оставило две копии после почти одновременной записиВторая копия узнаётся по имени, и о ней говорят один раз
Оставило недописанный соседний файлПодметается через час, и только если имя в точности наше

Открытый профиль не трогается, и открывается он на одной машине

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

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

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

«Мой» значит та же машина, а не тот же человек. Запрос, который себя не назвал, не может доказать, что замок его, и не получает его. Без учётной записи замка нет и не нужно: профили живут только на этом компьютере, и делить их не с кем.

Замок держится
3 минуты
Продление
каждые 60 секунд, пока профиль открыт
Вторая машина
получает отказ с именем держателя и временем
Профиль закрыли
замок отпускается сразу
Машину выключили
замок истекает сам

Числа взяты из apps/server/src/profiles/profiles.service.ts и из таймера продления в программе.

Машина занимает место, и его можно вернуть

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

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

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

ТарифМест под машиныПрофилей
Free12
Professional2от 10 до 100
Business5от 200 до 1000
Enterprise205000 и больше

Чего это не делает

  • Ничего за вас не хранит. Нет папки или не запущено облачное приложение, значит нет и обмена. Пока облако не докачало файл, программа ждёт и в этот раз не делает ничего.
  • Не сводит две сессии в одну. Когда менялись обе стороны, вы выбираете одну, вторая откладывается копией, а свести их придётся руками.
  • Не трогает открытый профиль ни в одну сторону. Профиль, открытый весь день, не уедет, пока вы его не закроете или не нажмёте «отправить все».
  • Это не зеркало в реальном времени. Сессии ездят перед открытием профиля, через несколько секунд после закрытия, при запуске программы и по кнопке.
  • Потерянный пароль не восстанавливается: файлы, уже лежащие в папке, открыть будет нечем. Так задумано, копии пароля у нас нет.

Как проверить

За каждым утверждением выше стоит файл, а за большинством ещё и стенд, который исполняет настоящий код.

В папке лежит шифрованный файл, и полный круг возвращает те же куки
apps/desktop/src/lib/sessionSync.js · apps/desktop/test/session-sync-folder.js
Менялись обе стороны: не затирается ничего, а заменённое откладывается рядом
apps/desktop/src/main/main.js · apps/desktop/test/conflict-keeps-copy.js
Архив, выгруженный облаком или ещё не докачанный, не читается как пустая папка
apps/desktop/src/lib/sessionSync.js · apps/desktop/test/cloud-evicted-file.js
Профиль открывается на одной машине за раз, а перехват осознанный
apps/server/src/profiles/profiles.service.ts · apps/server/test/profile-lock.js
Места идут за действующим тарифом, а отвязка машины запоминается
apps/server/src/devices/devices.service.ts · apps/desktop/test/device-identity.js

Настройте это на обоих компьютерах

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