Блог ·
Панелі під власним брендом: що бачить клієнт
Поставити своє імʼя на панель реселера це легша половина. Складніша це вирішити, які екрани взагалі існують для вашого клієнта, і це забезпечити.
Автор: Provibr
Якщо ви перепродаєте VPS або хостинг, ваші клієнти рано чи пізно захочуть панель. Вони хочуть перезавантажити власну машину о другій ночі замість того, щоб відкривати тікет, і ви теж цього хочете.
Це перетворюється на два питання, які мають вигляд одного і ним не є. Чиє імʼя стоїть на панелі і які частини панелі взагалі існують для тієї людини. Перше є брендуванням, і воно здебільшого про подання. Друге є межею, і саме помилка в ньому призводить до того, що ваш клієнт читає рахунок від вашого постачальника.
Брендування спиняється там, де починаються документи
Перебрендувати панель означає змінити обрамлення: словесний знак у бічній панелі, заголовок сторінки, фавікон, назву в блоці облікового запису. Це корисний обсяг, і саме на ньому більшість функцій під власним брендом і спиняється.
Цікавою частиною є перелік того, що ніколи не має нести імені реселера.
| Екран | Чиє імʼя він несе | Чому |
|---|---|---|
| Обрамлення панелі, заголовки, фавікон | Реселера | Відносини, у яких перебуває клієнт |
| Заява про конфіденційність | Платформи | Повідомлення про обробку описує того, хто справді обробляє |
| Умови надання послуг | Платформи | Це договір платформи, а не реселера |
| Договір про обробку даних | Платформи | Те саме, і він називає субобробників |
| Рахунки та проформи | Платформи | Це фінансовий запис справжньої операції |
| Рядок у банківській виписці | Платформи | Постійний запис, який ніхто не прокоментує згодом |
Міркування вміщається в одне речення: клієнт вашого клієнта ніколи не має почати думати, що має договір з кимось іншим, ніж та сторона, з якою він його справді має. Усе, що має юридичний або фінансовий характер, несе імʼя контрагента в тому документі, і це не вподобання в дизайні.
Важливіше за саме правило те, де воно живе. У нашій кодовій базі це перелік шляхів до файлів, і тест обходить транзитивне дерево імпортів від кожного з них, падаючи тієї миті, коли хоч один може дотягнутися до модуля брендування. Обхід у ширину, тож помилка називає найкоротший ланцюжок, а саме його й треба розірвати.
Перевірку прямих імпортів надто легко обійти: покладіть пошук бренду в допоміжну функцію, імпортуйте її, готово. І сторожа перевіряє себе в обидва боки. Перелічений шлях, який зник, є помилкою, а не мовчазним пропуском, а окремо вона стверджує, що макет панелі таки дістає модуль брендування, бо розвʼязувач, який тихо нічого не розвʼязує, позначив би зеленим кожен файл.
Власний вхід реселера ніколи не перебрендовують
Є друге правило, менш очевидне, у якому ми помилилися б, якби його не проговорили: брендування діє лише на власному домені клієнта.
Коли реселер входить на власному хості платформи, він бачить платформу, а не свій бренд. Саме там живуть рахунки, підписка й відносини з нами. Пошук бренду відкочується до звичайного вигляду тієї миті, коли запит не привʼязаний до домену облікового запису, тож вирішує рівно одне місце, і жодному екранові не треба це памʼятати.
Екран керування брендом показує попередній вигляд обрамлення, зверненого до клієнта, а не перебрендовується сам. Це звучить педантично, доки ви не подумаєте, чого вчить альтернатива: реселер, який бачить власний логотип над власним рахунком, слушно виснує, що його клієнти бачать щось подібне.
Білий логотип на білій бічній панелі
Тло нашої панелі біле, тож логотип із прозорим тлом і білою фарбою невидимий, а той, хто його завантажує, про це не дізнається: він дивиться на нього в дизайнерському редакторі на сірому полотні.
Ми виміряли, а не вгадували, накладаючи кожен логотип на справжній колір поверхні в безголовому браузері:
| Логотип | Контраст щодо поверхні панелі |
|---|---|
| Темна фарба, прозоре тло | 16,46:1 |
| Біла фарба, прозоре тло | 1,00:1 |
| Біла фарба на власній непрозорій підкладці | 17,74:1 |
| Світло-сіра фарба | 1,24:1 |
Рядок 1,00:1 не означає «важко прочитати». Кожен піксель тотожний тлу. Логотип намальовано, і дивитися нема на що.
З цього вийшли два рішення. Під логотипом свідомо немає підкладки, бо вона перемалювала б бренд клієнта і дала б кожному звичайному логотипу рамку заради порятунку одного винятку. А екран завантаження попереджає, а не відмовляє, бо бренду дозволено бути світло-сірим.
Вимірювання рахує фарбу, а не збіг. Логотип із широкими прозорими полями збігається з тлом на більшій частині своєї площі й при цьому чудово видимий; значення має те, яку його частку намальовано і як далеко та фарба стоїть від кольору поверхні.
Відсутність не є дозволом
Тепер складніша половина. Які екрани мають існувати для клієнта реселера?
Інстинкт каже змоделювати це як дозволи: дати субклієнтові роль, поставити менше галочок. Це неправильна форма, і причина проявляється лише скраю. Дозволи відповідають на «чи можна цьому учасникові це зробити». Питання ж тут інше: «чи існує цей екран на цьому домені», і ці двоє розходяться тієї миті, коли власник облікового запису входить подивитися на власну клієнтську панель. Він власник. Кожна перевірка дозволів пропускає його помахом руки.
Тож модель є інверсією, а не правом. Фіксований перелік каже, які поверхні відсутні на домені облікового запису: рахунки, налаштування облікового запису, тікети, агенти, інтеграції, журнал активності облікового запису, вигляд топології, розділ адміністрування платформи, а також сторінки реєстрації та відновлення пароля. Відсутні для всіх, включно з власником.
Три з них потребують обґрунтування, бо причина не та, що спадає на думку.
Тікети відсутні, бо клієнт реселера має відносини з підтримки саме з реселером, а не з нами. Якби той екран існував, клієнт прочитав би відповідь, у якій названо компанію, що, судячи з його власної панелі, не існує.
Журнал активності відсутній, бо це журнал облікового запису, а не читача. Чесним результатом є не відфільтрований журнал, а «цього екрана тут немає». Вкладка активності на окремому сервері лишається, бо вона справді обмежена машиною, яка в них є.
Вигляд топології доводить модель. Він працює на модулі серверів, а модуль серверів є рівно тією єдиною річчю, яку субклієнт таки має. Ворота на дозволах не відсіяли б геть нічого.
Три засуви, бо сторінка не є межею
Однієї перевірки не досить, і кожна з трьох ловить те, чого не можуть інші.
Перша живе в самій функції дозволів, де порядок двох рядків і є всією суттю:
- Чи існує цей модуль на цій поверхні? Якщо ні, відмовити.
- Чи має ця роль повний доступ? Якщо так, дозволити.
Саме постановка перевірки поверхні першою робить так, що «не існує» перемагає «можна все», і саме вона змушує інверсію діяти всюди, а не лише на тих екранах, про які хтось згадав.
Друга є сторожею в кожній сторінці під тими шляхами і дає звичайну 404. Вона свідомо не приймає жодного аргументу: виклик, який називав би власний екран, дозволив би одруківці стати тихо відчиненими дверима.
Третя живе у зворотному проксі, бо сторінка не може зловити запит, який до сторінки не доходить. POST на відсутній шлях відхиляють раніше, ніж запуститься хоч якийсь код сторінки. Переходи пропускають, щоб відрендерилася власна 404 застосунку, а не гола помилка проксі.
Кука є правилом браузера, а не правилом сервера
Це та знахідка, яку варто забрати з собою, навіть якщо ви не будуватимете нічого з описаного вище.
Наші сесійні куки привʼязані лише до хоста. Жодного атрибута Domain, тож сесія на одному клієнтському домені не надсилається на інший і на хост платформи теж. Це правильно і це перевірено, включно з негативним випадком, де вмикання кук між піддоменами змушує Domain зʼявитися.
І це також не межа. Субклієнт тримає власний сесійний токен і може надіслати його куди завгодно за допомогою HTTP-клієнта з командного рядка. Відмовився б лише браузер.
Ми виміряли, що це дозволяло, і виявилося гірше, ніж очікували: субклієнт міг створити цілком нову організацію з собою як власником, разом із власною пробною підпискою, двома незалежними шляхами в коді, досяжними з чотирьох різних точок входу. Чотири організації, полічені в базі даних після того. На його власному домені той самий запит відхиляв проксі, тож двері були зачинені з одного боку й відчинені з другого.
Виправлення полягало не в тому, щоб додати перевірки на ті два шляхи. Воно полягало в тому, щоб поставити межу в єдиній точці, через яку проходить кожен автентифікований запит, а інваріант «субклієнт ніколи не стає власником організації» в тій одній функції, яку поділяють усі шляхи створення.
Той самий раунд знайшов загальну версію цієї проблеми в іншому місці. Ключ API несе роль, але не поверхню. Скористатися цим було неможливо, бо вкладка, де створюють ключ, на домені облікового запису не існує. Але це схована кнопка, а не межа, і різниця виявиться того дня, коли хтось додасть другий спосіб створювати ключі. Виправлення відхиляє самого учасника, а не позначає ключ.
Жодна колонка не каже «це субклієнт»
Остання проєктна нотатка, бо це саме той різновид рішення, що окупається тихо.
Субклієнт є звичайним рядком користувача із зарезервованою поштовою адресою вигляду username@<organisation-id>.invalid плюс звичайним рядком членства з вузьким профілем дозволів. Булевої колонки, що їх позначає, немає, і це навмисне: друге джерело правди може розійтися з адресою, і тоді дві частини системи не сходяться в тому, ким хтось є.
Оскільки ідентифікатор організації сидить усередині адреси, унікальність дістається задарма від індексу, який там уже був, і те саме імʼя користувача може існувати у двох реселерів. Форма входу питає імʼя користувача, а ідентифікатор організації бере з хоста, а не з форми, тож ніхто не зайде в чужий обліковий запис, угадавши ідентифікатор.
А їхню адресу ніколи не позначають як підтверджену, бо підтвердити її ніхто не може. Та колонка означає «ця адреса доказово належить цій особі», і виставити її істинною для адреси, яка не доходить до жодної поштової скриньки, означало б перенести брехню туди, де її гірше видно.
Чого воно не робить
Перебрендування покриває обрамлення. Тексти інтерфейсу все одно читаються як наш продукт тією мовою, якою користується відвідувач, а вдавати інше означало б перекладати словник реселера девʼятьма мовами замість нього. Перелік відсутніх поверхонь є рішенням про форму продукту, а не самостійною моделлю безпеки: він працює, бо працюють три засуви за ним.
Саме так працюють домени облікових записів у Provibr, де агент працює на вашому власному залізі і зʼєднується лише назовні.