appsendr 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,375 @@
1
+ module AppSendr::Command
2
+ class Portal < Base
3
+
4
+ attr_accessor :credentials
5
+
6
+ require 'rubygems'
7
+ require 'mechanize'
8
+
9
+ @@agent = Mechanize.new
10
+ @@agent.user_agent_alias = 'Mac FireFox'
11
+ @@agent.follow_meta_refresh = true
12
+
13
+ @@available_devices = []
14
+ @@available_profiles = []
15
+
16
+ LOGIN_URL = 'https://developer.apple.com/ios/manage/overview/index.action'
17
+ DEVICES_URL = "https://developer.apple.com/ios/manage/devices/index.action"
18
+ DEVICE_BULK_UPLOAD_URL = "http://developer.apple.com/ios/manage/devices/saveupload.action"
19
+ SAVE_TEAM_URL = "http://developer.apple.com/membercenter/saveTeamSelection.action"
20
+
21
+ DEV_PROVISIONING_PROFILE_URL = "https://developer.apple.com/ios/manage/provisioningprofiles/index.action"
22
+ DIST_PROVISIONING_PROFILE_URL = "https://developer.apple.com/ios/manage/provisioningprofiles/viewDistributionProfiles.action"
23
+
24
+ CREATE_ADHOC_PROFILE_URL = "http://developer.apple.com/ios/manage/provisioningprofiles/create.action?type=2"
25
+ DOWNLOAD_PROFILE_URL_WO_ID ="/ios/manage/provisioningprofiles/download.action?blobId="
26
+ EDIT_PROFILE_URL_WO_ID = "/ios/manage/provisioningprofiles/edit.action?provDisplayId="
27
+
28
+
29
+ def index
30
+
31
+ result = check_for_manual_login
32
+
33
+ if result
34
+ @available_devices = get_devices
35
+ @available_dev_profiles = development_provisioning_profiles
36
+ @available_dist_profiles = distribution_provisioning_profiles
37
+
38
+ display "#{@available_devices.length} Devices"
39
+ display "#{@available_dev_profiles.length} Development Profiles"
40
+ display "#{@available_dist_profiles.length} Distribution Profiles"
41
+
42
+ end
43
+ end
44
+
45
+ def devices
46
+ result = check_for_manual_login
47
+
48
+ if result
49
+ @available_devices = get_devices
50
+ @available_devices.each{|device|
51
+ display "#{device[:name]} - #{device[:id]}"
52
+ }
53
+ end
54
+ end
55
+
56
+ def profiles
57
+ result = check_for_manual_login
58
+
59
+ if result
60
+ @available_dev_profiles = development_provisioning_profiles
61
+ @available_dist_profiles = distribution_provisioning_profiles
62
+
63
+ display "\nDevelopment Profiles\n"
64
+ @available_dev_profiles.each{|profile|
65
+
66
+ display "#{profile[:name]} - #{profile[:app_id]}"
67
+ }
68
+ display "\nDistribution Profiles\n"
69
+ @available_dist_profiles.each{|profile|
70
+ display "#{profile[:name]} - #{profile[:app_id]}"
71
+ }
72
+
73
+
74
+ end
75
+ end
76
+
77
+ def update
78
+
79
+ @remote_devices = appsendr.devices(nil,false)
80
+ @available_devices = get_devices
81
+
82
+ ## get devices for users for this app
83
+ ## get all devices from portal
84
+ ## reconcile
85
+ ## add device not on portal
86
+ ## get profile for app
87
+ ##
88
+ end
89
+
90
+
91
+ private
92
+ def check_for_manual_login
93
+ username = extract_option('--username', false)
94
+ password = extract_option('--password', false)
95
+
96
+ result = false
97
+ if username and password
98
+ result = login(username,password)
99
+
100
+ error "\nAuthentication failed" unless result
101
+
102
+ else
103
+ result = login(user,pass)
104
+ end
105
+
106
+ return result
107
+ end
108
+
109
+
110
+ ###
111
+
112
+
113
+ def login(username, password)
114
+
115
+ # Get login page
116
+ #puts "- fetching login page"
117
+ #page = agent.get('https://phobos.apple.com/WebObjects/MZLabel.woa/wa/default')
118
+ page = @@agent.get(LOGIN_URL)
119
+
120
+
121
+ # Submit form to login
122
+ login_form = page.forms.first
123
+ login_form['theAccountName']=username
124
+ login_form['theAccountPW']=password
125
+ page = @@agent.submit(login_form)
126
+
127
+ # Fail if it looks like we ended up back at a login page
128
+ if page.form('appleConnectForm')
129
+ #puts "Error: Login failed"
130
+ return nil
131
+ #exit
132
+ else
133
+ select_form = page.form('saveTeamSelection')
134
+ if select_form
135
+ options = []
136
+ select_form.fields.first.options.each{|option|
137
+ display "#{options.length + 1}. #{option.text}"
138
+ options.push([option.text,option.value])
139
+
140
+ }
141
+ print "Enter the # for the account you wish to login to: "
142
+ selection = ask
143
+ if selection.to_i > (options.length )
144
+ error "Invalid selection"
145
+ return nil
146
+
147
+ end
148
+
149
+ team = options[selection.to_i - 1]
150
+ select_form['memberDisplayId'] = team[1]
151
+ page = @@agent.submit(select_form, select_form.buttons[1])
152
+ return page
153
+ else
154
+ return page
155
+ end
156
+ end
157
+ end
158
+
159
+ def get_details(username, password)
160
+ if login(username,password)
161
+ @available_devices = get_devices
162
+ @available_dev_profiles = development_provisioning_profiles
163
+ @available_dist_profiles = distribution_provisioning_profiles
164
+ display ""
165
+
166
+
167
+ end
168
+ end
169
+
170
+
171
+ #####
172
+ # provisioning
173
+ def get_devices
174
+ page = @@agent.get(DEVICES_URL)
175
+ table = page.at("//table/tbody") # This passes through to hpricot
176
+ devices = []
177
+ return devices unless table
178
+ table.children.each{|tr|
179
+ children = tr.children
180
+ device_name = children[2].content.strip
181
+ device_id = children[4].content.strip
182
+ devices.push({:name => device_name, :id => device_id })
183
+ }
184
+
185
+ return devices;
186
+
187
+ end
188
+
189
+ def upload_bulk_file
190
+ temp_file = TempFile.new('bulk_upload')
191
+ temp_file.write(device_file)
192
+ temp_file.close
193
+ @@agent.post(DEVICE_BULK_UPLOAD_URL, {:upload => temp_file})
194
+ end
195
+
196
+
197
+
198
+ #####
199
+ # provisioning
200
+
201
+ def provisioning_profiles(url)
202
+ page = @@agent.get(url)
203
+ table = page.at("//table/tbody")
204
+ profiles = []
205
+ return profiles unless table
206
+
207
+ table.children.each{|tr|
208
+ children = tr.children
209
+ cert_key = children[0].children[0]['value'].strip
210
+ cert_name = children[2].content.strip
211
+ app_id = children[4].content.strip
212
+ profiles.push({:name => cert_name, :id => cert_key, :app_id => app_id })
213
+ #p children
214
+ }
215
+ return profiles
216
+ end
217
+
218
+ def development_provisioning_profiles
219
+ provisioning_profiles(DEV_PROVISIONING_PROFILE_URL)
220
+ end
221
+
222
+ def distribution_provisioning_profiles
223
+
224
+ provisioning_profiles(DIST_PROVISIONING_PROFILE_URL)
225
+
226
+ end
227
+
228
+
229
+ def download_provisioning_profile(id)
230
+ page = @@agent.get(DOWNLOAD_PROFILE_URL_WO_ID+id)
231
+ return page
232
+ end
233
+
234
+ def edit_provisioning_profile(id)
235
+ page = @@agent.get(EDIT_PROFILE_URL_WO_ID+id)
236
+ end
237
+
238
+ def create_provisioning_profile
239
+ page = @@agent.get(CREATE_ADHOC_PROFILE_URL) #adhoc profiles
240
+ create_form = page.forms.first
241
+
242
+ end
243
+
244
+ ## credentials
245
+
246
+ def user # :nodoc:
247
+ get_credentials
248
+ @credentials[0]
249
+ end
250
+
251
+ def pass # :nodoc:
252
+ get_credentials
253
+ @credentials[1]
254
+ end
255
+
256
+
257
+ def reauthorize
258
+ user_pass = ask_for_credentials
259
+ @credentials = auth_credentials(user_pass[0],user_pass[1])
260
+ write_credentials
261
+ end
262
+
263
+ def auth_credentials(username,password)
264
+ login_agent = Mechanize.new
265
+
266
+ page = login_agent.get(LOGIN_URL)
267
+
268
+
269
+ # Submit form to login
270
+ login_form = page.forms.first
271
+ login_form['theAccountName']=username
272
+ login_form['theAccountPW']=password
273
+ page = login_agent.submit(login_form);
274
+ # Fail if it looks like we ended up back at a login page
275
+ if (!page.form('appleConnectForm').nil?)
276
+ return false
277
+ else
278
+ return [username,password]
279
+ end
280
+ end
281
+
282
+ def get_credentials # :nodoc:
283
+ return if @credentials
284
+ unless @credentials = read_credentials
285
+ user_pass = ask_for_credentials
286
+
287
+ @credentials = auth_credentials(user_pass[0],user_pass[1])
288
+ retry unless @credentials
289
+ save_credentials
290
+ end
291
+ @credentials
292
+ end
293
+
294
+ def read_credentials
295
+ File.exists?(credentials_file) and File.read(credentials_file).split("\n")
296
+ end
297
+
298
+ def echo_off
299
+ system "stty -echo"
300
+ end
301
+
302
+ def echo_on
303
+ system "stty echo"
304
+ end
305
+
306
+ def ask_for_credentials
307
+ puts "Enter your Apple Developer credentials. (These are never sent to AppSendr)"
308
+
309
+ print "Username: "
310
+ user = ask
311
+
312
+ print "Password: "
313
+ password = ask_for_password
314
+
315
+ [ user, password ]
316
+ end
317
+
318
+ def ask_for_password
319
+ echo_off
320
+ password = ask
321
+ puts
322
+ echo_on
323
+ return password
324
+ end
325
+
326
+ def save_credentials
327
+ begin
328
+ write_credentials
329
+ # if self.credentials
330
+ # delete_credentials
331
+ # raise e unless retry_login?
332
+ #
333
+ # display "\nAuthentication failed"
334
+ # user_pass = ask_for_credentials
335
+ # @credentials = auth_credentials(user_pass[0],user_pass[1])
336
+ # retry
337
+ rescue Exception => e
338
+ delete_credentials
339
+ end
340
+ end
341
+
342
+ def retry_login?
343
+ @login_attempts ||= 0
344
+ @login_attempts += 1
345
+ @login_attempts < 3
346
+ end
347
+
348
+ def write_credentials
349
+ FileUtils.mkdir_p(File.dirname(credentials_file))
350
+ File.open(credentials_file, 'w') do |f|
351
+ f.puts self.credentials
352
+ end
353
+ set_credentials_permissions
354
+ end
355
+
356
+ def set_credentials_permissions
357
+ FileUtils.chmod 0700, File.dirname(credentials_file)
358
+ FileUtils.chmod 0600, credentials_file
359
+ end
360
+
361
+ def delete_credentials
362
+ FileUtils.rm_f(credentials_file)
363
+ end
364
+
365
+ def credentials_file
366
+ "#{home_directory}/#{AppSendr::APPDROPPR_DIR}/portal_credentials"
367
+ end
368
+
369
+ def credentials_setup?
370
+ File.exist?(credentials_file)
371
+ end
372
+
373
+
374
+ end
375
+ end
@@ -33,16 +33,15 @@ module AppSendr::Command
33
33
  def add
34
34
 
35
35
  if require_project(2,"add testers","an email and name", true)
36
- f = testers_file_append
37
- return unless f
38
36
  email = args.shift.strip
39
37
  name = args.join(" ").strip
40
- f.puts "#{email},#{name}"
41
- f.close
38
+
42
39
  begin
43
40
  response = appsendr.add_tester(read_app_id,email,name)
41
+ message "#{email} added"
42
+
44
43
  rescue RestClient::RequestFailed => e
45
- display "=== Errors"
44
+ message "Errors"
46
45
  response = JSON.parse(e.http_body)
47
46
  response['message'].each{|err|
48
47
  display err.join(" ")
@@ -55,45 +54,29 @@ module AppSendr::Command
55
54
  def remove
56
55
  if require_project(1,"remove testers","an email")
57
56
  entered_email = args.shift.strip
58
-
59
- f = testers_file
60
- return unless f
61
- out = ""
62
- found_email = nil
63
- f.each do |line|
64
- tester = line.split(',')
65
- email = tester.first.strip
66
- if email == entered_email
67
- found_email = email
68
- out << ""
69
- else
70
- out << line
71
- end
72
- end
73
- f.pos = 0
74
- f.print out
75
- f.truncate(f.pos)
76
-
77
57
  appsendr.remove_tester(read_app_id,entered_email)
58
+ message "Removed tester"
78
59
 
79
60
  end
80
61
  end
81
62
 
82
63
  def clear
83
64
  if require_project(0,"clear testers",nil)
84
- f = testers_file_truncate
85
- return unless f
86
- f.close
87
-
65
+ message "Removing all testers"
88
66
  appsendr.add_tester(read_app_id)
89
67
 
90
68
  end
91
69
  end
92
70
 
93
71
  def notify
94
- require_project_dir("to notify testers")
95
- require_project_droppr
96
- appsendr.notify(read_app_id)
72
+ if require_project(0,"clear testers",nil)
73
+ require_project_droppr
74
+ message "Notifying testers"
75
+ group = args.join(" ").strip
76
+
77
+ appsendr.notify(read_app_id,group)
78
+ end
79
+
97
80
 
98
81
  end
99
82
 
@@ -1,5 +1,5 @@
1
1
  module AppSendr
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.5"
3
3
  PROJECT_DIR = ".appsendr"
4
4
  APPDROPPR_DIR = ".appsendr"
5
5
  end
@@ -44,13 +44,40 @@ module AppSendr
44
44
  File.exists?(project_appsendr_app) and File.read(project_appsendr_app).split("\n")
45
45
  end
46
46
 
47
+ def error(msg)
48
+ STDERR.puts(msg)
49
+ exit 1
50
+ end
51
+
52
+ def message(msg)
53
+ puts("=== #{msg}")
54
+ end
55
+
56
+ ### split
57
+ def is_file_to_large?(file)
58
+ in_mb = size_of_file(file).to_f
59
+ if in_mb > 10
60
+ return true
61
+ else
62
+ return false
63
+ end
64
+ end
65
+
66
+ def size_of_file(file)
67
+ size = File.size(file)
68
+ mb = 1024.0 * 1024.0
69
+ in_mb = size / mb
70
+
71
+ end
72
+
73
+ ## droppr
47
74
  def has_project_droppr?
48
75
  return false unless File.directory?(project_appsendr)
49
76
  return File.exist?(project_appsendr_app)
50
77
  end
51
78
 
52
79
  def require_project_droppr
53
- error "Project directory doesn't exist. Have you created an app droppr for this app?" unless has_project_droppr?
80
+ error "Project directory doesn't exist. Have you created an this app on appsendr?" unless has_project_droppr?
54
81
  end
55
82
 
56
83
  def require_project_dir(action)
@@ -98,16 +125,13 @@ module AppSendr
98
125
  else
99
126
  require_project_dir(action)
100
127
  error "This app is already linked to appsendr." unless !has_project_droppr?
101
-
102
128
  end
103
129
 
104
130
  return false
105
131
  end
106
-
107
- def error(msg)
108
- STDERR.puts(msg)
109
- exit 1
110
- end
132
+
133
+
134
+
111
135
  end
112
136
  end
113
137