PK!lXffLICENSECopyright (c) 2018 macheins Provided that these terms and disclaimer and all copyright notices are retained or reproduced in an accompanying document, permission is granted to deal in this work without restriction, including un- limited rights to use, publicly perform, distribute, sell, modify, merge, give away, or sublicence. This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to the utmost extent permitted by applicable law, neither express nor implied; without malicious intent or gross negligence. In no event may a licensor, author or contributor be held liable for indirect, direct, other damage, loss, or other issues arising in any way out of dealing in the work, even if advised of the possibility of such damage or existence of a defect, except proven that it results out of said person's immediate fault when using the work as intended. PK!`^mkprofile/__init__.pyimport pkg_resources try: __version__ = pkg_resources.get_distribution(__name__).version except pkg_resources.DistributionNotFound: # pragma: no cover pass PK!mkprofile/__main__.pyimport sys from collections import defaultdict import click import yaml from .mobileconfig import Configuration, MCXPayload, Payload, toxml def _extend_dict(a, b): for k, v in b.items(): if k in a and v != a[k]: raise Exception() a[k] = v def _create_configuration_payloads(reqs, scope="system"): def merged(prop): out = defaultdict(lambda: defaultdict(dict)) for req in reqs: for scope, domains in req.get(prop, {}).items(): for domain, keys in domains.items(): _extend_dict(out[scope][domain], keys) return out profiles = merged("profiles") defaults = merged("defaults") payloads = [] for domain, keys in profiles[scope].items(): payloads.append(Payload(domain, **keys)) for domain, keys in defaults[scope].items(): payloads.append(MCXPayload(domain, **keys)) return payloads def _write_output(output, s): if isinstance(s, str): s = s.encode() if output is None: sys.stdout.buffer.write(s) else: with open(output, "wb") as fp: fp.write(s) @click.command() @click.option("-id", "--identifier", type=str, required=True) @click.option("-n", "--display-name", type=str) @click.option("-s", "--scope", type=str, default="system") @click.option("-o", "--output", type=str) @click.argument("files", type=click.File('rt'), nargs=-1) def cli(files, identifier, display_name, scope, output): kwargs = {} if display_name is not None: kwargs["PayloadDisplayName"] = display_name input_ = "" for f in files: input_ += f"{f.read()}\n" f.close() reqs = yaml.load(input_) or {} payloads = _create_configuration_payloads(reqs, scope) conf = Configuration( PayloadIdentifier=identifier, PayloadContent=payloads, **kwargs ) _write_output(output, toxml(conf)) if __name__ == "__main__": cli() PK!3 3 mkprofile/mobileconfig.pyimport uuid from lxml import etree as ET from lxml.builder import E __all__ = ["Configuration", "Payload", "MCXPayload", "toxml"] _UUID_NAMESPACE = uuid.UUID("edc00e4a-065a-4f58-ab24-3432f14b9e9e") def _Element(k, v): if isinstance(v, bool): v = E.true if v else E.false elif isinstance(v, int): v = E.integer(str(v)) elif isinstance(v, float): v = E.real(str(v)) elif isinstance(v, str): v = E.string(v) elif isinstance(v, list): v = E.array(*v) # TODO data # TODO date elif not isinstance(v, ET._Element): raise TypeError() return E.key(k), v def _Elements(**kwargs): els = [] for k, v in kwargs.items(): els.extend(_Element(k, v)) return els def Payload( PayloadType, *, PayloadUUID=None, PayloadIdentifier=None, PayloadVersion=1, **kwargs, ): if PayloadUUID is None: PayloadUUID = uuid.uuid4() PayloadUUID = str(PayloadUUID).upper() if PayloadIdentifier is None: PayloadIdentifier = PayloadType PayloadIdentifier = f"{PayloadIdentifier}.{PayloadUUID}" return E.dict( *_Elements( PayloadType=PayloadType, PayloadUUID=PayloadUUID, PayloadIdentifier=PayloadIdentifier, PayloadVersion=PayloadVersion, **kwargs, ) ) def MCXPayload(__domain__, **kwargs): # fmt: off return Payload( PayloadType="com.apple.ManagedClient.preferences", PayloadContent=E.dict(*_Element( __domain__, E.dict(*_Element( "Forced", [E.dict(*_Element( "mcx_preference_settings", E.dict( *_Elements(**kwargs) ), ))], )), )), ) # fmt: on def Configuration( PayloadIdentifier, *, PayloadUUID=None, PayloadDisplayName=None, PayloadScope="System", PayloadRemovalDisallowed=True, **kwargs, ): if PayloadDisplayName is None: PayloadDisplayName = PayloadIdentifier if PayloadUUID is None: PayloadUUID = uuid.uuid5(_UUID_NAMESPACE, PayloadIdentifier) root = E.plist( Payload( PayloadType="Configuration", PayloadUUID=PayloadUUID, PayloadIdentifier=PayloadIdentifier, PayloadDisplayName=PayloadDisplayName, PayloadScope=PayloadScope, PayloadRemovalDisallowed=PayloadRemovalDisallowed, **kwargs, ), version="1.0", ) tree = root.getroottree() tree.docinfo.public_id = "-//Apple//DTD PLIST 1.0//EN" tree.docinfo.system_url = "http://www.apple.com/DTDs/PropertyList-1.0.dtd" return tree def toxml(tree): return ET.tostring( tree, encoding="UTF-8", xml_declaration=True, pretty_print=True ) PK!H.4*mkprofile-2.0.0.dist-info/entry_points.txtN+I/N.,().(OIs3㭒s2PK!lXff!mkprofile-2.0.0.dist-info/LICENSECopyright (c) 2018 macheins Provided that these terms and disclaimer and all copyright notices are retained or reproduced in an accompanying document, permission is granted to deal in this work without restriction, including un- limited rights to use, publicly perform, distribute, sell, modify, merge, give away, or sublicence. This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to the utmost extent permitted by applicable law, neither express nor implied; without malicious intent or gross negligence. In no event may a licensor, author or contributor be held liable for indirect, direct, other damage, loss, or other issues arising in any way out of dealing in the work, even if advised of the possibility of such damage or existence of a defect, except proven that it results out of said person's immediate fault when using the work as intended. PK!HnHTUmkprofile-2.0.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!Hڢ"mkprofile-2.0.0.dist-info/METADATAT]o0}TiZvJ}ZۤjRs!v4~ 0}uϹ;x1Ϣ`EBS2a ꥐ@ZA< iUBW 2l{~%|^.bU_1(\^p('&ӟ2*}-a-*`͛a|ѻ:·9'p((Nc;[a@ѭѼ2 ^<2:ۂ⑓4LF 2ρA^)R 5{ >aڙUqwgߪ]M3ԡ~"u+41}Vt6 x'FX=nW?ݧi 9^R GS K-6SX -fjKx  0v7[iVn`11fsqvu=X'X7 Ȯ Q;-{eOG!v ijTT0qUhPK!HAw mkprofile-2.0.0.dist-info/RECORD;@|~ 8h (QI(5vh'Npmj7.I]_)Q@5n4wfv~hp[E>¦ʴ#s=Ӳc4F_Z^:X!ecD~`j-5mn ~TϡBjS_Զl6;GPi& ި; Y㡗8*:!kWotalPe PK!lXffLICENSEPK!`^mkprofile/__init__.pyPK!dmkprofile/__main__.pyPK!3 3 ; mkprofile/mobileconfig.pyPK!H.4*mkprofile-2.0.0.dist-info/entry_points.txtPK!lXff!mkprofile-2.0.0.dist-info/LICENSEPK!HnHTUmkprofile-2.0.0.dist-info/WHEELPK!Hڢ"Qmkprofile-2.0.0.dist-info/METADATAPK!HAw 3mkprofile-2.0.0.dist-info/RECORDPK !