adsedare 0.0.1

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.
data/lib/starship.rb ADDED
@@ -0,0 +1,293 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+
6
+ require_relative "starship/auth_helper"
7
+
8
+ module Starship
9
+ class Client
10
+ DEV_SERVICES_V1 = "https://developer.apple.com/services-account/v1"
11
+ DEV_SERVICES_QH65B2 = "https://developer.apple.com/services-account/QH65B2"
12
+
13
+ class << self
14
+ def auth_helper
15
+ @auth_helper ||= AuthHelper.new
16
+ end
17
+
18
+ def get_bundle_ids(team_id)
19
+ response = authenticated_request(
20
+ DEV_SERVICES_V1 + "/bundleIds",
21
+ method: :post,
22
+ body: { teamId: team_id, urlEncodedQueryParams: "limit=1000&sort=name&filter[platform]=IOS,MACOS" }.to_json,
23
+ headers: { "Content-Type" => "application/vnd.api+json" }
24
+ )
25
+
26
+ if response.status == 200
27
+ JSON.parse(response.body)["data"]
28
+ else
29
+ raise "Failed to get bundle IDs: #{response.status}"
30
+ end
31
+ end
32
+
33
+ def get_devices(team_id)
34
+ response = authenticated_request(
35
+ DEV_SERVICES_V1 + "/devices",
36
+ method: :post,
37
+ body: { teamId: team_id, urlEncodedQueryParams: "limit=1000&sort=name" }.to_json,
38
+ headers: { "Content-Type" => "application/vnd.api+json" }
39
+ )
40
+
41
+ if response.status == 200
42
+ JSON.parse(response.body)["data"]
43
+ else
44
+ raise "Failed to get devices: #{response.status}"
45
+ end
46
+ end
47
+
48
+ def get_profiles(team_id)
49
+ response = authenticated_request(
50
+ DEV_SERVICES_V1 + "/profiles",
51
+ method: :post,
52
+ body: { teamId: team_id, urlEncodedQueryParams: "limit=1000&sort=name" }.to_json,
53
+ headers: { "Content-Type" => "application/vnd.api+json" }
54
+ )
55
+
56
+ if response.status == 200
57
+ JSON.parse(response.body)["data"]
58
+ else
59
+ raise "Failed to get profiles: #{response.status}"
60
+ end
61
+ end
62
+
63
+ def get_provisioning_profile(profile_id, team_id)
64
+ response = authenticated_request(
65
+ DEV_SERVICES_QH65B2 + "/account/ios/profile/getProvisioningProfile.action",
66
+ method: :post,
67
+ body: URI.encode_www_form(
68
+ "teamId" => team_id,
69
+ "includeInactiveProfiles" => true,
70
+ "provisioningProfileId" => profile_id,
71
+ ),
72
+ headers: { "Content-Type" => "application/x-www-form-urlencoded" }
73
+ )
74
+
75
+ if response.status == 200
76
+ JSON.parse(response.body)
77
+ else
78
+ raise "Failed to get profile: #{response.status}"
79
+ end
80
+ end
81
+
82
+ def get_bundle_info(bundle_id, team_id)
83
+ response = authenticated_request(
84
+ DEV_SERVICES_V1 + "/bundleIds/#{bundle_id}?include=bundleIdCapabilities,bundleIdCapabilities.capability,bundleIdCapabilities.appGroups",
85
+ method: :post,
86
+ body: { teamId: team_id }.to_json,
87
+ headers: { "Content-Type" => "application/vnd.api+json" }
88
+ )
89
+
90
+ if response.status == 200
91
+ JSON.parse(response.body)
92
+ else
93
+ raise "Failed to get bundle info: #{response.status}"
94
+ end
95
+ end
96
+
97
+ def get_app_groups(team_id)
98
+ response = authenticated_request(
99
+ DEV_SERVICES_QH65B2 + "/account/ios/identifiers/listApplicationGroups.action",
100
+ method: :post,
101
+ body: URI.encode_www_form(
102
+ "teamId" => team_id,
103
+ "pageSize" => 1000,
104
+ "pageNumber" => 1,
105
+ "sort" => "name%3Dasc"
106
+ ),
107
+ headers: { "Content-Type" => "application/x-www-form-urlencoded" }
108
+ )
109
+ if response.status == 200
110
+ JSON.parse(response.body)["applicationGroupList"]
111
+ else
112
+ raise "Failed to list bundle IDs: #{response.status}"
113
+ end
114
+ end
115
+
116
+ def create_app_group(app_group, team_id)
117
+ response = authenticated_request(
118
+ DEV_SERVICES_QH65B2 + "/account/ios/identifiers/addApplicationGroup.action",
119
+ method: :post,
120
+ body: URI.encode_www_form(
121
+ "name" => generate_name_for(app_group),
122
+ "identifier" => app_group,
123
+ "teamId" => team_id,
124
+ ),
125
+ headers: { "Content-Type" => "application/x-www-form-urlencoded" }
126
+ )
127
+ if response.status == 200
128
+ JSON.parse(response.body)
129
+ else
130
+ raise "Failed to create app group: #{response.status}"
131
+ end
132
+ end
133
+
134
+ def create_bundle(bundle_identifier, team_id, capabilities)
135
+ response = authenticated_request(
136
+ DEV_SERVICES_V1 + "/bundleIds",
137
+ method: :post,
138
+ body: {
139
+ data: {
140
+ type: "bundleIds",
141
+ attributes: {
142
+ identifier: bundle_identifier,
143
+ name: generate_name_for(bundle_identifier),
144
+ seedId: team_id,
145
+ teamId: team_id
146
+ },
147
+ relationships: {
148
+ bundleIdCapabilities: {
149
+ data: capabilities
150
+ }
151
+ }
152
+ }
153
+ }.to_json,
154
+ headers: {
155
+ "Content-Type" => "application/vnd.api+json",
156
+ "X-HTTP-Method-Override" => nil
157
+ }
158
+ )
159
+ if response.status == 201
160
+ JSON.parse(response.body)
161
+ else
162
+ raise "Failed to create bundle: #{response.status}"
163
+ end
164
+ end
165
+
166
+ def patch_bundle(bundleInfo, team_id, capabilities)
167
+ bundle_id = bundleInfo["data"]["id"]
168
+ bundle_attributes = bundleInfo["data"]["attributes"]
169
+
170
+ response = authenticated_request(
171
+ DEV_SERVICES_V1 + "/bundleIds/#{bundle_id}",
172
+ method: :patch,
173
+ body: {
174
+ data: {
175
+ type: "bundleIds",
176
+ id: bundle_id,
177
+ attributes: {
178
+ identifier: bundle_attributes["identifier"],
179
+ permissions: { "edit": true, "delete": true },
180
+ seedId: bundle_attributes["seedId"],
181
+ name: bundle_attributes["name"],
182
+ wildcard: bundle_attributes["wildcard"],
183
+ teamId: team_id
184
+ },
185
+ relationships: {
186
+ bundleIdCapabilities: {
187
+ data: capabilities
188
+ }
189
+ }
190
+ }
191
+ }.to_json,
192
+ headers: { "Content-Type" => "application/vnd.api+json" }
193
+ )
194
+
195
+ if response.status == 200
196
+ JSON.parse(response.body)
197
+ else
198
+ raise "Failed to patch bundle capabilities: #{response.status}"
199
+ end
200
+ end
201
+
202
+ def create_provisioning_profile(team_id, bundle_id, bundle_identifier, certificate_id, devices)
203
+ response = authenticated_request(
204
+ DEV_SERVICES_V1 + "/profiles",
205
+ method: :post,
206
+ body: {
207
+ data: {
208
+ type: "profiles",
209
+ attributes: {
210
+ name: generate_name_for(bundle_identifier),
211
+ profileType: "IOS_APP_ADHOC",
212
+ teamId: team_id
213
+ },
214
+ relationships: {
215
+ bundleId: {
216
+ data: {
217
+ type: "bundleIds",
218
+ id: bundle_id
219
+ }
220
+ },
221
+ certificates: {
222
+ data: [{
223
+ type: "certificates",
224
+ id: certificate_id
225
+ }]
226
+ },
227
+ devices: {
228
+ data: devices.map { |device| { type: "devices", id: device["id"] } }
229
+ }
230
+ }
231
+ }
232
+ }.to_json,
233
+ headers: {
234
+ "Content-Type" => "application/vnd.api+json",
235
+ "X-HTTP-Method-Override" => nil
236
+ }
237
+ )
238
+ if response.status == 201
239
+ JSON.parse(response.body)
240
+ else
241
+ raise "Failed to create profile: #{response.status}"
242
+ end
243
+ end
244
+
245
+ def regen_provisioning_profile(profile, team_id, devices)
246
+ response = authenticated_request(
247
+ DEV_SERVICES_QH65B2 + "/account/ios/profile/regenProvisioningProfile.action",
248
+ method: :post,
249
+ body: URI.encode_www_form(
250
+ "appIdId" => profile["provisioningProfile"]["appIdId"],
251
+ "provisioningProfileId" => profile["provisioningProfile"]["provisioningProfileId"],
252
+ "distributionType" => profile["provisioningProfile"]["distributionType"],
253
+ # TODO: figure out how to get this from old profile
254
+ "isOfflineProfile" => false,
255
+ "provisioningProfileName" => profile["provisioningProfile"]["name"],
256
+ "certificateIds" => profile["provisioningProfile"]["certificateIds"].join(","),
257
+ "deviceIds" => devices,
258
+ "teamId" => team_id
259
+ ),
260
+ headers: { "Content-Type" => "application/x-www-form-urlencoded" }
261
+ )
262
+ if response.status == 200
263
+ JSON.parse(response.body)
264
+ else
265
+ raise "Failed to regenerate profile: #{response.status}"
266
+ end
267
+ end
268
+
269
+ private
270
+
271
+ def generate_name_for(resource_id)
272
+ latinized = resource_id.gsub(/[^0-9A-Za-z\d\s]/, ' ')
273
+
274
+ return "ADSEDARE #{latinized}"
275
+ end
276
+
277
+ def authenticated_request(endpoint, method: :get, params: nil, body: nil, headers: nil)
278
+ unless auth_helper.validate_token
279
+ auth_helper.sign_in
280
+ end
281
+
282
+ # Make the request
283
+ return auth_helper.request(
284
+ endpoint,
285
+ method: method,
286
+ params: params,
287
+ body: body,
288
+ headers: headers
289
+ )
290
+ end
291
+ end
292
+ end
293
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: adsedare
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - alexstrnik
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-05-04 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rake
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '13.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '13.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: xcodeproj
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 1.27.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 1.27.0
40
+ - !ruby/object:Gem::Dependency
41
+ name: jwt
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.7'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.7'
54
+ - !ruby/object:Gem::Dependency
55
+ name: faraday
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.7'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.7'
68
+ - !ruby/object:Gem::Dependency
69
+ name: faraday-cookie_jar
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 0.0.7
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.0.7
82
+ - !ruby/object:Gem::Dependency
83
+ name: plist
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 3.2.0
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 3.2.0
96
+ description: AdSedare is a powerful library designed to simplify the process of iOS
97
+ ad-hoc distribution. By automating and streamlining the distribution of builds,
98
+ it ensures a smooth, pain-free experience for developers and testers. AdSedare is
99
+ ideal for anyone looking to automate the distribution of iOS apps, without the usual
100
+ headaches associated with managing provisioning profiles, certificates, and manual
101
+ setups.
102
+ email:
103
+ - alex.str.nik@gmail.com
104
+ executables:
105
+ - adsedare
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - adsedare.gemspec
113
+ - exe/adsedare
114
+ - lib/adsedare.rb
115
+ - lib/adsedare/capabilities.rb
116
+ - lib/adsedare/version.rb
117
+ - lib/appstoreconnect.rb
118
+ - lib/logging.rb
119
+ - lib/starship.rb
120
+ - lib/starship/2fa_provider.rb
121
+ - lib/starship/auth_helper.rb
122
+ homepage: https://github.com/AlexStrNik/AdSedare
123
+ licenses:
124
+ - MIT
125
+ metadata:
126
+ homepage_uri: https://github.com/AlexStrNik/AdSedare
127
+ source_code_uri: https://github.com/AlexStrNik/AdSedare
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: 2.6.0
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubygems_version: 3.6.3
143
+ specification_version: 4
144
+ summary: A cross-platform library for seamless, pain-free iOS ad-hoc distribution.
145
+ test_files: []