Get it working with vue js
This commit is contained in:
parent
9d67216a6d
commit
2944056fc0
3 changed files with 204 additions and 161 deletions
|
@ -0,0 +1,6 @@
|
||||||
|
body {
|
||||||
|
font-family: "JetBrains Mono", "Roboto Mono", "Menlo", monospace;
|
||||||
|
}
|
||||||
|
#profile {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
112
index.html
112
index.html
|
@ -6,16 +6,116 @@
|
||||||
<title></title>
|
<title></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="css/main.css">
|
<link rel="stylesheet" href="css/main.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<form id="profile-form">
|
<div id="app">
|
||||||
<button type="button" onclick="generateProfile()">Generate</button>
|
<h1>1. Fill in the forms for your email configuration profile</h1>
|
||||||
<p>
|
<p>Documentation can be found
|
||||||
<label for="profile">Generated profile</label>
|
<a href="https://developer.apple.com/documentation/devicemanagement/configuring_multiple_devices_using_profiles">here</a>
|
||||||
<textarea name="profile" id="profile" cols="80" rows="15"></textarea>
|
for common fields and
|
||||||
|
<a href="https://developer.apple.com/documentation/devicemanagement/mail">here</a>
|
||||||
|
for email specific fields.
|
||||||
</p>
|
</p>
|
||||||
</form>
|
<div id="profile">
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version='1.0'>
|
||||||
|
<dict>
|
||||||
|
<key>PayloadContent</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>EmailAccountType</key>
|
||||||
|
<string><select v-model="payload.EmailAccountType">
|
||||||
|
<option value="" disabled>Select...</option>
|
||||||
|
<option>EmailTypeIMAP</option>
|
||||||
|
<option>EmailTypePOP</option>
|
||||||
|
</select></string>
|
||||||
|
<key>EmailAddress</key>
|
||||||
|
<string><input type="email" v-model="payload.EmailAddress" v-bind:placeholder="payloadPlaceholders.EmailAddress"></string>
|
||||||
|
<key>EmailAccountDescription</key>
|
||||||
|
<string><input type="text" v-model="payload.EmailAccountDescription" v-bind:placeholder="payloadPlaceholders.EmailAccountDescription"></string>
|
||||||
|
|
||||||
|
<!-- Incoming -->
|
||||||
|
<key>IncomingMailServerAuthentication</key>
|
||||||
|
<string><select v-model="payload.IncomingMailServerAuthentication">
|
||||||
|
<option value="" disabled>Select...</option>
|
||||||
|
<option>EmailAuthNone</option>
|
||||||
|
<option>EmailAuthPassword</option>
|
||||||
|
<option>EmailAuthCRAMMD5</option>
|
||||||
|
<option>EmailAuthNTLM</option>
|
||||||
|
<option>EmailAuthHTTPMD5</option>
|
||||||
|
</select></string>
|
||||||
|
<key>IncomingMailServerHostName</key>
|
||||||
|
<string><input type="text" v-model="payload.IncomingMailServerHostName" v-bind:placeholder="payloadPlaceholders.IncomingMailServerHostName"></string>
|
||||||
|
<key>IncomingMailServerPortNumber</key>
|
||||||
|
<integer><input type="number" v-model="payload.IncomingMailServerPortNumber" v-bind:placeholder="payloadPlaceholders.IncomingMailServerPortNumber"></integer>
|
||||||
|
<key>IncomingMailServerUsername</key>
|
||||||
|
<string><input type="text" v-model="payload.IncomingMailServerUsername" v-bind:placeholder="payloadPlaceholders.IncomingMailServerUsername"></string>
|
||||||
|
<key>IncomingMailServerUseSSL</key>
|
||||||
|
<<input type="checkbox" v-model="payload.IncomingMailServerUseSSL">/>
|
||||||
|
|
||||||
|
<!-- Outgoing -->
|
||||||
|
<key>OutgoingMailServerAuthentication</key>
|
||||||
|
<string><select v-model="payload.OutgoingMailServerAuthentication">
|
||||||
|
<option value="" disabled>Select...</option>
|
||||||
|
<option>EmailAuthNone</option>
|
||||||
|
<option>EmailAuthPassword</option>
|
||||||
|
<option>EmailAuthCRAMMD5</option>
|
||||||
|
<option>EmailAuthNTLM</option>
|
||||||
|
<option>EmailAuthHTTPMD5</option>
|
||||||
|
</select></string>
|
||||||
|
<key>OutgoingMailServerHostName</key>
|
||||||
|
<string><input type="text" v-model="payload.OutgoingMailServerHostName" v-bind:placeholder="payloadPlaceholders.OutgoingMailServerHostName"></string>
|
||||||
|
<key>OutgoingMailServerPortNumber</key>
|
||||||
|
<integer><input type="number" v-model="payload.OutgoingMailServerPortNumber" v-bind:placeholder="payloadPlaceholders.OutgoingMailServerPortNumber"></integer>
|
||||||
|
<key>OutgoingMailServerUsername</key>
|
||||||
|
<string><input type="text" v-model="payload.OutgoingMailServerUsername" v-bind:placeholder="payloadPlaceholders.OutgoingMailServerUsername"></string>
|
||||||
|
<key>OutgoingMailServerUseSSL</key>
|
||||||
|
<<input type="checkbox" v-model="payload.OutgoingMailServerUseSSL">/>
|
||||||
|
<key>OutgoingPasswordSameAsIncomingPassword</key>
|
||||||
|
<<input type="checkbox" v-model="payload.OutgoingPasswordSameAsIncomingPassword">/>
|
||||||
|
|
||||||
|
<!-- Common keys -->
|
||||||
|
<key>PayloadDisplayName</key>
|
||||||
|
<string><input type="text" v-model="payload.PayloadDisplayName" v-bind:placeholder="payloadPlaceholders.PayloadDisplayName"></string>
|
||||||
|
<key>PayloadDescription</key>
|
||||||
|
<string><input type="text" v-model="payload.PayloadDescription" v-bind:placeholder="payloadPlaceholders.PayloadDescription"></string>
|
||||||
|
<key>PayloadIdentifier</key>
|
||||||
|
<string><input type="text" v-model="payload.PayloadIdentifier" v-bind:placeholder="payloadPlaceholders.PayloadIdentifier"></string>
|
||||||
|
<key>PayloadType</key>
|
||||||
|
<string>{{ payload.PayloadType }}</string>
|
||||||
|
<key>PayloadUUID</key>
|
||||||
|
<string>{{ payload.PayloadUUID() }}</string>
|
||||||
|
<key>PayloadVersion</key>
|
||||||
|
<integer>{{ payload.PayloadVersion }}</integer>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<!-- Common keys -->
|
||||||
|
<key>PayloadDisplayName</key>
|
||||||
|
<string><input type="text" v-model="container.PayloadDisplayName" v-bind:placeholder="containerPlaceholders.PayloadDisplayName"></string>
|
||||||
|
<key>PayloadDescription</key>
|
||||||
|
<string><input type="text" v-model="container.PayloadDescription" v-bind:placeholder="containerPlaceholders.PayloadDescription"></string>
|
||||||
|
<key>PayloadIdentifier</key>
|
||||||
|
<string><input type="text" v-model="container.PayloadIdentifier" v-bind:placeholder="containerPlaceholders.PayloadIdentifier"></string>
|
||||||
|
<key>PayloadType</key>
|
||||||
|
<string>{{ container.PayloadType }}</string>
|
||||||
|
<key>PayloadUUID</key>
|
||||||
|
<string>{{ container.PayloadUUID() }}</string>
|
||||||
|
<key>PayloadVersion</key>
|
||||||
|
<integer>{{ container.PayloadVersion }}</integer>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>2. Download your profile</h1>
|
||||||
|
<a v-bind:href="generatedProfileLink" v-bind:download="downloadFileName">Download</a>
|
||||||
|
|
||||||
|
<h1>3. Or copy/paste</h1>
|
||||||
|
<textarea rows="30" cols="80">{{ generatedProfile }}</textarea>
|
||||||
|
</div>
|
||||||
<script src="js/main.js"></script>
|
<script src="js/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
221
js/main.js
221
js/main.js
|
@ -1,41 +1,61 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
payload: {
|
||||||
|
EmailAccountType: "",
|
||||||
|
EmailAddress: "",
|
||||||
|
EmailAccountDescription: "",
|
||||||
|
|
||||||
|
IncomingMailServerAuthentication: "",
|
||||||
|
IncomingMailServerHostName: "",
|
||||||
|
IncomingMailServerPortNumber: null,
|
||||||
|
IncomingMailServerUsername: "",
|
||||||
|
IncomingMailServerUseSSL: null,
|
||||||
|
|
||||||
|
OutgoingMailServerAuthentication: "",
|
||||||
|
OutgoingMailServerHostName: "",
|
||||||
|
OutgoingMailServerPortNumber: null,
|
||||||
|
OutgoingMailServerUsername: "",
|
||||||
|
OutgoingMailServerUseSSL: null,
|
||||||
|
OutgoingPasswordSameAsIncomingPassword: null,
|
||||||
|
|
||||||
let payloadForm = {
|
PayloadDescription: "",
|
||||||
EmailAccountType: {type: "string", choices: ["EmailTypeIMAP"]},
|
PayloadDisplayName: "",
|
||||||
EmailAddress: {type: "string"},
|
PayloadIdentifier: "",
|
||||||
EmailAccountDescription: {type: "string"},
|
PayloadType: "com.apple.mail.managed",
|
||||||
|
PayloadUUID: generateUUID,
|
||||||
|
PayloadVersion: 1,
|
||||||
|
},
|
||||||
|
payloadPlaceholders: {
|
||||||
|
EmailAddress: "john@example.com",
|
||||||
|
EmailAccountDescription: "Example email account",
|
||||||
|
|
||||||
IncomingMailServerAuthentication: {type: "string", choices: ["EmailAuthPassword"]},
|
IncomingMailServerHostName: "imap.example.com",
|
||||||
IncomingMailServerHostName: {type: "string"},
|
IncomingMailServerPortNumber: 993,
|
||||||
IncomingMailServerPortNumber: {type: "number"},
|
IncomingMailServerUsername: "john@example.com",
|
||||||
IncomingMailServerUsername: {type: "string"},
|
|
||||||
IncomingMailServerUseSSL: {type: "boolean"},
|
|
||||||
|
|
||||||
OutgoingMailServerAuthentication: {type: "string", choices: ["EmailAuthPassword"]},
|
OutgoingMailServerHostName: "smtp.example.com",
|
||||||
OutgoingMailServerHostName: {type: "string"},
|
OutgoingMailServerPortNumber: 465,
|
||||||
OutgoingMailServerPortNumber: {type: "number"},
|
OutgoingMailServerUsername: "john@example.com",
|
||||||
OutgoingMailServerUsername: {type: "string"},
|
|
||||||
OutgoingMailServerUseSSL: {type: "boolean"},
|
|
||||||
OutgoingPasswordSameAsIncomingPassword: {type: "boolean"},
|
|
||||||
|
|
||||||
PayloadDescription: {type: "string"},
|
PayloadDescription: "Email configuration profile",
|
||||||
PayloadDisplayName: {type: "string"},
|
PayloadDisplayName: "Display name",
|
||||||
PayloadIdentifier: {type: "string"},
|
PayloadIdentifier: "com.apple.dns.reverse",
|
||||||
PayloadType: {type: "string", constant: true, value: "com.apple.mail.managed"},
|
},
|
||||||
PayloadUUID: {type: "function", constant: true, value: generateUUID},
|
container: {
|
||||||
PayloadVersion: {type: "number", constant: true, value: 1},
|
PayloadDescription: "",
|
||||||
}
|
PayloadDisplayName: "",
|
||||||
|
PayloadIdentifier: "",
|
||||||
let containerForm = {
|
PayloadType: "Configuration",
|
||||||
PayloadDescription: {type: "string"},
|
PayloadUUID: generateUUID,
|
||||||
PayloadDisplayName: {type: "string"},
|
PayloadVersion: 1,
|
||||||
PayloadIdentifier: {type: "string"},
|
},
|
||||||
PayloadType: {type: "string", constant: true, value: "Configuration"},
|
containerPlaceholders: {
|
||||||
PayloadUUID: {type: "function", constant: true, value: generateUUID},
|
PayloadDescription: "Email configuration profile",
|
||||||
PayloadVersion: {type: "number", constant: true, value: 1},
|
PayloadDisplayName: "Display name",
|
||||||
|
PayloadIdentifier: "com.apple.dns.reverse",
|
||||||
|
},
|
||||||
|
generated: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateUUID() {
|
function generateUUID() {
|
||||||
|
@ -45,7 +65,7 @@ function generateUUID() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertKeyValueToXml(xmlDoc, key, value) {
|
function convertKeyValueToXml(xmlDoc, key, value) {
|
||||||
let keyElement = xmlDoc.createElement("key");
|
const keyElement = xmlDoc.createElement("key");
|
||||||
keyElement.innerHTML = key;
|
keyElement.innerHTML = key;
|
||||||
|
|
||||||
let valueElementTag = null;
|
let valueElementTag = null;
|
||||||
|
@ -64,138 +84,55 @@ function convertKeyValueToXml(xmlDoc, key, value) {
|
||||||
if (valueElementTag === null) {
|
if (valueElementTag === null) {
|
||||||
throw Error("Value type not recognized")
|
throw Error("Value type not recognized")
|
||||||
}
|
}
|
||||||
let valueElement = xmlDoc.createElement(valueElementTag);
|
const valueElement = xmlDoc.createElement(valueElementTag);
|
||||||
if (typeof value === "number" || typeof value === "string"){
|
if (typeof value === "number" || typeof value === "string"){
|
||||||
valueElement.innerHTML = value;
|
valueElement.innerHTML = value;
|
||||||
}
|
}
|
||||||
return [keyElement, valueElement];
|
return [keyElement, valueElement];
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateProfile(event) {
|
const app = new Vue({
|
||||||
let payload = {
|
el: '#app',
|
||||||
EmailAccountType: "EmailTypeIMAP",
|
data: data,
|
||||||
EmailAddress: "gabriel@augendre.info",
|
computed: {
|
||||||
EmailAccountDescription: "Migadu",
|
generatedProfile: function () {
|
||||||
|
const template = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||||
IncomingMailServerAuthentication: "EmailAuthPassword",
|
|
||||||
IncomingMailServerHostName: "imap.migadu.com",
|
|
||||||
IncomingMailServerPortNumber: 993,
|
|
||||||
IncomingMailServerUsername: "gabriel@augendre.info",
|
|
||||||
IncomingMailServerUseSSL: true,
|
|
||||||
|
|
||||||
OutgoingMailServerAuthentication: "EmailAuthPassword",
|
|
||||||
OutgoingMailServerHostName: "smtp.migadu.com",
|
|
||||||
OutgoingMailServerPortNumber: 465,
|
|
||||||
OutgoingMailServerUsername: "gabriel@augendre.info",
|
|
||||||
OutgoingMailServerUseSSL: true,
|
|
||||||
OutgoingPasswordSameAsIncomingPassword: true,
|
|
||||||
|
|
||||||
PayloadDisplayName: "Migadu",
|
|
||||||
PayloadIdentifier: "info.augendre.mail.config.migadu",
|
|
||||||
PayloadType: "com.apple.mail.managed",
|
|
||||||
PayloadUUID: generateUUID,
|
|
||||||
PayloadVersion: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
let container = {
|
|
||||||
PayloadDescription: "Migadu email configuration profile",
|
|
||||||
PayloadDisplayName: "Migadu",
|
|
||||||
PayloadIdentifier: "info.augendre.mail.config.migadu",
|
|
||||||
PayloadType: "Configuration",
|
|
||||||
PayloadUUID: generateUUID,
|
|
||||||
PayloadVersion: 1,
|
|
||||||
}
|
|
||||||
let downloadLink = document.getElementById("download-link");
|
|
||||||
if (downloadLink) {
|
|
||||||
document.body.removeChild(downloadLink);
|
|
||||||
}
|
|
||||||
|
|
||||||
let template = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
|
||||||
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
|
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
|
||||||
"<plist version='1.0'><dict></dict></plist>"
|
"<plist version='1.0'><dict></dict></plist>"
|
||||||
let parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
let xmlDoc = parser.parseFromString(template, "application/xml");
|
const xmlDoc = parser.parseFromString(template, "application/xml");
|
||||||
let dict = xmlDoc.getElementsByTagName("dict")[0];
|
const dict = xmlDoc.getElementsByTagName("dict")[0];
|
||||||
|
|
||||||
let contentElement = xmlDoc.createElement("key");
|
const contentElement = xmlDoc.createElement("key");
|
||||||
contentElement.innerHTML = "PayloadContent";
|
contentElement.innerHTML = "PayloadContent";
|
||||||
dict.appendChild(contentElement);
|
dict.appendChild(contentElement);
|
||||||
let arrayElement = xmlDoc.createElement("array");
|
const arrayElement = xmlDoc.createElement("array");
|
||||||
dict.appendChild(arrayElement);
|
dict.appendChild(arrayElement);
|
||||||
let contentDict = xmlDoc.createElement("dict");
|
const contentDict = xmlDoc.createElement("dict");
|
||||||
arrayElement.appendChild(contentDict);
|
arrayElement.appendChild(contentDict);
|
||||||
|
|
||||||
for (let [key, value] of Object.entries(payload)) {
|
for (const [key, value] of Object.entries(this.payload)) {
|
||||||
let [keyElement, valueElement] = convertKeyValueToXml(xmlDoc, key, value);
|
const [keyElement, valueElement] = convertKeyValueToXml(xmlDoc, key, value);
|
||||||
contentDict.appendChild(keyElement);
|
contentDict.appendChild(keyElement);
|
||||||
contentDict.appendChild(valueElement);
|
contentDict.appendChild(valueElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let [key, value] of Object.entries(container)) {
|
for (const [key, value] of Object.entries(this.container)) {
|
||||||
let [keyElement, valueElement] = convertKeyValueToXml(xmlDoc, key, value);
|
const [keyElement, valueElement] = convertKeyValueToXml(xmlDoc, key, value);
|
||||||
dict.appendChild(keyElement);
|
dict.appendChild(keyElement);
|
||||||
dict.appendChild(valueElement);
|
dict.appendChild(valueElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const serializer = new XMLSerializer();
|
||||||
var serializer = new XMLSerializer();
|
return serializer.serializeToString(xmlDoc);
|
||||||
var xmlString = serializer.serializeToString(xmlDoc);
|
},
|
||||||
|
generatedProfileLink: function () {
|
||||||
let area = document.getElementById("profile");
|
const xmlString = this.generatedProfile;
|
||||||
area.value = xmlString;
|
return 'data:application/xml;charset=utf-8,' + encodeURIComponent(xmlString);
|
||||||
|
},
|
||||||
let link = document.createElement('a');
|
downloadFileName: function() {
|
||||||
link.setAttribute("id", "download-link")
|
return `${this.payload.EmailAddress}.mobileconfig`;
|
||||||
link.setAttribute('href', 'data:application/xml;charset=utf-8,' + encodeURIComponent(xmlString));
|
},
|
||||||
link.setAttribute('download', `${payload.EmailAddress}.mobileconfig`);
|
|
||||||
link.innerHTML = "Download profile";
|
|
||||||
document.body.appendChild(link);
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
function getElemFromConfig(key, value, prefix) {
|
|
||||||
const identifier = `${prefix}-${key}`;
|
|
||||||
let input = document.createElement("input");
|
|
||||||
input.setAttribute("type", value.type);
|
|
||||||
input.setAttribute("id", identifier);
|
|
||||||
input.setAttribute("name", identifier);
|
|
||||||
|
|
||||||
let defaultValue = value.value;
|
|
||||||
if (typeof defaultValue === "function") {
|
|
||||||
defaultValue = defaultValue();
|
|
||||||
}
|
|
||||||
if (defaultValue) {
|
|
||||||
input.value = defaultValue;
|
|
||||||
}
|
|
||||||
if (value.constant) {
|
|
||||||
input.setAttribute("disabled", "disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
let label = document.createElement("label");
|
|
||||||
label.setAttribute("for", identifier);
|
|
||||||
label.innerHTML = key;
|
|
||||||
|
|
||||||
const p = document.createElement("p");
|
|
||||||
p.appendChild(label);
|
|
||||||
p.appendChild(input);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function(){
|
|
||||||
let form = document.getElementById("profile-form");
|
|
||||||
let button = document.querySelector("form#profile-form button[type='button']");
|
|
||||||
let title = document.createElement("h2");
|
|
||||||
title.innerHTML = "Container"
|
|
||||||
form.insertBefore(title, button);
|
|
||||||
for (let [key, value] of Object.entries(containerForm)) {
|
|
||||||
let line = getElemFromConfig(key, value, "container");
|
|
||||||
form.insertBefore(line, button);
|
|
||||||
}
|
|
||||||
title = document.createElement("h2");
|
|
||||||
title.innerHTML = "Payload"
|
|
||||||
form.insertBefore(title, button);
|
|
||||||
for (let [key, value] of Object.entries(payloadForm)) {
|
|
||||||
let line = getElemFromConfig(key, value, "payload");
|
|
||||||
form.insertBefore(line, button);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue