files.js
5.08 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
const express = require('express');
const multer = require('multer');
const fs = require('fs');
const path = require('path');
const { isAuthenticated } = require('../middleware/auth');
const router = express.Router();
const PXE_ROOT = process.env.PXE_ROOT || '/var/www/html';
const LIVE_DIR = path.join(PXE_ROOT, 'debian12/live');
const BOOT_FILE = path.join(PXE_ROOT, 'boot.ipxe');
// Hapus semua file di direktori yang cocok dengan pattern prefix
// Contoh: hapus vmlinuz-6.1.0-anything, initrd.img-anything, dll
function deleteMatchingFiles(dir, prefix) {
try {
const allFiles = fs.readdirSync(dir);
allFiles.forEach(f => {
// Cocokkan file yang diawali prefix (case-insensitive)
if (f.toLowerCase().startsWith(prefix.toLowerCase())) {
const filePath = path.join(dir, f);
fs.unlinkSync(filePath);
console.log(`Dihapus: ${filePath}`);
}
});
} catch(e) {
console.error('Gagal hapus file lama:', e.message);
}
}
// Halaman editor boot.ipxe
router.get('/boot-editor', isAuthenticated, (req, res) => {
let content = '';
let fileExists = false;
try {
content = fs.readFileSync(BOOT_FILE, 'utf8');
fileExists = true;
} catch(e) {
content = '# File boot.ipxe tidak ditemukan atau tidak dapat dibaca\n# Path: ' + BOOT_FILE;
}
res.render('boot-editor', { content, fileExists, bootFile: BOOT_FILE, title: 'Boot Editor' });
});
// Simpan boot.ipxe
router.post('/boot-editor/save', isAuthenticated, (req, res) => {
const { content } = req.body;
try {
if (fs.existsSync(BOOT_FILE)) {
fs.copyFileSync(BOOT_FILE, BOOT_FILE + '.bak');
}
fs.writeFileSync(BOOT_FILE, content, 'utf8');
req.flash('success', 'File boot.ipxe berhasil disimpan! Backup dibuat di boot.ipxe.bak');
} catch(e) {
req.flash('error', 'Gagal menyimpan: ' + e.message);
}
res.redirect('/files/boot-editor');
});
// Halaman upload file live
router.get('/upload', isAuthenticated, (req, res) => {
// Cari file aktual di LIVE_DIR (bisa vmlinuz-6.1.0 dll)
function findFile(dir, prefix) {
try {
const files = fs.readdirSync(dir);
// Cari exact match dulu
if (files.includes(prefix)) {
const p = path.join(dir, prefix);
const stat = fs.statSync(p);
return { exists: true, actualName: prefix, size: stat.size, mtime: stat.mtime };
}
// Cari yang berawalan prefix
const match = files.find(f => f.toLowerCase().startsWith(prefix.toLowerCase()));
if (match) {
const p = path.join(dir, match);
const stat = fs.statSync(p);
return { exists: true, actualName: match, size: stat.size, mtime: stat.mtime };
}
} catch(e) {}
return { exists: false, actualName: null, size: 0, mtime: null };
}
const files = [
{ name: 'vmlinuz', ...findFile(LIVE_DIR, 'vmlinuz') },
{ name: 'initrd.img', ...findFile(LIVE_DIR, 'initrd') },
{ name: 'filesystem.squashfs', ...findFile(LIVE_DIR, 'filesystem') },
];
res.render('upload', { files, liveDir: LIVE_DIR, title: 'Upload File' });
});
// Proses upload — hapus file lama dengan prefix apapun, simpan dengan nama standar
router.post('/upload', isAuthenticated, (req, res) => {
// Map fieldname → { targetDir, deletePrefix, finalName }
const fileConfig = {
vmlinuz: { dir: LIVE_DIR, prefix: 'vmlinuz', finalName: 'vmlinuz' },
initrd: { dir: LIVE_DIR, prefix: 'initrd', finalName: 'initrd.img' },
squashfs: { dir: LIVE_DIR, prefix: 'filesystem', finalName: 'filesystem.squashfs' },
boot_ipxe:{ dir: PXE_ROOT, prefix: 'boot', finalName: 'boot.ipxe' },
};
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
const cfg = fileConfig[file.fieldname];
fs.mkdirSync(cfg.dir, { recursive: true });
// Hapus semua file lama dengan prefix yang sama sebelum upload
deleteMatchingFiles(cfg.dir, cfg.prefix);
cb(null, cfg.dir);
},
filename: (req, file, cb) => {
const cfg = fileConfig[file.fieldname];
cb(null, cfg ? cfg.finalName : file.originalname);
}
}),
limits: { fileSize: 4 * 1024 * 1024 * 1024 } // 4GB max untuk squashfs
}).fields([
{ name: 'vmlinuz', maxCount: 1 },
{ name: 'initrd', maxCount: 1 },
{ name: 'squashfs', maxCount: 1 },
{ name: 'boot_ipxe', maxCount: 1 },
]);
upload(req, res, (err) => {
if (err) {
req.flash('error', 'Upload gagal: ' + err.message);
return res.redirect('/files/upload');
}
const uploaded = req.files || {};
const keys = Object.keys(uploaded);
if (keys.length === 0) {
req.flash('error', 'Tidak ada file yang dipilih untuk diupload');
return res.redirect('/files/upload');
}
// Buat pesan sukses yang informatif
const messages = keys.map(field => {
const cfg = fileConfig[field];
const original = uploaded[field][0].originalname;
return `${original} → ${cfg.finalName}`;
});
req.flash('success', `Berhasil upload & rename: ${messages.join(' | ')}`);
res.redirect('/files/upload');
});
});
module.exports = router;