Module: GitFit::Auth::Garmin::DIExchange

Defined in:
lib/git_fit/auth/garmin/di_exchange.rb

Constant Summary collapse

DI_CLIENT_IDS =
%w[
  GARMIN_CONNECT_MOBILE_ANDROID_DI_2025Q2
  GARMIN_CONNECT_MOBILE_ANDROID_DI_2024Q4
  GARMIN_CONNECT_MOBILE_ANDROID_DI
].freeze
DI_TOKEN_URL =
'https://diauth.garmin.com/di-oauth2-service/oauth/token'
DI_GRANT_TYPE =
'https://connectapi.garmin.com/di-oauth2-service/oauth/grant/service_ticket'
DI_USER_AGENT =
'GCM-Android-5.23'
DEFAULT_EXPIRES_IN =
64800

Class Method Summary collapse

Class Method Details

.attempt(cid, domain, ticket, service_url) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/git_fit/auth/garmin/di_exchange.rb', line 40

def attempt(cid, domain, ticket, service_url)
  resp = post(cid, domain, ticket, service_url)
  unless resp.code.to_i == 200
    warn "DI exchange #{cid}: HTTP #{resp.code}"
    return nil
  end

  token = JSON.parse(resp.body)
  token['di_client_id'] = cid
  token['expires_at'] = Time.now.to_i + (token['expires_in'] || DEFAULT_EXPIRES_IN).to_i
  if token['refresh_token_expires_in']
    token['refresh_token_expires_at'] = Time.now.to_i + token['refresh_token_expires_in'].to_i
  end
  token
rescue StandardError => e
  warn "DI exchange #{cid}: #{e.message}"
  nil
end

.build_url(domain) ⇒ Object



36
37
38
# File 'lib/git_fit/auth/garmin/di_exchange.rb', line 36

def build_url(domain)
  DI_TOKEN_URL.sub('garmin.com', domain)
end

.call(domain, ticket, service_url) ⇒ Object



27
28
29
30
31
32
33
34
# File 'lib/git_fit/auth/garmin/di_exchange.rb', line 27

def call(domain, ticket, service_url)
  DI_CLIENT_IDS.each do |cid|
    token = attempt(cid, domain, ticket, service_url)
    return token if token
  end

  raise GitFit::Sync::AuthError, 'All DI client IDs failed for ticket exchange'
end

.post(cid, domain, ticket, service_url) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/git_fit/auth/garmin/di_exchange.rb', line 59

def post(cid, domain, ticket, service_url)
  uri = URI(build_url(domain))
  req = Net::HTTP::Post.new(uri)
  req['Authorization'] = "Basic #{Base64.strict_encode64("#{cid}:")}"
  req['Accept'] = 'application/json,text/html;q=0.9,*/*;q=0.8'
  req['Content-Type'] = 'application/x-www-form-urlencoded'
  req['Cache-Control'] = 'no-cache'
  req['User-Agent'] = DI_USER_AGENT
  req.body = URI.encode_www_form(
    client_id: cid,
    service_ticket: ticket,
    grant_type: DI_GRANT_TYPE,
    service_url: service_url,
  )
  send_http(uri, req)
end

.send_http(uri, request) ⇒ Object



76
77
78
79
80
81
82
# File 'lib/git_fit/auth/garmin/di_exchange.rb', line 76

def send_http(uri, request)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = uri.scheme == 'https'
  http.open_timeout = 30
  http.read_timeout = 60
  http.start { |h| h.request(request) }
end