sigh 0.4.10 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -0
- data/bin/sigh +16 -1
- data/lib/assets/resign.sh +1 -1
- data/lib/sigh.rb +0 -1
- data/lib/sigh/developer_center.rb +83 -37
- data/lib/sigh/local_manage.rb +121 -0
- data/lib/sigh/manager.rb +9 -2
- data/lib/sigh/options.rb +1 -1
- data/lib/sigh/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8e062edc21ba3bd0acf86486468c8baab7c1403
|
4
|
+
data.tar.gz: 4de0a9955ef3f4dfe42da0859d3fdd3929d26ac0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8af5e581a46bf4d30d366924faba7b4ffb473fbaa1cb8b8ba43cf1527f1542210c508da12c7b9a118cada96ac2b931e04a57da452e42e04cbe60728965c8196f
|
7
|
+
data.tar.gz: 0ebf33635e3efa1e5c51ffbd425d64ab5a5a8a604d63d1e62e9ce4959c8c0f137525578c2bb06aaa0eaa889f0382adc09d1058901130ff46f470886f8f08e95f
|
data/README.md
CHANGED
@@ -147,6 +147,20 @@ You can pass more information using the command line:
|
|
147
147
|
|
148
148
|
sigh resign ./path/app.ipa -i "iPhone Distribution: Felix Krause" -p "my.mobileprovision"
|
149
149
|
|
150
|
+
# Manage
|
151
|
+
|
152
|
+
With `sigh manage` you can list all provisioning profiles installed locally.
|
153
|
+
|
154
|
+
sigh manage
|
155
|
+
|
156
|
+
Delete all expired provisioning profiles
|
157
|
+
|
158
|
+
sigh manage -e
|
159
|
+
|
160
|
+
Or delete all `iOS Team Provisioning Profile` by using a regular expression
|
161
|
+
|
162
|
+
sigh manage -p "iOS\ ?Team Provisioning Profile:"
|
163
|
+
|
150
164
|
## Environment Variables
|
151
165
|
In case you prefer environment variables:
|
152
166
|
|
data/bin/sigh
CHANGED
@@ -8,6 +8,7 @@ require 'credentials_manager/password_manager'
|
|
8
8
|
require 'credentials_manager/appfile_config'
|
9
9
|
require 'sigh/options'
|
10
10
|
require 'sigh/manager'
|
11
|
+
require 'sigh/local_manage'
|
11
12
|
|
12
13
|
HighLine.track_eof = false
|
13
14
|
|
@@ -20,7 +21,7 @@ class SighApplication
|
|
20
21
|
program :help, 'Author', 'Felix Krause <sigh@krausefx.com>'
|
21
22
|
program :help, 'Website', 'https://fastlane.tools'
|
22
23
|
program :help, 'GitHub', 'https://github.com/krausefx/sigh'
|
23
|
-
program :help_formatter, :compact
|
24
|
+
# program :help_formatter, :compact # https://github.com/commander-rb/commander/issues/12
|
24
25
|
|
25
26
|
always_trace!
|
26
27
|
|
@@ -47,6 +48,20 @@ class SighApplication
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
51
|
+
command :manage do |c|
|
52
|
+
c.syntax = 'sigh manage'
|
53
|
+
c.description = 'Manage installed provisioning profiles on your system.'
|
54
|
+
|
55
|
+
c.option '-e', '--clean_expired', 'Remove all expired provisioning profiles.'
|
56
|
+
|
57
|
+
c.option '-p', '--clean_pattern STRING', String, 'Remove any provisioning profiles that matches the regular expression.'
|
58
|
+
c.example 'Remove all "iOS Team Provisioning" provisioning profiles', 'sigh manage -p "iOS\ ?Team Provisioning Profile"'
|
59
|
+
|
60
|
+
c.action do |args, options|
|
61
|
+
Sigh::LocalManage.start(options, args)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
50
65
|
default_command :renew
|
51
66
|
|
52
67
|
run!
|
data/lib/assets/resign.sh
CHANGED
@@ -293,7 +293,7 @@ then
|
|
293
293
|
echo "Resigning embedded frameworks using certificate: '$CERTIFICATE'" >&2
|
294
294
|
for framework in "$FRAMEWORKS_DIR"/*
|
295
295
|
do
|
296
|
-
if [[ "$framework" == *.framework ]]
|
296
|
+
if [[ "$framework" == *.framework || "$framework" == *.dylib ]]
|
297
297
|
then
|
298
298
|
/usr/bin/codesign -f -s "$CERTIFICATE" "$framework"
|
299
299
|
checkStatus
|
data/lib/sigh.rb
CHANGED
@@ -17,8 +17,13 @@ module Sigh
|
|
17
17
|
|
18
18
|
cert = maintain_app_certificate # create/download the certificate
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
if @type == APPSTORE # both enterprise and App Store
|
21
|
+
type_name = "Distribution"
|
22
|
+
elsif @type == ADHOC
|
23
|
+
type_name = "AdHoc"
|
24
|
+
else
|
25
|
+
type_name = "Development"
|
26
|
+
end
|
22
27
|
cert_name ||= "#{type_name}_#{Sigh.config[:app_identifier]}.mobileprovision" # default name
|
23
28
|
cert_name += '.mobileprovision' unless cert_name.include?'mobileprovision'
|
24
29
|
|
@@ -48,41 +53,63 @@ module Sigh
|
|
48
53
|
@list_certs_url = wait_for_variable('profileDataURL')
|
49
54
|
# list_certs_url will look like this: "https://developer.apple.com/services-account/..../account/ios/profile/listProvisioningProfiles.action?content-type=application/x-www-form-urlencoded&accept=application/json&requestId=id&userLocale=en_US&teamId=xy&includeInactiveProfiles=true&onlyCountLists=true"
|
50
55
|
Helper.log.info "Fetching all available provisioning profiles..."
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
56
|
+
|
57
|
+
has_all_profiles = false
|
58
|
+
page_index = 1
|
59
|
+
page_size = 500
|
60
|
+
|
61
|
+
until has_all_profiles do
|
62
|
+
bundle_id = Sigh.config[:app_identifier]
|
63
|
+
|
64
|
+
certs = post_ajax(@list_certs_url, "{pageNumber: #{page_index}, pageSize: #{page_size}, sort: 'name%3dasc', search: 'name%3D#{bundle_id}%26type%3D#{bundle_id}%26status%3D#{bundle_id}%26appId%3D#{bundle_id}'}")
|
65
|
+
|
66
|
+
if certs
|
67
|
+
profile_name = Sigh.config[:provisioning_name]
|
68
|
+
|
69
|
+
profile_count = certs['provisioningProfiles'].count
|
70
|
+
|
71
|
+
Helper.log.info "Checking if profile is available. (#{profile_count} profiles found on page #{page_index})"
|
72
|
+
required_cert_types = (@type == DEVELOPMENT ? ['iOS Development'] : ['iOS Distribution', 'iOS UniversalDistribution'])
|
73
|
+
certs['provisioningProfiles'].each do |current_cert|
|
74
|
+
next unless required_cert_types.include?(current_cert['type'])
|
75
|
+
|
76
|
+
details = profile_details(current_cert['provisioningProfileId'])
|
77
|
+
|
78
|
+
if details['provisioningProfile']['appId']['identifier'] == bundle_id
|
79
|
+
|
80
|
+
next if profile_name && details['provisioningProfile']['name'] != profile_name
|
81
|
+
|
82
|
+
# that's an Ad Hoc profile. I didn't find a better way to detect if it's one ... skipping it
|
83
|
+
next if @type == APPSTORE && details['provisioningProfile']['deviceCount'] > 0
|
84
|
+
|
85
|
+
# that's an App Store profile ... skipping it
|
86
|
+
next if @type != APPSTORE && details['provisioningProfile']['deviceCount'] == 0
|
87
|
+
|
88
|
+
# We found the correct certificate
|
89
|
+
if force
|
90
|
+
renew_profile(current_cert['provisioningProfileId']) # This one needs to be forcefully renewed
|
91
|
+
return maintain_app_certificate(false) # recursive
|
92
|
+
elsif current_cert['status'] == 'Active'
|
93
|
+
return download_profile(details['provisioningProfile']['provisioningProfileId']) # this one is already finished. Just download it.
|
94
|
+
elsif ['Expired', 'Invalid'].include? current_cert['status']
|
95
|
+
# Broken profile
|
96
|
+
begin
|
97
|
+
renew_profile(current_cert['provisioningProfileId']) # This one needs to be renewed
|
98
|
+
return maintain_app_certificate(false) # recursive
|
99
|
+
rescue
|
100
|
+
# Something went wrong, just create a new one instead
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
break
|
105
|
+
end
|
83
106
|
end
|
84
107
|
|
85
|
-
|
108
|
+
if page_size <= profile_count
|
109
|
+
page_index += 1
|
110
|
+
else
|
111
|
+
has_all_profiles = true
|
112
|
+
end
|
86
113
|
end
|
87
114
|
end
|
88
115
|
|
@@ -181,6 +208,12 @@ module Sigh
|
|
181
208
|
profile_name ||= [app_identifier, @type].join(' ')
|
182
209
|
fill_in "provisioningProfileName", with: profile_name
|
183
210
|
click_next
|
211
|
+
|
212
|
+
if page.has_content?"Multiple profiles found with the name"
|
213
|
+
fill_in "provisioningProfileName", with: (profile_name + " sigh")
|
214
|
+
click_next
|
215
|
+
end
|
216
|
+
|
184
217
|
wait_for_elements('.row-details')
|
185
218
|
end
|
186
219
|
|
@@ -212,8 +245,21 @@ module Sigh
|
|
212
245
|
wait_for_elements('.row-details')
|
213
246
|
click_on "Done"
|
214
247
|
else
|
215
|
-
|
216
|
-
|
248
|
+
if @type != APPSTORE
|
249
|
+
# Add all devices
|
250
|
+
wait_for_elements('.selectAll.column')
|
251
|
+
sleep 3
|
252
|
+
unless all(:xpath, "//div[@class='selectAll column']/input").last["checked"]
|
253
|
+
all(:xpath, "//div[@class='selectAll column']/input").last.click # select all the devices
|
254
|
+
end
|
255
|
+
click_next
|
256
|
+
|
257
|
+
wait_for_elements('.row-details')
|
258
|
+
click_on "Done"
|
259
|
+
else
|
260
|
+
Helper.log.info "Looking for certificate: #{certificate}."
|
261
|
+
raise "Could not find certificate in the list of available certificates."
|
262
|
+
end
|
217
263
|
end
|
218
264
|
end
|
219
265
|
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Sigh
|
2
|
+
class LocalManage
|
3
|
+
LIST = "list"
|
4
|
+
CLEANUP = "cleanup"
|
5
|
+
|
6
|
+
def self.start(options, args)
|
7
|
+
command, clean_expired, clean_pattern = get_inputs(options, args)
|
8
|
+
if command == LIST
|
9
|
+
list_profiles
|
10
|
+
elsif command == CLEANUP
|
11
|
+
cleanup_profiles(clean_expired, clean_pattern)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.install_profile(profile)
|
16
|
+
Helper.log.info "Installing provisioning profile..."
|
17
|
+
profile_path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/"
|
18
|
+
profile_filename = ENV["SIGH_UDID"] + ".mobileprovision"
|
19
|
+
destination = profile_path + profile_filename
|
20
|
+
|
21
|
+
# If the directory doesn't exist, make it first
|
22
|
+
unless File.directory?(profile_path)
|
23
|
+
FileUtils.mkdir_p(profile_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
# copy to Xcode provisioning profile directory
|
27
|
+
FileUtils.copy profile, destination
|
28
|
+
|
29
|
+
if File.exists? destination
|
30
|
+
Helper.log.info "Profile installed at \"#{destination}\""
|
31
|
+
else
|
32
|
+
raise "Failed installation of provisioning profile at location: #{destination}".red
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.get_inputs(options, args)
|
37
|
+
clean_expired = options.clean_expired
|
38
|
+
clean_pattern = /#{options.clean_pattern}/ if options.clean_pattern
|
39
|
+
command = (clean_expired != nil || clean_pattern != nil) ? CLEANUP : LIST
|
40
|
+
return command, clean_expired, clean_pattern
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.list_profiles
|
44
|
+
profiles = load_profiles
|
45
|
+
|
46
|
+
now = DateTime.now
|
47
|
+
soon = (Date.today + 30).to_datetime
|
48
|
+
|
49
|
+
profiles_valid = profiles.select { |profile| profile["ExpirationDate"] > now && profile["ExpirationDate"] > soon }
|
50
|
+
if profiles_valid.count > 0
|
51
|
+
Helper.log.info "Provisioning profiles installed"
|
52
|
+
Helper.log.info "Valid:"
|
53
|
+
profiles_valid.each do |profile|
|
54
|
+
Helper.log.info profile["Name"].green
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
profiles_soon = profiles.select { |profile| profile["ExpirationDate"] > now && profile["ExpirationDate"] < soon }
|
59
|
+
if profiles_soon.count > 0
|
60
|
+
Helper.log.info ""
|
61
|
+
Helper.log.info "Expiring within 30 day:"
|
62
|
+
profiles_soon.each do |profile|
|
63
|
+
Helper.log.info profile["Name"].yellow
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
profiles_expired = profiles.select { |profile| profile["ExpirationDate"] < now }
|
68
|
+
if profiles_expired.count > 0
|
69
|
+
Helper.log.info ""
|
70
|
+
Helper.log.info "Expired:"
|
71
|
+
profiles_expired.each do |profile|
|
72
|
+
Helper.log.info profile["Name"].red
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
Helper.log.info ""
|
77
|
+
Helper.log.info "Summary"
|
78
|
+
Helper.log.info "#{profiles.count} installed profiles"
|
79
|
+
Helper.log.info "#{profiles_expired.count} are expired".red
|
80
|
+
Helper.log.info "#{profiles_soon.count} are valid but will expire within 30 days".yellow
|
81
|
+
Helper.log.info "#{profiles_valid.count} are valid".green
|
82
|
+
|
83
|
+
Helper.log.info "You can remove all expired profiles using `sigh manage -e`" if profiles_expired.count > 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.cleanup_profiles(expired = false, pattern = nil)
|
87
|
+
now = DateTime.now
|
88
|
+
|
89
|
+
profiles = load_profiles.select { |profile| (expired && profile["ExpirationDate"] < now) || (pattern != nil && profile["Name"] =~ pattern) }
|
90
|
+
|
91
|
+
Helper.log.info "The following provisioning profiles are either expired or matches your pattern:"
|
92
|
+
profiles.each do |profile|
|
93
|
+
Helper.log.info profile["Name"].red
|
94
|
+
end
|
95
|
+
|
96
|
+
if agree("Delete these provisioning profiles #{profiles.length}? (y/n) ", true)
|
97
|
+
profiles.each do |profile|
|
98
|
+
File.delete profile["Path"]
|
99
|
+
end
|
100
|
+
Helper.log.info "\n\nDeleted #{profiles.length} profiles".green
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.load_profiles
|
105
|
+
Helper.log.info "Loading Provisioning profiles from ~/Library/MobileDevice/Provisioning Profiles/"
|
106
|
+
profiles_path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/*.mobileprovision"
|
107
|
+
profile_paths = Dir[profiles_path]
|
108
|
+
|
109
|
+
profiles = []
|
110
|
+
profile_paths.each do |profile_path|
|
111
|
+
profile = Plist::parse_xml(`security cms -D -i '#{profile_path}'`)
|
112
|
+
profile['Path'] = profile_path
|
113
|
+
profiles << profile
|
114
|
+
end
|
115
|
+
|
116
|
+
profiles = profiles.sort_by {|profile| profile["Name"].downcase}
|
117
|
+
|
118
|
+
return profiles
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/sigh/manager.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'plist'
|
2
|
+
|
1
3
|
module Sigh
|
2
4
|
class Manager
|
3
5
|
def self.start
|
@@ -27,8 +29,13 @@ module Sigh
|
|
27
29
|
profile_filename = ENV["SIGH_UDID"] + ".mobileprovision"
|
28
30
|
destination = profile_path + profile_filename
|
29
31
|
|
32
|
+
# If the directory doesn't exist, make it first
|
33
|
+
unless File.directory?(profile_path)
|
34
|
+
FileUtils.mkdir_p(profile_path)
|
35
|
+
end
|
36
|
+
|
30
37
|
# copy to Xcode provisioning profile directory
|
31
|
-
FileUtils.copy profile, destination
|
38
|
+
(FileUtils.copy profile, destination rescue nil) # if the directory doesn't exist yet
|
32
39
|
|
33
40
|
if File.exists? destination
|
34
41
|
Helper.log.info "Profile installed at \"#{destination}\""
|
@@ -37,4 +44,4 @@ module Sigh
|
|
37
44
|
end
|
38
45
|
end
|
39
46
|
end
|
40
|
-
end
|
47
|
+
end
|
data/lib/sigh/options.rb
CHANGED
@@ -18,7 +18,7 @@ module Sigh
|
|
18
18
|
FastlaneCore::ConfigItem.new(key: :development,
|
19
19
|
env_name: "SIGH_DEVELOPMENT",
|
20
20
|
description: "Renew the development certificate instead of the production one",
|
21
|
-
is_string: false,
|
21
|
+
is_string: false,
|
22
22
|
default_value: false),
|
23
23
|
FastlaneCore::ConfigItem.new(key: :force,
|
24
24
|
env_name: "SIGH_FORCE",
|
data/lib/sigh/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sigh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fastlane_core
|
@@ -153,6 +153,7 @@ files:
|
|
153
153
|
- lib/sigh/dependency_checker.rb
|
154
154
|
- lib/sigh/developer_center.rb
|
155
155
|
- lib/sigh/developer_center_signing.rb
|
156
|
+
- lib/sigh/local_manage.rb
|
156
157
|
- lib/sigh/manager.rb
|
157
158
|
- lib/sigh/options.rb
|
158
159
|
- lib/sigh/profile_analyser.rb
|