@openmdm/cli 0.2.0
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.
- package/LICENSE +21 -0
- package/dist/device-2DJ2HDTB.js +210 -0
- package/dist/device-2DJ2HDTB.js.map +1 -0
- package/dist/enroll-WDHCQQCE.js +111 -0
- package/dist/enroll-WDHCQQCE.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/init-625O2CRF.js +141 -0
- package/dist/init-625O2CRF.js.map +1 -0
- package/dist/migrate-HMECTTGA.js +245 -0
- package/dist/migrate-HMECTTGA.js.map +1 -0
- package/dist/policy-QGI5X7DH.js +222 -0
- package/dist/policy-QGI5X7DH.js.map +1 -0
- package/dist/push-GOOMUZVI.js +27 -0
- package/dist/push-GOOMUZVI.js.map +1 -0
- package/dist/stats-7LZFNZT2.js +78 -0
- package/dist/stats-7LZFNZT2.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present OpenMDM Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/device.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
import ora from "ora";
|
|
7
|
+
var mockDevices = [
|
|
8
|
+
{
|
|
9
|
+
id: "device_001",
|
|
10
|
+
enrollmentId: "ENR-001",
|
|
11
|
+
model: "Pixel 6 Pro",
|
|
12
|
+
manufacturer: "Google",
|
|
13
|
+
status: "enrolled",
|
|
14
|
+
osVersion: "14",
|
|
15
|
+
lastHeartbeat: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16
|
+
batteryLevel: 85
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "device_002",
|
|
20
|
+
enrollmentId: "ENR-002",
|
|
21
|
+
model: "Galaxy S23",
|
|
22
|
+
manufacturer: "Samsung",
|
|
23
|
+
status: "enrolled",
|
|
24
|
+
osVersion: "13",
|
|
25
|
+
lastHeartbeat: new Date(Date.now() - 36e5).toISOString(),
|
|
26
|
+
batteryLevel: 42
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "device_003",
|
|
30
|
+
enrollmentId: "ENR-003",
|
|
31
|
+
model: "Redmi Note 12",
|
|
32
|
+
manufacturer: "Xiaomi",
|
|
33
|
+
status: "pending",
|
|
34
|
+
osVersion: "12",
|
|
35
|
+
lastHeartbeat: null,
|
|
36
|
+
batteryLevel: null
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
async function listDevices(options) {
|
|
40
|
+
const spinner = ora("Fetching devices...").start();
|
|
41
|
+
try {
|
|
42
|
+
let devices = [...mockDevices];
|
|
43
|
+
if (options.status) {
|
|
44
|
+
devices = devices.filter((d) => d.status === options.status);
|
|
45
|
+
}
|
|
46
|
+
const limit = parseInt(options.limit || "50");
|
|
47
|
+
devices = devices.slice(0, limit);
|
|
48
|
+
spinner.stop();
|
|
49
|
+
if (options.json) {
|
|
50
|
+
console.log(JSON.stringify(devices, null, 2));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
console.log(chalk.blue("\\n\u{1F4F1} Enrolled Devices\\n"));
|
|
54
|
+
if (devices.length === 0) {
|
|
55
|
+
console.log(chalk.gray("No devices found."));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
console.log(
|
|
59
|
+
chalk.gray(
|
|
60
|
+
`${"ID".padEnd(15)} ${"Model".padEnd(20)} ${"Status".padEnd(12)} ${"OS".padEnd(6)} ${"Battery".padEnd(8)} ${"Last Seen".padEnd(20)}`
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
console.log(chalk.gray("-".repeat(85)));
|
|
64
|
+
for (const device of devices) {
|
|
65
|
+
const statusColor = device.status === "enrolled" ? chalk.green : device.status === "pending" ? chalk.yellow : chalk.red;
|
|
66
|
+
const lastSeen = device.lastHeartbeat ? formatRelativeTime(new Date(device.lastHeartbeat)) : "Never";
|
|
67
|
+
const battery = device.batteryLevel !== null ? `${device.batteryLevel}%` : "-";
|
|
68
|
+
console.log(
|
|
69
|
+
`${device.id.padEnd(15)} ${device.model.padEnd(20)} ${statusColor(
|
|
70
|
+
device.status.padEnd(12)
|
|
71
|
+
)} ${device.osVersion.padEnd(6)} ${battery.padEnd(8)} ${lastSeen.padEnd(20)}`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
console.log(chalk.gray(`\\nTotal: ${devices.length} devices`));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
spinner.fail("Failed to fetch devices");
|
|
77
|
+
console.error(chalk.red(error));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function showDevice(deviceId, options) {
|
|
81
|
+
const spinner = ora(`Fetching device ${deviceId}...`).start();
|
|
82
|
+
try {
|
|
83
|
+
const device = mockDevices.find((d) => d.id === deviceId);
|
|
84
|
+
spinner.stop();
|
|
85
|
+
if (!device) {
|
|
86
|
+
console.log(chalk.red(`\\nDevice not found: ${deviceId}`));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (options.json) {
|
|
90
|
+
console.log(JSON.stringify(device, null, 2));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.log(chalk.blue(`\\n\u{1F4F1} Device Details: ${deviceId}\\n`));
|
|
94
|
+
console.log(` ${chalk.gray("Enrollment ID:")} ${device.enrollmentId}`);
|
|
95
|
+
console.log(` ${chalk.gray("Model:")} ${device.model}`);
|
|
96
|
+
console.log(` ${chalk.gray("Manufacturer:")} ${device.manufacturer}`);
|
|
97
|
+
console.log(` ${chalk.gray("OS Version:")} Android ${device.osVersion}`);
|
|
98
|
+
console.log(
|
|
99
|
+
` ${chalk.gray("Status:")} ${device.status === "enrolled" ? chalk.green(device.status) : chalk.yellow(device.status)}`
|
|
100
|
+
);
|
|
101
|
+
console.log(
|
|
102
|
+
` ${chalk.gray("Battery:")} ${device.batteryLevel !== null ? `${device.batteryLevel}%` : "-"}`
|
|
103
|
+
);
|
|
104
|
+
console.log(
|
|
105
|
+
` ${chalk.gray("Last Heartbeat:")} ${device.lastHeartbeat ? formatRelativeTime(new Date(device.lastHeartbeat)) : "Never"}`
|
|
106
|
+
);
|
|
107
|
+
console.log("");
|
|
108
|
+
} catch (error) {
|
|
109
|
+
spinner.fail("Failed to fetch device");
|
|
110
|
+
console.error(chalk.red(error));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async function syncDevice(deviceId) {
|
|
114
|
+
const spinner = ora(`Sending sync command to ${deviceId}...`).start();
|
|
115
|
+
try {
|
|
116
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
117
|
+
spinner.succeed(`Sync command sent to ${deviceId}`);
|
|
118
|
+
console.log(chalk.gray("The device will sync on its next connection."));
|
|
119
|
+
} catch (error) {
|
|
120
|
+
spinner.fail("Failed to send sync command");
|
|
121
|
+
console.error(chalk.red(error));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function lockDevice(deviceId, options) {
|
|
125
|
+
const spinner = ora(`Sending lock command to ${deviceId}...`).start();
|
|
126
|
+
try {
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
128
|
+
spinner.succeed(`Lock command sent to ${deviceId}`);
|
|
129
|
+
if (options.message) {
|
|
130
|
+
console.log(chalk.gray(`Lock screen message: "${options.message}"`));
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
spinner.fail("Failed to send lock command");
|
|
134
|
+
console.error(chalk.red(error));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async function wipeDevice(deviceId, options) {
|
|
138
|
+
if (!options.force) {
|
|
139
|
+
console.log(chalk.red("\\n\u26A0\uFE0F WARNING: This will factory reset the device!"));
|
|
140
|
+
console.log(chalk.red("All data will be permanently deleted.\\n"));
|
|
141
|
+
const { confirm } = await inquirer.prompt([
|
|
142
|
+
{
|
|
143
|
+
type: "confirm",
|
|
144
|
+
name: "confirm",
|
|
145
|
+
message: `Are you sure you want to wipe device ${deviceId}?`,
|
|
146
|
+
default: false
|
|
147
|
+
}
|
|
148
|
+
]);
|
|
149
|
+
if (!confirm) {
|
|
150
|
+
console.log(chalk.yellow("Wipe cancelled."));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const spinner = ora(`Sending wipe command to ${deviceId}...`).start();
|
|
155
|
+
try {
|
|
156
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
157
|
+
spinner.succeed(`Wipe command sent to ${deviceId}`);
|
|
158
|
+
if (options.preserveData) {
|
|
159
|
+
console.log(chalk.gray("SD card data will be preserved."));
|
|
160
|
+
}
|
|
161
|
+
console.log(chalk.yellow("\\nThe device will be wiped on its next connection."));
|
|
162
|
+
} catch (error) {
|
|
163
|
+
spinner.fail("Failed to send wipe command");
|
|
164
|
+
console.error(chalk.red(error));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function removeDevice(deviceId, options) {
|
|
168
|
+
if (!options.force) {
|
|
169
|
+
const { confirm } = await inquirer.prompt([
|
|
170
|
+
{
|
|
171
|
+
type: "confirm",
|
|
172
|
+
name: "confirm",
|
|
173
|
+
message: `Are you sure you want to remove device ${deviceId} from MDM?`,
|
|
174
|
+
default: false
|
|
175
|
+
}
|
|
176
|
+
]);
|
|
177
|
+
if (!confirm) {
|
|
178
|
+
console.log(chalk.yellow("Removal cancelled."));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const spinner = ora(`Removing device ${deviceId}...`).start();
|
|
183
|
+
try {
|
|
184
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
185
|
+
spinner.succeed(`Device ${deviceId} removed from MDM`);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
spinner.fail("Failed to remove device");
|
|
188
|
+
console.error(chalk.red(error));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function formatRelativeTime(date) {
|
|
192
|
+
const now = /* @__PURE__ */ new Date();
|
|
193
|
+
const diff = now.getTime() - date.getTime();
|
|
194
|
+
const minutes = Math.floor(diff / 6e4);
|
|
195
|
+
const hours = Math.floor(diff / 36e5);
|
|
196
|
+
const days = Math.floor(diff / 864e5);
|
|
197
|
+
if (minutes < 1) return "Just now";
|
|
198
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
199
|
+
if (hours < 24) return `${hours}h ago`;
|
|
200
|
+
return `${days}d ago`;
|
|
201
|
+
}
|
|
202
|
+
export {
|
|
203
|
+
listDevices,
|
|
204
|
+
lockDevice,
|
|
205
|
+
removeDevice,
|
|
206
|
+
showDevice,
|
|
207
|
+
syncDevice,
|
|
208
|
+
wipeDevice
|
|
209
|
+
};
|
|
210
|
+
//# sourceMappingURL=device-2DJ2HDTB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/device.ts"],"sourcesContent":["import chalk from 'chalk';\nimport inquirer from 'inquirer';\nimport ora from 'ora';\n\ninterface ListOptions {\n status?: string;\n limit?: string;\n json?: boolean;\n}\n\ninterface ShowOptions {\n json?: boolean;\n}\n\ninterface LockOptions {\n message?: string;\n}\n\ninterface WipeOptions {\n force?: boolean;\n preserveData?: boolean;\n}\n\ninterface RemoveOptions {\n force?: boolean;\n}\n\n// Mock data for demonstration\nconst mockDevices = [\n {\n id: 'device_001',\n enrollmentId: 'ENR-001',\n model: 'Pixel 6 Pro',\n manufacturer: 'Google',\n status: 'enrolled',\n osVersion: '14',\n lastHeartbeat: new Date().toISOString(),\n batteryLevel: 85,\n },\n {\n id: 'device_002',\n enrollmentId: 'ENR-002',\n model: 'Galaxy S23',\n manufacturer: 'Samsung',\n status: 'enrolled',\n osVersion: '13',\n lastHeartbeat: new Date(Date.now() - 3600000).toISOString(),\n batteryLevel: 42,\n },\n {\n id: 'device_003',\n enrollmentId: 'ENR-003',\n model: 'Redmi Note 12',\n manufacturer: 'Xiaomi',\n status: 'pending',\n osVersion: '12',\n lastHeartbeat: null,\n batteryLevel: null,\n },\n];\n\nexport async function listDevices(options: ListOptions): Promise<void> {\n const spinner = ora('Fetching devices...').start();\n\n try {\n // In real implementation, this would query the database\n let devices = [...mockDevices];\n\n if (options.status) {\n devices = devices.filter(d => d.status === options.status);\n }\n\n const limit = parseInt(options.limit || '50');\n devices = devices.slice(0, limit);\n\n spinner.stop();\n\n if (options.json) {\n console.log(JSON.stringify(devices, null, 2));\n return;\n }\n\n console.log(chalk.blue('\\\\n📱 Enrolled Devices\\\\n'));\n\n if (devices.length === 0) {\n console.log(chalk.gray('No devices found.'));\n return;\n }\n\n // Table header\n console.log(\n chalk.gray(\n `${'ID'.padEnd(15)} ${'Model'.padEnd(20)} ${'Status'.padEnd(12)} ${'OS'.padEnd(6)} ${'Battery'.padEnd(8)} ${'Last Seen'.padEnd(20)}`\n )\n );\n console.log(chalk.gray('-'.repeat(85)));\n\n // Table rows\n for (const device of devices) {\n const statusColor =\n device.status === 'enrolled'\n ? chalk.green\n : device.status === 'pending'\n ? chalk.yellow\n : chalk.red;\n\n const lastSeen = device.lastHeartbeat\n ? formatRelativeTime(new Date(device.lastHeartbeat))\n : 'Never';\n\n const battery = device.batteryLevel !== null ? `${device.batteryLevel}%` : '-';\n\n console.log(\n `${device.id.padEnd(15)} ${device.model.padEnd(20)} ${statusColor(\n device.status.padEnd(12)\n )} ${device.osVersion.padEnd(6)} ${battery.padEnd(8)} ${lastSeen.padEnd(20)}`\n );\n }\n\n console.log(chalk.gray(`\\\\nTotal: ${devices.length} devices`));\n } catch (error) {\n spinner.fail('Failed to fetch devices');\n console.error(chalk.red(error));\n }\n}\n\nexport async function showDevice(deviceId: string, options: ShowOptions): Promise<void> {\n const spinner = ora(`Fetching device ${deviceId}...`).start();\n\n try {\n // In real implementation, this would query the database\n const device = mockDevices.find(d => d.id === deviceId);\n\n spinner.stop();\n\n if (!device) {\n console.log(chalk.red(`\\\\nDevice not found: ${deviceId}`));\n return;\n }\n\n if (options.json) {\n console.log(JSON.stringify(device, null, 2));\n return;\n }\n\n console.log(chalk.blue(`\\\\n📱 Device Details: ${deviceId}\\\\n`));\n console.log(` ${chalk.gray('Enrollment ID:')} ${device.enrollmentId}`);\n console.log(` ${chalk.gray('Model:')} ${device.model}`);\n console.log(` ${chalk.gray('Manufacturer:')} ${device.manufacturer}`);\n console.log(` ${chalk.gray('OS Version:')} Android ${device.osVersion}`);\n console.log(\n ` ${chalk.gray('Status:')} ${\n device.status === 'enrolled' ? chalk.green(device.status) : chalk.yellow(device.status)\n }`\n );\n console.log(\n ` ${chalk.gray('Battery:')} ${device.batteryLevel !== null ? `${device.batteryLevel}%` : '-'}`\n );\n console.log(\n ` ${chalk.gray('Last Heartbeat:')} ${\n device.lastHeartbeat ? formatRelativeTime(new Date(device.lastHeartbeat)) : 'Never'\n }`\n );\n console.log('');\n } catch (error) {\n spinner.fail('Failed to fetch device');\n console.error(chalk.red(error));\n }\n}\n\nexport async function syncDevice(deviceId: string): Promise<void> {\n const spinner = ora(`Sending sync command to ${deviceId}...`).start();\n\n try {\n // In real implementation, this would send a command via the MDM\n await new Promise(resolve => setTimeout(resolve, 1000));\n spinner.succeed(`Sync command sent to ${deviceId}`);\n console.log(chalk.gray('The device will sync on its next connection.'));\n } catch (error) {\n spinner.fail('Failed to send sync command');\n console.error(chalk.red(error));\n }\n}\n\nexport async function lockDevice(deviceId: string, options: LockOptions): Promise<void> {\n const spinner = ora(`Sending lock command to ${deviceId}...`).start();\n\n try {\n // In real implementation, this would send a lock command\n await new Promise(resolve => setTimeout(resolve, 1000));\n spinner.succeed(`Lock command sent to ${deviceId}`);\n\n if (options.message) {\n console.log(chalk.gray(`Lock screen message: \"${options.message}\"`));\n }\n } catch (error) {\n spinner.fail('Failed to send lock command');\n console.error(chalk.red(error));\n }\n}\n\nexport async function wipeDevice(deviceId: string, options: WipeOptions): Promise<void> {\n if (!options.force) {\n console.log(chalk.red('\\\\n⚠️ WARNING: This will factory reset the device!'));\n console.log(chalk.red('All data will be permanently deleted.\\\\n'));\n\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: `Are you sure you want to wipe device ${deviceId}?`,\n default: false,\n },\n ]);\n\n if (!confirm) {\n console.log(chalk.yellow('Wipe cancelled.'));\n return;\n }\n }\n\n const spinner = ora(`Sending wipe command to ${deviceId}...`).start();\n\n try {\n // In real implementation, this would send a wipe command\n await new Promise(resolve => setTimeout(resolve, 1500));\n spinner.succeed(`Wipe command sent to ${deviceId}`);\n\n if (options.preserveData) {\n console.log(chalk.gray('SD card data will be preserved.'));\n }\n\n console.log(chalk.yellow('\\\\nThe device will be wiped on its next connection.'));\n } catch (error) {\n spinner.fail('Failed to send wipe command');\n console.error(chalk.red(error));\n }\n}\n\nexport async function removeDevice(deviceId: string, options: RemoveOptions): Promise<void> {\n if (!options.force) {\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: `Are you sure you want to remove device ${deviceId} from MDM?`,\n default: false,\n },\n ]);\n\n if (!confirm) {\n console.log(chalk.yellow('Removal cancelled.'));\n return;\n }\n }\n\n const spinner = ora(`Removing device ${deviceId}...`).start();\n\n try {\n // In real implementation, this would remove the device\n await new Promise(resolve => setTimeout(resolve, 1000));\n spinner.succeed(`Device ${deviceId} removed from MDM`);\n } catch (error) {\n spinner.fail('Failed to remove device');\n console.error(chalk.red(error));\n }\n}\n\nfunction formatRelativeTime(date: Date): string {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n return `${days}d ago`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/enroll.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
import QRCode from "qrcode";
|
|
7
|
+
async function generateQR(options) {
|
|
8
|
+
console.log(chalk.blue("\\n\u{1F517} Generate Enrollment QR Code\\n"));
|
|
9
|
+
const serverUrl = process.env.SERVER_URL || "https://mdm.example.com";
|
|
10
|
+
const deviceSecret = process.env.DEVICE_SECRET;
|
|
11
|
+
if (!deviceSecret) {
|
|
12
|
+
console.log(chalk.yellow("Warning: DEVICE_SECRET not set. Using placeholder."));
|
|
13
|
+
}
|
|
14
|
+
const enrollmentData = {
|
|
15
|
+
serverUrl,
|
|
16
|
+
enrollmentToken: generateEnrollmentToken(),
|
|
17
|
+
policyId: options.policy,
|
|
18
|
+
groupId: options.group,
|
|
19
|
+
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1e3).toISOString()
|
|
20
|
+
};
|
|
21
|
+
const enrollmentUrl = `${serverUrl}/enroll?token=${enrollmentData.enrollmentToken}`;
|
|
22
|
+
const spinner = ora("Generating QR code...").start();
|
|
23
|
+
try {
|
|
24
|
+
if (options.ascii) {
|
|
25
|
+
const ascii = await QRCode.toString(enrollmentUrl, {
|
|
26
|
+
type: "terminal",
|
|
27
|
+
small: true
|
|
28
|
+
});
|
|
29
|
+
spinner.stop();
|
|
30
|
+
console.log(ascii);
|
|
31
|
+
} else if (options.output) {
|
|
32
|
+
await QRCode.toFile(options.output, enrollmentUrl, {
|
|
33
|
+
width: 400,
|
|
34
|
+
margin: 2,
|
|
35
|
+
color: {
|
|
36
|
+
dark: "#000000",
|
|
37
|
+
light: "#FFFFFF"
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
spinner.succeed(`QR code saved to ${options.output}`);
|
|
41
|
+
} else {
|
|
42
|
+
const dataUrl = await QRCode.toDataURL(enrollmentUrl, {
|
|
43
|
+
width: 200,
|
|
44
|
+
margin: 1
|
|
45
|
+
});
|
|
46
|
+
spinner.succeed("QR code generated");
|
|
47
|
+
console.log(chalk.gray("\\nEnrollment URL:"));
|
|
48
|
+
console.log(chalk.cyan(enrollmentUrl));
|
|
49
|
+
console.log("");
|
|
50
|
+
console.log(chalk.gray("Base64 Data URL (first 100 chars):"));
|
|
51
|
+
console.log(chalk.gray(dataUrl.substring(0, 100) + "..."));
|
|
52
|
+
console.log("");
|
|
53
|
+
console.log(chalk.gray("Use --output to save to file, or --ascii to display in terminal."));
|
|
54
|
+
}
|
|
55
|
+
console.log("");
|
|
56
|
+
console.log(chalk.gray("Enrollment details:"));
|
|
57
|
+
console.log(chalk.gray(` Token: ${enrollmentData.enrollmentToken}`));
|
|
58
|
+
console.log(chalk.gray(` Expires: ${enrollmentData.expiresAt}`));
|
|
59
|
+
if (options.policy) {
|
|
60
|
+
console.log(chalk.gray(` Policy: ${options.policy}`));
|
|
61
|
+
}
|
|
62
|
+
if (options.group) {
|
|
63
|
+
console.log(chalk.gray(` Group: ${options.group}`));
|
|
64
|
+
}
|
|
65
|
+
console.log("");
|
|
66
|
+
} catch (error) {
|
|
67
|
+
spinner.fail("Failed to generate QR code");
|
|
68
|
+
console.error(chalk.red(error));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function generateToken(options) {
|
|
72
|
+
console.log(chalk.blue("\\n\u{1F511} Generate Enrollment Token\\n"));
|
|
73
|
+
const serverUrl = process.env.SERVER_URL || "https://mdm.example.com";
|
|
74
|
+
const expiresHours = parseInt(options.expires || "24");
|
|
75
|
+
const token = generateEnrollmentToken();
|
|
76
|
+
const expiresAt = new Date(Date.now() + expiresHours * 60 * 60 * 1e3);
|
|
77
|
+
console.log(chalk.green("Enrollment Token Generated\\n"));
|
|
78
|
+
console.log(` ${chalk.gray("Token:")} ${chalk.cyan(token)}`);
|
|
79
|
+
console.log(` ${chalk.gray("Expires:")} ${expiresAt.toISOString()}`);
|
|
80
|
+
console.log(` ${chalk.gray("Server:")} ${serverUrl}`);
|
|
81
|
+
if (options.policy) {
|
|
82
|
+
console.log(` ${chalk.gray("Policy:")} ${options.policy}`);
|
|
83
|
+
}
|
|
84
|
+
if (options.group) {
|
|
85
|
+
console.log(` ${chalk.gray("Group:")} ${options.group}`);
|
|
86
|
+
}
|
|
87
|
+
console.log("\\n" + chalk.gray("Enrollment URL:"));
|
|
88
|
+
console.log(chalk.cyan(`${serverUrl}/enroll?token=${token}`));
|
|
89
|
+
console.log("\\n" + chalk.gray("Android Intent URL:"));
|
|
90
|
+
console.log(
|
|
91
|
+
chalk.cyan(`intent://enroll?token=${token}#Intent;scheme=openmdm;package=com.openmdm.agent;end`)
|
|
92
|
+
);
|
|
93
|
+
console.log("");
|
|
94
|
+
}
|
|
95
|
+
function generateEnrollmentToken() {
|
|
96
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
97
|
+
const segments = [];
|
|
98
|
+
for (let i = 0; i < 4; i++) {
|
|
99
|
+
let segment = "";
|
|
100
|
+
for (let j = 0; j < 4; j++) {
|
|
101
|
+
segment += chars[Math.floor(Math.random() * chars.length)];
|
|
102
|
+
}
|
|
103
|
+
segments.push(segment);
|
|
104
|
+
}
|
|
105
|
+
return segments.join("-");
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
generateQR,
|
|
109
|
+
generateToken
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=enroll-WDHCQQCE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/enroll.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora from 'ora';\nimport QRCode from 'qrcode';\nimport fs from 'fs/promises';\n\ninterface QROptions {\n policy?: string;\n group?: string;\n output?: string;\n ascii?: boolean;\n}\n\ninterface TokenOptions {\n policy?: string;\n group?: string;\n expires?: string;\n}\n\nexport async function generateQR(options: QROptions): Promise<void> {\n console.log(chalk.blue('\\\\n🔗 Generate Enrollment QR Code\\\\n'));\n\n const serverUrl = process.env.SERVER_URL || 'https://mdm.example.com';\n const deviceSecret = process.env.DEVICE_SECRET;\n\n if (!deviceSecret) {\n console.log(chalk.yellow('Warning: DEVICE_SECRET not set. Using placeholder.'));\n }\n\n // Generate enrollment token\n const enrollmentData = {\n serverUrl,\n enrollmentToken: generateEnrollmentToken(),\n policyId: options.policy,\n groupId: options.group,\n expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),\n };\n\n const enrollmentUrl = `${serverUrl}/enroll?token=${enrollmentData.enrollmentToken}`;\n\n const spinner = ora('Generating QR code...').start();\n\n try {\n if (options.ascii) {\n // Generate ASCII QR for terminal\n const ascii = await QRCode.toString(enrollmentUrl, {\n type: 'terminal',\n small: true,\n });\n spinner.stop();\n console.log(ascii);\n } else if (options.output) {\n // Save to file\n await QRCode.toFile(options.output, enrollmentUrl, {\n width: 400,\n margin: 2,\n color: {\n dark: '#000000',\n light: '#FFFFFF',\n },\n });\n spinner.succeed(`QR code saved to ${options.output}`);\n } else {\n // Generate Data URL and display info\n const dataUrl = await QRCode.toDataURL(enrollmentUrl, {\n width: 200,\n margin: 1,\n });\n spinner.succeed('QR code generated');\n\n console.log(chalk.gray('\\\\nEnrollment URL:'));\n console.log(chalk.cyan(enrollmentUrl));\n console.log('');\n console.log(chalk.gray('Base64 Data URL (first 100 chars):'));\n console.log(chalk.gray(dataUrl.substring(0, 100) + '...'));\n console.log('');\n console.log(chalk.gray('Use --output to save to file, or --ascii to display in terminal.'));\n }\n\n console.log('');\n console.log(chalk.gray('Enrollment details:'));\n console.log(chalk.gray(` Token: ${enrollmentData.enrollmentToken}`));\n console.log(chalk.gray(` Expires: ${enrollmentData.expiresAt}`));\n if (options.policy) {\n console.log(chalk.gray(` Policy: ${options.policy}`));\n }\n if (options.group) {\n console.log(chalk.gray(` Group: ${options.group}`));\n }\n console.log('');\n } catch (error) {\n spinner.fail('Failed to generate QR code');\n console.error(chalk.red(error));\n }\n}\n\nexport async function generateToken(options: TokenOptions): Promise<void> {\n console.log(chalk.blue('\\\\n🔑 Generate Enrollment Token\\\\n'));\n\n const serverUrl = process.env.SERVER_URL || 'https://mdm.example.com';\n const expiresHours = parseInt(options.expires || '24');\n\n const token = generateEnrollmentToken();\n const expiresAt = new Date(Date.now() + expiresHours * 60 * 60 * 1000);\n\n console.log(chalk.green('Enrollment Token Generated\\\\n'));\n console.log(` ${chalk.gray('Token:')} ${chalk.cyan(token)}`);\n console.log(` ${chalk.gray('Expires:')} ${expiresAt.toISOString()}`);\n console.log(` ${chalk.gray('Server:')} ${serverUrl}`);\n\n if (options.policy) {\n console.log(` ${chalk.gray('Policy:')} ${options.policy}`);\n }\n if (options.group) {\n console.log(` ${chalk.gray('Group:')} ${options.group}`);\n }\n\n console.log('\\\\n' + chalk.gray('Enrollment URL:'));\n console.log(chalk.cyan(`${serverUrl}/enroll?token=${token}`));\n\n console.log('\\\\n' + chalk.gray('Android Intent URL:'));\n console.log(\n chalk.cyan(`intent://enroll?token=${token}#Intent;scheme=openmdm;package=com.openmdm.agent;end`)\n );\n console.log('');\n}\n\nfunction generateEnrollmentToken(): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n const segments = [];\n for (let i = 0; i < 4; i++) {\n let segment = '';\n for (let j = 0; j < 4; j++) {\n segment += chars[Math.floor(Math.random() * chars.length)];\n }\n segments.push(segment);\n }\n return segments.join('-');\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import "chalk";
|
|
6
|
+
import { config as dotenvConfig } from "dotenv";
|
|
7
|
+
dotenvConfig();
|
|
8
|
+
var program = new Command();
|
|
9
|
+
program.name("openmdm").description("OpenMDM CLI - Mobile Device Management tools").version("0.1.0");
|
|
10
|
+
program.command("init").description("Initialize a new OpenMDM configuration").option("-d, --database <type>", "Database type (postgres, mysql, sqlite)", "postgres").option("-p, --push <type>", "Push provider (fcm, mqtt, polling)", "fcm").action(async (options) => {
|
|
11
|
+
const { initProject } = await import("./init-625O2CRF.js");
|
|
12
|
+
await initProject(options);
|
|
13
|
+
});
|
|
14
|
+
program.command("migrate").description("Run database migrations").option("--dry-run", "Show migration SQL without executing").option("--rollback", "Rollback last migration").action(async (options) => {
|
|
15
|
+
const { runMigrations } = await import("./migrate-HMECTTGA.js");
|
|
16
|
+
await runMigrations(options);
|
|
17
|
+
});
|
|
18
|
+
var deviceCmd = program.command("device").description("Device management commands");
|
|
19
|
+
deviceCmd.command("list").description("List all enrolled devices").option("-s, --status <status>", "Filter by status (enrolled, pending, blocked)").option("-l, --limit <number>", "Limit results", "50").option("-j, --json", "Output as JSON").action(async (options) => {
|
|
20
|
+
const { listDevices } = await import("./device-2DJ2HDTB.js");
|
|
21
|
+
await listDevices(options);
|
|
22
|
+
});
|
|
23
|
+
deviceCmd.command("show <deviceId>").description("Show device details").option("-j, --json", "Output as JSON").action(async (deviceId, options) => {
|
|
24
|
+
const { showDevice } = await import("./device-2DJ2HDTB.js");
|
|
25
|
+
await showDevice(deviceId, options);
|
|
26
|
+
});
|
|
27
|
+
deviceCmd.command("sync <deviceId>").description("Send sync command to device").action(async (deviceId) => {
|
|
28
|
+
const { syncDevice } = await import("./device-2DJ2HDTB.js");
|
|
29
|
+
await syncDevice(deviceId);
|
|
30
|
+
});
|
|
31
|
+
deviceCmd.command("lock <deviceId>").description("Lock a device").option("-m, --message <message>", "Lock screen message").action(async (deviceId, options) => {
|
|
32
|
+
const { lockDevice } = await import("./device-2DJ2HDTB.js");
|
|
33
|
+
await lockDevice(deviceId, options);
|
|
34
|
+
});
|
|
35
|
+
deviceCmd.command("wipe <deviceId>").description("Wipe/factory reset a device").option("-f, --force", "Skip confirmation").option("--preserve-data", "Preserve SD card data").action(async (deviceId, options) => {
|
|
36
|
+
const { wipeDevice } = await import("./device-2DJ2HDTB.js");
|
|
37
|
+
await wipeDevice(deviceId, options);
|
|
38
|
+
});
|
|
39
|
+
deviceCmd.command("remove <deviceId>").description("Remove a device from MDM").option("-f, --force", "Skip confirmation").action(async (deviceId, options) => {
|
|
40
|
+
const { removeDevice } = await import("./device-2DJ2HDTB.js");
|
|
41
|
+
await removeDevice(deviceId, options);
|
|
42
|
+
});
|
|
43
|
+
var policyCmd = program.command("policy").description("Policy management commands");
|
|
44
|
+
policyCmd.command("list").description("List all policies").option("-j, --json", "Output as JSON").action(async (options) => {
|
|
45
|
+
const { listPolicies } = await import("./policy-QGI5X7DH.js");
|
|
46
|
+
await listPolicies(options);
|
|
47
|
+
});
|
|
48
|
+
policyCmd.command("show <policyId>").description("Show policy details").option("-j, --json", "Output as JSON").action(async (policyId, options) => {
|
|
49
|
+
const { showPolicy } = await import("./policy-QGI5X7DH.js");
|
|
50
|
+
await showPolicy(policyId, options);
|
|
51
|
+
});
|
|
52
|
+
policyCmd.command("create").description("Create a new policy interactively").option("-f, --file <path>", "Create from JSON file").action(async (options) => {
|
|
53
|
+
const { createPolicy } = await import("./policy-QGI5X7DH.js");
|
|
54
|
+
await createPolicy(options);
|
|
55
|
+
});
|
|
56
|
+
policyCmd.command("apply <policyId> <deviceId>").description("Apply policy to a device").action(async (policyId, deviceId) => {
|
|
57
|
+
const { applyPolicy } = await import("./policy-QGI5X7DH.js");
|
|
58
|
+
await applyPolicy(policyId, deviceId);
|
|
59
|
+
});
|
|
60
|
+
var enrollCmd = program.command("enroll").description("Device enrollment commands");
|
|
61
|
+
enrollCmd.command("qr").description("Generate enrollment QR code").option("-p, --policy <policyId>", "Pre-assign policy").option("-g, --group <groupId>", "Pre-assign group").option("-o, --output <path>", "Save QR code to file").option("--ascii", "Output ASCII QR code to terminal").action(async (options) => {
|
|
62
|
+
const { generateQR } = await import("./enroll-WDHCQQCE.js");
|
|
63
|
+
await generateQR(options);
|
|
64
|
+
});
|
|
65
|
+
enrollCmd.command("token").description("Generate enrollment token").option("-p, --policy <policyId>", "Pre-assign policy").option("-g, --group <groupId>", "Pre-assign group").option("-e, --expires <hours>", "Token expiration in hours", "24").action(async (options) => {
|
|
66
|
+
const { generateToken } = await import("./enroll-WDHCQQCE.js");
|
|
67
|
+
await generateToken(options);
|
|
68
|
+
});
|
|
69
|
+
program.command("push-test <deviceId>").description("Send test push notification to device").option("-t, --title <title>", "Notification title", "Test Notification").option("-m, --message <message>", "Notification message", "This is a test from OpenMDM").action(async (deviceId, options) => {
|
|
70
|
+
const { testPush } = await import("./push-GOOMUZVI.js");
|
|
71
|
+
await testPush(deviceId, options);
|
|
72
|
+
});
|
|
73
|
+
program.command("stats").description("Show MDM statistics").option("-j, --json", "Output as JSON").action(async (options) => {
|
|
74
|
+
const { showStats } = await import("./stats-7LZFNZT2.js");
|
|
75
|
+
await showStats(options);
|
|
76
|
+
});
|
|
77
|
+
program.parse();
|
|
78
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * OpenMDM CLI\n *\n * Command-line tools for managing OpenMDM deployments.\n *\n * Commands:\n * - init: Initialize a new OpenMDM project\n * - migrate: Run database migrations\n * - device: Manage devices (list, show, wipe, etc.)\n * - policy: Manage policies\n * - enroll: Generate enrollment QR codes/tokens\n * - push: Test push notifications\n */\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { config as dotenvConfig } from 'dotenv';\n\n// Load environment variables\ndotenvConfig();\n\nconst program = new Command();\n\nprogram\n .name('openmdm')\n .description('OpenMDM CLI - Mobile Device Management tools')\n .version('0.1.0');\n\n// Init command\nprogram\n .command('init')\n .description('Initialize a new OpenMDM configuration')\n .option('-d, --database <type>', 'Database type (postgres, mysql, sqlite)', 'postgres')\n .option('-p, --push <type>', 'Push provider (fcm, mqtt, polling)', 'fcm')\n .action(async (options) => {\n const { initProject } = await import('./commands/init.js');\n await initProject(options);\n });\n\n// Migrate command\nprogram\n .command('migrate')\n .description('Run database migrations')\n .option('--dry-run', 'Show migration SQL without executing')\n .option('--rollback', 'Rollback last migration')\n .action(async (options) => {\n const { runMigrations } = await import('./commands/migrate.js');\n await runMigrations(options);\n });\n\n// Device commands\nconst deviceCmd = program\n .command('device')\n .description('Device management commands');\n\ndeviceCmd\n .command('list')\n .description('List all enrolled devices')\n .option('-s, --status <status>', 'Filter by status (enrolled, pending, blocked)')\n .option('-l, --limit <number>', 'Limit results', '50')\n .option('-j, --json', 'Output as JSON')\n .action(async (options) => {\n const { listDevices } = await import('./commands/device.js');\n await listDevices(options);\n });\n\ndeviceCmd\n .command('show <deviceId>')\n .description('Show device details')\n .option('-j, --json', 'Output as JSON')\n .action(async (deviceId, options) => {\n const { showDevice } = await import('./commands/device.js');\n await showDevice(deviceId, options);\n });\n\ndeviceCmd\n .command('sync <deviceId>')\n .description('Send sync command to device')\n .action(async (deviceId) => {\n const { syncDevice } = await import('./commands/device.js');\n await syncDevice(deviceId);\n });\n\ndeviceCmd\n .command('lock <deviceId>')\n .description('Lock a device')\n .option('-m, --message <message>', 'Lock screen message')\n .action(async (deviceId, options) => {\n const { lockDevice } = await import('./commands/device.js');\n await lockDevice(deviceId, options);\n });\n\ndeviceCmd\n .command('wipe <deviceId>')\n .description('Wipe/factory reset a device')\n .option('-f, --force', 'Skip confirmation')\n .option('--preserve-data', 'Preserve SD card data')\n .action(async (deviceId, options) => {\n const { wipeDevice } = await import('./commands/device.js');\n await wipeDevice(deviceId, options);\n });\n\ndeviceCmd\n .command('remove <deviceId>')\n .description('Remove a device from MDM')\n .option('-f, --force', 'Skip confirmation')\n .action(async (deviceId, options) => {\n const { removeDevice } = await import('./commands/device.js');\n await removeDevice(deviceId, options);\n });\n\n// Policy commands\nconst policyCmd = program\n .command('policy')\n .description('Policy management commands');\n\npolicyCmd\n .command('list')\n .description('List all policies')\n .option('-j, --json', 'Output as JSON')\n .action(async (options) => {\n const { listPolicies } = await import('./commands/policy.js');\n await listPolicies(options);\n });\n\npolicyCmd\n .command('show <policyId>')\n .description('Show policy details')\n .option('-j, --json', 'Output as JSON')\n .action(async (policyId, options) => {\n const { showPolicy } = await import('./commands/policy.js');\n await showPolicy(policyId, options);\n });\n\npolicyCmd\n .command('create')\n .description('Create a new policy interactively')\n .option('-f, --file <path>', 'Create from JSON file')\n .action(async (options) => {\n const { createPolicy } = await import('./commands/policy.js');\n await createPolicy(options);\n });\n\npolicyCmd\n .command('apply <policyId> <deviceId>')\n .description('Apply policy to a device')\n .action(async (policyId, deviceId) => {\n const { applyPolicy } = await import('./commands/policy.js');\n await applyPolicy(policyId, deviceId);\n });\n\n// Enrollment commands\nconst enrollCmd = program\n .command('enroll')\n .description('Device enrollment commands');\n\nenrollCmd\n .command('qr')\n .description('Generate enrollment QR code')\n .option('-p, --policy <policyId>', 'Pre-assign policy')\n .option('-g, --group <groupId>', 'Pre-assign group')\n .option('-o, --output <path>', 'Save QR code to file')\n .option('--ascii', 'Output ASCII QR code to terminal')\n .action(async (options) => {\n const { generateQR } = await import('./commands/enroll.js');\n await generateQR(options);\n });\n\nenrollCmd\n .command('token')\n .description('Generate enrollment token')\n .option('-p, --policy <policyId>', 'Pre-assign policy')\n .option('-g, --group <groupId>', 'Pre-assign group')\n .option('-e, --expires <hours>', 'Token expiration in hours', '24')\n .action(async (options) => {\n const { generateToken } = await import('./commands/enroll.js');\n await generateToken(options);\n });\n\n// Push test command\nprogram\n .command('push-test <deviceId>')\n .description('Send test push notification to device')\n .option('-t, --title <title>', 'Notification title', 'Test Notification')\n .option('-m, --message <message>', 'Notification message', 'This is a test from OpenMDM')\n .action(async (deviceId, options) => {\n const { testPush } = await import('./commands/push.js');\n await testPush(deviceId, options);\n });\n\n// Stats command\nprogram\n .command('stats')\n .description('Show MDM statistics')\n .option('-j, --json', 'Output as JSON')\n .action(async (options) => {\n const { showStats } = await import('./commands/stats.js');\n await showStats(options);\n });\n\n// Parse and execute\nprogram.parse();\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/init.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import ora from "ora";
|
|
8
|
+
var TEMPLATE_ENV = `# OpenMDM Configuration
|
|
9
|
+
# Generated by openmdm init
|
|
10
|
+
|
|
11
|
+
# Database Configuration
|
|
12
|
+
DATABASE_URL=postgres://user:password@localhost:5432/openmdm
|
|
13
|
+
|
|
14
|
+
# Push Notification Configuration
|
|
15
|
+
PUSH_PROVIDER={{push}}
|
|
16
|
+
|
|
17
|
+
# FCM Configuration (if using FCM)
|
|
18
|
+
# GOOGLE_APPLICATION_CREDENTIALS=./firebase-service-account.json
|
|
19
|
+
# FIREBASE_PROJECT_ID=your-project-id
|
|
20
|
+
|
|
21
|
+
# MQTT Configuration (if using MQTT)
|
|
22
|
+
# MQTT_BROKER_URL=mqtt://localhost:1883
|
|
23
|
+
# MQTT_USERNAME=
|
|
24
|
+
# MQTT_PASSWORD=
|
|
25
|
+
|
|
26
|
+
# Security
|
|
27
|
+
DEVICE_SECRET={{deviceSecret}}
|
|
28
|
+
JWT_SECRET={{jwtSecret}}
|
|
29
|
+
|
|
30
|
+
# Server
|
|
31
|
+
PORT=3000
|
|
32
|
+
SERVER_URL=http://localhost:3000
|
|
33
|
+
`;
|
|
34
|
+
var TEMPLATE_CONFIG = `import { createMDM } from '@openmdm/core';
|
|
35
|
+
import { drizzleAdapter } from '@openmdm/drizzle-adapter';
|
|
36
|
+
{{pushImport}}
|
|
37
|
+
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
38
|
+
import postgres from 'postgres';
|
|
39
|
+
|
|
40
|
+
// Database connection
|
|
41
|
+
const connection = postgres(process.env.DATABASE_URL!);
|
|
42
|
+
const db = drizzle(connection);
|
|
43
|
+
|
|
44
|
+
// Create MDM instance
|
|
45
|
+
export const mdm = createMDM({
|
|
46
|
+
database: drizzleAdapter(db),
|
|
47
|
+
{{pushConfig}}
|
|
48
|
+
enrollment: {
|
|
49
|
+
deviceSecret: process.env.DEVICE_SECRET!,
|
|
50
|
+
autoEnroll: true,
|
|
51
|
+
},
|
|
52
|
+
auth: {
|
|
53
|
+
deviceTokenSecret: process.env.JWT_SECRET!,
|
|
54
|
+
},
|
|
55
|
+
serverUrl: process.env.SERVER_URL,
|
|
56
|
+
});
|
|
57
|
+
`;
|
|
58
|
+
async function initProject(options) {
|
|
59
|
+
console.log(chalk.blue("\\n\u{1F680} Initializing OpenMDM Project\\n"));
|
|
60
|
+
const answers = await inquirer.prompt([
|
|
61
|
+
{
|
|
62
|
+
type: "input",
|
|
63
|
+
name: "projectName",
|
|
64
|
+
message: "Project name:",
|
|
65
|
+
default: "my-mdm-server"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: "list",
|
|
69
|
+
name: "database",
|
|
70
|
+
message: "Database:",
|
|
71
|
+
choices: ["postgres", "mysql", "sqlite"],
|
|
72
|
+
default: options.database
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
type: "list",
|
|
76
|
+
name: "push",
|
|
77
|
+
message: "Push notification provider:",
|
|
78
|
+
choices: ["fcm", "mqtt", "polling"],
|
|
79
|
+
default: options.push
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: "confirm",
|
|
83
|
+
name: "createFiles",
|
|
84
|
+
message: "Create configuration files?",
|
|
85
|
+
default: true
|
|
86
|
+
}
|
|
87
|
+
]);
|
|
88
|
+
if (!answers.createFiles) {
|
|
89
|
+
console.log(chalk.yellow("\\nSkipping file creation."));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const spinner = ora("Creating configuration files...").start();
|
|
93
|
+
try {
|
|
94
|
+
const deviceSecret = generateSecret(32);
|
|
95
|
+
const jwtSecret = generateSecret(64);
|
|
96
|
+
const envContent = TEMPLATE_ENV.replace("{{push}}", answers.push).replace("{{deviceSecret}}", deviceSecret).replace("{{jwtSecret}}", jwtSecret);
|
|
97
|
+
await fs.writeFile(".env.example", envContent);
|
|
98
|
+
spinner.succeed("Created .env.example");
|
|
99
|
+
let pushImport = "";
|
|
100
|
+
let pushConfig = "";
|
|
101
|
+
switch (answers.push) {
|
|
102
|
+
case "fcm":
|
|
103
|
+
pushImport = "import { fcmPushAdapterFromEnv } from '@openmdm/push-fcm';";
|
|
104
|
+
pushConfig = "push: fcmPushAdapterFromEnv(),";
|
|
105
|
+
break;
|
|
106
|
+
case "mqtt":
|
|
107
|
+
pushImport = "import { mqttPushAdapterFromEnv } from '@openmdm/push-mqtt';";
|
|
108
|
+
pushConfig = "push: mqttPushAdapterFromEnv(),";
|
|
109
|
+
break;
|
|
110
|
+
default:
|
|
111
|
+
pushConfig = "// No push provider configured";
|
|
112
|
+
}
|
|
113
|
+
const configContent = TEMPLATE_CONFIG.replace("{{pushImport}}", pushImport).replace("{{pushConfig}}", pushConfig);
|
|
114
|
+
await fs.mkdir("src", { recursive: true });
|
|
115
|
+
await fs.writeFile("src/mdm.ts", configContent);
|
|
116
|
+
spinner.succeed("Created src/mdm.ts");
|
|
117
|
+
console.log(chalk.green("\\n\u2705 OpenMDM project initialized!\\n"));
|
|
118
|
+
console.log(chalk.white("Next steps:"));
|
|
119
|
+
console.log(chalk.gray(" 1. Copy .env.example to .env and configure"));
|
|
120
|
+
console.log(chalk.gray(" 2. Run database migrations: openmdm migrate"));
|
|
121
|
+
console.log(chalk.gray(" 3. Start your server and integrate the MDM instance"));
|
|
122
|
+
console.log("");
|
|
123
|
+
} catch (error) {
|
|
124
|
+
spinner.fail("Failed to create files");
|
|
125
|
+
console.error(chalk.red(error));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function generateSecret(length) {
|
|
129
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
130
|
+
let result = "";
|
|
131
|
+
const randomArray = new Uint8Array(length);
|
|
132
|
+
crypto.getRandomValues(randomArray);
|
|
133
|
+
for (let i = 0; i < length; i++) {
|
|
134
|
+
result += chars[randomArray[i] % chars.length];
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
export {
|
|
139
|
+
initProject
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=init-625O2CRF.js.map
|