motion-provisioning 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b943a1370641d985fcc5ff8b17e1d7d371972e491c8af1b2f34ebd9bbdb950ef
4
- data.tar.gz: 322e1d8e91d79cad29bd87f07689b9290406e116e11d33c5155b125e53fb745f
3
+ metadata.gz: 48e42fb68d7a25eb15c82c1aa8a5b3a1c6e228ced5d59682f75a4c115a30fcae
4
+ data.tar.gz: 88e05257a72160fb218b36780c16ce6c9a93094a2121820f3294a80f7a7c79e2
5
5
  SHA512:
6
- metadata.gz: b5f3fa4e86d33e2a03e4bb7f54b3d61242eeab905a0b3876df8bf9e698d3933fe237db8d49e1403570d5b33e87c21dfd4a4c4d6aacb8ad727bb2e7c2697f40d5
7
- data.tar.gz: d135cf35c5cf17a2bfabd89d9a62073ad085c12bd2b05cbd11d67890c6dd77b7f4feecb975370d60ce8aaa769650f6c0985dc7e8454cb581644677783a9bbf77
6
+ metadata.gz: cd5e4c1d65e25e5d9ec9defb1b93a33296e09a7ee94aa1545430f387558089dc7e95da007ff87a9522ca5bca1534355cae5d3aa51c4b96b10b3767396895e58a
7
+ data.tar.gz: '0238f533575b8bb4f52d8ef38cfd6ce1480b3b11cd10018d5839d9bc04b5a0d0b5f75e3017051d2dfb6d9f747190e919dca3d51d788b65b48722c22fbdb86a5e'
data/README.md CHANGED
@@ -170,6 +170,10 @@ After you create a new distribution certificate, share the
170
170
  corresponding `.cer` and `.p12` files located in the `provisioning`
171
171
  folder with your team members.
172
172
 
173
+ After copying the files to the team member's `provisioning` directory,
174
+ drag and drop the certificate file into the Keychain Access app's login
175
+ keychain in order to install the certificate.
176
+
173
177
  ## Recreate certificates and profiles
174
178
 
175
179
  Once the certificates and profiles are cached in the `provisioning`
@@ -184,6 +188,9 @@ Or to recreate the development certificate:
184
188
 
185
189
  rake device recreate_certificate=1
186
190
 
191
+ Or to recreate the distribution certificate:
192
+
193
+ rake archive:distribution recreate_certificate=1
187
194
 
188
195
  ## Entitlements and App Services
189
196
 
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "motion-provisioning"
5
+
6
+ require "irb"
7
+ IRB.start
Binary file
data/bin/setup ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+ rake generate_certificates
8
+ rake build_export_private_key
9
+
@@ -0,0 +1,144 @@
1
+ /*
2
+ * This file contains modified code with copyright:
3
+ *
4
+ * Copyright (c) 2003-2010,2012,2014 Apple Inc. All Rights Reserved.
5
+ *
6
+ * Covered by the APPLE PUBLIC SOURCE LICENSE
7
+ * (http://opensource.apple.com/license/apsl/)
8
+ */
9
+
10
+ #import <CoreFoundation/CoreFoundation.h>
11
+ #import <Security/Security.h>
12
+
13
+ #define DEBUG 0
14
+
15
+ unsigned char
16
+ hexValue(char c)
17
+ {
18
+ static const char digits[] = "0123456789abcdef";
19
+ char *p;
20
+ if (p = strchr(digits, tolower(c)))
21
+ return p - digits;
22
+ else
23
+ return 0;
24
+ }
25
+
26
+ void
27
+ fromHex(const char *hexDigits, CSSM_DATA *data)
28
+ {
29
+ size_t bytes = strlen(hexDigits) / 2; // (discards malformed odd end)
30
+ if (bytes > data->Length)
31
+ return;
32
+ // length(bytes); // (will assert if we try to grow it)
33
+ size_t n;
34
+ for (n = 0; n < bytes; n++) {
35
+ data->Data[n] = (uint8)(hexValue(hexDigits[2*n]) << 4 | hexValue(hexDigits[2*n+1]));
36
+ }
37
+ }
38
+
39
+ int main(int argc, char *argv[]) {
40
+
41
+ if (argc != 4) {
42
+ exit(1);
43
+ }
44
+
45
+ char* identity_name = argv[1];
46
+ char* hash = argv[2];
47
+ char* key_password = argv[3];
48
+
49
+ // First get a list of Identities matching the specified name
50
+ const void* values[] = {
51
+ kSecClassIdentity,
52
+ kCFBooleanTrue,
53
+ CFStringCreateWithCString(NULL, identity_name, kCFStringEncodingUTF8),
54
+ kSecMatchLimitAll
55
+ };
56
+ const void* keys[] = {
57
+ kSecClass,
58
+ kSecReturnRef,
59
+ kSecMatchSubjectContains,
60
+ kSecMatchLimit
61
+ };
62
+ CFIndex numValues = sizeof(keys)/sizeof(void*);
63
+ CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, numValues, NULL, NULL);
64
+
65
+ CFTypeRef results;
66
+ if (SecItemCopyMatching(query, &results) != noErr) {
67
+ exit(1);
68
+ }
69
+
70
+ // Prepare the Identity hash
71
+ CSSM_DATA hashData = { 0, NULL };
72
+ CSSM_SIZE len = strlen(hash)/2;
73
+ hashData.Length = len;
74
+ hashData.Data = (uint8 *)malloc(hashData.Length);
75
+ fromHex(hash, &hashData);
76
+
77
+ SecIdentityRef item;
78
+ CSSM_DATA certData = { 0, NULL };
79
+ SecCertificateRef cert = NULL;
80
+ Boolean found = FALSE;
81
+
82
+ // Check all found identitied, looking for one whose certificate matches the
83
+ // specified hash
84
+ CFIndex count = CFArrayGetCount(results);
85
+ for (int i = 0; i < count; i++) {
86
+ item = CFArrayGetValueAtIndex(results, i);
87
+
88
+ if (SecIdentityCopyCertificate(item, &cert) != noErr) {
89
+ CFRelease(&item);
90
+ continue;
91
+ }
92
+
93
+ if (SecCertificateGetData(cert, &certData) != noErr) {
94
+ CFRelease(&cert);
95
+ CFRelease(&item);
96
+ continue;
97
+ }
98
+
99
+ uint8 candidate_sha1_hash[20];
100
+ CSSM_DATA digest;
101
+ digest.Length = sizeof(candidate_sha1_hash);
102
+ digest.Data = candidate_sha1_hash;
103
+ if ((SecDigestGetData(CSSM_ALGID_SHA1, &digest, &certData) == CSSM_OK) &&
104
+ (hashData.Length == digest.Length) &&
105
+ (!memcmp(hashData.Data, digest.Data, digest.Length))) {
106
+ found = TRUE;
107
+ break;
108
+ }
109
+ }
110
+
111
+ if (found) {
112
+ #if DEBUG
113
+ CFStringRef nameRef = NULL;
114
+ if (SecCertificateCopyCommonName(cert, &nameRef) != noErr) {
115
+ exit(1);
116
+ }
117
+
118
+ char *cert_name = CFStringGetCStringPtr(nameRef, kCFStringEncodingUTF8);
119
+ printf("%s\n", cert_name);
120
+ #endif
121
+
122
+ // Finally, get the encrypted private key using the specified password
123
+ // and print it to stdout in PEM format
124
+ SecKeyRef key = NULL;
125
+ if (SecIdentityCopyPrivateKey(item, &key) != noErr) {
126
+ exit(1);
127
+ }
128
+
129
+ SecKeyImportExportParameters keyParams;
130
+ keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
131
+ keyParams.flags = 0;
132
+ keyParams.passphrase = CFDataCreate(NULL, key_password, 5);
133
+ keyParams.alertTitle = 0;
134
+ keyParams.alertPrompt = 0;
135
+
136
+ CFDataRef key_data;
137
+ OSStatus status = SecKeychainItemExport(key, kSecFormatWrappedPKCS8,
138
+ kSecItemPemArmour, &keyParams, &key_data);
139
+
140
+ if(status == noErr) {
141
+ write(fileno(stdout), CFDataGetBytePtr(key_data), CFDataGetLength(key_data));
142
+ }
143
+ }
144
+ }
@@ -24,14 +24,13 @@ module MotionProvisioning
24
24
  installed_cert = identities.detect { |e| e[:fingerprint] == fingerprint }
25
25
  if installed_cert
26
26
  Utils.log("Info", "Using certificate '#{installed_cert[:name]}'.")
27
- return installed_cert[:name]
27
+ return installed_cert[:fingerprint]
28
28
  else
29
29
  # The certificate is not installed, so we install the cert and the key
30
30
  import_file(private_key_path)
31
31
  import_file(certificate_path)
32
- name = common_name(certificate_path)
33
- Utils.log("Info", "Using certificate '#{name}'.")
34
- return name
32
+ Utils.log("Info", "Using certificate '#{common_name(certificate_path)}'.")
33
+ return sha1_fingerprint(certificate_path)
35
34
  end
36
35
  end
37
36
 
@@ -48,23 +47,23 @@ module MotionProvisioning
48
47
  end
49
48
  end
50
49
 
51
- # There are no certificates in the server so we create a new one
52
50
  if certificates.empty?
53
- Utils.log("Warning", "Couldn't find any existing certificates... creating a new one.")
51
+ # There are no certificates in the server so we create a new one
52
+ Utils.log("Warning", "Couldn't find any existing certificates. Creating a new certificate...")
54
53
  if certificate = create_certificate
55
- return common_name(certificate)
54
+ return sha1_fingerprint(certificate)
56
55
  else
57
56
  Utils.log("Error", "Something went wrong when trying to create a new certificate.")
58
57
  abort
59
58
  end
60
- # There are certificates in the server, but none is installed locally. Revoke all and create a new one.
61
59
  elsif installed_certificate.nil?
62
- Utils.log("Error", "None of the available certificates (#{certificates.count}) is installed on the local machine. Revoking...")
60
+ # There are certificates in the server, but none are installed locally. Revoke all and create a new one.
61
+ Utils.log("Error", "None of the available certificates (#{certificates.count}) are installed locally. Revoking...")
63
62
 
64
63
  # For distribution, ask before revoking
65
64
  if self.type == :distribution
66
- answer = Utils.ask("Info", "There are #{certificates.count} distribution certificates in your account, but none installed locally.\n" \
67
- "Before revoking and creating a new one, ask other team members who might have them installed to share them with you.\n" \
65
+ answer = Utils.ask("Info", "There #{certificates.count == 1 ? 'is 1' : "are #{certificates.count}"} distribution certificate(s) in your account, but none installed locally.\n" \
66
+ "Before revoking and creating a new certificate, ask other team members who might have them installed to share them with you.\n" \
68
67
  "Do you want to continue revoking the certificates? (Y/n):")
69
68
  abort if answer.no?
70
69
  end
@@ -79,13 +78,43 @@ module MotionProvisioning
79
78
  end
80
79
 
81
80
  if certificate = create_certificate
82
- return common_name(certificate)
81
+ return sha1_fingerprint(certificate)
83
82
  else
84
83
  Utils.log("Error", "Something went wrong when trying to create a new certificate...")
85
84
  abort
86
85
  end
87
- # There are certificates on the server, and one of them is installed locally.
86
+ elsif ENV['recreate_certificate'] != nil
87
+ # Force recreate certificate, even though a valid certificate is already installed locally
88
+
89
+ if self.type == :distribution
90
+ answer = Utils.ask("Info", "There are #{certificates.count} distribution certificates in your account.\n" \
91
+ "Before revoking and creating a new one, ask other team members who might have them installed to share them with you.\n" \
92
+ "Do you want to revoke the existing certificates? (Y/n):")
93
+ if answer.yes?
94
+ certificates.each(&:revoke!)
95
+ end
96
+ else
97
+ answer = Utils.ask("Info", "You have #{certificates.count} development certificates in your account.\n" \
98
+ "Do you want to revoke your existing certificates? (Y/n):")
99
+ if answer.yes?
100
+ if MotionProvisioning.free
101
+ certificates.each do |certificate|
102
+ client.revoke_development_certificate(certificate.motionprovisioning_serialNumber)
103
+ end
104
+ else
105
+ certificates.each(&:revoke!)
106
+ end
107
+ end
108
+ end
109
+
110
+ if certificate = create_certificate
111
+ return sha1_fingerprint(certificate)
112
+ else
113
+ Utils.log("Error", "Something went wrong when trying to create a new certificate.")
114
+ abort
115
+ end
88
116
  else
117
+ # There are certificates on the server, and one of them is installed locally.
89
118
  Utils.log("Info", "Found certificate '#{installed_certificate.name}' which is installed in the local machine.")
90
119
 
91
120
  path = store_certificate_raw(installed_certificate.motionprovisioning_certContent || installed_certificate.download_raw)
@@ -97,7 +126,7 @@ module MotionProvisioning
97
126
  # This certificate is installed on the local machine
98
127
  Utils.log("Info", "Using certificate '#{installed_certificate.name}'.")
99
128
 
100
- common_name(path)
129
+ sha1_fingerprint(path)
101
130
  end
102
131
  end
103
132
 
@@ -134,7 +163,7 @@ module MotionProvisioning
134
163
  when :mac
135
164
  cert_type = Spaceship.certificate.mac_development
136
165
  cert_type = Spaceship.certificate.mac_app_distribution if self.type == :distribution
137
- cert_type = Spaceship.certificate.developer_i_d_application if self.type == :developer_id
166
+ cert_type = Spaceship.certificate.developer_id_application if self.type == :developer_id
138
167
  end
139
168
  cert_type
140
169
  end
@@ -191,9 +220,9 @@ module MotionProvisioning
191
220
  Utils.log("Info", "Successfully installed certificate.")
192
221
 
193
222
  if self.type == :distribution
194
- Utils.log("Warning", "You have just created a distribution certificate. These certificates must be shared with other team members by sending them the private key (.p12) and certificate (.cer) files in your output folder and install them in the keychain.")
223
+ Utils.log("Warning", "You have just created a distribution certificate. These certificates must be shared with other team members by sending them the private key (.p12) and certificate (.cer) files in your 'provisioning' folder and install them in the keychain.")
195
224
  else
196
- Utils.log("Warning", "You have just created a development certificate. If you want to use this certificate on another machine, transfer the private key (.p12) and certificate (.cer) files in your output folder and install them in the keychain.")
225
+ Utils.log("Warning", "You have just created a development certificate. If you want to use this certificate on another machine, transfer the private key (.p12) and certificate (.cer) files in your 'provisioning' folder and install them in the keychain.")
197
226
  end
198
227
  Utils.ask("Info", "Press any key to continue...")
199
228
 
@@ -30,8 +30,7 @@ module MotionProvisioning
30
30
  end
31
31
  end
32
32
 
33
- # ensure a client is created and logged in
34
- client
33
+ client # ensure a client is created and logged in
35
34
 
36
35
  app = Application.find_or_create(bundle_id: bundle_id, name: app_name, mac: platform == :mac)
37
36
 
@@ -78,6 +77,7 @@ module MotionProvisioning
78
77
  certificate_platform = platform == :mac ? :mac : :ios
79
78
  certificate_sha1 = OpenSSL::Digest::SHA1.new(File.read(File.join(output_path, "#{certificate_platform}_distribution_certificate.cer")))
80
79
  cert = client.distribution_certificates(mac: platform == :mac).detect do |c|
80
+ # Compare downloaded cert content against local cert content to make sure they match
81
81
  OpenSSL::Digest::SHA1.new(c['certContent'].read) == certificate_sha1
82
82
  end
83
83
 
@@ -5,7 +5,7 @@ module Spaceship
5
5
  def teams
6
6
  return @teams if @teams
7
7
  req = request(:post, "https://developerservices2.apple.com/services/#{PROTOCOL_VERSION}/listTeams.action", nil, {
8
- 'X-Xcode-Version' => XCODE_VERSION # necessary in order to work with Xcode free team
8
+ 'X-Xcode-Version' => XCODE_VERSION # necessary in order to list Xcode free team
9
9
  })
10
10
  @teams = parse_response(req, 'teams').sort_by do |team|
11
11
  [
@@ -1,4 +1,5 @@
1
1
  require 'rake'
2
+
2
3
  namespace 'motion-provisioning' do
3
4
  desc 'Add a device to the provisioning portal: rake "motion-provisioning:add-device[device_name,device_id]"'
4
5
  task 'add-device', [:name, :id] do |t, args|
@@ -1,3 +1,3 @@
1
1
  module MotionProvisioning
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -5,7 +5,6 @@ require 'date'
5
5
 
6
6
  require 'plist'
7
7
  require 'security'
8
- require 'highline/import'
9
8
  require 'spaceship'
10
9
  require 'motion-provisioning/spaceship/portal/certificate'
11
10
  require 'motion-provisioning/spaceship/portal_client'
metadata CHANGED
@@ -1,63 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-provisioning
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Villacampa
8
- autorequire:
8
+ - Andrew Havens
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2019-01-22 00:00:00.000000000 Z
12
+ date: 2021-08-27 00:00:00.000000000 Z
12
13
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: highline
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.7.2
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: 2.0.0
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 1.7.2
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: 2.0.0
33
14
  - !ruby/object:Gem::Dependency
34
15
  name: fastlane
35
16
  requirement: !ruby/object:Gem::Requirement
36
17
  requirements:
37
18
  - - "~>"
38
19
  - !ruby/object:Gem::Version
39
- version: 2.113.0
20
+ version: '2.182'
40
21
  type: :runtime
41
22
  prerelease: false
42
23
  version_requirements: !ruby/object:Gem::Requirement
43
24
  requirements:
44
25
  - - "~>"
45
26
  - !ruby/object:Gem::Version
46
- version: 2.113.0
47
- - !ruby/object:Gem::Dependency
48
- name: bundler
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '1.12'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '1.12'
27
+ version: '2.182'
61
28
  - !ruby/object:Gem::Dependency
62
29
  name: rake
63
30
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +73,14 @@ dependencies:
106
73
  requirements:
107
74
  - - "~>"
108
75
  - !ruby/object:Gem::Version
109
- version: '1.21'
76
+ version: '3.7'
110
77
  type: :development
111
78
  prerelease: false
112
79
  version_requirements: !ruby/object:Gem::Requirement
113
80
  requirements:
114
81
  - - "~>"
115
82
  - !ruby/object:Gem::Version
116
- version: '1.21'
83
+ version: '3.7'
117
84
  - !ruby/object:Gem::Dependency
118
85
  name: simplecov
119
86
  requirement: !ruby/object:Gem::Requirement
@@ -132,13 +99,17 @@ description: A small library that manages certificates and profiles automaticall
132
99
  from the command line, with minimal configuration.
133
100
  email:
134
101
  - m@markvillacampa.com
102
+ - email@andrewhavens.com
135
103
  executables: []
136
104
  extensions: []
137
105
  extra_rdoc_files: []
138
106
  files:
139
107
  - LICENSE.txt
140
108
  - README.md
109
+ - bin/console
141
110
  - bin/export_private_key
111
+ - bin/setup
112
+ - export_private_key/export_private_key.c
142
113
  - lib/motion-provisioning.rb
143
114
  - lib/motion-provisioning/application.rb
144
115
  - lib/motion-provisioning/certificate.rb
@@ -150,11 +121,11 @@ files:
150
121
  - lib/motion-provisioning/tasks.rb
151
122
  - lib/motion-provisioning/utils.rb
152
123
  - lib/motion-provisioning/version.rb
153
- homepage: https://github.com/HipByte/motion-provisioning
124
+ homepage: https://github.com/rubymotion-community/motion-provisioning
154
125
  licenses:
155
126
  - BSD
156
127
  metadata: {}
157
- post_install_message:
128
+ post_install_message:
158
129
  rdoc_options: []
159
130
  require_paths:
160
131
  - lib
@@ -169,9 +140,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
140
  - !ruby/object:Gem::Version
170
141
  version: '0'
171
142
  requirements: []
172
- rubyforge_project:
173
- rubygems_version: 2.7.6
174
- signing_key:
143
+ rubygems_version: 3.2.15
144
+ signing_key:
175
145
  specification_version: 4
176
146
  summary: Simplified provisioning for RubyMotion iOS, tvOS and macOS apps.
177
147
  test_files: []