download-profiles 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c8533cc7f76d098767baf67703a2ebba51372001
4
+ data.tar.gz: 27a68f10c07d41eff9791e3e0c64b15e6eeb4fea
5
+ SHA512:
6
+ metadata.gz: f30c46e0902a6b79af8fb671b2f988fc6dd39139c38362a3951d24efd5ca12b41b1af2c2a030a3fad81efa2fb28407fa0afdbfd20daa54987cc5fc1492d5e1f7
7
+ data.tar.gz: 8c146d5e638c1dba3e9a0c7716ceb89e1b883547217bfc4f5a90abe6e0250bc9276e9a0933f8f7878eb1286a8d759fc16acea488051b5a726c149009803cdda8
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ download-profiles (1.0.0)
5
+ certified (>= 0.1.0)
6
+ commander (~> 4.2.0)
7
+ mechanize (~> 2.7.3)
8
+ nokogiri (~> 1.6.3)
9
+ security (~> 0.1.2)
10
+ term-ansicolor (~> 1.0.7)
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ certified (1.0.0)
16
+ commander (4.2.1)
17
+ highline (~> 1.6.11)
18
+ diff-lcs (1.2.5)
19
+ domain_name (0.5.23)
20
+ unf (>= 0.0.5, < 1.0.0)
21
+ highline (1.6.21)
22
+ http-cookie (1.0.2)
23
+ domain_name (~> 0.5)
24
+ mechanize (2.7.3)
25
+ domain_name (~> 0.5, >= 0.5.1)
26
+ http-cookie (~> 1.0)
27
+ mime-types (~> 2.0)
28
+ net-http-digest_auth (~> 1.1, >= 1.1.1)
29
+ net-http-persistent (~> 2.5, >= 2.5.2)
30
+ nokogiri (~> 1.4)
31
+ ntlm-http (~> 0.1, >= 0.1.1)
32
+ webrobots (>= 0.0.9, < 0.2)
33
+ mime-types (2.4.3)
34
+ mini_portile (0.6.2)
35
+ net-http-digest_auth (1.4)
36
+ net-http-persistent (2.9.4)
37
+ nokogiri (1.6.5)
38
+ mini_portile (~> 0.6.0)
39
+ ntlm-http (0.1.1)
40
+ rake (10.4.2)
41
+ rspec (3.1.0)
42
+ rspec-core (~> 3.1.0)
43
+ rspec-expectations (~> 3.1.0)
44
+ rspec-mocks (~> 3.1.0)
45
+ rspec-core (3.1.7)
46
+ rspec-support (~> 3.1.0)
47
+ rspec-expectations (3.1.2)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.1.0)
50
+ rspec-mocks (3.1.3)
51
+ rspec-support (~> 3.1.0)
52
+ rspec-support (3.1.2)
53
+ security (0.1.3)
54
+ term-ansicolor (1.0.7)
55
+ unf (0.1.4)
56
+ unf_ext
57
+ unf_ext (0.0.6)
58
+ webrobots (0.1.1)
59
+
60
+ PLATFORMS
61
+ ruby
62
+
63
+ DEPENDENCIES
64
+ download-profiles!
65
+ rake
66
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Mattt Thompson (http://mattt.me/)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,182 @@
1
+ ![Cupertino](https://raw.github.com/nomad/nomad.github.io/assets/cupertino-banner.png)
2
+
3
+ Automate administrative tasks that you would normally have to do through the Apple Dev Center websites. Life's too short to manage device identifiers by hand!
4
+
5
+ > Cupertino is named after [Cupertino, CA](http://en.wikipedia.org/wiki/Cupertino,_California): home to Apple, Inc.'s world headquarters.
6
+ > It's part of a series of world-class command-line utilities for iOS development, which includes [Shenzhen](https://github.com/mattt/shenzhen) (Building & Distribution), [Houston](https://github.com/mattt/houston) (Push Notifications), [Venice](https://github.com/mattt/venice) (In-App Purchase Receipt Verification), [Dubai](https://github.com/mattt/dubai) (Passbook pass generation), and [Nashville](https://github.com/nomad/nashville) (iTunes Store API).
7
+
8
+ ## Requirements
9
+
10
+ Cupertino requires the [Xcode Command Line Tools](https://developer.apple.com/xcode/), which can be installed with the following command:
11
+
12
+ ```
13
+ $ xcode-select --install
14
+ ```
15
+
16
+ ## Installation
17
+
18
+ ```
19
+ $ gem install cupertino
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Authentication
25
+
26
+ ```
27
+ $ ios login
28
+ ```
29
+
30
+ _Credentials are saved in the Keychain. You will not be prompted for your username or password by commands while you are logged in. (Mac only)_
31
+
32
+ ### Devices
33
+
34
+ ```
35
+ $ ios devices:list
36
+
37
+ +------------------------------+---------------------------------------+
38
+ | Listing 2 devices. You can register 98 additional devices. |
39
+ +---------------------------+------------------------------------------+
40
+ | Device Name | Device Identifier |
41
+ +---------------------------+------------------------------------------+
42
+ | Johnny Appleseed iPad | 0123456789012345678901234567890123abcdef |
43
+ | Johnny Appleseed iPhone | abcdef0123456789012345678901234567890123 |
44
+ +---------------------------+------------------------------------------+
45
+
46
+ $ ios devices:add "iPad 1"=abc123
47
+ $ ios devices:add "iPad 2"=def456 "iPad 3"=ghi789 ...
48
+ ```
49
+
50
+ ### Provisioning Profiles
51
+
52
+ ```
53
+ $ ios profiles:list
54
+
55
+ +----------------------------------+--------------+---------+
56
+ | Profile | App ID | Status |
57
+ +----------------------------------+--------------+---------+
58
+ | iOS Team Provisioning Profile: * | ABCDEFG123.* | Valid |
59
+ +----------------------------------+--------------+---------+
60
+ ```
61
+
62
+ ---
63
+
64
+ ```
65
+ $ ios profiles:manage:devices
66
+ ```
67
+
68
+ _Opens an editor with a list of devices, each of which can be commented / uncommented to turn them off / on for that provisioning profile._
69
+
70
+ ```
71
+ # Comment / Uncomment Devices to Turn Off / On for Provisioning Profile
72
+ Johnny Appleseed iPad 0123456789012345678901234567890123abcdef
73
+ # Johnny Appleseed iPhone abcdef0123456789012345678901234567890123
74
+ ```
75
+
76
+ ```
77
+ $ ios profiles:devices:add MyApp_Development_Profile "Johnny Appleseed iPad"=0123456789012345678901234567890123abcdef "Johnny Appleseed iPhone"=abcdef0123456789012345678901234567890123
78
+ ```
79
+
80
+ _Adds (without an editor) a list of devices to a provisioning profile_
81
+
82
+ ```
83
+ $ ios profiles:devices:remove MyApp_Development_Profile "Johnny Old iPad"=0123456789012345678901234567890123abcdef "Johnny Old iPhone"=abcdef0123456789012345678901234567890123
84
+ ```
85
+
86
+ _Removes (without an editor) a list of devices from a provisioning profile_
87
+
88
+ ---
89
+
90
+ ```
91
+ $ ios profiles:devices:list MyApp_Development_Profile
92
+
93
+ +--------------------------+------------------------------------------+--------+
94
+ | Listing devices for provisioning profile MyApp_Development_Profile |
95
+ +--------------------------+------------------------------------------+--------+
96
+ | Device Name | Device Identifier | Active |
97
+ +--------------------------+------------------------------------------+--------+
98
+ | Person's iPhone 5 | 888888883e48a3e0458aab2691d565a8a63f7888 | Y |
99
+ +--------------------------+------------------------------------------+--------+
100
+
101
+ ```
102
+
103
+ ### App IDs
104
+
105
+ ```
106
+ $ ios app_ids:list
107
+
108
+ +-----------------------------+------------------------+-------------------+-------------------+
109
+ | Bundle Seed ID | Description | Development | Distribution |
110
+ +-----------------------------+------------------------+-------------------+-------------------+
111
+ | 123ABCDEFG.com.mattt.bundle | App Bundle Description | Passes | Passes |
112
+ | | | Data Protection | Data Protection |
113
+ | | | iCloud | iCloud |
114
+ | | | In-App Purchase | In-App Purchase |
115
+ | | | Game Center | Game Center |
116
+ | | | Push Notification | Push Notification |
117
+ +-----------------------------+------------------------+-------------------+-------------------+
118
+ ```
119
+
120
+ ```
121
+ $ ios app_ids:add "App Bundle Description"=123ABCDEFG.com.mattt.bundle
122
+ ```
123
+
124
+ ### Certificates
125
+
126
+ ```
127
+ $ ios certificates:list
128
+
129
+ +------------------+----------------------------------+-----------------+--------+
130
+ | Name | Provisioning Profiles | Expiration Date | Status |
131
+ +------------------+----------------------------------+-----------------+--------+
132
+ | Johnny Appleseed | iOS Team Provisioning Profile: * | Dec 23, 2012 | Issued |
133
+ +------------------+----------------------------------+-----------------+--------+
134
+ ```
135
+
136
+ ```
137
+ $ ios certificates:download
138
+ $ ios certificates:download --type distribution
139
+ $ ios certificates:download NAME
140
+ ```
141
+
142
+ ## CSV Output
143
+
144
+ The following commands will format their output as [comma-separated values](http://en.wikipedia.org/wiki/Comma-separated_values) when the `--format csv` argument is passed:
145
+
146
+ - `app_ids:list`
147
+ - `devices:list`
148
+ - `profiles:list`
149
+ - `profiles:manage:devices:list`
150
+
151
+ ## Commands
152
+
153
+ - `login`
154
+ - `logout`
155
+ - `devices:add`
156
+ - `devices:list`
157
+ - `profiles:list`
158
+ - `profiles:manage:devices`
159
+ - `profiles:manage:devices:add`
160
+ - `profiles:manage:devices:remove`
161
+ - `profiles:download`
162
+ - `profiles:download:all`
163
+ - `profiles:devices:list`
164
+ - `certificates:list`
165
+ - `certificates:download`
166
+ - `app_ids:list`
167
+
168
+ ## Proxies
169
+
170
+ Cupertino will access the provisioning portal through a proxy if the `HTTP_PROXY` environment variable is set, with optional credentials `HTTP_PROXY_USER` and `HTTP_PROXY_PASSWORD`.
171
+
172
+ ## Contact
173
+
174
+ Mattt Thompson
175
+
176
+ - http://github.com/mattt
177
+ - http://twitter.com/mattt
178
+ - m@mattt.me
179
+
180
+ ## License
181
+
182
+ Cupertino is available under the MIT license. See the LICENSE file for more info.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ gemspec = eval(File.read("download-profiles.gemspec"))
5
+
6
+ task :build => "#{gemspec.full_name}.gem"
7
+
8
+ file "#{gemspec.full_name}.gem" => gemspec.files + ["download-profiles.gemspec"] do
9
+ system "gem build download-profiles.gemspec"
10
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'commander/import'
4
+ require 'term/ansicolor'
5
+ require 'csv'
6
+
7
+ require 'download-profiles'
8
+
9
+ HighLine.track_eof = false # Fix for built-in Ruby
10
+ Signal.trap("INT") {} # Suppress backtrace when exiting command
11
+
12
+ program :version, Cupertino::VERSION
13
+ program :description, 'CLI tool for downloading iOS and Mac provisioning profiles'
14
+
15
+ program :help, 'Author', 'Radek Pietruszewski <this.is@radex.io>'
16
+ program :help, 'Website', 'https://github.com/radex'
17
+ program :help_formatter, :compact
18
+
19
+ default_command :download
20
+
21
+ require 'download-profiles/provisioning_portal'
22
+ require 'download-profiles/provisioning_portal/commands'
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require "download-profiles/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "download-profiles"
8
+ s.license = "MIT"
9
+ s.authors = ["Mattt Thompson", "Radek Pietruszewski"]
10
+ s.email = "this.is@radex.io"
11
+ s.homepage = 'https://github.com/radex/download-profiles'
12
+ s.version = Cupertino::VERSION
13
+ s.platform = Gem::Platform::RUBY
14
+ s.summary = "download-profiles"
15
+ s.description = "CLI tool for downloading iOS and Mac provisioning profiles"
16
+
17
+ s.add_dependency "commander", "~> 4.2.0"
18
+ s.add_dependency "term-ansicolor", "~> 1.0.7"
19
+ s.add_dependency "mechanize", "~> 2.7.3"
20
+ s.add_dependency "nokogiri", "~> 1.6.3"
21
+ s.add_dependency "security", "~> 0.1.2"
22
+ s.add_dependency "certified", ">= 0.1.0"
23
+
24
+ s.add_development_dependency "rspec"
25
+ s.add_development_dependency "rake"
26
+
27
+ s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
28
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
29
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
30
+ s.require_paths = ["lib"]
31
+ end
@@ -0,0 +1,146 @@
1
+ require 'mechanize'
2
+ require 'security'
3
+ require 'uri'
4
+ require 'json'
5
+ require 'date'
6
+ require 'time'
7
+ require 'logger'
8
+
9
+ module Cupertino
10
+ module ProvisioningPortal
11
+ class Agent < ::Mechanize
12
+ attr_accessor :username, :password, :team, :team_id
13
+
14
+ def initialize
15
+ super
16
+ @profile_csrf_headers = {}
17
+ self.user_agent_alias = 'Mac Safari'
18
+
19
+ self.log ||= Logger.new(STDOUT)
20
+ self.log.level = Logger::ERROR
21
+
22
+ if ENV['HTTP_PROXY']
23
+ uri = URI.parse(ENV['HTTP_PROXY'])
24
+ user = ENV['HTTP_PROXY_USER'] if ENV['HTTP_PROXY_USER']
25
+ password = ENV['HTTP_PROXY_PASSWORD'] if ENV['HTTP_PROXY_PASSWORD']
26
+
27
+ set_proxy(uri.host, uri.port, user || uri.user, password || uri.password)
28
+ end
29
+
30
+ pw = Security::InternetPassword.find(:server => Cupertino::ProvisioningPortal::HOST)
31
+ @username, @password = pw.attributes['acct'], pw.password if pw
32
+ end
33
+
34
+ def username=(value)
35
+ @username = value
36
+
37
+ pw = Security::InternetPassword.find(:a => self.username, :server => Cupertino::ProvisioningPortal::HOST)
38
+ @password = pw.password if pw
39
+ end
40
+
41
+ def get(uri, parameters = [], referer = nil, headers = {})
42
+ uri = ::File.join("https://#{Cupertino::ProvisioningPortal::HOST}", uri) unless /^https?/ === uri
43
+
44
+ 3.times do
45
+ super(uri, parameters, referer, headers)
46
+
47
+ return page unless page.respond_to?(:title)
48
+
49
+ case page.title
50
+ when /Sign in with your Apple ID/
51
+ login!
52
+ when /Select Team/
53
+ select_team!
54
+ else
55
+ return page
56
+ end
57
+ end
58
+
59
+ raise UnsuccessfulAuthenticationError
60
+ end
61
+
62
+ def list_profiles(platform, type)
63
+ url = case type
64
+ when :development
65
+ "https://developer.apple.com/account/#{platform}/profile/profileList.action?type=limited"
66
+ when :distribution
67
+ "https://developer.apple.com/account/#{platform}/profile/profileList.action?type=production"
68
+ else
69
+ raise ArgumentError, 'Provisioning profile type must be :development or :distribution'
70
+ end
71
+
72
+ self.pluggable_parser.default = Mechanize::File
73
+ get(url)
74
+
75
+ regex = /profileDataURL = "([^"]*)"/
76
+ profile_data_url = (page.body.match regex or raise UnexpectedContentError)[1]
77
+
78
+ profile_data_url += case type
79
+ when :development
80
+ '&type=limited'
81
+ when :distribution
82
+ '&type=production'
83
+ end
84
+
85
+ post(profile_data_url)
86
+ @profile_csrf_headers = {
87
+ 'csrf' => page.response['csrf'],
88
+ 'csrf_ts' => page.response['csrf_ts']
89
+ }
90
+
91
+ @profile_csrf_headers = {
92
+ 'csrf' => page.response['csrf'],
93
+ 'csrf_ts' => page.response['csrf_ts']
94
+ }
95
+
96
+ profile_data = page.content
97
+ parsed_profile_data = JSON.parse(profile_data)
98
+
99
+ profiles = []
100
+ parsed_profile_data['provisioningProfiles'].each do |row|
101
+ profile = ProvisioningProfile.new
102
+ profile.name = row['name']
103
+ profile.type = type
104
+ profile.platform = platform
105
+ profile.status = row['status']
106
+ profile.expiration = (Time.parse(row['dateExpire']) rescue nil)
107
+ profile.download_url = "https://developer.apple.com/account/#{platform}/profile/profileContentDownload.action?displayId=#{row['provisioningProfileId']}"
108
+ profile.edit_url = "https://developer.apple.com/account/#{platform}/profile/profileEdit.action?provisioningProfileId=#{row['provisioningProfileId']}"
109
+ profile.identifier = row['UUID']
110
+ profiles << profile
111
+ end
112
+
113
+ profiles
114
+ end
115
+
116
+ def download_profile(profile)
117
+ ext = (profile.platform == :ios) ? 'mobileprovision' : 'provisionprofile'
118
+ self.pluggable_parser.default = Mechanize::Download
119
+ download = get(profile.download_url)
120
+ download.save!(::File.expand_path("~/Library/MobileDevice/Provisioning Profiles/#{profile.identifier}.#{ext}"))
121
+ download.filename
122
+ end
123
+
124
+ private
125
+
126
+ def login!
127
+ if form = page.forms.first
128
+ form.fields_with(type: 'text').first.value = self.username
129
+ form.fields_with(type: 'password').first.value = self.password
130
+
131
+ form.submit
132
+ end
133
+ end
134
+
135
+ def select_team!
136
+ if form = page.form_with(:name => 'saveTeamSelection')
137
+ team_option = form.radiobutton_with(:value => self.team_id)
138
+ team_option.check
139
+
140
+ button = form.button_with(:name => 'action:saveTeamSelection!save')
141
+ form.click_button(button)
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,17 @@
1
+ command :login do |c|
2
+ c.syntax = 'ios login'
3
+ c.summary = 'Save account credentials'
4
+
5
+ c.action do |args, options|
6
+ say_warning "You are already authenticated" if Security::InternetPassword.find(:server => Cupertino::ProvisioningPortal::HOST)
7
+
8
+ user = ask "Username:"
9
+ pass = password "Password:"
10
+
11
+ if Security::InternetPassword.add(Cupertino::ProvisioningPortal::HOST, user, pass)
12
+ say_ok "Account credentials saved"
13
+ else
14
+ say_error "Error saving credentials"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ command :logout do |c|
2
+ c.syntax = 'ios logout'
3
+ c.summary = 'Remove account credentials'
4
+
5
+ c.action do |args, options|
6
+ say_error "You are not authenticated" and abort unless Security::InternetPassword.find(:server => Cupertino::ProvisioningPortal::HOST)
7
+
8
+ if Security::InternetPassword.delete(:server => Cupertino::ProvisioningPortal::HOST)
9
+ say_ok "Account credentials removed"
10
+ else
11
+ say_error "Error removing credentials"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ command :download do |c|
2
+ c.syntax = 'download-profiles'
3
+ c.summary = 'Download provisioning profiles'
4
+ c.description = "By default, downloads and installs all (development, distribution, iOS, Mac) provisioning profiles. Pass appropriate options to constrain."
5
+
6
+ c.option '--platform [PLATFORM]', [:ios, :mac, :all], "Platform of profile (ios, mac or all)"
7
+ c.option '--type [TYPE]', [:development, :distribution, :all], "Type of profile (development, distribution or all)"
8
+
9
+ c.action do |args, options|
10
+ # parse options
11
+ platform = options.platform ? options.platform.downcase.to_sym : :all
12
+ type = options.type ? options.type.downcase.to_sym : :all
13
+
14
+ platforms = (platform == :all) ? [:ios, :mac] : [platform]
15
+ types = (type == :all) ? [:development, :distribution] : [type]
16
+
17
+ # get list of profiles
18
+ profiles =
19
+ platforms.product(types).flat_map { |platform, type| try{agent.list_profiles(platform, type)} }
20
+ .select { |profile| profile.status == 'Active'}
21
+
22
+ say_warning "No active #{type} profiles found." and abort if profiles.empty?
23
+
24
+ # download
25
+ failure = false
26
+ profiles.each do |profile|
27
+ if filename = agent.download_profile(profile)
28
+ say "Downloaded #{filename}"
29
+ else
30
+ say_error "Could not download profile: '#{profile.name}'"
31
+ failure = true
32
+ end
33
+ end
34
+
35
+ if failure
36
+ say_warning "Not all profiles downloaded successfully"
37
+ else
38
+ say_ok "All profiles downloaded successfully"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ include Cupertino::ProvisioningPortal
2
+
3
+ require 'download-profiles/provisioning_portal/helpers'
4
+ include Cupertino::ProvisioningPortal::Helpers
5
+
6
+ global_option('-u', '--username USER', 'Username') { |arg| agent.username = arg unless arg.nil? }
7
+ global_option('-p', '--password PASSWORD', 'Password') { |arg| agent.password = arg unless arg.nil? }
8
+ global_option('--team TEAM', 'Team') { |arg| agent.team = arg if arg }
9
+ global_option('--info', 'Set log level to INFO') { agent.log.level = Logger::INFO }
10
+ global_option('--debug', 'Set log level to DEBUG') { agent.log.level = Logger::DEBUG }
11
+ global_option('--format FORMAT', [:table, :csv], "Set output format (default: table)")
12
+
13
+ require 'download-profiles/provisioning_portal/commands/profiles'
14
+ require 'download-profiles/provisioning_portal/commands/login'
15
+ require 'download-profiles/provisioning_portal/commands/logout'
@@ -0,0 +1,65 @@
1
+ # Monkey Patch Commander::UI to alias password to avoid conflicts
2
+ module Commander::UI
3
+ alias :pw :password
4
+ end
5
+
6
+ class String
7
+ include Term::ANSIColor
8
+ end
9
+
10
+ module Cupertino
11
+ module ProvisioningPortal
12
+ module Helpers
13
+ def agent
14
+ unless @agent
15
+ @agent = Cupertino::ProvisioningPortal::Agent.new
16
+
17
+ @agent.instance_eval do
18
+ def username
19
+ @username ||= ask "Username:"
20
+ end
21
+
22
+ def password
23
+ @password ||= pw "Password:"
24
+ end
25
+
26
+ def team_id
27
+ unless @team_id
28
+ teams = []
29
+ page.form_with(:name => 'saveTeamSelection').radiobuttons.each do |radio|
30
+ name = page.search(".label-primary[for=\"#{radio.dom_id}\"]").first.text.strip
31
+ programs = page.search(".label-secondary[for=\"#{radio.dom_id}\"]").first.text.strip.split(/\,\s+/)
32
+ teams << Team.new(name, programs, radio.value)
33
+ end
34
+
35
+ unless team = teams.detect{|t| t.name == @team || t.identifier == @team}
36
+ team = choose("Select a team:", *teams)
37
+ end
38
+
39
+ @team_id = team.identifier
40
+ end
41
+
42
+ @team_id
43
+ end
44
+ end
45
+ end
46
+
47
+ @agent
48
+ end
49
+
50
+ def pluralize(n, singular, plural = nil)
51
+ n.to_i == 1 ? "1 #{singular}" : "#{n} #{plural || singular + 's'}"
52
+ end
53
+
54
+ def try
55
+ return unless block_given?
56
+
57
+ begin
58
+ yield
59
+ rescue UnsuccessfulAuthenticationError
60
+ say_error "Could not authenticate with Apple Developer Center. Check that your username & password are correct, and that your membership is valid and all pending Terms of Service & agreements are accepted. If this problem continues, try logging into https://developer.apple.com/membercenter/ from a browser to see what's going on." and abort
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,19 @@
1
+ require 'mechanize'
2
+ require 'certified'
3
+
4
+ module Cupertino
5
+ module ProvisioningPortal
6
+ HOST = "developer.apple.com"
7
+
8
+ class UnsuccessfulAuthenticationError < RuntimeError; end
9
+ class UnexpectedContentError < RuntimeError; end
10
+
11
+ class ProvisioningProfile < Struct.new(:name, :type, :platform, :app_id, :status, :expiration, :download_url, :edit_url, :identifier)
12
+ def to_s
13
+ "#{self.name}"
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ require 'download-profiles/provisioning_portal/agent'
@@ -0,0 +1,3 @@
1
+ module Cupertino
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1 @@
1
+ require 'download-profiles/version'
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: download-profiles
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mattt Thompson
8
+ - Radek Pietruszewski
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-01-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: commander
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 4.2.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 4.2.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: term-ansicolor
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 1.0.7
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 1.0.7
42
+ - !ruby/object:Gem::Dependency
43
+ name: mechanize
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 2.7.3
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 2.7.3
56
+ - !ruby/object:Gem::Dependency
57
+ name: nokogiri
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 1.6.3
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.6.3
70
+ - !ruby/object:Gem::Dependency
71
+ name: security
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.1.2
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 0.1.2
84
+ - !ruby/object:Gem::Dependency
85
+ name: certified
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 0.1.0
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 0.1.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rake
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: CLI tool for downloading iOS and Mac provisioning profiles
127
+ email: this.is@radex.io
128
+ executables:
129
+ - download-profiles
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - "./Gemfile"
134
+ - "./Gemfile.lock"
135
+ - "./LICENSE"
136
+ - "./README.md"
137
+ - "./Rakefile"
138
+ - "./download-profiles.gemspec"
139
+ - "./lib/download-profiles.rb"
140
+ - "./lib/download-profiles/provisioning_portal.rb"
141
+ - "./lib/download-profiles/provisioning_portal/agent.rb"
142
+ - "./lib/download-profiles/provisioning_portal/commands.rb"
143
+ - "./lib/download-profiles/provisioning_portal/commands/login.rb"
144
+ - "./lib/download-profiles/provisioning_portal/commands/logout.rb"
145
+ - "./lib/download-profiles/provisioning_portal/commands/profiles.rb"
146
+ - "./lib/download-profiles/provisioning_portal/helpers.rb"
147
+ - "./lib/download-profiles/version.rb"
148
+ - bin/download-profiles
149
+ homepage: https://github.com/radex/download-profiles
150
+ licenses:
151
+ - MIT
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 2.2.2
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: download-profiles
173
+ test_files: []