Class: Spaceship::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/spaceship/ui.rb,
lib/spaceship/portal/ui/select_team.rb,
lib/spaceship/client.rb

Direct Known Subclasses

DUClient, PortalClient, TunesClient

Defined Under Namespace

Classes: AppleTimeoutError, InvalidUserCredentialsError, NoUserCredentialsError, UnauthorizedAccessError, UnexpectedResponse, UserInterface

Constant Summary collapse

PROTOCOL_VERSION =
"QH65B2"
USER_AGENT =
"Spaceship #{Spaceship::VERSION}"

Instance Attribute Summary collapse

Automatic Paging collapse

Login and Team Selection collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeClient

Returns a new instance of Client.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/spaceship/client.rb', line 71

def initialize
  options = {
   request: {
      timeout:       300,
      open_timeout:  300
    }
  }
  @cookie = HTTP::CookieJar.new
  @client = Faraday.new(self.class.hostname, options) do |c|
    c.response :json, content_type: /\bjson$/
    c.response :xml, content_type: /\bxml$/
    c.response :plist, content_type: /\bplist$/
    c.use :cookie_jar, jar: @cookie
    c.adapter Faraday.default_adapter

    if ENV['DEBUG']
      # for debugging only
      # This enables tracking of networking requests using Charles Web Proxy
      c.response :logger
      c.proxy "https://127.0.0.1:8888"
    end
  end
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



22
23
24
# File 'lib/spaceship/client.rb', line 22

def client
  @client
end

#loggerObject

The logger in which all requests are logged /tmp/spaceship_.log by default



29
30
31
# File 'lib/spaceship/client.rb', line 29

def logger
  @logger
end

#userObject

The user that is currently logged in



25
26
27
# File 'lib/spaceship/client.rb', line 25

def user
  @user
end

Class Method Details

.hostnameObject



67
68
69
# File 'lib/spaceship/client.rb', line 67

def self.hostname
  raise "You must implemented self.hostname"
end

.login(user = nil, password = nil) ⇒ Spaceship::Client

Authenticates with Apple’s web services. This method has to be called once to generate a valid session. The session will automatically be used from then on.

This method will automatically use the username from the Appfile (if available) and fetch the password from the Keychain (if available)

Parameters:

  • user (String) (defaults to: nil)

    (optional): The username (usually the email address)

  • password (String) (defaults to: nil)

    (optional): The password

Returns:

Raises:

  • InvalidUserCredentialsError: raised if authentication failed



58
59
60
61
62
63
64
65
# File 'lib/spaceship/client.rb', line 58

def self.(user = nil, password = nil)
  instance = self.new
  if instance.(user, password)
    instance
  else
    raise InvalidUserCredentialsError.new, "Invalid User Credentials"
  end
end

Instance Method Details

Return the session cookie.

Returns:



119
120
121
# File 'lib/spaceship/client.rb', line 119

def cookie
  @cookie.map(&:to_s).join(';')
end

#login(user = nil, password = nil) ⇒ Spaceship::Client

Authenticates with Apple’s web services. This method has to be called once to generate a valid session. The session will automatically be used from then on.

This method will automatically use the username from the Appfile (if available) and fetch the password from the Keychain (if available)

Parameters:

  • user (String) (defaults to: nil)

    (optional): The username (usually the email address)

  • password (String) (defaults to: nil)

    (optional): The password

Returns:

Raises:

  • InvalidUserCredentialsError: raised if authentication failed



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/spaceship/client.rb', line 166

def (user = nil, password = nil)
  if user.to_s.empty? or password.to_s.empty?
    require 'credentials_manager'

    keychain_entry = CredentialsManager::AccountManager.new(user: user, password: password)
    user ||= keychain_entry.user
    password = keychain_entry.password
  end

  if user.to_s.strip.empty? or password.to_s.strip.empty?
    raise NoUserCredentialsError.new, "No login data provided"
  end

  self.user = user
  @password = password
  begin
    (user, password)
  rescue InvalidUserCredentialsError => ex
    raise ex unless keychain_entry

    if keychain_entry.invalid_credentials
      (user)
    else
      puts "Please run this tool again to apply the new password"
    end
  end
end

#page_sizeObject

The page size we want to request, defaults to 500



128
129
130
# File 'lib/spaceship/client.rb', line 128

def page_size
  @page_size ||= 500
end

#pagingObject

Handles the paging for you… for free Just pass a block and use the parameter as page number



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/spaceship/client.rb', line 134

def paging
  page = 0
  results = []
  loop do
    page += 1
    current = yield(page)

    results += current

    break if (current || []).count < page_size # no more results
  end

  return results
end

#UIObject

Public getter for all UI related code rubocop:disable Style/MethodName



11
12
13
# File 'lib/spaceship/ui.rb', line 11

def UI
  UserInterface.new(self)
end

#with_retry(tries = 5, &_block) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/spaceship/client.rb', line 194

def with_retry(tries = 5, &_block)
  return yield
rescue Faraday::Error::ConnectionFailed, Faraday::Error::TimeoutError, AppleTimeoutError, Errno::EPIPE => ex # New Faraday version: Faraday::TimeoutError => ex
  unless (tries -= 1).zero?
    logger.warn("Timeout received: '#{ex.message}'.  Retrying after 3 seconds (remaining: #{tries})...")
    sleep 3 unless defined? SpecHelper
    retry
  end
  raise ex # re-raise the exception
rescue UnauthorizedAccessError => ex
  if @loggedin && !(tries -= 1).zero?
    msg = "Auth error received: '#{ex.message}'. Login in again then retrying after 3 seconds (remaining: #{tries})..."
    puts msg if $verbose
    logger.warn msg
    (self.user, @password)
    sleep 3 unless defined? SpecHelper
    retry
  end
  raise ex # re-raise the exception
end