dotfiles/shell.nix

551 lines
16 KiB
Nix

{ pkgs, inputs, ...}:
let
decryptBooxUpdateUpx = pkgs.fetchFromGitHub {
owner = "Hagb";
repo = "decryptBooxUpdateUpx";
rev = "96ab23f757ab7bdad1b153d0bafce97ce099c647";
hash = "sha256-8r3F4Df1NHI/e+Y+ArZlScH5OzVqQxHLO4ak4x9jo8c=";
};
pythonEnv = pkgs.python3.withPackages (ps: [ ps.pycryptodome ]);
boox-decrypt-firmware = pkgs.writeShellScriptBin "boox-decrypt-firmware" ''
set -euo pipefail
MODEL="''${1:-GoColor7_2}"
INPUT="''${2:-update.upx}"
echo "Decrypting $INPUT for model $MODEL..."
${pythonEnv}/bin/python ${decryptBooxUpdateUpx}/DeBooxUpx.py "$MODEL" "$INPUT"
echo "Done. Output: update.zip"
'';
boox-status = pkgs.writeShellScriptBin "boox-status" ''
set -euo pipefail
echo "=== Boox Device Status ==="
echo ""
echo "ADB Connection:"
${pkgs.android-tools}/bin/adb devices -l
echo ""
if ${pkgs.android-tools}/bin/adb get-state 2>/dev/null | grep -q "device"; then
echo "Root Status:"
${pkgs.android-tools}/bin/adb shell "su -c 'echo Root: OK'" 2>/dev/null || echo "Root: Not available"
echo ""
echo "Disabled Packages:"
${pkgs.android-tools}/bin/adb shell pm list packages -d | sed 's/package:/ /'
else
echo "No device connected"
fi
'';
boox-download-firmware = pkgs.writeShellScriptBin "boox-download-firmware" ''
set -euo pipefail
URL="http://firmware-us.boox.com/d833df9e7d14802acefd9da0a94fbcf3/update.upx"
MD5="d833df9e7d14802acefd9da0a94fbcf3"
OUTPUT="''${1:-update.upx}"
echo "Downloading Go Color 7 Gen 2 firmware (~1.96 GB)..."
${pkgs.curl}/bin/curl -L -o "$OUTPUT" "$URL"
echo "Verifying checksum..."
echo "$MD5 $OUTPUT" | md5sum -c
echo "Done: $OUTPUT"
'';
boox-extract-boot = pkgs.writeShellScriptBin "boox-extract-boot" ''
set -euo pipefail
INPUT="''${1:-update.zip}"
OUTPUT_DIR="''${2:-.}"
echo "Extracting payload.bin from $INPUT..."
${pkgs.unzip}/bin/unzip -p "$INPUT" payload.bin > /tmp/payload.bin
echo "Extracting boot.img..."
${pkgs.payload-dumper-go}/bin/payload-dumper-go -p boot -o "$OUTPUT_DIR" /tmp/payload.bin
rm /tmp/payload.bin
echo "Done: $OUTPUT_DIR/boot.img"
'';
boox-push-magisk = pkgs.writeShellScriptBin "boox-push-magisk" ''
set -euo pipefail
MAGISK_VERSION="''${1:-v30.6}"
MAGISK_URL="https://github.com/topjohnwu/Magisk/releases/download/$MAGISK_VERSION/Magisk-$MAGISK_VERSION.apk"
echo "Downloading Magisk $MAGISK_VERSION..."
${pkgs.curl}/bin/curl -L -o /tmp/Magisk.apk "$MAGISK_URL"
echo "Installing Magisk on device..."
${pkgs.android-tools}/bin/adb install /tmp/Magisk.apk
echo "Pushing boot.img to device..."
${pkgs.android-tools}/bin/adb push boot.img /storage/emulated/0/Download/
rm /tmp/Magisk.apk
echo ""
echo "=== Next Steps ==="
echo "1. Open Magisk app on device"
echo "2. Tap Install Select and Patch a File"
echo "3. Select /Download/boot.img"
echo "4. Run: boox-flash-patched"
'';
boox-flash-patched = pkgs.writeShellScriptBin "boox-flash-patched" ''
set -euo pipefail
echo "Pulling patched boot image from device..."
PATCHED=$(${pkgs.android-tools}/bin/adb shell ls /storage/emulated/0/Download/magisk_patched*.img 2>/dev/null | tr -d '\r' | head -1)
if [ -z "$PATCHED" ]; then
echo "Error: No patched image found. Did you patch boot.img with Magisk?"
exit 1
fi
echo "Found: $PATCHED"
${pkgs.android-tools}/bin/adb pull "$PATCHED" ./magisk_patched.img
echo ""
echo "Rebooting to fastboot..."
${pkgs.android-tools}/bin/adb reboot bootloader
sleep 10
echo "Flashing patched boot image..."
${pkgs.android-tools}/bin/fastboot flash boot ./magisk_patched.img
echo ""
echo "Rebooting device..."
${pkgs.android-tools}/bin/fastboot reboot
echo ""
echo "=== Done! ==="
echo "Device should boot with Magisk root access."
'';
configDir = ./scripts/boox/config;
boox-debloat = pkgs.writeShellScriptBin "boox-debloat" ''
set -euo pipefail
CONFIG_DIR="${configDir}"
DRY_RUN=""
PACKAGES_FILE=""
usage() {
echo "Usage: boox-debloat [OPTIONS]"
echo ""
echo "Options:"
echo " --safe Remove safe bloatware (recommended first)"
echo " --optional Remove optional packages (user preference)"
echo " --all Remove both safe and optional"
echo " --dry-run Show what would be removed without doing it"
echo " --list List packages in each category"
echo " -h, --help Show this help"
}
list_packages() {
echo "=== Safe to Remove ==="
${pkgs.gnugrep}/bin/grep -v '^#' "$CONFIG_DIR/packages-safe.txt" | ${pkgs.gnugrep}/bin/grep -v '^$' | ${pkgs.gawk}/bin/awk '{print " " $1}'
echo ""
echo "=== Optional (user preference) ==="
${pkgs.gnugrep}/bin/grep -v '^#' "$CONFIG_DIR/packages-optional.txt" | ${pkgs.gnugrep}/bin/grep -v '^$' | ${pkgs.gawk}/bin/awk '{print " " $1}'
}
disable_packages() {
local file="$1"
local count=0
local failed=0
# Read packages into array first to avoid stdin issues with adb
local packages=()
while IFS= read -r line; do
# Skip comments and empty lines
[[ "$line" =~ ^#.*$ ]] && continue
[[ -z "$line" ]] && continue
# Extract package name (first word)
pkg=$(echo "$line" | ${pkgs.gawk}/bin/awk '{print $1}')
packages+=("$pkg")
done < "$file"
for pkg in "''${packages[@]}"; do
if [ -n "$DRY_RUN" ]; then
echo "[DRY-RUN] Would disable: $pkg"
((count++)) || true
else
echo -n "Disabling $pkg... "
if ${pkgs.android-tools}/bin/adb shell pm disable-user --user 0 "$pkg" 2>/dev/null | ${pkgs.gnugrep}/bin/grep -q "disabled"; then
echo "OK"
((count++)) || true
else
echo "SKIP (not found or already disabled)"
((failed++)) || true
fi
fi
done
echo ""
if [ -n "$DRY_RUN" ]; then
echo "Would disable $count packages"
else
echo "Disabled $count packages ($failed skipped)"
fi
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--safe)
PACKAGES_FILE="safe"
shift
;;
--optional)
PACKAGES_FILE="optional"
shift
;;
--all)
PACKAGES_FILE="all"
shift
;;
--dry-run)
DRY_RUN="1"
shift
;;
--list)
list_packages
exit 0
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done
if [ -z "$PACKAGES_FILE" ]; then
usage
exit 1
fi
# Check device connection
if ! ${pkgs.android-tools}/bin/adb get-state 2>/dev/null | ${pkgs.gnugrep}/bin/grep -q "device"; then
echo "Error: No device connected"
exit 1
fi
echo "=== Boox Debloat ==="
[ -n "$DRY_RUN" ] && echo "(DRY RUN - no changes will be made)"
echo ""
case "$PACKAGES_FILE" in
safe)
disable_packages "$CONFIG_DIR/packages-safe.txt"
;;
optional)
disable_packages "$CONFIG_DIR/packages-optional.txt"
;;
all)
echo "--- Safe packages ---"
disable_packages "$CONFIG_DIR/packages-safe.txt"
echo ""
echo "--- Optional packages ---"
disable_packages "$CONFIG_DIR/packages-optional.txt"
;;
esac
'';
boox-restore = pkgs.writeShellScriptBin "boox-restore" ''
set -euo pipefail
usage() {
echo "Usage: boox-restore [OPTIONS] [PACKAGE...]"
echo ""
echo "Options:"
echo " --all Re-enable all disabled packages"
echo " --list List currently disabled packages"
echo " -h, --help Show this help"
echo ""
echo "Examples:"
echo " boox-restore --list"
echo " boox-restore com.onyx.calculator"
echo " boox-restore --all"
}
# Check device connection
check_device() {
if ! ${pkgs.android-tools}/bin/adb get-state 2>/dev/null | ${pkgs.gnugrep}/bin/grep -q "device"; then
echo "Error: No device connected"
exit 1
fi
}
list_disabled() {
echo "=== Disabled Packages ==="
${pkgs.android-tools}/bin/adb shell pm list packages -d | sed 's/package:/ /'
}
restore_package() {
local pkg="$1"
echo -n "Restoring $pkg... "
if ${pkgs.android-tools}/bin/adb shell pm enable "$pkg" 2>/dev/null | ${pkgs.gnugrep}/bin/grep -q "enabled"; then
echo "OK"
return 0
elif ${pkgs.android-tools}/bin/adb shell pm install-existing "$pkg" 2>/dev/null | ${pkgs.gnugrep}/bin/grep -q "installed"; then
echo "OK (reinstalled)"
return 0
else
echo "FAILED"
return 1
fi
}
restore_all() {
local count=0
local failed=0
for pkg in $(${pkgs.android-tools}/bin/adb shell pm list packages -d | sed 's/package://'); do
pkg=$(echo "$pkg" | tr -d '\r')
if restore_package "$pkg"; then
((count++)) || true
else
((failed++)) || true
fi
done
echo ""
echo "Restored $count packages ($failed failed)"
}
if [[ $# -eq 0 ]]; then
usage
exit 1
fi
check_device
case "$1" in
--all)
restore_all
;;
--list)
list_disabled
;;
-h|--help)
usage
;;
*)
for pkg in "$@"; do
restore_package "$pkg"
done
;;
esac
'';
pixel8a-reroot = pkgs.writeShellScriptBin "pixel8a-reroot" ''
set -euo pipefail
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Device codename
DEVICE="akita"
error() {
echo -e "''${RED}ERROR: $1''${NC}" >&2
exit 1
}
info() {
echo -e "''${BLUE}>>> $1''${NC}"
}
success() {
echo -e "''${GREEN} $1''${NC}"
}
warn() {
echo -e "''${YELLOW}! $1''${NC}"
}
check_adb_device() {
info "Checking ADB connection..."
if ! ${pkgs.android-tools}/bin/adb devices | ${pkgs.gnugrep}/bin/grep -q "device$"; then
error "No device connected. Please connect your Pixel 8a and authorize USB debugging."
fi
success "Device connected"
}
check_fastboot_device() {
info "Checking fastboot connection..."
if ! ${pkgs.android-tools}/bin/fastboot devices | ${pkgs.gnugrep}/bin/grep -q "fastboot"; then
error "Device not in fastboot mode"
fi
success "Device in fastboot mode"
}
# Parse arguments
if [[ $# -ne 1 ]]; then
echo "Usage: pixel8a-reroot <release-version>"
echo ""
echo "Example: pixel8a-reroot 2026011000"
echo ""
echo "To find the latest release version:"
echo " Visit https://grapheneos.org/releases"
echo " Or check your current build: adb shell getprop ro.build.id"
exit 1
fi
RELEASE="$1"
OTA_FILE="''${DEVICE}-ota-''${RELEASE}.zip"
OTA_URL="https://releases.grapheneos.org/''${DEVICE}-ota_update-''${RELEASE}.zip"
info "Pixel 8a GrapheneOS Re-rooting Script"
info "Release: $RELEASE"
echo ""
# Step 1: Download OTA image
if [[ -f "$OTA_FILE" ]]; then
warn "OTA file already exists: $OTA_FILE"
read -p "Download again? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -f "$OTA_FILE"
fi
fi
if [[ ! -f "$OTA_FILE" ]]; then
info "Downloading GrapheneOS OTA image (~1.2 GB)..."
${pkgs.curl}/bin/curl -L -o "$OTA_FILE" "$OTA_URL" || error "Failed to download OTA image"
success "Downloaded OTA image"
else
success "Using existing OTA file"
fi
# Step 2: Extract init_boot.img
info "Extracting init_boot.img from payload..."
${pkgs.unzip}/bin/unzip -p "$OTA_FILE" payload.bin > payload.bin || error "Failed to extract payload.bin"
${pkgs.payload-dumper-go}/bin/payload-dumper-go -p init_boot -o . payload.bin || error "Failed to extract init_boot.img"
rm -f payload.bin
success "Extracted init_boot.img"
# Step 3: Push to device
check_adb_device
info "Pushing init_boot.img to device..."
${pkgs.android-tools}/bin/adb push init_boot.img /sdcard/Download/init_boot.img || error "Failed to push init_boot.img"
success "Pushed init_boot.img to /sdcard/Download/"
# Step 4: Wait for user to patch with Magisk
echo ""
warn "==== ACTION REQUIRED ===="
echo "On your Pixel 8a:"
echo " 1. Open the Magisk app"
echo " 2. Tap 'Install' (next to Magisk)"
echo " 3. Select 'Select and Patch a File'"
echo " 4. Navigate to Downloads and select 'init_boot.img'"
echo " 5. Tap 'Let's Go' and wait for patching to complete"
echo ""
read -p "Press ENTER when patching is complete..."
# Step 5: Find and pull patched image
info "Finding patched image on device..."
PATCHED_NAME=$(${pkgs.android-tools}/bin/adb shell ls /sdcard/Download/magisk_patched*.img 2>/dev/null | tr -d '\r' | head -1)
if [[ -z "$PATCHED_NAME" ]]; then
error "No patched image found. Did you patch the file with Magisk?"
fi
info "Found patched image: $(basename $PATCHED_NAME)"
${pkgs.android-tools}/bin/adb pull "$PATCHED_NAME" ./magisk_patched_init_boot.img || error "Failed to pull patched image"
success "Pulled patched init_boot.img"
# Step 6: Reboot to fastboot
info "Rebooting to fastboot mode..."
${pkgs.android-tools}/bin/adb reboot bootloader
sleep 10
# Step 7: Flash to both slots
check_fastboot_device
info "Flashing patched init_boot to both slots..."
${pkgs.android-tools}/bin/fastboot flash init_boot_a ./magisk_patched_init_boot.img || error "Failed to flash init_boot_a"
${pkgs.android-tools}/bin/fastboot flash init_boot_b ./magisk_patched_init_boot.img || error "Failed to flash init_boot_b"
success "Flashed to init_boot_a and init_boot_b"
# Step 8: Reboot
info "Rebooting to Android..."
${pkgs.android-tools}/bin/fastboot reboot
sleep 30
# Step 9: Verify root
info "Waiting for device to boot..."
${pkgs.android-tools}/bin/adb wait-for-device
sleep 5
info "Verifying root access..."
if ${pkgs.android-tools}/bin/adb shell 'su -c "id"' | ${pkgs.gnugrep}/bin/grep -q "uid=0(root)"; then
success "Root access verified!"
echo ""
success "=== Re-rooting Complete ==="
echo ""
info "Your Pixel 8a is now rooted with Magisk"
info "You can now run your router scripts:"
echo " adb shell"
echo " su"
echo " /data/local/tmp/router-start"
else
error "Root verification failed. Please check Magisk app."
fi
# Cleanup
info "Cleaning up temporary files..."
rm -f payload.bin
success "Done!"
'';
in
pkgs.mkShell {
name = "boox";
packages = [
pkgs.android-tools
pkgs.curl
pkgs.unzip
pkgs.payload-dumper-go
pkgs.gnugrep
pkgs.gawk
pythonEnv
boox-decrypt-firmware
boox-extract-boot
boox-status
boox-download-firmware
boox-push-magisk
boox-flash-patched
boox-debloat
boox-restore
pixel8a-reroot
];
shellHook = ''
echo "🔖 Android Device Management Shell"
echo ""
echo "=== Boox Go Color 7 Gen 2 ==="
echo "Rooting & Firmware:"
echo " boox-status - Check device connection and root status"
echo " boox-download-firmware - Download stock firmware UPX"
echo " boox-decrypt-firmware - Decrypt UPX update.zip"
echo " boox-extract-boot - Extract boot.img from update.zip"
echo " boox-push-magisk - Install Magisk + push boot.img to device"
echo " boox-flash-patched - Flash Magisk-patched boot image"
echo ""
echo "Debloating:"
echo " boox-debloat --list - List packages by category"
echo " boox-debloat --safe - Remove safe bloatware"
echo " boox-debloat --dry-run - Preview changes"
echo " boox-restore --list - List disabled packages"
echo " boox-restore <pkg> - Re-enable a package"
echo ""
echo "=== Pixel 8a (GrapheneOS) ==="
echo " pixel8a-reroot <version> - Re-root after GrapheneOS update"
echo " Example: pixel8a-reroot 2026011000"
echo ""
echo "Manual tools: adb, fastboot, payload-dumper-go, python"
echo ""
'';
}