Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add auto-generated json schema for every payload type.
- Loading branch information
Showing
73 changed files
with
7,512 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/usr/bin/env bash | ||
DESTDIR="./source/_static/json-schema" | ||
|
||
for filename in ./source/_static/manifests/*.plist; do | ||
echo ${filename} | ||
BASENAME=$(basename "${filename}") | ||
|
||
python ./pfm2jsonschema/pfm2jsonschema.py -o "${DESTDIR}" "${filename}" | ||
done | ||
|
||
for filename in ./source/payloads/manifests/manual/*.plist; do | ||
echo ${filename} | ||
BASENAME=$(basename "${filename}") | ||
|
||
python ./pfm2jsonschema/pfm2jsonschema.py -o "${DESTDIR}" "${filename}" | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#!/usr/bin/env python | ||
|
||
import plistlib | ||
import json | ||
import os.path | ||
import logging | ||
from optparse import OptionParser | ||
|
||
logger = logging.getLogger('pfm2jsonschema') | ||
|
||
def generate_pfm_header(data, result): | ||
"""Generate a top-level JSON schema""" | ||
result['title'] = data.get('pfm_domain', 'Untitled') | ||
result['type'] = 'object' | ||
|
||
properties = {} | ||
generate(data['pfm_subkeys'], properties) | ||
|
||
result['properties'] = properties | ||
|
||
def pfm_to_jsontype(pfm_type): | ||
"""Return the JSON Schema form of the given pfm_type""" | ||
translated = { | ||
'integer': 'number', | ||
'real': 'number', | ||
'data': 'string', | ||
'date': 'string', | ||
'dictionary': 'object' | ||
} | ||
|
||
if pfm_type in translated: | ||
return translated[pfm_type] | ||
else: | ||
logger.debug("possibly unhandled pfm_type: {}".format(pfm_type)) | ||
# Types that are identically named: array, string | ||
return pfm_type | ||
|
||
def generate_pfm_item(data, result): | ||
"""Generate a JSON Schema object from a pfm item i.e an item in the schema that has at least a pfm_name.""" | ||
logger.debug("generating schema for property: {}".format(data['pfm_name'])) | ||
|
||
if data['pfm_name'] in result: | ||
raise Exception('Already in properties dict: {}'.format(data['pfm_name'])) | ||
|
||
prop = {} | ||
prop['type'] = pfm_to_jsontype(data['pfm_type']) | ||
|
||
if 'pfm_description' in data: | ||
prop['description'] = data['pfm_description'] | ||
|
||
if 'pfm_default' in data: | ||
# TODO: need processing of dict defaults | ||
prop['default'] = data['pfm_default'] | ||
|
||
if 'pfm_range_list' in data: | ||
prop['enum'] = data['pfm_range_list'] | ||
|
||
if 'pfm_range_min' in data: | ||
prop['minimum'] = data['pfm_range_min'] | ||
|
||
if 'pfm_range_max' in data: | ||
prop['maximum'] = data['pfm_range_max'] | ||
|
||
if 'pfm_format' in data: | ||
prop['pattern'] = data['pfm_format'] | ||
|
||
if data['pfm_type'] == 'date': | ||
prop['format'] = 'date-time' # Use predefined RFC3339 formatting | ||
|
||
if 'pfm_subkeys' in data: | ||
if prop['type'] == 'array': | ||
prop['items'] = {} | ||
# Have to discard the pfm_name in the items sub schema | ||
|
||
item = {} | ||
generate(data['pfm_subkeys'][0], item) | ||
name, value = item.items()[0] | ||
|
||
prop['items'] = value | ||
else: | ||
prop['properties'] = {} | ||
generate(data['pfm_subkeys'], prop['properties']) | ||
|
||
result[data['pfm_name']] = prop | ||
|
||
|
||
def generate(data, result): | ||
"""Generate a JSON Schema object as a dict from a parsed plist manifest given as a dict""" | ||
logger.debug("generate()") | ||
|
||
if isinstance(data, dict): | ||
if 'pfm_name' in data: | ||
logging.debug("generate pfm dict: {}".format(data['pfm_name'])) | ||
return generate_pfm_item(data, result) | ||
elif 'pfm_version' in data: # probably top level dict | ||
logging.debug("generate pfm header") | ||
generate_pfm_header(data, result) | ||
else: | ||
logger.debug("generate non pfm dict") | ||
elif isinstance(data, list): | ||
logger.debug("generating list") | ||
for item in data: | ||
generate(item, result) | ||
else: | ||
logger.debug("unhandled type") | ||
|
||
return None | ||
|
||
|
||
if __name__ == "__main__": | ||
usage = "usage: %prog [options] manifest.plist" | ||
parser = OptionParser(usage=usage) | ||
parser.add_option("-o", "--output", dest="output", | ||
help="write template to output dir", metavar="DIR") | ||
|
||
(options, args) = parser.parse_args() | ||
|
||
ch = logging.StreamHandler() | ||
logger.addHandler(ch) | ||
logger.setLevel(logging.DEBUG) | ||
|
||
plist = plistlib.readPlist(args[-1]) | ||
domain = plist['pfm_domain'] | ||
|
||
result = { | ||
"$schema": "http://json-schema.org/schema#" | ||
} | ||
generate(plist, result) | ||
|
||
if options.output: | ||
with open(os.path.join(options.output, '{}.json'.format(domain)), 'w+') as f: | ||
json.dump(result, f, indent=4) | ||
else: | ||
print(json.dumps(result)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
{ | ||
"$schema": "http://json-schema.org/schema#", | ||
"type": "object", | ||
"properties": { | ||
"PayloadUUID": { | ||
"default": "", | ||
"pattern": "^[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}$", | ||
"type": "string", | ||
"description": "Unique identifier for the payload (format 01234567-89AB-CDEF-0123-456789ABCDEF)" | ||
}, | ||
"PayloadDescription": { | ||
"default": "Loginwindow GlobalPreferences", | ||
"type": "string", | ||
"description": "Description of the payload" | ||
}, | ||
"com.apple.autologout.AutoLogOutDelay": { | ||
"default": 0, | ||
"type": "number", | ||
"description": "Automatically log out after this many seconds of inactivity" | ||
}, | ||
"PayloadOrganization": { | ||
"type": "string", | ||
"description": "This value describes the issuing organization of the profile, as displayed to the user" | ||
}, | ||
"MultipleSessionEnabled": { | ||
"type": "boolean", | ||
"description": "Enable fast user switching" | ||
}, | ||
"PayloadIdentifier": { | ||
"default": "GlobalPreferences", | ||
"type": "string", | ||
"description": "A unique identifier for the payload, dot-delimited. Usually root PayloadIdentifier+subidentifier" | ||
}, | ||
"PayloadDisplayName": { | ||
"default": "Loginwindow GlobalPreferences", | ||
"type": "string", | ||
"description": "Name of the payload" | ||
}, | ||
"PayloadType": { | ||
"default": ".GlobalPreferences", | ||
"type": "string", | ||
"description": "The type of the payload, a reverse dns string" | ||
}, | ||
"PayloadVersion": { | ||
"default": 1, | ||
"type": "number", | ||
"description": "The version of the whole configuration profile." | ||
} | ||
}, | ||
"title": ".GlobalPreferences" | ||
} |
100 changes: 100 additions & 0 deletions
100
source/_static/json-schema/com.apple.ADCertificate.managed.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
{ | ||
"$schema": "http://json-schema.org/schema#", | ||
"type": "object", | ||
"properties": { | ||
"PayloadUUID": { | ||
"default": "", | ||
"pattern": "^[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}$", | ||
"type": "string", | ||
"description": "Unique identifier for the payload (format 01234567-89AB-CDEF-0123-456789ABCDEF)" | ||
}, | ||
"UserName": { | ||
"type": "string", | ||
"description": "The user name with which to authenticate to the certificate server" | ||
}, | ||
"PayloadDescription": { | ||
"default": "Requests an Active Directory certificate", | ||
"type": "string", | ||
"description": "Description of the payload" | ||
}, | ||
"KeyIsExtractable": { | ||
"default": false, | ||
"type": "boolean", | ||
"description": "Allow admin to export private key from the keychain" | ||
}, | ||
"Description": { | ||
"type": "string", | ||
"description": "The description of the certificate request as shown in the certificate selector of other payloads such as VPN and Network" | ||
}, | ||
"CertificateAuthority": { | ||
"type": "string", | ||
"description": "Name of the CA. This value is determined from the Common Name (CN) of the Active Directory entry: CN=(your CA name), CN='Certification Authorities', CN='Public Key Services', CN='Services', or CN='Configuration', (your base Domain Name)." | ||
}, | ||
"AllowAllAppsAccess": { | ||
"default": false, | ||
"type": "boolean", | ||
"description": "Allow all apps to access the certificate in the keychain" | ||
}, | ||
"PayloadOrganization": { | ||
"type": "string", | ||
"description": "This value describes the issuing organization of the profile, as displayed to the user" | ||
}, | ||
"PayloadIdentifier": { | ||
"default": "com.apple.ADCertificate.managed", | ||
"type": "string", | ||
"description": "A unique identifier for the payload, dot-delimited. Usually root PayloadIdentifier+subidentifier" | ||
}, | ||
"PayloadDisplayName": { | ||
"default": "AD Certificate", | ||
"type": "string", | ||
"description": "Name of the payload" | ||
}, | ||
"CertTemplate": { | ||
"default": "User", | ||
"type": "string", | ||
"description": "Template Name as it appears in the General tab of the template\u2019s object in the Certificate Templates\u2019 Microsoft Management Console snap-in component." | ||
}, | ||
"PayloadType": { | ||
"default": "com.apple.ADCertificate.managed", | ||
"type": "string", | ||
"description": "The type of the payload, a reverse dns string" | ||
}, | ||
"CertificateAcquisitionMechanism": { | ||
"enum": [ | ||
"RPC", | ||
"HTTP" | ||
], | ||
"type": "string", | ||
"description": "Most commonly RPC. If using Web enrollment, HTTP." | ||
}, | ||
"Keysize": { | ||
"default": 2048, | ||
"type": "number", | ||
"description": "The RSA key size for the Certificate Signing Request (CSR)." | ||
}, | ||
"PromptForCredentials": { | ||
"default": false, | ||
"type": "boolean", | ||
"description": "Prompt the user for credentials. This setting is not supported for pushed profiles" | ||
}, | ||
"PayloadVersion": { | ||
"default": 1, | ||
"type": "number", | ||
"description": "The version of the whole configuration profile." | ||
}, | ||
"CertificateRenewalTimeInterval": { | ||
"default": 14, | ||
"type": "number", | ||
"description": "The number of days before the certificate expires at which to start showing the expiration notification" | ||
}, | ||
"Password": { | ||
"type": "string", | ||
"description": "The password with which to authenticate to the certificate server" | ||
}, | ||
"CertServer": { | ||
"type": "string", | ||
"description": "Fully qualified host name of the Active Directory issuing CA." | ||
} | ||
}, | ||
"title": "com.apple.ADCertificate.managed" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
{ | ||
"$schema": "http://json-schema.org/schema#", | ||
"type": "object", | ||
"properties": { | ||
"PayloadUUID": { | ||
"default": "", | ||
"pattern": "^[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}$", | ||
"type": "string", | ||
"description": "Unique identifier for the payload (format 01234567-89AB-CDEF-0123-456789ABCDEF)" | ||
}, | ||
"PayloadDescription": { | ||
"default": "Parental Controls: Dictionary", | ||
"type": "string", | ||
"description": "Description of the payload" | ||
}, | ||
"PayloadOrganization": { | ||
"type": "string", | ||
"description": "This value describes the issuing organization of the profile, as displayed to the user" | ||
}, | ||
"PayloadIdentifier": { | ||
"default": "com.apple.Dictionary", | ||
"type": "string", | ||
"description": "A unique identifier for the payload, dot-delimited. Usually root PayloadIdentifier+subidentifier" | ||
}, | ||
"PayloadDisplayName": { | ||
"default": "Parental Controls: Dictionary", | ||
"type": "string", | ||
"description": "Name of the payload" | ||
}, | ||
"PayloadType": { | ||
"default": "com.apple.Dictionary", | ||
"type": "string", | ||
"description": "The type of the payload, a reverse dns string" | ||
}, | ||
"PayloadVersion": { | ||
"default": 1, | ||
"type": "number", | ||
"description": "The version of the whole configuration profile." | ||
}, | ||
"parentalControl": { | ||
"type": "boolean", | ||
"description": "Required. Set to true to enable parental controls dictionary restrictions." | ||
} | ||
}, | ||
"title": "com.apple.Dictionary" | ||
} |
Oops, something went wrong.