mirror of
https://github.com/elseif/MikroTikPatch.git
synced 2026-08-26 10:05:50 +00:00
Compare commits
100 Commits
7.19.6-arm
...
7.23-arm64
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba0ffe3cd7 | ||
|
|
7cf469dc0c | ||
|
|
30d6ac5fe6 | ||
|
|
7fd1b6c563 | ||
|
|
ed3dcd0ab1 | ||
|
|
0a270a1108 | ||
|
|
7a6fdb6323 | ||
|
|
44bc4346c6 | ||
|
|
98d6af79f7 | ||
|
|
11eec19e7d | ||
|
|
9e1d7a5239 | ||
|
|
569e0b5749 | ||
|
|
5d9cc6d745 | ||
|
|
0f62f5de4e | ||
|
|
7f2120dca8 | ||
|
|
9be7cdc6ec | ||
|
|
b7eccac7c5 | ||
|
|
e0afc29cca | ||
|
|
98dfe256e6 | ||
|
|
f179b74d3e | ||
|
|
c71a8ff9c1 | ||
|
|
b35ce475ab | ||
|
|
976e562e83 | ||
|
|
86e11b647d | ||
|
|
07c6617805 | ||
|
|
bf2865921a | ||
|
|
604631539c | ||
|
|
fc7bb4f206 | ||
|
|
410c19d2ce | ||
|
|
d5eea3df4b | ||
|
|
73559ce979 | ||
|
|
c54b46c760 | ||
|
|
8603498d39 | ||
|
|
d3fa483c4b | ||
|
|
e338ddb7b2 | ||
|
|
826072d302 | ||
|
|
5eee7b4dbb | ||
|
|
1691d01550 | ||
|
|
4543b7b3b2 | ||
|
|
3cddd9e6fb | ||
|
|
3fb99a94ac | ||
|
|
356575af79 | ||
|
|
58970bd829 | ||
|
|
6e8d5cf26c | ||
|
|
502136464a | ||
|
|
6b7d1a849f | ||
|
|
77f07bbf27 | ||
|
|
06a9d80798 | ||
|
|
3c2e1197ce | ||
|
|
befaa60509 | ||
|
|
1a2f73d363 | ||
|
|
e7063fdcbd | ||
|
|
b26437cb47 | ||
|
|
b6c24eb657 | ||
|
|
f1d3c640f8 | ||
|
|
2f627420a2 | ||
|
|
482041cac3 | ||
|
|
c139e9012a | ||
|
|
89e9e0a92e | ||
|
|
9ad1b924a1 | ||
|
|
68c53e4a19 | ||
|
|
e70a8aff16 | ||
|
|
1b857342ba | ||
|
|
4b4b257b4a | ||
|
|
597cbf30d8 | ||
|
|
6d7f3c0fd7 | ||
|
|
fc6fc897e1 | ||
|
|
0f45d580ba | ||
|
|
930a496ce4 | ||
|
|
b7f321f748 | ||
|
|
f9662f6d23 | ||
|
|
db5c0c3c8f | ||
|
|
93455ac7e7 | ||
|
|
29e25d9e8a | ||
|
|
30a45fc829 | ||
|
|
9d91a8348d | ||
|
|
66877c2071 | ||
|
|
671ad79933 | ||
|
|
61ba016da0 | ||
|
|
96d23defd3 | ||
|
|
5e80b52278 | ||
|
|
54252e8645 | ||
|
|
f03d0300d2 | ||
|
|
8281f0193f | ||
|
|
500c7b5748 | ||
|
|
e5b8288b35 | ||
|
|
fe493a8f0f | ||
|
|
e8bd998953 | ||
|
|
9ad4028007 | ||
|
|
f55fba6699 | ||
|
|
e2debac366 | ||
|
|
7fe82f7498 | ||
|
|
e7a08895f5 | ||
|
|
b436141665 | ||
|
|
86e2727c56 | ||
|
|
96670cbe60 | ||
|
|
f91f8e15d0 | ||
|
|
c4dd46205b | ||
|
|
4f9d2133fd | ||
|
|
b6721ffd7d |
14
.github/workflows/mikrotik_patch_6.yml
vendored
14
.github/workflows/mikrotik_patch_6.yml
vendored
@@ -98,10 +98,10 @@ jobs:
|
||||
RELEASE: ${{ needs.Set_Variables.outputs.RELEASE }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
@@ -212,8 +212,8 @@ jobs:
|
||||
fi
|
||||
sudo cp -f system-$LATEST_VERSION.npk ./new_iso/
|
||||
sudo -E python3 patch.py kernel ./new_iso/isolinux/initrd.rgz
|
||||
# sudo -E python3 npk.py create ./new_iso/gps-$LATEST_VERSION.npk ./option-$LATEST_VERSION.npk option ./option.sfs -desc="busybox"
|
||||
# sudo cp option-$LATEST_VERSION.npk ./new_iso/
|
||||
sudo -E python3 npk.py create ./new_iso/gps-$LATEST_VERSION.npk ./option-$LATEST_VERSION.npk option ./option.sfs -desc="busybox"
|
||||
sudo cp option-$LATEST_VERSION.npk ./new_iso/
|
||||
sudo mkisofs -o mikrotik-$LATEST_VERSION.iso \
|
||||
-V "MikroTik $LATEST_VERSION" \
|
||||
-sysid "" -preparer "MiKroTiK" \
|
||||
@@ -291,8 +291,10 @@ jobs:
|
||||
sudo cp ./all_packages/dude-$LATEST_VERSION.npk ./chr/var/pdb/dude/image
|
||||
sudo -E python3 patch.py npk ./chr/var/pdb/routeros-x86/image
|
||||
sudo cp ./chr/var/pdb/routeros-x86/image ./all_packages/routeros-x86-$LATEST_VERSION.npk
|
||||
# sudo mkdir -p ./chr/var/pdb/option
|
||||
# sudo cp ./all_packages/option-$LATEST_VERSION.npk ./chr/var/pdb/option/image
|
||||
sudo mkdir -p ./chr/var/pdb/option
|
||||
sudo cp ./all_packages/option-$LATEST_VERSION.npk ./chr/var/pdb/option/image
|
||||
sudo mkdir -p ./chr/rw/disk
|
||||
echo -e '#!/bin/sh\n# This script will be executed *before* RouterOS *loader* start.\n# You can put your own initialization stuff in here\n' | sudo tee ./chr/rw/disk/rc.local
|
||||
sudo umount ./chr
|
||||
sudo qemu-nbd -d /dev/nbd0
|
||||
sudo rm -rf ./chr
|
||||
|
||||
112
.github/workflows/mikrotik_patch_7.yml
vendored
112
.github/workflows/mikrotik_patch_7.yml
vendored
@@ -22,6 +22,7 @@ on:
|
||||
type: choice
|
||||
options:
|
||||
- stable
|
||||
- long-term
|
||||
- testing
|
||||
version:
|
||||
description: "Specify version (e.g., 7.19.2), empty for latest"
|
||||
@@ -87,7 +88,7 @@ jobs:
|
||||
BUILD_TIME=$(date +'%s')
|
||||
RELEASE=true
|
||||
MATRIX_JSON='[{"arch":"x86","channel":"stable"},{"arch":"arm64","channel":"stable"},{"arch":"arm","channel":"stable"},{"arch":"x86","channel":"testing"},{"arch":"arm64","channel":"testing"},{"arch":"arm","channel":"testing"}]'
|
||||
MATRIX_JSON='[{"arch":"x86","channel":"stable"},{"arch":"arm64","channel":"stable"},{"arch":"x86","channel":"testing"},{"arch":"arm64","channel":"testing"}]'
|
||||
MATRIX_JSON='[{"arch":"x86","channel":"stable"},{"arch":"arm64","channel":"stable"},{"arch":"x86","channel":"long-term"},{"arch":"arm64","channel":"long-term"},{"arch":"x86","channel":"testing"},{"arch":"arm64","channel":"testing"}]'
|
||||
fi
|
||||
echo "BUILD_TIME=$BUILD_TIME" >> $GITHUB_OUTPUT
|
||||
echo "RELEASE=$RELEASE" >> $GITHUB_OUTPUT
|
||||
@@ -108,10 +109,10 @@ jobs:
|
||||
RELEASE: ${{ needs.Set_Variables.outputs.RELEASE }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
@@ -190,11 +191,11 @@ jobs:
|
||||
sudo mksquashfs option-root option.sfs -quiet -comp xz -no-xattrs -b 256k
|
||||
sudo rm -rf option-root
|
||||
if [ "${{ matrix.arch }}" == "x86" ]; then
|
||||
sudo wget -O cpython.tar.gz -nv https://github.com/indygreg/python-build-standalone/releases/download/20250708/cpython-3.11.13+20250708-x86_64-unknown-linux-musl-install_only_stripped.tar.gz
|
||||
sudo wget -O cpython.tar.gz -nv https://github.com/astral-sh/python-build-standalone/releases/download/20241206/cpython-3.11.11+20241206-x86_64-unknown-linux-musl-install_only_stripped.tar.gz
|
||||
elif [ "${{ matrix.arch }}" == "arm64" ]; then
|
||||
sudo wget -O cpython.tar.gz -nv https://github.com/indygreg/python-build-standalone/releases/download/20250708/cpython-3.11.13+20250708-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz
|
||||
sudo wget -O cpython.tar.gz -nv https://github.com/indygreg/python-build-standalone/releases/download/20241206/cpython-3.11.11+20241206-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz
|
||||
elif [ "${{ matrix.arch }}" == "arm" ]; then
|
||||
sudo wget -O cpython.tar.gz -nv https://github.com/indygreg/python-build-standalone/releases/download/20250708/cpython-3.11.13+20250708-armv7-unknown-linux-gnueabi-install_only_stripped.tar.gz
|
||||
sudo wget -O cpython.tar.gz -nv https://github.com/indygreg/python-build-standalone/releases/download/20241206/cpython-3.11.11+20241206-armv7-unknown-linux-gnueabi-install_only_stripped.tar.gz
|
||||
fi
|
||||
sudo tar -xf cpython.tar.gz
|
||||
sudo rm cpython.tar.gz
|
||||
@@ -206,7 +207,7 @@ jobs:
|
||||
- name: Cache mikrotik-${{ env.LATEST_VERSION }}${{ env.ARCH }}.iso
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && (matrix.arch == 'x86' || matrix.arch == 'arm64')
|
||||
id: cache-mikrotik
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
mikrotik.iso
|
||||
@@ -218,11 +219,23 @@ jobs:
|
||||
run: |
|
||||
sudo wget -nv -O mikrotik.iso https://download.mikrotik.com/routeros/$LATEST_VERSION/mikrotik-$LATEST_VERSION$ARCH.iso
|
||||
|
||||
- name: Cache refind
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch == 'x86'
|
||||
id: cache-refind
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: refind-bin-0.14.2.zip
|
||||
key: refind
|
||||
restore-keys: refind
|
||||
|
||||
- name: Get refind
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch == 'x86' && steps.cache-refind.outputs.cache-hit != 'true'
|
||||
run: sudo wget -O refind-bin-0.14.2.zip https://downloads.sourceforge.net/project/refind/0.14.2/refind-bin-0.14.2.zip
|
||||
|
||||
- name: Patch mikrotik-${{ env.LATEST_VERSION }}${{ env.ARCH }}.iso
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && (matrix.arch == 'x86' || matrix.arch == 'arm64')
|
||||
run: |
|
||||
sudo apt-get install -y mkisofs xorriso > /dev/null
|
||||
sudo apt-get install -y build-essential binutils-arm-linux-gnueabi mkisofs xorriso > /dev/null
|
||||
sudo mkdir ./iso
|
||||
sudo mount -o loop,ro mikrotik.iso ./iso
|
||||
sudo mkdir ./new_iso
|
||||
@@ -246,18 +259,39 @@ jobs:
|
||||
sudo -E python3 npk.py sign "$file" "$file"
|
||||
done
|
||||
fi
|
||||
if [ "$LATEST_VERSION" = "7.12.1" ]; then
|
||||
URL="https://download.mikrotik.com/routeros/$LATEST_VERSION/routeros-${{ matrix.arch }}-$LATEST_VERSION.npk"
|
||||
sudo wget -nv -O "routeros-${{ matrix.arch }}-$LATEST_VERSION.npk" "$URL"
|
||||
sudo -E python3 patch.py npk routeros-${{ matrix.arch }}-$LATEST_VERSION.npk
|
||||
sudo mv "routeros-${{ matrix.arch }}-$LATEST_VERSION.npk" ./new_iso
|
||||
URL="https://download.mikrotik.com/routeros/$LATEST_VERSION/system-$LATEST_VERSION.npk"
|
||||
sudo wget -nv -O "system-$LATEST_VERSION.npk" "$URL"
|
||||
sudo -E python3 patch.py npk system-$LATEST_VERSION.npk
|
||||
sudo mv "system-$LATEST_VERSION.npk" ./new_iso
|
||||
fi
|
||||
sudo cp -f routeros-$LATEST_VERSION$ARCH.npk ./new_iso/
|
||||
sudo -E python3 npk.py create ./new_iso/gps-$LATEST_VERSION$ARCH.npk ./option-$LATEST_VERSION$ARCH.npk option ./option.sfs -desc="busybox"
|
||||
sudo cp option-$LATEST_VERSION$ARCH.npk ./new_iso/
|
||||
sudo -E python3 npk.py create ./new_iso/gps-$LATEST_VERSION$ARCH.npk ./python3-$LATEST_VERSION$ARCH.npk python3 ./python3.sfs -desc="python 3.11.13"
|
||||
sudo cp python3-$LATEST_VERSION$ARCH.npk ./new_iso/
|
||||
sudo mkdir ./efiboot
|
||||
sudo mount -o loop ./new_iso/efiboot.img ./efiboot
|
||||
if [ "${{ matrix.arch }}" == "x86" ]; then
|
||||
sudo -E python3 patch.py kernel ./efiboot/linux.x86_64
|
||||
sudo cp ./efiboot/linux.x86_64 ./BOOTX64.EFI
|
||||
sudo cp ./BOOTX64.EFI ./new_iso/isolinux/linux
|
||||
sudo umount ./efiboot
|
||||
truncate --size 32M efiboot.img
|
||||
sudo mkfs.fat -F16 -n ROUTEROS efiboot.img
|
||||
sudo mount -o loop efiboot.img efiboot
|
||||
sudo mkdir -p efiboot/EFI/BOOT
|
||||
sudo unzip refind-bin-0.14.2.zip refind-bin-0.14.2/refind/refind_x64.efi
|
||||
sudo cp refind-bin-0.14.2/refind/refind_x64.efi ./efiboot/EFI/BOOT/BOOTX64.EFI
|
||||
sudo rm -rf refind-bin-0.14.2
|
||||
echo -e 'timeout 0\ntextonly\ntextmode 0\nshowtools shutdown, reboot, exit\nmenuentry "Install RouterOS" {\n\tloader /linux.x86_64\n\toptions "load_ramdisk=1 root=/dev/ram0 -install -cdrom debug"\n}\ndefault_selection /EFI/BOOT/BOOTX64.EFI' \
|
||||
> refind.conf
|
||||
sudo cp refind.conf ./efiboot/EFI/BOOT/
|
||||
sudo rm refind.conf
|
||||
sudo -E python3 patch.py kernel ./new_iso/isolinux/linux
|
||||
sudo cp ./new_iso/isolinux/linux ./efiboot/linux.x86_64
|
||||
sudo cp ./new_iso/isolinux/linux ./linux.x86_64
|
||||
sudo umount ./efiboot
|
||||
sudo cp -f efiboot.img ./new_iso/efiboot.img
|
||||
sudo mkisofs -o mikrotik-$LATEST_VERSION$ARCH.iso \
|
||||
-V "MikroTik $LATEST_VERSION ${{ matrix.arch }}" \
|
||||
-sysid "" -preparer "MiKroTiK" \
|
||||
@@ -274,6 +308,7 @@ jobs:
|
||||
-R -J \
|
||||
./new_iso
|
||||
elif [ "${{ matrix.arch }}" == "arm64" ]; then
|
||||
sudo mount -o loop ./new_iso/efiboot.img ./efiboot
|
||||
sudo -E python3 patch.py kernel ./efiboot/EFI/BOOT/BOOTAA64.EFI
|
||||
sudo umount ./efiboot
|
||||
sudo xorriso -as mkisofs -o mikrotik-$LATEST_VERSION$ARCH.iso \
|
||||
@@ -297,7 +332,7 @@ jobs:
|
||||
- name: Cache chr-${{ env.LATEST_VERSION }}${{ env.ARCH }}.img.zip
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && (matrix.arch == 'x86' || matrix.arch == 'arm64')
|
||||
id: cache-chr-img
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
chr.img
|
||||
@@ -322,7 +357,7 @@ jobs:
|
||||
</References>
|
||||
<DiskSection>
|
||||
<Info>Virtual disk information</Info>
|
||||
<Disk ovf:capacity="{CAPACITY_MB}" ovf:capacityAllocationUnits="byte * 2^20" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="{POPULATED_SIZE}"/>
|
||||
<Disk ovf:capacity="{CAPACITY_MB}" ovf:capacityAllocationUnits="byte * 2^20" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"/>
|
||||
</DiskSection>
|
||||
<NetworkSection>
|
||||
<Info>The list of logical networks</Info>
|
||||
@@ -404,7 +439,7 @@ jobs:
|
||||
</VirtualHardwareSection>
|
||||
<AnnotationSection ovf:required="false">
|
||||
<Info>A human-readable annotation</Info>
|
||||
<Annotation>MikroTik RouterOS CHR v7.19.4</Annotation>
|
||||
<Annotation>MikroTik RouterOS CHR</Annotation>
|
||||
</AnnotationSection>
|
||||
</VirtualSystem>
|
||||
</Envelope>'
|
||||
@@ -553,7 +588,7 @@ jobs:
|
||||
- name: Cache all_packages${{ env.ARCH }}-${{ env.LATEST_VERSION }}.zip
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch != 'x86' && matrix.arch != 'arm64'
|
||||
id: cache-all-packages
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: all_packages.zip
|
||||
key: all_packages${{ env.ARCH }}-${{ env.LATEST_VERSION }}.zip
|
||||
@@ -567,7 +602,7 @@ jobs:
|
||||
- name: Cache Main package routeros-${{ env.LATEST_VERSION }}${{ env.ARCH }}.npk
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch != 'x86' && matrix.arch != 'arm64'
|
||||
id: cache-main-package
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: routeros.npk
|
||||
key: routeros-${{ env.LATEST_VERSION }}${{ env.ARCH }}.npk
|
||||
@@ -595,19 +630,6 @@ jobs:
|
||||
sudo zip ../all_packages-${{ matrix.arch }}-$LATEST_VERSION.zip *.npk
|
||||
cd ..
|
||||
|
||||
- name: Cache refind
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch == 'x86' && env.RELEASE == 'true'
|
||||
id: cache-refind
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: refind-bin-0.14.2.zip
|
||||
key: refind
|
||||
restore-keys: refind
|
||||
|
||||
- name: Get refind
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch == 'x86' && steps.cache-refind.outputs.cache-hit != 'true' && env.RELEASE == 'true'
|
||||
run: sudo wget -nv -O refind-bin-0.14.2.zip https://nchc.dl.sourceforge.net/project/refind/0.14.2/refind-bin-0.14.2.zip
|
||||
|
||||
- name: Create install-image-${{ env.LATEST_VERSION }}${{ env.ARCH }}.img
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch == 'x86' && env.RELEASE == 'true'
|
||||
run: |
|
||||
@@ -631,7 +653,7 @@ jobs:
|
||||
> syslinux.cfg
|
||||
sudo cp syslinux.cfg ./install/
|
||||
sudo rm syslinux.cfg
|
||||
sudo cp ./BOOTX64.EFI ./install/linux
|
||||
sudo cp ./linux.x86_64 ./install/linux
|
||||
NPK_FILES=($(find ./all_packages/*.npk))
|
||||
for ((i=1; i<=${#NPK_FILES[@]}; i++))
|
||||
do
|
||||
@@ -650,7 +672,7 @@ jobs:
|
||||
- name: Cache NetInstall ${{ env.LATEST_VERSION }}${{ env.ARCH }}
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && matrix.arch == 'x86' && env.RELEASE == 'true'
|
||||
id: cache-netinstall
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
netinstall.zip
|
||||
@@ -670,9 +692,9 @@ jobs:
|
||||
sudo unzip netinstall.zip
|
||||
sudo -E python3 patch.py netinstall netinstall.exe
|
||||
sudo zip netinstall-$LATEST_VERSION.zip ./netinstall.exe
|
||||
sudo tar -xvf netinstall.tar.gz
|
||||
sudo -E python3 patch.py netinstall netinstall-cli
|
||||
sudo tar -czvf netinstall-$LATEST_VERSION.tar.gz ./netinstall-cli
|
||||
# sudo tar -xvf netinstall.tar.gz
|
||||
# sudo -E python3 patch.py netinstall netinstall-cli
|
||||
# sudo tar -czvf netinstall-$LATEST_VERSION.tar.gz ./netinstall-cli
|
||||
|
||||
- name: Prepare for Upload
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && env.RELEASE == 'true'
|
||||
@@ -689,6 +711,20 @@ jobs:
|
||||
- name: Upload Files
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && env.RELEASE == 'true'
|
||||
run: |
|
||||
sudo apt-get install -y knockd lftp > /dev/null
|
||||
knock -4 ${{ secrets.SSH_SERVER }} ${{ secrets.SSH_KNOCK_PORT }}
|
||||
echo "Knocking on server..."
|
||||
for i in 1 2 3; do
|
||||
if knock -4 ${{ secrets.SSH_SERVER }} ${{ secrets.SSH_KNOCK_PORT }} ; then
|
||||
echo "Knock successful"
|
||||
break
|
||||
else
|
||||
echo "Knock attempt $i failed, retrying..."
|
||||
sleep 2
|
||||
fi
|
||||
done
|
||||
echo "Waiting for firewall to open SSH port..."
|
||||
sleep 3
|
||||
sudo chown -R root:root ./publish/
|
||||
LOCAL_PATH=./publish/$LATEST_VERSION
|
||||
REMOTE_PATH=${{ secrets.SSH_DIRECTORY }}
|
||||
@@ -753,7 +789,7 @@ jobs:
|
||||
|
||||
- name: Create Release tag ${{ env.LATEST_VERSION }} ${{ env.ARCH }}
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && env.RELEASE == 'true'
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
name: "RouterOS ${{ env.LATEST_VERSION }} ${{ env.ARCH }}"
|
||||
body_path: "CHANGELOG"
|
||||
@@ -770,7 +806,7 @@ jobs:
|
||||
|
||||
- name: Upload Files as Artifact (No Release)
|
||||
if: steps.get_latest.outputs.has_new_version == 'true' && env.RELEASE == 'false'
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: mikrotik-${{ env.LATEST_VERSION }}${{ env.ARCH }}
|
||||
path: |
|
||||
|
||||
13
README.md
13
README.md
@@ -1,6 +1,10 @@
|
||||
[](https://github.com/elseif/MikroTikPatch/actions/workflows/mikrotik_patch_6.yml)
|
||||
[](https://github.com/elseif/MikroTikPatch/actions/workflows/mikrotik_patch_7.yml)
|
||||
|
||||
### 感谢赞助
|
||||
[](https://www.digitalocean.com/?refcode=dbf6ed365068&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge)
|
||||
[DartNode(aff)](https://dartnode.com?aff=SnazzyLobster067) | [ZMTO(aff)](https://console.zmto.com/?affid=1588) | [Vultr(aff)](https://www.vultr.com/?ref=9807160-9J)
|
||||
|
||||
# MikroTik RouterOS Patch [[English](README_EN.md)]
|
||||
[](./LICENSE)
|
||||
[](./CODE_OF_CONDUCT.md)
|
||||
@@ -58,10 +62,11 @@ graph TD
|
||||
### patch.py
|
||||
替换公钥并签名
|
||||
|
||||
## 所有的修补操作都自动运行在[Github Action](https://github.com/elseif/MikroTikPatch/blob/main/.github/workflows/)。
|
||||
|
||||
### 感谢赞助
|
||||
[ZMTO](https://console.zmto.com)
|
||||
[](https://dartnode.com "Powered by DartNode - Free VPS for Open Source")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
399
chr.sh
399
chr.sh
@@ -1,97 +1,346 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
LATEST_VERSION="${1:-7.19.4}"
|
||||
echo "VERSION: $LATEST_VERSION"
|
||||
ARCH=$(uname -m)
|
||||
_ask() {
|
||||
local _redo=0
|
||||
|
||||
if [[ $LATEST_VERSION == 7.* ]]; then
|
||||
read resp
|
||||
case "$resp" in
|
||||
!) echo "Type 'exit' to return to setup."
|
||||
sh
|
||||
_redo=1
|
||||
;;
|
||||
!*) eval "${resp#?}"
|
||||
_redo=1
|
||||
;;
|
||||
esac
|
||||
return $_redo
|
||||
}
|
||||
ask() {
|
||||
local _question="$1" _default="$2"
|
||||
while :; do
|
||||
printf %s "$_question "
|
||||
[ -z "$_default" ] || printf "[%s] " "$_default"
|
||||
_ask && : ${resp:=$_default} && break
|
||||
done
|
||||
}
|
||||
ask_until() {
|
||||
resp=
|
||||
while [ -z "$resp" ] ; do
|
||||
ask "$1" "$2"
|
||||
done
|
||||
}
|
||||
yesno() {
|
||||
case $1 in
|
||||
[Yy]) return 0;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
ask_yesno() {
|
||||
while true; do
|
||||
ask "$1" "$2"
|
||||
case "$resp" in
|
||||
Y|y|N|n) break;;
|
||||
esac
|
||||
done
|
||||
yesno "$resp"
|
||||
}
|
||||
|
||||
|
||||
select_language() {
|
||||
while true; do
|
||||
echo "Select your language:"
|
||||
echo "1. English"
|
||||
echo "2. 简体中文"
|
||||
ask_until "Please choose an option" "1"
|
||||
case $resp in
|
||||
1)
|
||||
MSG_ARCH="Arch:"
|
||||
MSG_BOOTMODE="BootMode:"
|
||||
MSG_STORAGE_DEVICE="Input storage device name:"
|
||||
MSG_ADDRESS="Input IP address:"
|
||||
MSG_GATEWAY="Input gateway:"
|
||||
MSG_DNS="Input domain name server:"
|
||||
MSG_SELECT_VERSION="Select the version you want to install:"
|
||||
MSG_STABLE="stable (v7)"
|
||||
MSG_TEST="testing (v7)"
|
||||
MSG_LTS="long-term (v6)"
|
||||
MSG_STABLE6="stable (v6)"
|
||||
MSG_PLEASE_CHOOSE="Please choose an option:"
|
||||
MSG_UNSUPPORTED_ARCH="Error: Unsupported architecture: "
|
||||
MSG_INVALID_OPTION="Error: Invalid option!"
|
||||
MSG_ARM64_NOT_SUPPORT_V6="arm64 does not support v6 version for now."
|
||||
MSG_SELECTED_VERSION="Selected version:"
|
||||
MSG_FILE_DOWNLOAD="Download file: "
|
||||
MSG_DOWNLOAD_ERROR="Error: No wget nor curl is installed. Cannot download."
|
||||
MSG_EXTRACT_ERROR="Error: No unzip nor gunzip is installed. Cannot uncompress."
|
||||
MSG_DOWNLOAD_FAILED="Error: Download failed!"
|
||||
MSG_OPERATION_ABORTED="Error: Operation aborted."
|
||||
MSG_WARNING="Warn: All data on /dev/%s will be lost!"
|
||||
MSG_REBOOTING="Ok, rebooting..."
|
||||
MSG_ADMIN_PASSWORD="admin password:"
|
||||
MSG_MANUAL_PASS_CHOICE="Do you want to enter a password manually? (y/N): "
|
||||
MSG_ENTER_NEW_PASS="Enter new password: "
|
||||
MSG_PASS_EMPTY="Password cannot be empty, please try again."
|
||||
MSG_ERROR_MOUNT="Error: Failed to mount partition"
|
||||
MSG_ERROR_LOOP="Error: Failed to setup loop device"
|
||||
MSG_AUTO_RUN_FILE_CREATED="autorun.scr file created."
|
||||
MSG_AUTO_RUN_FILE_NOT_CREATED="Warn: autorun.scr file create failed"
|
||||
MSG_CONFIRM_CONTINUE="Do you want to continue? [y/n]"
|
||||
;;
|
||||
2)
|
||||
MSG_ARCH="CPU架构:"
|
||||
MSG_BOOTMODE="引导模式:"
|
||||
MSG_STORAGE_DEVICE="输入存储设备名称:"
|
||||
MSG_ADDRESS="输入IP地址:"
|
||||
MSG_GATEWAY="输入网关地址:"
|
||||
MSG_DNS="输入DNS服务器:"
|
||||
MSG_SELECT_VERSION="请选择您要安装的版本:"
|
||||
MSG_STABLE="稳定版 (v7)"
|
||||
MSG_TEST="测试版 (v7)"
|
||||
MSG_LTS="长期支持版 (v6)"
|
||||
MSG_STABLE6="稳定版 (v6)"
|
||||
MSG_PLEASE_CHOOSE="请选择一个选项:"
|
||||
MSG_UNSUPPORTED_ARCH="错误: 不支持的架构: "
|
||||
MSG_INVALID_OPTION="错误: 无效选项"
|
||||
MSG_ARM64_NOT_SUPPORT_V6="ARM64架构暂不支持安装v6版本"
|
||||
MSG_SELECTED_VERSION="已选择版本:"
|
||||
MSG_FILE_DOWNLOAD="下载文件: "
|
||||
MSG_DOWNLOAD_ERROR="错误: wget 或 curl 都未安装,无法下载文件。"
|
||||
MSG_EXTRACT_ERROR="错误: unzip 或 gunzip 都未安装,无法解压文件。"
|
||||
MSG_DOWNLOAD_FAILED="错误: 下载失败!"
|
||||
MSG_OPERATION_ABORTED="错误: 操作已中止。"
|
||||
MSG_WARNING="警告:/dev/%s 上的数据将会丢失!"
|
||||
MSG_REBOOTING="好的,正在重启..."
|
||||
MSG_ADMIN_PASSWORD="管理员密码:"
|
||||
MSG_MANUAL_PASS_CHOICE="是否手动输入密码?(y/N): "
|
||||
MSG_ENTER_NEW_PASS="请输入新密码: "
|
||||
MSG_PASS_EMPTY="密码不能为空,请重新输入。"
|
||||
MSG_ERROR_MOUNT="错误: 挂载分区失败"
|
||||
MSG_ERROR_LOOP="错误: 设置 loop 设备失败"
|
||||
MSG_AUTO_RUN_FILE_CREATED="autorun.scr 文件已创建。"
|
||||
MSG_AUTO_RUN_FILE_NOT_CREATED="警告:autorun.scr 文件创建失败!"
|
||||
MSG_CONFIRM_CONTINUE="您是否确定继续? [y/n]"
|
||||
;;
|
||||
*)
|
||||
echo "Error: Invalid option!"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
break
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
show_system_info() {
|
||||
ARCH=$(uname -m)
|
||||
BOOT_MODE=$( [ -d "/sys/firmware/efi" ] && echo "UEFI" || echo "BIOS" )
|
||||
echo "$MSG_ARCH $ARCH"
|
||||
echo "$MSG_BOOTMODE $BOOT_MODE"
|
||||
}
|
||||
|
||||
confirm_storge() {
|
||||
if command -v lsblk >/dev/null 2>&1; then
|
||||
STORAGE=$(lsblk -d -n -o NAME,TYPE | awk '$2=="disk"{print $1; exit}')
|
||||
else
|
||||
STORAGE=$(fdisk -l | awk '/^Disk \/dev/ {print $2; exit}' | sed 's#:##' | sed 's#/dev/##')
|
||||
fi
|
||||
ask_until "$MSG_STORAGE_DEVICE" "$STORAGE"
|
||||
STORAGE=$resp
|
||||
}
|
||||
confirm_address() {
|
||||
ETH=$(ip route show default | grep '^default' | sed -n 's/.* dev \([^\ ]*\) .*/\1/p')
|
||||
ADDRESS=$(ip addr show $ETH | grep global | cut -d' ' -f 6 | head -n 1)
|
||||
GATEWAY=$(ip route list | grep default | cut -d' ' -f 3)
|
||||
if [ -f "/etc/resolv.conf" ]; then
|
||||
DNS=$(grep '^nameserver' /etc/resolv.conf | awk '{print $2}' | head -n 1)
|
||||
fi
|
||||
[ -z "$DNS" ] && DNS="8.8.8.8"
|
||||
ask_until "$MSG_ADDRESS" "$ADDRESS"
|
||||
ADDRESS=$resp
|
||||
ask_until "$MSG_GATEWAY" "$GATEWAY"
|
||||
GATEWAY=$resp
|
||||
ask_until "$MSG_DNS" "$DNS"
|
||||
DNS=$resp
|
||||
}
|
||||
|
||||
http_get() {
|
||||
local url=$1
|
||||
local dest_file=$2
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
if [ -z "$dest_file" ]; then
|
||||
curl -Ls "$url"
|
||||
else
|
||||
curl -L -# -o "$dest_file" "$url" || { echo "$MSG_DOWNLOAD_FAILED"; exit 1; }
|
||||
fi
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
if [ -z "$dest_file" ]; then
|
||||
wget --no-check-certificate -qO- "$url"
|
||||
else
|
||||
wget --no-check-certificate -O "$dest_file" "$url" || { echo "$MSG_DOWNLOAD_FAILED"; exit 1; }
|
||||
fi
|
||||
else
|
||||
echo "$MSG_DOWNLOAD_ERROR"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
extract_zip() {
|
||||
local zip_file=$1
|
||||
local dest_file=$2
|
||||
if command -v unzip >/dev/null 2>&1; then
|
||||
unzip -p "$zip_file" > "$dest_file" || { echo "$MSG_EXTRACT_ERROR"; exit 1; }
|
||||
elif command -v gunzip >/dev/null 2>&1; then
|
||||
gunzip -c "$zip_file" > "$dest_file" || { echo "$MSG_EXTRACT_ERROR"; exit 1; }
|
||||
else
|
||||
echo "$MSG_EXTRACT_ERROR"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
select_version() {
|
||||
if [[ -n "$VERSION" ]]; then
|
||||
if [[ "$VERSION" == 7.* ]]; then
|
||||
V7=1
|
||||
elif [[ "$VERSION" == 6.* ]]; then
|
||||
V7=0
|
||||
else
|
||||
echo "Error: Unsupported version $VERSION"
|
||||
exit 1
|
||||
fi
|
||||
echo "$MSG_SELECTED_VERSION $VERSION"
|
||||
return
|
||||
fi
|
||||
while true; do
|
||||
case $ARCH in
|
||||
x86_64|i386|i486|i586|i686)
|
||||
echo "$MSG_SELECT_VERSION"
|
||||
echo "1. $MSG_STABLE"
|
||||
echo "2. $MSG_TEST"
|
||||
echo "3. $MSG_LTS"
|
||||
echo "4. $MSG_STABLE6"
|
||||
read -p "$MSG_PLEASE_CHOOSE [1-4]" version_choice
|
||||
;;
|
||||
aarch64)
|
||||
echo "$MSG_SELECT_VERSION"
|
||||
echo "1. $MSG_STABLE"
|
||||
echo "2. $MSG_TEST"
|
||||
read -p "$MSG_PLEASE_CHOOSE [1-2]" version_choice
|
||||
;;
|
||||
*)
|
||||
echo "$MSG_UNSUPPORTED_ARCH $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case $version_choice in
|
||||
1)
|
||||
VERSION=$(http_get "https://upgrade.mikrotik.ltd/routeros/NEWESTa7.stable" | cut -d' ' -f1)
|
||||
V7=1
|
||||
;;
|
||||
2)
|
||||
VERSION=$(http_get "https://upgrade.mikrotik.ltd/routeros/NEWESTa7.testing" | cut -d' ' -f1)
|
||||
V7=1
|
||||
;;
|
||||
3)
|
||||
if [[ "$ARCH" == "aarch64" ]]; then
|
||||
echo "$MSG_ARM64_NOT_SUPPORT_V6"
|
||||
continue
|
||||
fi
|
||||
VERSION=$(http_get "https://upgrade.mikrotik.ltd/routeros/NEWEST6.long-term" | cut -d' ' -f1)
|
||||
V7=0
|
||||
;;
|
||||
4)
|
||||
if [[ "$ARCH" == "aarch64" ]]; then
|
||||
echo "$MSG_ARM64_NOT_SUPPORT_V6"
|
||||
continue
|
||||
fi
|
||||
VERSION=$(http_get "https://upgrade.mikrotik.ltd/routeros/NEWEST6.stable" | cut -d' ' -f1)
|
||||
V7=0
|
||||
;;
|
||||
*)
|
||||
echo "$MSG_INVALID_OPTION"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
echo "$MSG_SELECTED_VERSION $VERSION"
|
||||
break
|
||||
done
|
||||
}
|
||||
|
||||
download_image(){
|
||||
case $ARCH in
|
||||
x86_64|i386|i486|i586|i686)
|
||||
echo "ARCH: $ARCH"
|
||||
if [ -d /sys/firmware/efi ]; then
|
||||
echo "BOOT MODE: UEFI"
|
||||
IMG_URL="https://github.com/elseif/MikroTikPatch/releases/download/$LATEST_VERSION/chr-$LATEST_VERSION.img.zip"
|
||||
if [[ $V7 == 1 && $BOOT_MODE == "BIOS" ]]; then
|
||||
IMG_URL="https://github.com/elseif/MikroTikPatch/releases/download/$VERSION/chr-$VERSION-legacy-bios.img.zip"
|
||||
else
|
||||
echo "BOOT MODE: BIOS/MBR"
|
||||
IMG_URL="https://github.com/elseif/MikroTikPatch/releases/download/$LATEST_VERSION/chr-$LATEST_VERSION-legacy-bios.img.zip"
|
||||
IMG_URL="https://github.com/elseif/MikroTikPatch/releases/download/$VERSION/chr-$VERSION.img.zip"
|
||||
fi
|
||||
;;
|
||||
aarch64)
|
||||
echo "ARCH: $ARCH"
|
||||
IMG_URL="https://github.com/elseif/MikroTikPatch/releases/download/$LATEST_VERSION-arm64/chr-$LATEST_VERSION-arm64.img.zip"
|
||||
IMG_URL="https://github.com/elseif/MikroTikPatch/releases/download/$VERSION-arm64/chr-$VERSION-arm64.img.zip"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $ARCH"
|
||||
echo "$MSG_UNSUPPORTED_ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
case $ARCH in
|
||||
x86_64|i386|i486|i586|i686)
|
||||
echo "ARCH: $ARCH"
|
||||
IMG_URL="https://github.com/elseif/MikroTikPatch/releases/download/$LATEST_VERSION/chr-$LATEST_VERSION.img.zip"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
echo "$MSG_FILE_DOWNLOAD $(basename "$IMG_URL")"
|
||||
http_get "$IMG_URL" "/tmp/chr.img.zip"
|
||||
cd /tmp
|
||||
extract_zip "chr.img.zip" chr.img
|
||||
}
|
||||
|
||||
STORAGE=$(lsblk -d -n -o NAME,TYPE | awk '$2=="disk"{print $1; exit}')
|
||||
echo "STORAGE: $STORAGE"
|
||||
ETH=$(ip route show default | grep '^default' | sed -n 's/.* dev \([^\ ]*\) .*/\1/p')
|
||||
echo "ETH: $ETH"
|
||||
ADDRESS=$(ip addr show $ETH | grep global | cut -d' ' -f 6 | head -n 1)
|
||||
echo "ADDRESS: $ADDRESS"
|
||||
GATEWAY=$(ip route list | grep default | cut -d' ' -f 3)
|
||||
echo "GATEWAY: $GATEWAY"
|
||||
DNS=$(grep '^nameserver' /etc/resolv.conf | awk '{print $2}' | head -n 1)
|
||||
[ -z "$DNS" ] && DNS="8.8.8.8"
|
||||
echo "DNS: $DNS"
|
||||
|
||||
echo "FILE: $(basename $IMG_URL)"
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget --no-check-certificate -O /tmp/chr.img.zip "$IMG_URL" || { echo "Download failed!"; exit 1; }
|
||||
elif command -v curl >/dev/null 2>&1; then
|
||||
curl -L --insecure -o /tmp/chr.img.zip "$IMG_URL" || { echo "Download failed!"; exit 1; }
|
||||
else
|
||||
echo "Neither wget nor curl is installed. Cannot download $url"
|
||||
exit 1
|
||||
fi
|
||||
cd /tmp
|
||||
gunzip -c chr.img.zip > chr.img
|
||||
RANDOM_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 8)
|
||||
if LOOP=$(losetup -Pf --show chr.img 2>/dev/null); then
|
||||
sleep 3
|
||||
MNT=/tmp/chr
|
||||
mkdir -p $MNT
|
||||
if mount ${LOOP}p2 $MNT 2>/dev/null; then
|
||||
cat <<EOF | tee $MNT/rw/autorun.scr
|
||||
create_autorun() {
|
||||
if LOOP=$(losetup -Pf --show chr.img 2>/dev/null); then
|
||||
sleep 1
|
||||
MNT=/tmp/chr
|
||||
mkdir -p $MNT
|
||||
PARTITION=$([ "$V7" == 1 ] && echo "p2" || echo "p1")
|
||||
if mount "${LOOP}${PARTITION}" "$MNT" 2>/dev/null; then
|
||||
confirm_address
|
||||
RANDOM_ADMIN_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 16)
|
||||
ask_until "$MSG_ADMIN_PASSWORD" "$RANDOM_ADMIN_PASS"
|
||||
RANDOM_ADMIN_PASS=$resp
|
||||
cat <<EOF > "$MNT/rw/autorun.scr"
|
||||
/user set admin password="$RANDOM_ADMIN_PASS"
|
||||
/ip dns set servers=$DNS
|
||||
/ip address add address=$ADDRESS interface=ether1
|
||||
/ip route add gateway=$GATEWAY
|
||||
/ip dns set servers=$DNS
|
||||
/user set admin password="$RANDOM_PASS"
|
||||
EOF
|
||||
echo "autorun.scr file created."
|
||||
echo -e "admin password: \e[31m$RANDOM_PASS\e[0m"
|
||||
umount $MNT
|
||||
echo "$MSG_AUTO_RUN_FILE_CREATED"
|
||||
umount $MNT
|
||||
losetup -d "$LOOP"
|
||||
else
|
||||
losetup -d "$LOOP"
|
||||
echo "$MSG_ERROR_MOUNT $PARTITION"
|
||||
echo "$MSG_AUTO_RUN_FILE_NOT_CREATED"
|
||||
fi
|
||||
else
|
||||
echo "Failed to mount partition 2, skipping autorun.scr creation."
|
||||
echo "$MSG_ERROR_LOOP"
|
||||
echo "$MSG_AUTO_RUN_FILE_NOT_CREATED"
|
||||
fi
|
||||
losetup -d $LOOP
|
||||
fi
|
||||
}
|
||||
|
||||
echo "WARNING: All data on /dev/$STORAGE will be lost!"
|
||||
read -p "Do you want to continue? [Y/n]: " confirm < /dev/tty
|
||||
confirm=${confirm:-Y}
|
||||
if [[ "$confirm" =~ ^[Nn]$ ]]; then
|
||||
echo "Operation aborted."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dd if=chr.img of=/dev/$STORAGE bs=4M conv=fsync
|
||||
echo "Ok, rebooting..."
|
||||
echo 1 > /proc/sys/kernel/sysrq 2>/dev/null || true
|
||||
echo b > /proc/sysrq-trigger 2>/dev/null || true
|
||||
reboot -f
|
||||
write_and_reboot() {
|
||||
confirm_storge
|
||||
printf "$MSG_WARNING\n" "$STORAGE"
|
||||
ask_yesno "$MSG_CONFIRM_CONTINUE"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$MSG_OPERATION_ABORTED"
|
||||
exit 1
|
||||
fi
|
||||
dd if=chr.img of=/dev/$STORAGE bs=4M conv=fsync
|
||||
echo "$MSG_REBOOTING"
|
||||
echo 1 > /proc/sys/kernel/sysrq 2>/dev/null || true
|
||||
echo b > /proc/sysrq-trigger 2>/dev/null || true
|
||||
reboot -f
|
||||
}
|
||||
|
||||
select_language
|
||||
show_system_info
|
||||
select_version
|
||||
download_image
|
||||
create_autorun
|
||||
write_and_reboot
|
||||
exit 0
|
||||
|
||||
1603
index.html
1603
index.html
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
51
npk.py
51
npk.py
@@ -207,10 +207,9 @@ class NovaPackage(Package):
|
||||
self._parts.append(NpkPartItem(NpkPartID(part_id),NpkInfo.unserialize_from(part_data)))
|
||||
else:
|
||||
self._parts.append(NpkPartItem(NpkPartID(part_id),part_data))
|
||||
|
||||
def set_null_block(self):
|
||||
def rebuild_squashfs(data):
|
||||
if len(part.data) < 4 or part.data[:4] != b'hsqs':
|
||||
return part.data
|
||||
with open('squashfs.sfs', 'wb') as f:
|
||||
f.write(data)
|
||||
os.system('unsquashfs -d squashfs-root squashfs.sfs')
|
||||
@@ -219,19 +218,20 @@ class NovaPackage(Package):
|
||||
os.system('rm -rf squashfs-root')
|
||||
with open('squashfs.sfs', 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
if len(self._packages) > 0:
|
||||
def get_size(package,size):
|
||||
for part in package._parts:
|
||||
size += 6
|
||||
size += len(part.data)
|
||||
return size
|
||||
|
||||
def set_null(package,offset):
|
||||
has_squashfs = False
|
||||
for package in self._packages:
|
||||
for part in package._parts:
|
||||
if part.id == NpkPartID.SQUASHFS:
|
||||
part.data = rebuild_squashfs(part.data)
|
||||
has_squashfs = True
|
||||
|
||||
if not has_squashfs:
|
||||
return
|
||||
for package in self._packages:
|
||||
count = 8
|
||||
for part in package._parts:
|
||||
if part.id == NpkPartID.SQUASHFS and len(part.data) >= 4 and part.data[:4] in [b'hsqs',b'sqsh']:
|
||||
part.data = rebuild_squashfs(part.data)
|
||||
has_squashfs = True
|
||||
if has_squashfs:
|
||||
count = offset
|
||||
for part in package._parts:
|
||||
count += 6
|
||||
if part.id == NpkPartID.NULL_BLOCK:
|
||||
@@ -241,23 +241,12 @@ class NovaPackage(Package):
|
||||
pad_len = (4096 - (count % 4096)) % 4096
|
||||
package[NpkPartID.NULL_BLOCK].data = b'\x00' * pad_len
|
||||
|
||||
else:
|
||||
has_squashfs = False
|
||||
for part in self._parts:
|
||||
if part.id == NpkPartID.SQUASHFS:
|
||||
part.data = rebuild_squashfs(part.data)
|
||||
has_squashfs = True
|
||||
if not has_squashfs:
|
||||
return
|
||||
count = 8
|
||||
for part in self._parts:
|
||||
count += 6
|
||||
if part.id == NpkPartID.NULL_BLOCK:
|
||||
break
|
||||
count += len(part.data)
|
||||
count += 6
|
||||
pad_len = (4096 - (count % 4096)) % 4096
|
||||
self[NpkPartID.NULL_BLOCK].data = b'\x00' * pad_len
|
||||
set_null(self,8)
|
||||
offset = get_size(self,8)
|
||||
for package in self._packages:
|
||||
set_null(package,offset)
|
||||
offset += get_size(package,0)
|
||||
|
||||
def get_digest(self,hash_fnc,package:Package=None)->bytes:
|
||||
parts = package._parts if package else self._parts
|
||||
for part in parts:
|
||||
|
||||
99
patch.py
99
patch.py
@@ -321,40 +321,79 @@ def patch_loader(loader_file):
|
||||
print("loader module import failed. cannot run patch_loader.py")
|
||||
|
||||
def patch_squashfs(path,key_dict):
|
||||
url_replacements = {
|
||||
os.environ.get('MIKRO_LICENCE_URL', '').encode(): os.environ.get('CUSTOM_LICENCE_URL', '').encode(),
|
||||
os.environ.get('MIKRO_UPGRADE_URL', '').encode(): os.environ.get('CUSTOM_UPGRADE_URL', '').encode(),
|
||||
os.environ.get('MIKRO_CLOUD_URL', '').encode(): os.environ.get('CUSTOM_CLOUD_URL', '').encode(),
|
||||
os.environ.get('MIKRO_CLOUD_PUBLIC_KEY', '').encode(): os.environ.get('CUSTOM_CLOUD_PUBLIC_KEY', '').encode(),
|
||||
}
|
||||
url_replacements = {k: v for k, v in url_replacements.items() if k and v}
|
||||
renew_replacements = {
|
||||
os.environ.get('MIKRO_RENEW_URL', '').encode(): os.environ.get('CUSTOM_RENEW_URL', '').encode(),
|
||||
}
|
||||
renew_replacements = {k: v for k, v in renew_replacements.items() if k and v}
|
||||
|
||||
for root, dirs, files in os.walk(path):
|
||||
for _file in files:
|
||||
file = os.path.join(root,_file)
|
||||
if os.path.isfile(file):
|
||||
if _file =='loader':
|
||||
patch_loader(file)
|
||||
continue
|
||||
data = open(file,'rb').read()
|
||||
if 'mode' in files and 'keyman' in files:
|
||||
for file_path in [os.path.join(root, 'mode'),os.path.join(root, 'keyman')]:
|
||||
with open(file_path, 'rb') as f:
|
||||
data = f.read()
|
||||
modified = False
|
||||
for old_public_key,new_public_key in key_dict.items():
|
||||
_data = replace_key(old_public_key,new_public_key,data,file)
|
||||
if _data != data:
|
||||
open(file,'wb').write(_data)
|
||||
url_dict = {
|
||||
os.environ['MIKRO_LICENCE_URL'].encode():os.environ['CUSTOM_LICENCE_URL'].encode(),
|
||||
os.environ['MIKRO_UPGRADE_URL'].encode():os.environ['CUSTOM_UPGRADE_URL'].encode(),
|
||||
os.environ['MIKRO_CLOUD_URL'].encode():os.environ['CUSTOM_CLOUD_URL'].encode(),
|
||||
os.environ['MIKRO_CLOUD_PUBLIC_KEY'].encode():os.environ['CUSTOM_CLOUD_PUBLIC_KEY'].encode(),
|
||||
}
|
||||
data = open(file,'rb').read()
|
||||
for old_url,new_url in url_dict.items():
|
||||
new_data = replace_key(old_public_key,new_public_key,data,file_path)
|
||||
if new_data != data:
|
||||
data = new_data
|
||||
modified = True
|
||||
assert modified, f'{file_path} key not patched'
|
||||
with open(f'{file_path}_', 'wb') as f:
|
||||
f.write(data)
|
||||
if 'loader' in files and os.path.isfile(os.path.join(root, 'loader')):
|
||||
loader_file = os.path.join(root, 'loader')
|
||||
patch_loader(loader_file)
|
||||
|
||||
if 'BOOTX64.EFI' in files and os.path.isfile(os.path.join(root, 'BOOTX64.EFI')):
|
||||
efi_file = os.path.join(root, 'BOOTX64.EFI')
|
||||
with open(efi_file, 'rb') as f:
|
||||
data = f.read()
|
||||
new_data = patch_kernel(data,key_dict)
|
||||
assert new_data != data, f'{file_path} key not patched'
|
||||
with open(efi_file, 'wb') as f:
|
||||
f.write(new_data)
|
||||
|
||||
|
||||
for filename in files:
|
||||
if filename in ['mode','keyman','loader','BOOTX64.EFI']:
|
||||
continue
|
||||
file_path = os.path.join(root,filename)
|
||||
if not os.path.isfile(file_path):
|
||||
continue
|
||||
|
||||
modified = False
|
||||
with open(file_path, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
for old_public_key,new_public_key in key_dict.items():
|
||||
new_data = replace_key(old_public_key,new_public_key,data,file_path)
|
||||
if new_data != data:
|
||||
data = new_data
|
||||
modified = True
|
||||
|
||||
for old_url,new_url in url_replacements.items():
|
||||
if old_url in data:
|
||||
print(f'{file_path} url patched {old_url.decode()[:7]}...')
|
||||
data = data.replace(old_url,new_url)
|
||||
modified = True
|
||||
|
||||
if filename == 'licupgr':
|
||||
for old_url,new_url in renew_replacements.items():
|
||||
if old_url in data:
|
||||
print(f'{file} url patched {old_url.decode()[:7]}...')
|
||||
print(f'{file_path} url patched {old_url.decode()[:7]}...')
|
||||
data = data.replace(old_url,new_url)
|
||||
open(file,'wb').write(data)
|
||||
|
||||
if os.path.split(file)[1] == 'licupgr':
|
||||
url_dict = {
|
||||
os.environ['MIKRO_RENEW_URL'].encode():os.environ['CUSTOM_RENEW_URL'].encode(),
|
||||
}
|
||||
for old_url,new_url in url_dict.items():
|
||||
if old_url in data:
|
||||
print(f'{file} url patched {old_url.decode()[:7]}...')
|
||||
data = data.replace(old_url,new_url)
|
||||
open(file,'wb').write(data)
|
||||
modified = True
|
||||
|
||||
if modified:
|
||||
with open(file_path, 'wb') as f:
|
||||
f.write(data)
|
||||
|
||||
def run_shell_command(command):
|
||||
process = subprocess.run(command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
Reference in New Issue
Block a user