axm 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +5 -0
- data/README.md +8 -2
- data/Rakefile +3 -3
- data/lib/axm/client/mdm_servers.rb +3 -1
- data/lib/axm/client/organization_device_activities.rb +10 -6
- data/lib/axm/client/organization_devices.rb +5 -3
- data/lib/axm/client.rb +31 -16
- data/lib/axm/secret.rb +2 -0
- data/lib/axm/version.rb +1 -1
- data/lib/axm.rb +3 -3
- metadata +4 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 729a2e7795a94f807dc732928f6e704f42d4e93fdb712bde4083a04410fb1aa5
|
|
4
|
+
data.tar.gz: 8256543f1d81885b9ee2f6bae17f74506efaef554796b9ac2e03a415a3d50954
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f3ae6ad5f92c66c84284011b9bb3ac2e5f3297df2662783807bf0893ec46efd337490185b6871a131b8a12e2fbfa2b59d581e213921510fadf16be5532ec563f
|
|
7
|
+
data.tar.gz: 5bcb9240a6aae5f17e9e872c0bf5a5796c8b9b0665e583a9063f6d42dafd59161656c1645ea8fa35deba31e8ae899d13993b031c61bddb5c193f7f5381b09bed
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -58,7 +58,13 @@ key_id = Secret.read('key_id')
|
|
|
58
58
|
client = Axm::Client.new(private_key:, client_id:, key_id:)
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
61
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
62
|
+
|
|
63
|
+
## Releasing
|
|
64
|
+
|
|
65
|
+
1. Update the version number in [lib/axm/version.rb](./lib/axm/version.rb)
|
|
66
|
+
2. Add release notes to [CHANGELOG.md](CHANGELOG.md)
|
|
67
|
+
3. Run the "Release" Action
|
|
62
68
|
|
|
63
69
|
## Contributing
|
|
64
70
|
|
|
@@ -70,4 +76,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
70
76
|
|
|
71
77
|
## Code of Conduct
|
|
72
78
|
|
|
73
|
-
Everyone interacting
|
|
79
|
+
Everyone interacting with the AXM codebase and issue tracker is expected to follow the [code of conduct](https://github.com/nick-f/axm/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
require 'rspec/core/rake_task'
|
|
5
5
|
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
|
7
7
|
|
|
8
|
-
require
|
|
8
|
+
require 'rubocop/rake_task'
|
|
9
9
|
|
|
10
10
|
RuboCop::RakeTask.new
|
|
11
11
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Axm
|
|
2
4
|
class Client
|
|
3
5
|
module MdmServers
|
|
@@ -11,7 +13,7 @@ module Axm
|
|
|
11
13
|
# See: https://developer.apple.com/documentation/applebusinessmanagerapi/get-mdm-servers
|
|
12
14
|
# See: https://developer.apple.com/documentation/appleschoolmanagerapi/get-mdm-servers
|
|
13
15
|
def list_mdm_servers(options = {})
|
|
14
|
-
get(
|
|
16
|
+
get('v1/mdmServers', options)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
# Retrieves a list of IDs for the devices assigned to a specific MDM server.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Axm
|
|
2
4
|
class Client
|
|
3
5
|
module OrganizationDeviceActivities
|
|
@@ -19,7 +21,7 @@ module Axm
|
|
|
19
21
|
# @param mdm_server_id [String] The unique identifier of the MDM server to which the device will be assigned.
|
|
20
22
|
# @return [Hash, Integer] The response from the POST method, containing details of the assignment and status code.
|
|
21
23
|
def assign(device_id, mdm_server_id)
|
|
22
|
-
assignment_change(device_id, mdm_server_id,
|
|
24
|
+
assignment_change(device_id, mdm_server_id, 'ASSIGN_DEVICES')
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
# Unassigns a device from an MDM server.
|
|
@@ -28,7 +30,7 @@ module Axm
|
|
|
28
30
|
# @param mdm_server_id [String] The unique identifier of the MDM server to which the device will be assigned.
|
|
29
31
|
# @return [Hash, Integer] The response from the POST method, containing details of the assignment and status code.
|
|
30
32
|
def unassign(device_id, mdm_server_id)
|
|
31
|
-
assignment_change(device_id, mdm_server_id,
|
|
33
|
+
assignment_change(device_id, mdm_server_id, 'UNASSIGN_DEVICES')
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
private
|
|
@@ -39,24 +41,25 @@ module Axm
|
|
|
39
41
|
# @param mdm_server_id [String] The unique identifier of the MDM server.
|
|
40
42
|
# @param activity_type [String] The type of activity being performed ("ASSIGN_DEVICES" or "UNASSIGN_DEVICES").
|
|
41
43
|
# @return [Hash, Integer] The response from the POST request, containing details of the operation and status code.
|
|
44
|
+
# rubocop:disable Metrics/MethodLength
|
|
42
45
|
def assignment_change(device_ids, mdm_server_id, activity_type)
|
|
43
46
|
devices = device_ids.map do |device_id|
|
|
44
47
|
{
|
|
45
|
-
type:
|
|
48
|
+
type: 'orgDevices',
|
|
46
49
|
id: device_id
|
|
47
50
|
}
|
|
48
51
|
end
|
|
49
52
|
|
|
50
53
|
request_body = {
|
|
51
54
|
data: {
|
|
52
|
-
type:
|
|
55
|
+
type: 'orgDeviceActivities',
|
|
53
56
|
attributes: {
|
|
54
57
|
activityType: activity_type
|
|
55
58
|
},
|
|
56
59
|
relationships: {
|
|
57
60
|
mdmServer: {
|
|
58
61
|
data: {
|
|
59
|
-
type:
|
|
62
|
+
type: 'mdmServers',
|
|
60
63
|
id: mdm_server_id
|
|
61
64
|
}
|
|
62
65
|
},
|
|
@@ -67,8 +70,9 @@ module Axm
|
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
post(
|
|
73
|
+
post('v1/orgDeviceActivities', request_body)
|
|
71
74
|
end
|
|
75
|
+
# rubocop:enable Metrics/MethodLength
|
|
72
76
|
end
|
|
73
77
|
end
|
|
74
78
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Axm
|
|
2
4
|
class Client
|
|
3
5
|
module OrganizationDevices
|
|
@@ -11,7 +13,7 @@ module Axm
|
|
|
11
13
|
# See: https://developer.apple.com/documentation/applebusinessmanagerapi/get-org-devices
|
|
12
14
|
# See: https://developer.apple.com/documentation/appleschoolmanagerapi/get-org-devices
|
|
13
15
|
def list_org_devices(options = {})
|
|
14
|
-
get(
|
|
16
|
+
get('v1/orgDevices', options)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
# Retrieves information about a specific device in the organization.
|
|
@@ -49,7 +51,7 @@ module Axm
|
|
|
49
51
|
# See: https://developer.apple.com/documentation/applebusinessmanagerapi/get-the-assigned-server-information-for-an-orgdevice
|
|
50
52
|
# See: https://developer.apple.com/documentation/appleschoolmanagerapi/get-the-assigned-server-information-for-an-orgdevice
|
|
51
53
|
def assigned_mdm_server(device_id, options = {})
|
|
52
|
-
options[:fields_key] =
|
|
54
|
+
options[:fields_key] = 'mdmServers'
|
|
53
55
|
|
|
54
56
|
get("v1/orgDevices/#{device_id}/assignedServer", options)
|
|
55
57
|
end
|
|
@@ -65,7 +67,7 @@ module Axm
|
|
|
65
67
|
# See: https://developer.apple.com/documentation/applebusinessmanagerapi/get-all-apple-care-coverage-for-an-orgdevice
|
|
66
68
|
# See: https://developer.apple.com/documentation/appleschoolmanagerapi/get-all-apple-care-coverage-for-an-orgdevice
|
|
67
69
|
def applecare_coverage(device_id, options = {})
|
|
68
|
-
options[:fields_key] =
|
|
70
|
+
options[:fields_key] = 'appleCareCoverage'
|
|
69
71
|
|
|
70
72
|
get("v1/orgDevices/#{device_id}/appleCareCoverage", options)
|
|
71
73
|
end
|
data/lib/axm/client.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'json'
|
|
2
4
|
require 'jwt'
|
|
3
5
|
require 'net/http'
|
|
@@ -9,6 +11,7 @@ require 'axm/client/organization_device_activities'
|
|
|
9
11
|
require 'axm/client/organization_devices'
|
|
10
12
|
|
|
11
13
|
module Axm
|
|
14
|
+
# rubocop: disable Metrics/ClassLength
|
|
12
15
|
class Client
|
|
13
16
|
include MdmServers
|
|
14
17
|
include OrganizationDeviceActivities
|
|
@@ -58,13 +61,14 @@ module Axm
|
|
|
58
61
|
end
|
|
59
62
|
end
|
|
60
63
|
|
|
64
|
+
# rubocop: disable Metrics/MethodLength
|
|
61
65
|
def client_assertion
|
|
62
66
|
@client_assertion ||= begin
|
|
63
67
|
audience = 'https://account.apple.com/auth/oauth2/v2/token'
|
|
64
68
|
algo = 'ES256'
|
|
65
69
|
|
|
66
70
|
issued_at_timestamp = Time.now.utc.to_i
|
|
67
|
-
expiration_timestamp = issued_at_timestamp + 86_400 * 180 # 180 days
|
|
71
|
+
expiration_timestamp = issued_at_timestamp + (86_400 * 180) # 180 days
|
|
68
72
|
|
|
69
73
|
payload = {
|
|
70
74
|
sub: @client_id,
|
|
@@ -78,26 +82,23 @@ module Axm
|
|
|
78
82
|
JWT.encode(payload, @private_key, algo, kid: @key_id)
|
|
79
83
|
end
|
|
80
84
|
end
|
|
85
|
+
# rubocop: enable Metrics/MethodLength
|
|
81
86
|
|
|
82
87
|
def access_token
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if cached_access_token
|
|
86
|
-
token_expiration = Time.parse(cached_access_token['expires_at'])
|
|
88
|
+
if @cached_access_token
|
|
89
|
+
token_expiration = Time.parse(@cached_access_token['expires_at'])
|
|
87
90
|
token_expired = Time.now.utc >= token_expiration
|
|
88
91
|
|
|
89
|
-
return cached_access_token unless token_expired
|
|
92
|
+
return @cached_access_token unless token_expired
|
|
90
93
|
end
|
|
91
94
|
|
|
92
95
|
response = exchange_access_token_request
|
|
93
96
|
|
|
94
97
|
response_body = response.first if response.last.to_i == 200
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Secret.write('stub_access_token', token.to_json)
|
|
99
|
+
@cached_access_token = response_body.merge({ 'expires_at' => Time.now.utc + response_body['expires_in'] })
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
@cached_access_token
|
|
101
102
|
end
|
|
102
103
|
|
|
103
104
|
# Sends a GET request to the specified API endpoint.
|
|
@@ -107,6 +108,7 @@ module Axm
|
|
|
107
108
|
# - :paginate [Boolean] Whether to paginate through all results (unused).
|
|
108
109
|
# - :fields [Array<String>] Optional fields to include as fields[orgDevices].
|
|
109
110
|
# @return [Hash] The parsed JSON response.
|
|
111
|
+
# rubocop: disable Metrics/MethodLength, Metrics/AbcSize
|
|
110
112
|
def get(path, options = {})
|
|
111
113
|
options = options.dup
|
|
112
114
|
|
|
@@ -132,10 +134,12 @@ module Axm
|
|
|
132
134
|
|
|
133
135
|
JSON.parse(res.body)
|
|
134
136
|
end
|
|
137
|
+
# rubocop: enable Metrics/MethodLength, Metrics/AbcSize
|
|
135
138
|
|
|
136
139
|
# Sends a POST request to exchange the credentials for an access token.
|
|
137
140
|
#
|
|
138
141
|
# @return [Net::HTTPResponse, integer] The HTTP response object and status code.
|
|
142
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
139
143
|
def exchange_access_token_request
|
|
140
144
|
uri = URI('https://account.apple.com/auth/oauth2/v2/token')
|
|
141
145
|
|
|
@@ -166,6 +170,7 @@ module Axm
|
|
|
166
170
|
|
|
167
171
|
[response_json, response.code]
|
|
168
172
|
end
|
|
173
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
169
174
|
|
|
170
175
|
# Sends a POST request to the specified URI with given parameters.
|
|
171
176
|
#
|
|
@@ -175,13 +180,9 @@ module Axm
|
|
|
175
180
|
def post(path, request_body = {})
|
|
176
181
|
uri = URI("https://#{api_domain}/#{path}")
|
|
177
182
|
|
|
178
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
179
|
-
http.use_ssl = uri.scheme == 'https'
|
|
183
|
+
http = Net::HTTP.new(uri.host, uri.port, use_ssl: true)
|
|
180
184
|
|
|
181
|
-
request = Net::HTTP::Post.new(uri)
|
|
182
|
-
request['Host'] = uri.host
|
|
183
|
-
request['Content-Type'] = 'application/json'
|
|
184
|
-
request['Authorization'] = "Bearer #{access_token['access_token']}"
|
|
185
|
+
request = add_post_headers(Net::HTTP::Post.new(uri))
|
|
185
186
|
|
|
186
187
|
request.body = request_body.to_json unless request_body.empty?
|
|
187
188
|
|
|
@@ -191,5 +192,19 @@ module Axm
|
|
|
191
192
|
|
|
192
193
|
[response_body, response.code]
|
|
193
194
|
end
|
|
195
|
+
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
# Adds necessary headers to a POST request.
|
|
199
|
+
#
|
|
200
|
+
# @return [Net::HTTP::Post] The modified request with added headers.
|
|
201
|
+
def add_post_headers(request)
|
|
202
|
+
request['Host'] = uri.host
|
|
203
|
+
request['Content-Type'] = 'application/json'
|
|
204
|
+
request['Authorization'] = "Bearer #{access_token['access_token']}"
|
|
205
|
+
|
|
206
|
+
request
|
|
207
|
+
end
|
|
194
208
|
end
|
|
209
|
+
# rubocop: enable Metrics/ClassLength
|
|
195
210
|
end
|
data/lib/axm/secret.rb
CHANGED
data/lib/axm/version.rb
CHANGED
data/lib/axm.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
5
|
-
require_relative
|
|
3
|
+
require_relative 'axm/client'
|
|
4
|
+
require_relative 'axm/secret'
|
|
5
|
+
require_relative 'axm/version'
|
|
6
6
|
|
|
7
7
|
module Axm
|
|
8
8
|
class Error < StandardError; end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: axm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- nick-f
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
10
|
+
date: 2025-11-13 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: jwt
|
|
@@ -24,7 +23,6 @@ dependencies:
|
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '3.1'
|
|
27
|
-
description:
|
|
28
26
|
email:
|
|
29
27
|
- nick@nickf.dev
|
|
30
28
|
executables: []
|
|
@@ -53,7 +51,7 @@ licenses:
|
|
|
53
51
|
metadata:
|
|
54
52
|
homepage_uri: https://github.com/nick-f/axm
|
|
55
53
|
source_code_uri: https://github.com/nick-f/axm
|
|
56
|
-
|
|
54
|
+
rubygems_mfa_required: 'true'
|
|
57
55
|
rdoc_options: []
|
|
58
56
|
require_paths:
|
|
59
57
|
- lib
|
|
@@ -68,8 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
68
66
|
- !ruby/object:Gem::Version
|
|
69
67
|
version: '0'
|
|
70
68
|
requirements: []
|
|
71
|
-
rubygems_version: 3.5
|
|
72
|
-
signing_key:
|
|
69
|
+
rubygems_version: 3.6.5
|
|
73
70
|
specification_version: 4
|
|
74
71
|
summary: Gem to interact with the Apple Business Manager/Apple School Manager API
|
|
75
72
|
test_files: []
|