-
Notifications
You must be signed in to change notification settings - Fork 360
/
helpers.tsx
134 lines (126 loc) · 4.26 KB
/
helpers.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import React from "react";
import { AxiosResponse } from "axios";
import { IApiError } from "interfaces/errors";
// TODO: mobileconfig parser is a work in progress and not yet used in production
// https://developer.apple.com/documentation/devicemanagement/configuring_multiple_devices_using_profiles#3234127
const parseMobileconfig = (file: File): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsText(file);
reader.onerror = (error) => {
reject(error);
};
reader.onabort = (error) => {
reject(error);
};
reader.onload = () => {
try {
// parse mobile as xml
const xmlDoc = new DOMParser().parseFromString(
reader.result as string,
"text/xml"
);
// check for any parser errors
const parserErrors = xmlDoc.getElementsByTagName("parsererror");
if (parserErrors.length > 0) {
console.warn("parserErrors", parserErrors);
throw new Error("Invalid file: parser error");
}
// get the top-level object, we assume it is the first `<dict>` element in the `<plist>`
// https://developer.apple.com/documentation/devicemanagement/toplevel
const tlo = xmlDoc.getElementsByTagName("dict")?.[0];
if (tlo?.parentElement?.tagName !== "plist") {
throw new Error("Invalid file: missing plist");
}
// get the payload display name from the top-level object, note that there may be other
// `<dict>` elements in the `<plist>`, some of which contain `<key>PayloadDisplayName</key>`
// elements, but we ignore those for now
const pdnKey = Array.from(tlo.children).find(
(child) =>
child.tagName === "key" &&
child.textContent === "PayloadDisplayName"
);
const pdnVal =
(pdnKey?.nextElementSibling?.tagName === "string" &&
pdnKey?.nextElementSibling?.textContent) ||
"";
// if the payload display name is empty, use the file name
const result = pdnVal || file.name;
console.log("parseMobileconfig result: ", result);
resolve(result);
} catch (error) {
console.error("error", error);
reject(error);
}
};
});
};
export const parseFile = async (file: File): Promise<[string, string]> => {
// get the file name and extension
const nameParts = file.name.split(".");
const name = nameParts.slice(0, -1).join(".");
const ext = nameParts.slice(-1)[0];
switch (ext) {
case "xml": {
return [name, "Windows"];
}
case "mobileconfig": {
// // TODO: enable this once mobileconfig parser is vetted
// try {
// const parsedName = await parseMobileConfig(file);
// return [parsedName, "macOS"];
// } catch (e) {
// console.log("error", e);
// return [name, "macOS"];
// }
return [name, "macOS"];
}
case "json": {
return [name, "macOS"];
}
default: {
throw new Error(`Invalid file type: ${ext}`);
}
}
};
export const listNamesFromSelectedLabels = (dict: Record<string, boolean>) => {
return Object.entries(dict).reduce((acc, [labelName, isSelected]) => {
if (isSelected) {
acc.push(labelName);
}
return acc;
}, [] as string[]);
};
export const DEFAULT_ERROR_MESSAGE =
"Couldn’t add configuration profile. Please try again.";
/** We want to add some additional messageing to some of the error messages so
* we add them in this function. Otherwise, we'll just return the error message from the
* API.
*/
// eslint-disable-next-line import/prefer-default-export
export const getErrorMessage = (err: AxiosResponse<IApiError>) => {
const apiReason = err?.data?.errors?.[0]?.reason;
if (
apiReason.includes(
"The configuration profile can’t include BitLocker settings."
)
) {
return (
<span>
{apiReason} To control these settings, go to <b>Disk encryption</b>.
</span>
);
}
if (
apiReason.includes(
"The configuration profile can’t include Windows update settings."
)
) {
return (
<span>
{apiReason} To control these settings, go to <b>OS updates</b>.
</span>
);
}
return apiReason || DEFAULT_ERROR_MESSAGE;
};