суботу, 19 січня 2013 р.

Використовуємо life:) API за допомогою Ruby


У цій статті я хочу розповісти Вам, як на мові Ruby налагодити взаємодію з life:) API. Для тих хто не в курсі, life:) — український GSM-оператор мобільного зв'язку.

Все почалося тоді, що коли у офіційному твітері life:) з'явилося повідомлення про додаток "Мій life:)" для Android. Мені відразу стало цікаво — а як вони отримують інформацію, якщо не через свій сайт системи самообслуговування для індивідуальних абонентів Мій life:).

Добрі люди підказали мені, як декомпілювати файл apk. Але це не тема цієї статті.

Трохи покопавшись в горах Java-коду, мені вдалося зрозуміти за яким принципом здійснюється робота з сервісом life:). Варто зауважити, що офіційно нікого API у life:) немає. Тому все нижче написане використовуйте на свій страх і ризик.

Результатом цієї роботи стала бібліотека для Ruby - life-api, яка реалізує деякі методи API. Ви можете знайти її на Github.

Отже, що нам знадобиться щоб виконувати запити?
Розглянемо все по порядку.

Всі запити, включаючи авторизацію виконується до адреси https://api.life.com.ua/mobile.
З кожним запитом передається постійний ключ API accessKeyCode. А applicationKey використовується, як секретний ключ для підписання запиту. Про це трохи пізніше.

А зараз просто визначимо ці три змінні:
@access_key_code = '7'
@application_key = 'E6j_$4UnR_)0b'
@api_url         = 'https://api.life.com.ua/mobile/'

Для отримання токена потрібно передати методу signIn наступні параметри:
  • msisdn - номер телефону, що почитається з "380"
  • superPassword - ваш суперпароль
Пам'ятаєте, параметр accessKeyCode є обов'язковим для всіх методів.

Також обов'язково необхідно підписати запит. Значення параметра signature рівне криптографічній хеш-функції HMAC(SHA1) від конкатенації наступних рядків:
  • назва методу
  • пар "parameter_name=parameter_value"
  • рядок "&signature="

Наступний метод повертатиме валідний url для запиту. У якості параметрів він отримує назву функції і хеш параметрів з парами "ключ => значення".
require 'openssl'
require 'base64'

def create_signed_url(method, params)
  query = create_param(params)
  str = method + '?' + query + '&signature='

  digest = OpenSSL::Digest::Digest.new('sha1')
  hash = OpenSSL::HMAC.digest(digest, @application_key, str)

  hash = Base64.encode64(hash).chomp

  str += hash

  return @api_url + str
end

Зверніть увагу на метод create_param, який перетворює хеш параметрів у текстовий рядок, придатний для використання в рядку запиту url.
def create_param(params)
  params.map do |key, value|
    "#{key}=#{value}"
  end.sort * '&'
end

Наступний метод власне і виконує запит за допомогою вбудованої у Ruby бібліотеки 'net/https':
require 'net/https'

def request(method, params)
  params.merge!(accessKeyCode: @access_key_code)
  url = create_signed_url(method, params)

  uri = URI(url)
  request = Net::HTTP::Get.new(uri.request_uri)

  response = Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
    http.request(request)
  end

end

Виконуємо запит для отримання токена:
request('signId', { msisdn: '380631234567', superPassword: '1234'})

Приклад запиту:
https://api.life.com.ua/mobile/signIn?accessKeyCode=7&msisdn=380631234567&superPassword=1234&signature=KmLILbck40UJbCvlZMDOTtC2Z6o%3D

Приклад успішної відповіді від сервера у форматі XML:

0ghkIU9ju4i7Qlh

Після отримання токена взаємодія з іншими методами life:) API проводиться шляхом створення HTTP-запиту (GET) до адреси API-сервісу https://api.life.com.ua/mobile.

На цьому все. Сподіваюся, я досить докладно описав кожний свій крок. Буду радий відповісти на Ваші запитання, якщо такі виникнуть.

Дякую за увагу.

2 коментарі:

John Galt сказав...

що можна отримати? це буде працювати поки ключ не зміниться. Де його модна взяти потім?
чи є список url-ов і сигнатури виклику (api doc)?

Anton Maminov сказав...

Подробиці в репозиторії https://github.com/mamantoha/lifecell_api