Проблема OS X, Dual Stack и VK API

в 16:22, , рубрики: mac os x, vk api, Вконтакте API, разработка, метки: , ,

Я разрабатываю программу для OS X, которая взаимодействует с API VK и последний апдейт никак не принимали цензоры Mac App Store. После нескольких уточнений мне прислали видео работы программы, над которым я ломал голову несколько дней.

О причинах такого поведения я расскажу в этой статье. Сразу хочу сказать, что не считаю это багой vk.com или OS X, но они оба могут эту ситуацию исправить.

Мигающее окно

Для начала расскажу, что же за окно мигает на видео. Для этого пару слов о работе с API VK. И так для запросов к серверу api.vk.com, нужен токен, который необходимо получить путем авторизации чем веб интерфейс по адресу oauth.vk.com. Алгоритм следующий:

  1. Обращаемся к любому методу vk.com, передав последний известный токен
  2. Если в ответ получили ошибку авторизации, переходим к авторизации
  3. Показываем окно с загруженной веб формой, получаем токен
  4. Повторяем все с п. 1

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

Подсказка

Не помню по какой причине, но я решил посмотреть откуда происходили запросы и к своему удивлению в списке значился IPv6 адрес! Ну что ж, следующей задачей было раздобыть IPv6 канал. Помог раздел Q&A хабра. Я тут же поднял туннель и стал дебажиться. К огромному разочарованию все работало как надо.

Причина

Настраивая туннель я заметил, что не весь трафик идет через IPv6, кроме того, лишь малая его часть приходится на этот стек. Тут я пошел гуглить о том как все-таки поставить IPv6 приоритетным. Оказалось, что это невозможно. Можно лишь полностью отключить IPv4 и тогда останется только IPv6. Перерыв кучу информации в интернете, я нашел информацию о том, что OS X в случае доступности обеих стеков как на стороне сервера так и на стороне клиента сама выбирает каким из них пользоваться, решение принимается на основе скорости прошлых запросов и кешей. Вот она причина проблем! После нескольких ребутов, сбрасываний DNS и отключений/подключений туннеля я добился того, что бага повторилась. Вот как все было:

  1. Обращение к oauth.vk.com, система выбирает IPv6
  2. Сервер oauth.vk.com генерирует токен, привязанный к адресу пользователя IPv6
  3. Обращение к api.vk.com, система выбирает IPv4
  4. Сервер api.vk.com отклоняет запрос, так как токен не валиден, адрес пользователя изменился

Возможные решения:

1. Со стороны vk.com

Токен должен быть привязан к обеим адресам, как а IPv4 так и к IPv6. Прямо в момент написание статьи, мне ответили из vk, что это невозможно: «На счёт стеков. Мы точно не можем привязывать токен к двум ip, так как они никак между собой не связаны».

2. Прямая авторизация

У VK API есть метод для прямой авторизации, но за неделю обращений к команде vk я так и не смог получить к нему доступ.

3. Со стороны OS X

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

4. Со стороны клиента.

Для показа веб формы используется компонент WebView, для запросов — NSURLConnection. Если суметь форсировать весь трафик через один стек, то все должно работать. Сделать это можно написав свой NSURLProtocol, но это невероятно большое количество работы — надо самому описать весь протокол HTTP и HTTPS + кеширование.

5. Со стороны клиента.

При логине попросить права scope=offline, это позволит отвязаться от IP, но я очень подозрительно отношусь к программам, которые просят такой доступ.

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

Автор: TAURUSiv43

* - обязательные к заполнению поля