mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-18 14:37:19 +00:00
443 lines
15 KiB
Bash
443 lines
15 KiB
Bash
#!/bin/bash
|
|
set -e
|
|
|
|
# AeThex Linux ISO Builder - Containerized Edition
|
|
# Creates a bootable ISO using debootstrap + chroot
|
|
|
|
WORK_DIR="${1:-.}"
|
|
BUILD_DIR="$WORK_DIR/aethex-linux-build"
|
|
ROOTFS_DIR="$BUILD_DIR/rootfs"
|
|
ISO_DIR="$BUILD_DIR/iso"
|
|
ISO_NAME="AeThex-Linux-amd64.iso"
|
|
|
|
echo "[*] AeThex ISO Builder - Containerized Edition"
|
|
echo "[*] Build directory: $BUILD_DIR"
|
|
echo "[*] This build method works in Docker without privileged mode"
|
|
|
|
# Clean and prepare
|
|
if [ -d "$BUILD_DIR" ]; then
|
|
sudo rm -rf "$BUILD_DIR" 2>/dev/null || {
|
|
find "$BUILD_DIR" -type f -exec chmod 644 {} \; 2>/dev/null || true
|
|
find "$BUILD_DIR" -type d -exec chmod 755 {} \; 2>/dev/null || true
|
|
rm -rf "$BUILD_DIR"
|
|
}
|
|
fi
|
|
mkdir -p "$ROOTFS_DIR" "$ISO_DIR" "$ISO_DIR"/casper "$ISO_DIR"/isolinux "$ISO_DIR"/boot/grub
|
|
|
|
# Check dependencies
|
|
echo "[*] Checking dependencies..."
|
|
apt-get update -qq
|
|
apt-get install -y -qq \
|
|
debootstrap squashfs-tools xorriso grub-common grub-pc-bin grub-efi-amd64-bin \
|
|
syslinux-common isolinux mtools dosfstools wget ca-certificates 2>&1 | tail -10
|
|
|
|
echo "[+] Bootstrapping Ubuntu base (noble)..."
|
|
debootstrap --arch=amd64 noble "$ROOTFS_DIR" http://archive.ubuntu.com/ubuntu/
|
|
cp /etc/resolv.conf "$ROOTFS_DIR/etc/resolv.conf"
|
|
|
|
cleanup_mounts() {
|
|
umount -lf "$ROOTFS_DIR/proc" 2>/dev/null || true
|
|
umount -lf "$ROOTFS_DIR/sys" 2>/dev/null || true
|
|
umount -lf "$ROOTFS_DIR/dev/pts" 2>/dev/null || true
|
|
umount -lf "$ROOTFS_DIR/dev" 2>/dev/null || true
|
|
}
|
|
trap cleanup_mounts EXIT
|
|
|
|
echo "[+] Building AeThex application layer..."
|
|
mkdir -p "$ROOTFS_DIR/proc" "$ROOTFS_DIR/sys" "$ROOTFS_DIR/dev/pts"
|
|
mount -t proc proc "$ROOTFS_DIR/proc" || true
|
|
mount -t sysfs sys "$ROOTFS_DIR/sys" || true
|
|
mount --bind /dev "$ROOTFS_DIR/dev" || true
|
|
mount --bind /dev/pts "$ROOTFS_DIR/dev/pts" || true
|
|
|
|
echo "[+] Installing Xfce desktop, Firefox, and system tools..."
|
|
echo " (packages installing, ~15-20 minutes...)"
|
|
chroot "$ROOTFS_DIR" bash -c '
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
# Enable universe repository
|
|
sed -i "s/^# deb/deb/" /etc/apt/sources.list
|
|
echo "deb http://archive.ubuntu.com/ubuntu noble universe" >> /etc/apt/sources.list
|
|
echo "deb http://archive.ubuntu.com/ubuntu noble-updates universe" >> /etc/apt/sources.list
|
|
|
|
apt-get update
|
|
apt-get install -y \
|
|
linux-image-generic \
|
|
grub-pc-bin grub-efi-amd64-bin grub-common xorriso \
|
|
casper live-boot live-boot-initramfs-tools \
|
|
xorg xfce4 xfce4-goodies lightdm \
|
|
firefox network-manager \
|
|
sudo curl wget git ca-certificates gnupg \
|
|
pipewire-audio wireplumber \
|
|
file-roller thunar-archive-plugin \
|
|
xfce4-terminal mousepad ristretto \
|
|
dbus-x11
|
|
apt-get clean
|
|
|
|
# Verify kernel was installed
|
|
if ! ls /boot/vmlinuz-* 2>/dev/null | grep -q .; then
|
|
echo "ERROR: linux-image-generic failed to install!"
|
|
exit 1
|
|
fi
|
|
' 2>&1 | tail -50
|
|
|
|
echo "[+] Installing Node.js 20.x from NodeSource..."
|
|
chroot "$ROOTFS_DIR" bash -c '
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
# Install ca-certificates first
|
|
apt-get install -y ca-certificates curl gnupg
|
|
|
|
mkdir -p /etc/apt/keyrings
|
|
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
|
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
|
|
apt-get update
|
|
apt-get install -y nodejs
|
|
node --version || echo "Node install failed"
|
|
npm --version || echo "npm not found"
|
|
' 2>&1 | tail -10
|
|
|
|
echo "[+] Creating AeThex user with auto-login..."
|
|
chroot "$ROOTFS_DIR" bash -c '
|
|
useradd -m -s /bin/bash -G sudo aethex
|
|
echo "aethex:aethex" | chpasswd
|
|
echo "aethex ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
|
'
|
|
|
|
# Configure LightDM for auto-login
|
|
mkdir -p "$ROOTFS_DIR/etc/lightdm"
|
|
cat > "$ROOTFS_DIR/etc/lightdm/lightdm.conf" << 'LIGHTDM'
|
|
[Seat:*]
|
|
autologin-user=aethex
|
|
autologin-user-timeout=0
|
|
user-session=xfce
|
|
LIGHTDM
|
|
|
|
echo "[+] Setting up AeThex Desktop application..."
|
|
|
|
# Build mobile app if possible
|
|
if [ -f "package.json" ]; then
|
|
echo " Building AeThex mobile app..."
|
|
npm run build 2>&1 | tail -5 || echo " Build skipped"
|
|
fi
|
|
|
|
# Copy app files (if available, otherwise note for manual addition)
|
|
if [ -d "client" ] && [ -d "server" ]; then
|
|
echo " Copying AeThex Desktop files..."
|
|
mkdir -p "$ROOTFS_DIR/opt/aethex-desktop"
|
|
|
|
# Copy source files
|
|
cp -r client "$ROOTFS_DIR/opt/aethex-desktop/"
|
|
cp -r server "$ROOTFS_DIR/opt/aethex-desktop/"
|
|
cp -r shared "$ROOTFS_DIR/opt/aethex-desktop/" 2>/dev/null || true
|
|
cp package*.json "$ROOTFS_DIR/opt/aethex-desktop/" 2>/dev/null || true
|
|
cp tsconfig.json "$ROOTFS_DIR/opt/aethex-desktop/" 2>/dev/null || true
|
|
cp vite.config.ts "$ROOTFS_DIR/opt/aethex-desktop/" 2>/dev/null || true
|
|
|
|
# Copy built assets if they exist
|
|
if [ -d "dist" ]; then
|
|
cp -r dist "$ROOTFS_DIR/opt/aethex-desktop/"
|
|
fi
|
|
|
|
# Copy Capacitor Android build if it exists (for native features)
|
|
if [ -d "android" ]; then
|
|
mkdir -p "$ROOTFS_DIR/opt/aethex-desktop/android"
|
|
cp -r android/app "$ROOTFS_DIR/opt/aethex-desktop/android/" 2>/dev/null || true
|
|
fi
|
|
|
|
# Install dependencies in chroot
|
|
echo " Installing Node.js dependencies..."
|
|
chroot "$ROOTFS_DIR" bash -c 'cd /opt/aethex-desktop && npm install --production --legacy-peer-deps' 2>&1 | tail -10 || echo " npm install skipped"
|
|
|
|
# Set ownership
|
|
chroot "$ROOTFS_DIR" chown -R aethex:aethex /opt/aethex-desktop
|
|
else
|
|
echo " (client/server not found; skipping app copy)"
|
|
fi
|
|
|
|
# Create systemd service for AeThex mobile server
|
|
cat > "$ROOTFS_DIR/etc/systemd/system/aethex-mobile-server.service" << 'SERVICEEOF'
|
|
[Unit]
|
|
Description=AeThex Mobile Server
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=aethex
|
|
WorkingDirectory=/opt/aethex-desktop
|
|
Environment="NODE_ENV=production"
|
|
Environment="PORT=5000"
|
|
ExecStart=/usr/bin/npm start
|
|
Restart=always
|
|
RestartSec=10
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
SERVICEEOF
|
|
|
|
# Create backward-compatible legacy service name
|
|
cat > "$ROOTFS_DIR/etc/systemd/system/aethex-desktop.service" << 'SERVICEEOF'
|
|
[Unit]
|
|
Description=AeThex Desktop Server
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=aethex
|
|
WorkingDirectory=/opt/aethex-desktop
|
|
ExecStart=/usr/bin/npm start
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
SERVICEEOF
|
|
|
|
# Enable both services
|
|
chroot "$ROOTFS_DIR" systemctl enable aethex-mobile-server.service 2>/dev/null || echo " Mobile server service added"
|
|
chroot "$ROOTFS_DIR" systemctl enable aethex-desktop.service 2>/dev/null || echo " Desktop service added"
|
|
|
|
# Create auto-start script for Firefox kiosk pointing to mobile server
|
|
mkdir -p "$ROOTFS_DIR/home/aethex/.config/autostart"
|
|
cat > "$ROOTFS_DIR/home/aethex/.config/autostart/aethex-kiosk.desktop" << 'KIOSK'
|
|
[Desktop Entry]
|
|
Type=Application
|
|
Name=AeThex Mobile UI
|
|
Exec=sh -c "sleep 5 && firefox --kiosk http://localhost:5000"
|
|
Hidden=false
|
|
NoDisplay=false
|
|
X-GNOME-Autostart-enabled=true
|
|
Comment=Launch AeThex mobile interface in fullscreen
|
|
KIOSK
|
|
|
|
chroot "$ROOTFS_DIR" chown -R aethex:aethex /home/aethex
|
|
|
|
echo "[✓] AeThex Mobile UI integrated:"
|
|
echo " - Server runs on port 5000"
|
|
echo " - Firefox launches in kiosk mode"
|
|
echo " - Xfce desktop with auto-login"
|
|
echo " - Ingress-style mobile interface"
|
|
|
|
echo "[+] Extracting kernel and initrd from rootfs..."
|
|
KERNEL="$(ls -1 $ROOTFS_DIR/boot/vmlinuz-* 2>/dev/null | head -n 1)"
|
|
INITRD="$(ls -1 $ROOTFS_DIR/boot/initrd.img-* 2>/dev/null | head -n 1)"
|
|
|
|
if [ -z "$KERNEL" ] || [ -z "$INITRD" ]; then
|
|
echo "[!] FATAL: Kernel or initrd not found in $ROOTFS_DIR/boot/"
|
|
echo "[!] Contents of $ROOTFS_DIR/boot/:"
|
|
ls -la "$ROOTFS_DIR/boot/" || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "[+] Copying kernel and initrd to $ISO_DIR/casper/..."
|
|
cp -v "$KERNEL" "$ISO_DIR/casper/vmlinuz" || { echo "[!] Failed to copy kernel"; exit 1; }
|
|
cp -v "$INITRD" "$ISO_DIR/casper/initrd.img" || { echo "[!] Failed to copy initrd"; exit 1; }
|
|
|
|
# Verify files exist
|
|
if [ ! -f "$ISO_DIR/casper/vmlinuz" ]; then
|
|
echo "[!] ERROR: vmlinuz not found after copy"
|
|
ls -la "$ISO_DIR/casper/" || true
|
|
exit 1
|
|
fi
|
|
if [ ! -f "$ISO_DIR/casper/initrd.img" ]; then
|
|
echo "[!] ERROR: initrd.img not found after copy"
|
|
ls -la "$ISO_DIR/casper/" || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "[✓] Kernel: $(basename "$KERNEL") ($(du -h "$ISO_DIR/casper/vmlinuz" | cut -f1))"
|
|
echo "[✓] Initrd: $(basename "$INITRD") ($(du -h "$ISO_DIR/casper/initrd.img" | cut -f1))"
|
|
echo "[✓] Initrd -> $ISO_DIR/casper/initrd.img"
|
|
echo "[✓] Files verified in ISO directory"
|
|
|
|
# Unmount before squashfs
|
|
echo "[+] Unmounting chroot filesystems..."
|
|
umount -lf "$ROOTFS_DIR/proc" 2>/dev/null || true
|
|
umount -lf "$ROOTFS_DIR/sys" 2>/dev/null || true
|
|
umount -lf "$ROOTFS_DIR/dev/pts" 2>/dev/null || true
|
|
umount -lf "$ROOTFS_DIR/dev" 2>/dev/null || true
|
|
|
|
echo "[+] Creating SquashFS filesystem..."
|
|
echo " (compressing ~2-3GB desktop, takes 10-15 minutes...)"
|
|
if command -v mksquashfs &> /dev/null; then
|
|
mksquashfs "$ROOTFS_DIR" "$ISO_DIR/casper/filesystem.squashfs" -b 1048576 -comp xz -Xdict-size 100% 2>&1 | tail -3
|
|
else
|
|
echo "[!] mksquashfs not found; cannot create ISO."
|
|
mkdir -p "$BUILD_DIR"
|
|
echo "mksquashfs not available" > "$BUILD_DIR/README.txt"
|
|
exit 1
|
|
fi
|
|
|
|
echo "[+] Final verification before ISO creation..."
|
|
for file in "$ISO_DIR/casper/vmlinuz" "$ISO_DIR/casper/initrd.img" "$ISO_DIR/casper/filesystem.squashfs"; do
|
|
if [ ! -f "$file" ]; then
|
|
echo "[!] CRITICAL: Missing $file"
|
|
echo "[!] ISO directory contents:"
|
|
find "$ISO_DIR" -type f 2>/dev/null | head -20
|
|
exit 1
|
|
fi
|
|
echo "[✓] $(basename "$file") - $(du -h "$file" | cut -f1)"
|
|
done
|
|
echo "[+] Final verification before ISO creation..."
|
|
for f in "$ISO_DIR/casper/vmlinuz" "$ISO_DIR/casper/initrd.img" "$ISO_DIR/casper/filesystem.squashfs"; do
|
|
if [ ! -f "$f" ]; then
|
|
echo "[!] CRITICAL: Missing $f"
|
|
ls -la "$ISO_DIR/casper/" || true
|
|
exit 1
|
|
fi
|
|
echo "[✓] $(basename "$f") $(du -h "$f" | awk '{print $1}')"
|
|
done
|
|
|
|
echo "[+] Creating live boot manifest..."
|
|
printf $(du -sx --block-size=1 "$ROOTFS_DIR" | cut -f1) > "$ISO_DIR/casper/filesystem.size"
|
|
cat > "$ISO_DIR/casper/filesystem.manifest" << 'MANIFEST'
|
|
casper
|
|
live-boot
|
|
live-boot-initramfs-tools
|
|
MANIFEST
|
|
|
|
echo "[+] Setting up BIOS boot (isolinux)..."
|
|
mkdir -p "$ISO_DIR/isolinux"
|
|
cat > "$ISO_DIR/isolinux/isolinux.cfg" << 'EOF'
|
|
DEFAULT vesamenu.c32
|
|
PROMPT 0
|
|
TIMEOUT 100
|
|
|
|
LABEL live
|
|
MENU LABEL ^AeThex OS
|
|
KERNEL /casper/vmlinuz
|
|
APPEND initrd=/casper/initrd.img root=/dev/sr0 ro live-media=/dev/sr0 boot=live config ip=dhcp live-config hostname=aethex
|
|
|
|
LABEL safe
|
|
MENU LABEL AeThex OS (^Safe Mode)
|
|
KERNEL /casper/vmlinuz
|
|
APPEND initrd=/casper/initrd.img root=/dev/sr0 ro live-media=/dev/sr0 boot=live nomodeset config ip=dhcp live-config hostname=aethex
|
|
EOF
|
|
|
|
# Copy syslinux binaries
|
|
for src in /usr/lib/syslinux/modules/bios /usr/lib/ISOLINUX /usr/share/syslinux; do
|
|
if [ -f "$src/isolinux.bin" ]; then
|
|
cp "$src/isolinux.bin" "$ISO_DIR/isolinux/" 2>/dev/null
|
|
cp "$src/ldlinux.c32" "$ISO_DIR/isolinux/" 2>/dev/null || true
|
|
cp "$src/vesamenu.c32" "$ISO_DIR/isolinux/" 2>/dev/null || true
|
|
cp "$src/libcom32.c32" "$ISO_DIR/isolinux/" 2>/dev/null || true
|
|
cp "$src/libutil.c32" "$ISO_DIR/isolinux/" 2>/dev/null || true
|
|
fi
|
|
done
|
|
|
|
echo "[+] Setting up UEFI boot (GRUB)..."
|
|
mkdir -p "$ISO_DIR/boot/grub"
|
|
cat > "$ISO_DIR/boot/grub/grub.cfg" << 'EOF'
|
|
set timeout=10
|
|
set default=0
|
|
|
|
menuentry "AeThex OS" {
|
|
linux /casper/vmlinuz root=/dev/sr0 ro live-media=/dev/sr0 boot=live config ip=dhcp live-config hostname=aethex
|
|
initrd /casper/initrd.img
|
|
}
|
|
|
|
menuentry "AeThex OS (safe mode)" {
|
|
linux /casper/vmlinuz root=/dev/sr0 ro live-media=/dev/sr0 boot=live nomodeset config ip=dhcp live-config hostname=aethex
|
|
initrd /casper/initrd.img
|
|
}
|
|
EOF
|
|
|
|
echo "[+] Verifying ISO structure before xorriso..."
|
|
echo "[*] Checking ISO_DIR contents:"
|
|
ls -lh "$ISO_DIR/" || echo "ISO_DIR missing!"
|
|
echo "[*] Checking casper contents:"
|
|
ls -lh "$ISO_DIR/casper/" || echo "casper dir missing!"
|
|
echo "[*] Checking isolinux contents:"
|
|
ls -lh "$ISO_DIR/isolinux/" || echo "isolinux dir missing!"
|
|
|
|
if [ ! -f "$ISO_DIR/casper/vmlinuz" ]; then
|
|
echo "[!] CRITICAL: vmlinuz not in ISO_DIR/casper!"
|
|
find "$ISO_DIR" -name "vmlinuz*" 2>/dev/null || echo "vmlinuz not found anywhere in ISO_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$ISO_DIR/casper/initrd.img" ]; then
|
|
echo "[!] CRITICAL: initrd.img not in ISO_DIR/casper!"
|
|
exit 1
|
|
fi
|
|
|
|
echo "[✓] All casper files verified in place"
|
|
|
|
echo "[+] Creating EFI boot image..."
|
|
mkdir -p "$ISO_DIR/EFI/boot"
|
|
grub-mkstandalone \
|
|
--format=x86_64-efi \
|
|
--output="$ISO_DIR/EFI/boot/bootx64.efi" \
|
|
--locales="" \
|
|
--fonts="" \
|
|
"boot/grub/grub.cfg=$ISO_DIR/boot/grub/grub.cfg" 2>&1 | tail -5
|
|
|
|
# Create EFI image for ISO
|
|
dd if=/dev/zero of="$ISO_DIR/boot/grub/efi.img" bs=1M count=10 2>/dev/null
|
|
mkfs.vfat "$ISO_DIR/boot/grub/efi.img" >/dev/null 2>&1
|
|
EFI_MOUNT=$(mktemp -d)
|
|
mount -o loop "$ISO_DIR/boot/grub/efi.img" "$EFI_MOUNT"
|
|
mkdir -p "$EFI_MOUNT/EFI/boot"
|
|
cp "$ISO_DIR/EFI/boot/bootx64.efi" "$EFI_MOUNT/EFI/boot/"
|
|
umount "$EFI_MOUNT"
|
|
rmdir "$EFI_MOUNT"
|
|
|
|
echo "[+] Creating hybrid ISO with xorriso (El Torito boot)..."
|
|
xorriso -as mkisofs \
|
|
-iso-level 3 \
|
|
-full-iso9660-filenames \
|
|
-volid "AeThex-OS" \
|
|
-eltorito-boot isolinux/isolinux.bin \
|
|
-eltorito-catalog isolinux/boot.cat \
|
|
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
|
-eltorito-alt-boot \
|
|
-e boot/grub/efi.img \
|
|
-no-emul-boot \
|
|
-isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin \
|
|
-isohybrid-gpt-basdat \
|
|
-output "$BUILD_DIR/$ISO_NAME" \
|
|
"$ISO_DIR" 2>&1 | tail -20
|
|
|
|
echo "[+] Computing SHA256 checksum..."
|
|
if [ -f "$BUILD_DIR/$ISO_NAME" ]; then
|
|
cd "$BUILD_DIR"
|
|
sha256sum "$ISO_NAME" > "$ISO_NAME.sha256"
|
|
echo "[✓] ISO ready:"
|
|
ls -lh "$ISO_NAME" | awk '{print " Size: " $5}'
|
|
cat "$ISO_NAME.sha256" | awk '{print " SHA256: " $1}'
|
|
echo "[✓] Location: $BUILD_DIR/$ISO_NAME"
|
|
else
|
|
echo "[!] ISO creation failed."
|
|
exit 1
|
|
fi
|
|
|
|
echo "[*] Cleaning up rootfs..."
|
|
rm -rf "$ROOTFS_DIR"
|
|
|
|
echo "[✓] Build complete!"
|
|
echo ""
|
|
echo "=== AeThex OS - Mobile UI Edition ==="
|
|
echo "Features:"
|
|
echo " - Ubuntu 24.04 LTS base"
|
|
echo " - Xfce desktop environment"
|
|
echo " - Firefox browser (auto-launches mobile UI in kiosk mode)"
|
|
echo " - Node.js 20.x + npm"
|
|
echo " - AeThex Mobile App (Ingress-style) at /opt/aethex-desktop"
|
|
echo " - Server: http://localhost:5000"
|
|
echo " - Auto-login as user 'aethex' (password: aethex)"
|
|
echo " - NetworkManager for WiFi/Ethernet"
|
|
echo " - PipeWire audio support"
|
|
echo " - 18 Capacitor plugins integrated"
|
|
echo ""
|
|
echo "Mobile UI Features:"
|
|
echo " - Ingress-style hexagonal design"
|
|
echo " - Green/Cyan color scheme"
|
|
echo " - CSS-only animations (low CPU)"
|
|
echo " - Native-like performance"
|
|
echo " - Calculator, Notes, File Manager, Terminal, Games, etc."
|
|
echo ""
|
|
echo "Flash to USB: sudo ./script/flash-usb.sh -i $BUILD_DIR/$ISO_NAME"
|
|
echo "[✓] Done!"
|